github.com/turingchain2020/turingchain@v1.1.21/types/tx.go (about)

     1  // Copyright Turing Corp. 2018 All Rights Reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package types
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/hex"
    10  	"encoding/json"
    11  	"reflect"
    12  	"sort"
    13  	"time"
    14  
    15  	lru "github.com/hashicorp/golang-lru"
    16  
    17  	"strconv"
    18  
    19  	"github.com/turingchain2020/turingchain/common"
    20  	"github.com/turingchain2020/turingchain/common/address"
    21  	"github.com/turingchain2020/turingchain/common/crypto"
    22  )
    23  
    24  var (
    25  	bCoins   = []byte("coins")
    26  	bToken   = []byte("token")
    27  	withdraw = "withdraw"
    28  	txCache  *lru.Cache
    29  )
    30  
    31  func init() {
    32  	var err error
    33  	txCache, err = lru.New(10240)
    34  	if err != nil {
    35  		panic(err)
    36  	}
    37  }
    38  
    39  //TxCacheGet 某些交易的cache 加入缓存中,防止重复进行解析或者计算
    40  func TxCacheGet(tx *Transaction) (*TransactionCache, bool) {
    41  	txc, ok := txCache.Get(tx)
    42  	if !ok {
    43  		return nil, ok
    44  	}
    45  	return txc.(*TransactionCache), ok
    46  }
    47  
    48  //TxCacheSet 设置 cache
    49  func TxCacheSet(tx *Transaction, txc *TransactionCache) {
    50  	if txc == nil {
    51  		txCache.Remove(tx)
    52  		return
    53  	}
    54  	txCache.Add(tx, txc)
    55  }
    56  
    57  // CreateTxGroup 创建组交易, feeRate传入交易费率, 建议通过系统GetProperFee获取
    58  func CreateTxGroup(txs []*Transaction, feeRate int64) (*Transactions, error) {
    59  	if len(txs) < 2 {
    60  		return nil, ErrTxGroupCountLessThanTwo
    61  	}
    62  	txgroup := &Transactions{}
    63  	txgroup.Txs = txs
    64  	totalfee := int64(0)
    65  	minfee := int64(0)
    66  	header := txs[0].Hash()
    67  	for i := len(txs) - 1; i >= 0; i-- {
    68  		txs[i].GroupCount = int32(len(txs))
    69  		totalfee += txs[i].GetFee()
    70  		// Header和Fee设置是为了GetRealFee里面Size的计算,Fee是否为0和不同大小,size也是有差别的,header是否为空差别是common.Sha256Len+2
    71  		// 这里直接设置Header兼容性更好, Next不需要,已经设置过了,唯一不同的是,txs[0].fee会跟实际计算有差别,这里设置一个超大值只做计算
    72  		txs[i].Header = header
    73  		if i == 0 {
    74  			//对txs[0].fee设置一个超大值,大于后面实际计算出的fee,也就>=check时候计算出的fee, 对size影响10个字节,在1000临界值时候有差别
    75  			txs[i].Fee = 1 << 62
    76  		} else {
    77  			txs[i].Fee = 0
    78  		}
    79  		realfee, err := txs[i].GetRealFee(feeRate)
    80  		if err != nil {
    81  			return nil, err
    82  		}
    83  		minfee += realfee
    84  		if i == 0 {
    85  			if totalfee < minfee {
    86  				totalfee = minfee
    87  			}
    88  			txs[0].Fee = totalfee
    89  			header = txs[0].Hash()
    90  		} else {
    91  			txs[i].Fee = 0
    92  			txs[i-1].Next = txs[i].Hash()
    93  		}
    94  	}
    95  	for i := 0; i < len(txs); i++ {
    96  		txs[i].Header = header
    97  	}
    98  	return txgroup, nil
    99  }
   100  
   101  //Tx 这比用于检查的交易,包含了所有的交易。
   102  //主要是为了兼容原来的设计
   103  func (txgroup *Transactions) Tx() *Transaction {
   104  	if len(txgroup.GetTxs()) < 2 {
   105  		return nil
   106  	}
   107  	headtx := txgroup.GetTxs()[0]
   108  	//不会影响原来的tx
   109  	copytx := *headtx
   110  	data := Encode(txgroup)
   111  	//放到header中不影响交易的Hash
   112  	copytx.Header = data
   113  	return &copytx
   114  }
   115  
   116  //GetTxGroup 获取交易组
   117  func (txgroup *Transactions) GetTxGroup() *Transactions {
   118  	return txgroup
   119  }
   120  
   121  //SignN 对交易组的第n笔交易签名
   122  func (txgroup *Transactions) SignN(n int, ty int32, priv crypto.PrivKey) error {
   123  	if n >= len(txgroup.GetTxs()) {
   124  		return ErrIndex
   125  	}
   126  	txgroup.GetTxs()[n].Sign(ty, priv)
   127  	return nil
   128  }
   129  
   130  //CheckSign 检测交易组的签名
   131  func (txgroup *Transactions) CheckSign() bool {
   132  	txs := txgroup.Txs
   133  	for i := 0; i < len(txs); i++ {
   134  		if !txs[i].checkSign() {
   135  			return false
   136  		}
   137  	}
   138  	return true
   139  }
   140  
   141  //RebuiltGroup 交易内容有变化时需要重新构建交易组
   142  func (txgroup *Transactions) RebuiltGroup() {
   143  	header := txgroup.Txs[0].Hash()
   144  	for i := len(txgroup.Txs) - 1; i >= 0; i-- {
   145  		txgroup.Txs[i].Header = header
   146  		if i == 0 {
   147  			header = txgroup.Txs[0].Hash()
   148  		} else {
   149  			txgroup.Txs[i-1].Next = txgroup.Txs[i].Hash()
   150  		}
   151  	}
   152  	for i := 0; i < len(txgroup.Txs); i++ {
   153  		txgroup.Txs[i].Header = header
   154  	}
   155  }
   156  
   157  //SetExpire 设置交易组中交易的过期时间
   158  func (txgroup *Transactions) SetExpire(cfg *TuringchainConfig, n int, expire time.Duration) {
   159  	if n >= len(txgroup.GetTxs()) {
   160  		return
   161  	}
   162  	txgroup.GetTxs()[n].SetExpire(cfg, expire)
   163  }
   164  
   165  //IsExpire 交易是否过期
   166  func (txgroup *Transactions) IsExpire(cfg *TuringchainConfig, height, blocktime int64) bool {
   167  	txs := txgroup.Txs
   168  	for i := 0; i < len(txs); i++ {
   169  		if txs[i].isExpire(cfg, height, blocktime) {
   170  			return true
   171  		}
   172  	}
   173  	return false
   174  }
   175  
   176  //CheckWithFork 和fork 无关的有个检查函数
   177  func (txgroup *Transactions) CheckWithFork(cfg *TuringchainConfig, checkFork, paraFork bool, height, minfee, maxFee int64) error {
   178  	txs := txgroup.Txs
   179  	if len(txs) < 2 {
   180  		return ErrTxGroupCountLessThanTwo
   181  	}
   182  	para := make(map[string]bool)
   183  	for i := 0; i < len(txs); i++ {
   184  		if txs[i] == nil {
   185  			return ErrTxGroupEmpty
   186  		}
   187  		err := txs[i].check(cfg, height, 0, maxFee)
   188  		if err != nil {
   189  			return err
   190  		}
   191  		if title, ok := GetParaExecTitleName(string(txs[i].Execer)); ok {
   192  			para[title] = true
   193  		}
   194  	}
   195  	//txgroup 只允许一条平行链的交易, 且平行链txgroup须全部是平行链tx
   196  	//如果平行链已经在主链分叉高度前运行了一段时间且有跨链交易,平行链需要自己设置这个fork
   197  	if paraFork {
   198  		if len(para) > 1 {
   199  			tlog.Info("txgroup has multi para transaction")
   200  			return ErrTxGroupParaCount
   201  		}
   202  		if len(para) > 0 {
   203  			for _, tx := range txs {
   204  				if !IsParaExecName(string(tx.Execer)) {
   205  					tlog.Error("para txgroup has main chain transaction")
   206  					return ErrTxGroupParaMainMixed
   207  				}
   208  			}
   209  		}
   210  	}
   211  
   212  	for i := 1; i < len(txs); i++ {
   213  		if txs[i].Fee != 0 {
   214  			return ErrTxGroupFeeNotZero
   215  		}
   216  	}
   217  	//检查txs[0] 的费用是否满足要求
   218  	totalfee := int64(0)
   219  	for i := 0; i < len(txs); i++ {
   220  		fee, err := txs[i].GetRealFee(minfee)
   221  		if err != nil {
   222  			return err
   223  		}
   224  		totalfee += fee
   225  	}
   226  	if txs[0].Fee < totalfee {
   227  		return ErrTxFeeTooLow
   228  	}
   229  	if txs[0].Fee > maxFee && maxFee > 0 && checkFork {
   230  		return ErrTxFeeTooHigh
   231  	}
   232  	//检查hash是否符合要求
   233  	for i := 0; i < len(txs); i++ {
   234  		//检查头部是否等于头部hash
   235  		if i == 0 {
   236  			if !bytes.Equal(txs[i].Hash(), txs[i].Header) {
   237  				return ErrTxGroupHeader
   238  			}
   239  		} else {
   240  			if !bytes.Equal(txs[0].Header, txs[i].Header) {
   241  				return ErrTxGroupHeader
   242  			}
   243  		}
   244  		//检查group count
   245  		if txs[i].GroupCount > MaxTxGroupSize {
   246  			return ErrTxGroupCountBigThanMaxSize
   247  		}
   248  		if txs[i].GroupCount != int32(len(txs)) {
   249  			return ErrTxGroupCount
   250  		}
   251  		//检查next
   252  		if i < len(txs)-1 {
   253  			if !bytes.Equal(txs[i].Next, txs[i+1].Hash()) {
   254  				return ErrTxGroupNext
   255  			}
   256  		} else {
   257  			if txs[i].Next != nil {
   258  				return ErrTxGroupNext
   259  			}
   260  		}
   261  	}
   262  	return nil
   263  }
   264  
   265  //Check height == 0 的时候,不做检查
   266  func (txgroup *Transactions) Check(cfg *TuringchainConfig, height, minfee, maxFee int64) error {
   267  	paraFork := cfg.IsFork(height, "ForkTxGroupPara")
   268  	checkFork := cfg.IsFork(height, "ForkBlockCheck")
   269  	return txgroup.CheckWithFork(cfg, checkFork, paraFork, height, minfee, maxFee)
   270  }
   271  
   272  //TransactionCache 交易缓存结构
   273  type TransactionCache struct {
   274  	*Transaction
   275  	txGroup *Transactions
   276  	hash    []byte
   277  	size    int
   278  	signok  int   //init 0, ok 1, err 2
   279  	checkok error //init 0, ok 1, err 2
   280  	checked bool
   281  	payload reflect.Value
   282  	plname  string
   283  	plerr   error
   284  }
   285  
   286  //NewTransactionCache new交易缓存
   287  func NewTransactionCache(tx *Transaction) *TransactionCache {
   288  	return &TransactionCache{Transaction: tx}
   289  }
   290  
   291  //Hash 交易hash
   292  func (tx *TransactionCache) Hash() []byte {
   293  	if tx.hash == nil {
   294  		tx.hash = tx.Transaction.Hash()
   295  	}
   296  	return tx.hash
   297  }
   298  
   299  //SetPayloadValue 设置payload 的cache
   300  func (tx *TransactionCache) SetPayloadValue(plname string, payload reflect.Value, plerr error) {
   301  	tx.payload = payload
   302  	tx.plerr = plerr
   303  	tx.plname = plname
   304  }
   305  
   306  //GetPayloadValue 设置payload 的cache
   307  func (tx *TransactionCache) GetPayloadValue() (plname string, payload reflect.Value, plerr error) {
   308  	if tx.plerr != nil || tx.plname != "" {
   309  		return tx.plname, tx.payload, tx.plerr
   310  	}
   311  	exec := LoadExecutorType(string(tx.Execer))
   312  	if exec == nil {
   313  		tx.SetPayloadValue("", reflect.ValueOf(nil), ErrExecNotFound)
   314  		return "", reflect.ValueOf(nil), ErrExecNotFound
   315  	}
   316  	plname, payload, plerr = exec.DecodePayloadValue(tx.Tx())
   317  	tx.SetPayloadValue(plname, payload, plerr)
   318  	return
   319  }
   320  
   321  //Size 交易缓存的大小
   322  func (tx *TransactionCache) Size() int {
   323  	if tx.size == 0 {
   324  		tx.size = Size(tx.Tx())
   325  	}
   326  	return tx.size
   327  }
   328  
   329  //Tx 交易缓存中tx信息
   330  func (tx *TransactionCache) Tx() *Transaction {
   331  	return tx.Transaction
   332  }
   333  
   334  //Check 交易缓存中交易组合费用的检测
   335  func (tx *TransactionCache) Check(cfg *TuringchainConfig, height, minfee, maxFee int64) error {
   336  	if !tx.checked {
   337  		tx.checked = true
   338  		txs, err := tx.GetTxGroup()
   339  		if err != nil {
   340  			tx.checkok = err
   341  			return err
   342  		}
   343  		if txs == nil {
   344  			tx.checkok = tx.check(cfg, height, minfee, maxFee)
   345  		} else {
   346  			tx.checkok = txs.Check(cfg, height, minfee, maxFee)
   347  		}
   348  	}
   349  	return tx.checkok
   350  }
   351  
   352  //GetTotalFee 获取交易真实费用
   353  func (tx *TransactionCache) GetTotalFee(minFee int64) (int64, error) {
   354  	txgroup, err := tx.GetTxGroup()
   355  	if err != nil {
   356  		tx.checkok = err
   357  		return 0, err
   358  	}
   359  	var totalfee int64
   360  	if txgroup == nil {
   361  		return tx.GetRealFee(minFee)
   362  	}
   363  	txs := txgroup.Txs
   364  	for i := 0; i < len(txs); i++ {
   365  		fee, err := txs[i].GetRealFee(minFee)
   366  		if err != nil {
   367  			return 0, err
   368  		}
   369  		totalfee += fee
   370  	}
   371  	return totalfee, nil
   372  }
   373  
   374  //GetTxGroup 获取交易组
   375  func (tx *TransactionCache) GetTxGroup() (*Transactions, error) {
   376  	var err error
   377  	if tx.txGroup == nil {
   378  		tx.txGroup, err = tx.Transaction.GetTxGroup()
   379  		if err != nil {
   380  			return nil, err
   381  		}
   382  	}
   383  	return tx.txGroup, nil
   384  }
   385  
   386  //CheckSign 检测签名
   387  func (tx *TransactionCache) CheckSign() bool {
   388  	if tx.signok == 0 {
   389  		tx.signok = 2
   390  		group, err := tx.GetTxGroup()
   391  		if err != nil {
   392  			return false
   393  		}
   394  		if group == nil {
   395  			//非group,简单校验签名
   396  			if ok := tx.checkSign(); ok {
   397  				tx.signok = 1
   398  			}
   399  		} else {
   400  			if ok := group.CheckSign(); ok {
   401  				tx.signok = 1
   402  			}
   403  		}
   404  	}
   405  	return tx.signok == 1
   406  }
   407  
   408  //TxsToCache 缓存交易信息
   409  func TxsToCache(txs []*Transaction) (caches []*TransactionCache) {
   410  	caches = make([]*TransactionCache, len(txs))
   411  	for i := 0; i < len(caches); i++ {
   412  		caches[i] = NewTransactionCache(txs[i])
   413  	}
   414  	return caches
   415  }
   416  
   417  //CacheToTxs 从缓存中获取交易信息
   418  func CacheToTxs(caches []*TransactionCache) (txs []*Transaction) {
   419  	txs = make([]*Transaction, len(caches))
   420  	for i := 0; i < len(caches); i++ {
   421  		txs[i] = caches[i].Tx()
   422  	}
   423  	return txs
   424  }
   425  
   426  //HashSign hash 不包含签名,用户通过修改签名无法重新发送交易
   427  func (tx *Transaction) HashSign() []byte {
   428  	copytx := *tx
   429  	copytx.Signature = nil
   430  	data := Encode(&copytx)
   431  	return common.Sha256(data)
   432  }
   433  
   434  //Tx 交易详情
   435  func (tx *Transaction) Tx() *Transaction {
   436  	return tx
   437  }
   438  
   439  //GetTxGroup 交易组装成交易组格式
   440  func (tx *Transaction) GetTxGroup() (*Transactions, error) {
   441  	if tx.GroupCount < 0 || tx.GroupCount == 1 || tx.GroupCount > 20 {
   442  		return nil, ErrTxGroupCount
   443  	}
   444  	if tx.GroupCount > 0 {
   445  		var txs Transactions
   446  		err := Decode(tx.Header, &txs)
   447  		if err != nil {
   448  			return nil, err
   449  		}
   450  		return &txs, nil
   451  	}
   452  	if tx.Next != nil || tx.Header != nil {
   453  		return nil, ErrNomalTx
   454  	}
   455  	return nil, nil
   456  }
   457  
   458  //Size 交易大小
   459  func (tx *Transaction) Size() int {
   460  	return Size(tx)
   461  }
   462  
   463  //Sign 交易签名
   464  func (tx *Transaction) Sign(ty int32, priv crypto.PrivKey) {
   465  	tx.Signature = nil
   466  	data := Encode(tx)
   467  	pub := priv.PubKey()
   468  	sign := priv.Sign(data)
   469  	tx.Signature = &Signature{
   470  		Ty:        ty,
   471  		Pubkey:    pub.Bytes(),
   472  		Signature: sign.Bytes(),
   473  	}
   474  }
   475  
   476  //CheckSign tx 有些时候是一个交易组
   477  func (tx *Transaction) CheckSign() bool {
   478  	return tx.checkSign()
   479  }
   480  
   481  //txgroup 的情况
   482  func (tx *Transaction) checkSign() bool {
   483  	copytx := *tx
   484  	copytx.Signature = nil
   485  	data := Encode(&copytx)
   486  	if tx.GetSignature() == nil {
   487  		return false
   488  	}
   489  	return CheckSign(data, string(tx.Execer), tx.GetSignature())
   490  }
   491  
   492  //Check 交易检测
   493  func (tx *Transaction) Check(cfg *TuringchainConfig, height, minfee, maxFee int64) error {
   494  	group, err := tx.GetTxGroup()
   495  	if err != nil {
   496  		return err
   497  	}
   498  	if group == nil {
   499  		return tx.check(cfg, height, minfee, maxFee)
   500  	}
   501  	return group.Check(cfg, height, minfee, maxFee)
   502  }
   503  
   504  func (tx *Transaction) check(cfg *TuringchainConfig, height, minfee, maxFee int64) error {
   505  	if minfee == 0 {
   506  		return nil
   507  	}
   508  	// 获取当前交易最小交易费
   509  	realFee, err := tx.GetRealFee(minfee)
   510  	if err != nil {
   511  		return err
   512  	}
   513  	// 检查交易费是否小于最低值
   514  	if tx.Fee < realFee {
   515  		return ErrTxFeeTooLow
   516  	}
   517  	if tx.Fee > maxFee && maxFee > 0 && cfg.IsFork(height, "ForkBlockCheck") {
   518  		return ErrTxFeeTooHigh
   519  	}
   520  	return nil
   521  }
   522  
   523  //SetExpire 设置交易过期时间
   524  func (tx *Transaction) SetExpire(cfg *TuringchainConfig, expire time.Duration) {
   525  	//Txheight处理
   526  	if cfg.IsEnable("TxHeight") && int64(expire) > TxHeightFlag {
   527  		tx.Expire = int64(expire)
   528  		return
   529  	}
   530  
   531  	if int64(expire) > ExpireBound {
   532  		if expire < time.Second*120 {
   533  			expire = time.Second * 120
   534  		}
   535  		//用秒数来表示的时间
   536  		tx.Expire = Now().Unix() + int64(expire/time.Second)
   537  	} else {
   538  		tx.Expire = int64(expire)
   539  	}
   540  }
   541  
   542  //GetRealFee 获取交易真实费用
   543  func (tx *Transaction) GetRealFee(minFee int64) (int64, error) {
   544  	txSize := Size(tx)
   545  	//如果签名为空,那么加上签名的空间
   546  	if tx.Signature == nil {
   547  		txSize += 300
   548  	}
   549  	if txSize > MaxTxSize {
   550  		return 0, ErrTxMsgSizeTooBig
   551  	}
   552  	// 检查交易费是否小于最低值
   553  	realFee := int64(txSize/1000+1) * minFee
   554  	return realFee, nil
   555  }
   556  
   557  //SetRealFee 设置交易真实费用
   558  func (tx *Transaction) SetRealFee(minFee int64) error {
   559  	if tx.Fee == 0 {
   560  		fee, err := tx.GetRealFee(minFee)
   561  		if err != nil {
   562  			return err
   563  		}
   564  		tx.Fee = fee
   565  	}
   566  	return nil
   567  }
   568  
   569  //ExpireBound 交易过期边界值
   570  var ExpireBound int64 = 1000000000 // 交易过期分界线,小于expireBound比较height,大于expireBound比较blockTime
   571  
   572  //IsExpire 交易是否过期
   573  func (tx *Transaction) IsExpire(cfg *TuringchainConfig, height, blocktime int64) bool {
   574  	group, _ := tx.GetTxGroup()
   575  	if group == nil {
   576  		return tx.isExpire(cfg, height, blocktime)
   577  	}
   578  	return group.IsExpire(cfg, height, blocktime)
   579  }
   580  
   581  //GetTxFee 获取交易的费用,区分单笔交易和交易组
   582  func (tx *Transaction) GetTxFee() int64 {
   583  	group, _ := tx.GetTxGroup()
   584  	if group == nil {
   585  		return tx.Fee
   586  	}
   587  	return group.Txs[0].Fee
   588  }
   589  
   590  //From 交易from地址
   591  func (tx *Transaction) From() string {
   592  	return address.PubKeyToAddr(tx.GetSignature().GetPubkey())
   593  }
   594  
   595  //检查交易是否过期,过期返回true,未过期返回false
   596  func (tx *Transaction) isExpire(cfg *TuringchainConfig, height, blocktime int64) bool {
   597  	valid := tx.Expire
   598  	// Expire为0,返回false
   599  	if valid == 0 {
   600  		return false
   601  	}
   602  	if valid <= ExpireBound {
   603  		//Expire小于1e9,为height valid > height 未过期返回false else true过期
   604  		return valid <= height
   605  	}
   606  	//EnableTxHeight 选项开启, 并且符合条件
   607  	if txHeight := GetTxHeight(cfg, valid, height); txHeight > 0 {
   608  		if txHeight-LowAllowPackHeight <= height && height <= txHeight+HighAllowPackHeight {
   609  			return false
   610  		}
   611  		return true
   612  	}
   613  	// Expire大于1e9,为blockTime  valid > blocktime返回false 未过期 else true过期
   614  	return valid <= blocktime
   615  }
   616  
   617  //GetTxHeight 获取交易高度
   618  func GetTxHeight(cfg *TuringchainConfig, valid int64, height int64) int64 {
   619  	if cfg.IsPara() {
   620  		return -1
   621  	}
   622  	if cfg.IsEnableFork(height, "ForkTxHeight", cfg.IsEnable("TxHeight")) && valid > TxHeightFlag {
   623  		return valid - TxHeightFlag
   624  	}
   625  	return -1
   626  }
   627  
   628  //JSON Transaction交易信息转成json结构体
   629  func (tx *Transaction) JSON() string {
   630  	type transaction struct {
   631  		Hash      string     `json:"hash,omitempty"`
   632  		Execer    string     `json:"execer,omitempty"`
   633  		Payload   string     `json:"payload,omitempty"`
   634  		Signature *Signature `json:"signature,omitempty"`
   635  		Fee       int64      `json:"fee,omitempty"`
   636  		Expire    int64      `json:"expire,omitempty"`
   637  		// 随机ID,可以防止payload 相同的时候,交易重复
   638  		Nonce int64 `json:"nonce,omitempty"`
   639  		// 对方地址,如果没有对方地址,可以为空
   640  		To         string `json:"to,omitempty"`
   641  		GroupCount int32  `json:"groupCount,omitempty"`
   642  		Header     string `json:"header,omitempty"`
   643  		Next       string `json:"next,omitempty"`
   644  		ChainID    int32  `json:"chainID,omitempty"`
   645  	}
   646  
   647  	newtx := &transaction{}
   648  	newtx.Hash = hex.EncodeToString(tx.Hash())
   649  	newtx.Execer = string(tx.Execer)
   650  	newtx.Payload = hex.EncodeToString(tx.Payload)
   651  	newtx.Signature = tx.Signature
   652  	newtx.Fee = tx.Fee
   653  	newtx.Expire = tx.Expire
   654  	newtx.Nonce = tx.Nonce
   655  	newtx.To = tx.To
   656  	newtx.GroupCount = tx.GroupCount
   657  	newtx.Header = hex.EncodeToString(tx.Header)
   658  	newtx.Next = hex.EncodeToString(tx.Next)
   659  	newtx.ChainID = tx.ChainID
   660  
   661  	data, err := json.MarshalIndent(newtx, "", "\t")
   662  	if err != nil {
   663  		return err.Error()
   664  	}
   665  	return string(data)
   666  }
   667  
   668  //Amount 解析tx的payload获取amount值
   669  func (tx *Transaction) Amount() (int64, error) {
   670  	// TODO 原来有很多执行器 在这里没有代码, 用默认 0, nil 先
   671  	exec := LoadExecutorType(string(tx.Execer))
   672  	if exec == nil {
   673  		return 0, nil
   674  	}
   675  	return exec.Amount(tx)
   676  }
   677  
   678  //Assets  获取交易中的资产
   679  func (tx *Transaction) Assets() ([]*Asset, error) {
   680  	exec := LoadExecutorType(string(tx.Execer))
   681  	if exec == nil {
   682  		return nil, nil
   683  	}
   684  	return exec.GetAssets(tx)
   685  }
   686  
   687  //GetRealToAddr 解析tx的payload获取real to值
   688  func (tx *Transaction) GetRealToAddr() string {
   689  	exec := LoadExecutorType(string(tx.Execer))
   690  	if exec == nil {
   691  		return tx.To
   692  	}
   693  	return exec.GetRealToAddr(tx)
   694  }
   695  
   696  //GetViewFromToAddr 解析tx的payload获取view from to 值
   697  func (tx *Transaction) GetViewFromToAddr() (string, string) {
   698  	exec := LoadExecutorType(string(tx.Execer))
   699  	if exec == nil {
   700  		return tx.From(), tx.To
   701  	}
   702  	return exec.GetViewFromToAddr(tx)
   703  }
   704  
   705  //ActionName 获取tx交易的Actionname
   706  func (tx *Transaction) ActionName() string {
   707  	execName := string(tx.Execer)
   708  	exec := LoadExecutorType(execName)
   709  	if exec == nil {
   710  		//action name 不会影响系统状态,主要是做显示使用
   711  		realname := GetRealExecName(tx.Execer)
   712  		exec = LoadExecutorType(string(realname))
   713  		if exec == nil {
   714  			return "unknown"
   715  		}
   716  	}
   717  	return exec.ActionName(tx)
   718  }
   719  
   720  //IsWithdraw 判断交易是withdraw交易,需要做from和to地址的swap,方便上层客户理解
   721  func (tx *Transaction) IsWithdraw() bool {
   722  	if bytes.Equal(tx.GetExecer(), bCoins) || bytes.Equal(tx.GetExecer(), bToken) {
   723  		if tx.ActionName() == withdraw {
   724  			return true
   725  		}
   726  	}
   727  	return false
   728  }
   729  
   730  // ParseExpire parse expire to int from during or height
   731  func ParseExpire(expire string) (int64, error) {
   732  	if len(expire) == 0 {
   733  		return 0, ErrInvalidParam
   734  	}
   735  	if expire[0] == 'H' && expire[1] == ':' {
   736  		txHeight, err := strconv.ParseInt(expire[2:], 10, 64)
   737  		if err != nil {
   738  			return 0, err
   739  		}
   740  		if txHeight <= 0 {
   741  			//fmt.Printf("txHeight should be grate to 0")
   742  			return 0, ErrHeightLessZero
   743  		}
   744  		if txHeight+TxHeightFlag < txHeight {
   745  			return 0, ErrHeightOverflow
   746  		}
   747  
   748  		return txHeight + TxHeightFlag, nil
   749  	}
   750  
   751  	blockHeight, err := strconv.ParseInt(expire, 10, 64)
   752  	if err == nil {
   753  		return blockHeight, nil
   754  	}
   755  
   756  	expireTime, err := time.ParseDuration(expire)
   757  	if err == nil {
   758  		return int64(expireTime), nil
   759  	}
   760  
   761  	return 0, err
   762  }
   763  
   764  //CalcTxShortHash 取txhash的前指定字节,目前默认5
   765  func CalcTxShortHash(hash []byte) string {
   766  	if len(hash) >= 5 {
   767  		return hex.EncodeToString(hash[0:5])
   768  	}
   769  	return ""
   770  }
   771  
   772  //TransactionSort 对主链以及平行链交易分类
   773  //构造一个map用于临时存储各个子链的交易, 按照title分类,主链交易的title设置成main
   774  //并对map按照title进行排序,不然每次遍历map顺序会不一致
   775  func TransactionSort(rawtxs []*Transaction) []*Transaction {
   776  	txMap := make(map[string]*Transactions)
   777  
   778  	for _, tx := range rawtxs {
   779  		title, isPara := GetParaExecTitleName(string(tx.Execer))
   780  		if !isPara {
   781  			title = MainChainName
   782  		}
   783  		if txMap[title] != nil {
   784  			txMap[title].Txs = append(txMap[title].Txs, tx)
   785  		} else {
   786  			var temptxs Transactions
   787  			temptxs.Txs = append(temptxs.Txs, tx)
   788  			txMap[title] = &temptxs
   789  		}
   790  	}
   791  
   792  	//需要按照title排序,不然每次遍历的map的顺序会不一致
   793  	var newMp = make([]string, 0)
   794  	for k := range txMap {
   795  		newMp = append(newMp, k)
   796  	}
   797  	sort.Strings(newMp)
   798  
   799  	var txs Transactions
   800  	for _, v := range newMp {
   801  		txs.Txs = append(txs.Txs, txMap[v].GetTxs()...)
   802  	}
   803  	return txs.GetTxs()
   804  }
   805  
   806  //Hash 交易的hash不包含header的值,引入tx group的概念后,做了修改
   807  func (tx *Transaction) Hash() []byte {
   808  	copytx := cloneTx(tx)
   809  	copytx.Signature = nil
   810  	copytx.Header = nil
   811  	data := Encode(copytx)
   812  	return common.Sha256(data)
   813  }
   814  
   815  //FullHash 交易的fullhash包含交易的签名信息
   816  func (tx *Transaction) FullHash() []byte {
   817  	copytx := tx.Clone()
   818  	data := Encode(copytx)
   819  	return common.Sha256(data)
   820  }
   821  
   822  //TxGroup 交易组的接口,Transactions 和 Transaction 都符合这个接口
   823  type TxGroup interface {
   824  	Tx() *Transaction
   825  	GetTxGroup() (*Transactions, error)
   826  	CheckSign() bool
   827  }
   828  
   829  //这里要避免用 tmp := *tx 这样就会读 可能被 proto 其他线程修改的 size 字段
   830  //proto buffer 字段发生更改之后,一定要修改这里,否则可能引起严重的bug
   831  func cloneTx(tx *Transaction) *Transaction {
   832  	copytx := &Transaction{}
   833  	copytx.Execer = tx.Execer
   834  	copytx.Payload = tx.Payload
   835  	copytx.Signature = tx.Signature
   836  	copytx.Fee = tx.Fee
   837  	copytx.Expire = tx.Expire
   838  	copytx.Nonce = tx.Nonce
   839  	copytx.To = tx.To
   840  	copytx.GroupCount = tx.GroupCount
   841  	copytx.Header = tx.Header
   842  	copytx.Next = tx.Next
   843  	copytx.ChainID = tx.ChainID
   844  	return copytx
   845  }
   846  
   847  //Clone copytx := proto.Clone(tx).(*Transaction) too slow
   848  func (tx *Transaction) Clone() *Transaction {
   849  	if tx == nil {
   850  		return nil
   851  	}
   852  	tmp := cloneTx(tx)
   853  	tmp.Signature = tx.Signature.Clone()
   854  	return tmp
   855  }
   856  
   857  //cloneTxs  拷贝 txs
   858  func cloneTxs(b []*Transaction) []*Transaction {
   859  	if b == nil {
   860  		return nil
   861  	}
   862  	txs := make([]*Transaction, len(b))
   863  	for i := 0; i < len(b); i++ {
   864  		txs[i] = b[i].Clone()
   865  	}
   866  	return txs
   867  }