github.com/turingchain2020/turingchain@v1.1.21/system/mempool/check.go (about)

     1  package mempool
     2  
     3  import (
     4  	"errors"
     5  	"time"
     6  
     7  	"github.com/turingchain2020/turingchain/common"
     8  
     9  	"github.com/turingchain2020/turingchain/util"
    10  
    11  	"github.com/turingchain2020/turingchain/common/address"
    12  	"github.com/turingchain2020/turingchain/queue"
    13  	"github.com/turingchain2020/turingchain/types"
    14  )
    15  
    16  // CheckExpireValid 检查交易过期有效性,过期返回false,未过期返回true
    17  func (mem *Mempool) CheckExpireValid(msg *queue.Message) (bool, error) {
    18  	mem.proxyMtx.Lock()
    19  	defer mem.proxyMtx.Unlock()
    20  	if mem.header == nil {
    21  		return false, types.ErrHeaderNotSet
    22  	}
    23  	tx := msg.GetData().(types.TxGroup).Tx()
    24  	ok := mem.checkExpireValid(tx)
    25  	if !ok {
    26  		return ok, types.ErrTxExpire
    27  	}
    28  	return ok, nil
    29  }
    30  
    31  // checkTxListRemote 发送消息给执行模块检查交易
    32  func (mem *Mempool) checkTxListRemote(txlist *types.ExecTxList) (*types.ReceiptCheckTxList, error) {
    33  	if mem.client == nil {
    34  		panic("client not bind message queue.")
    35  	}
    36  	msg := mem.client.NewMessage("execs", types.EventCheckTx, txlist)
    37  	err := mem.client.Send(msg, true)
    38  	if err != nil {
    39  		mlog.Error("execs closed", "err", err.Error())
    40  		return nil, err
    41  	}
    42  	reply, err := mem.client.Wait(msg)
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  	txList := reply.GetData().(*types.ReceiptCheckTxList)
    47  	mem.client.FreeMessage(msg, reply)
    48  	return txList, nil
    49  }
    50  
    51  func (mem *Mempool) checkExpireValid(tx *types.Transaction) bool {
    52  	types.AssertConfig(mem.client)
    53  	//进入mempool中的交易可能被下一个区块打包,这里用下一个区块的高度和时间作为交易过期判定
    54  	if tx.IsExpire(mem.client.GetConfig(), mem.header.GetHeight()+1, mem.header.GetBlockTime()) {
    55  		return false
    56  	}
    57  	if tx.Expire > 1000000000 && tx.Expire < types.Now().Unix()+int64(time.Minute/time.Second) {
    58  		return false
    59  	}
    60  	return true
    61  }
    62  
    63  // CheckTx 初步检查并筛选交易消息
    64  func (mem *Mempool) checkTx(msg *queue.Message) *queue.Message {
    65  	tx := msg.GetData().(types.TxGroup).Tx()
    66  	// 检查接收地址是否合法
    67  	if err := address.CheckAddress(tx.To); err != nil {
    68  		msg.Data = types.ErrInvalidAddress
    69  		return msg
    70  	}
    71  	// 检查交易账户在mempool中是否存在过多交易
    72  	from := tx.From()
    73  	if mem.TxNumOfAccount(from) >= mem.cfg.MaxTxNumPerAccount {
    74  		msg.Data = types.ErrManyTx
    75  		return msg
    76  	}
    77  	// 检查交易是否过期
    78  	valid, err := mem.CheckExpireValid(msg)
    79  	if !valid {
    80  		msg.Data = err
    81  		return msg
    82  	}
    83  	return msg
    84  }
    85  
    86  // CheckTxs 初步检查并筛选交易消息
    87  func (mem *Mempool) checkTxs(msg *queue.Message) *queue.Message {
    88  	// 判断消息是否含有nil交易
    89  	if msg.GetData() == nil {
    90  		msg.Data = types.ErrEmptyTx
    91  		return msg
    92  	}
    93  	header := mem.GetHeader()
    94  	txmsg := msg.GetData().(*types.Transaction)
    95  	//普通的交易
    96  	tx := types.NewTransactionCache(txmsg)
    97  	types.AssertConfig(mem.client)
    98  	err := tx.Check(mem.client.GetConfig(), header.GetHeight(), mem.cfg.MinTxFeeRate, mem.cfg.MaxTxFee)
    99  	if err != nil {
   100  		msg.Data = err
   101  		return msg
   102  	}
   103  	if mem.cfg.IsLevelFee {
   104  		err = mem.checkLevelFee(tx)
   105  		if err != nil {
   106  			msg.Data = err
   107  			return msg
   108  		}
   109  	}
   110  	//放在交易费检查后面进行 哈希缓存设置,避免哈希缓存改变原始交易size
   111  	//txmsg.ReCalcCacheHash()
   112  	//检查txgroup 中的每个交易
   113  	txs, err := tx.GetTxGroup()
   114  	if err != nil {
   115  		msg.Data = err
   116  		return msg
   117  	}
   118  	msg.Data = tx
   119  	//普通交易
   120  	if txs == nil {
   121  		return mem.checkTx(msg)
   122  	}
   123  	//txgroup 的交易
   124  	for i := 0; i < len(txs.Txs); i++ {
   125  		msgitem := mem.checkTx(&queue.Message{Data: txs.Txs[i]})
   126  		if msgitem.Err() != nil {
   127  			msg.Data = msgitem.Err()
   128  			return msg
   129  		}
   130  	}
   131  	return msg
   132  }
   133  
   134  // checkLevelFee 检查阶梯手续费
   135  func (mem *Mempool) checkLevelFee(tx *types.TransactionCache) error {
   136  	//获取mempool里所有交易手续费总和
   137  	feeRate := mem.getLevelFeeRate(mem.cfg.MinTxFeeRate, 0, 0)
   138  	totalfee, err := tx.GetTotalFee(feeRate)
   139  	if err != nil {
   140  		return err
   141  	}
   142  	if tx.Fee < totalfee {
   143  		return types.ErrTxFeeTooLow
   144  	}
   145  	return nil
   146  }
   147  
   148  //checkTxRemote 检查账户余额是否足够,并加入到Mempool,成功则传入goodChan,若加入Mempool失败则传入badChan
   149  func (mem *Mempool) checkTxRemote(msg *queue.Message) *queue.Message {
   150  	tx := msg.GetData().(types.TxGroup)
   151  	lastheader := mem.GetHeader()
   152  
   153  	//add check dup tx需要区分单笔交易/交易组
   154  	temtxlist := &types.ExecTxList{}
   155  	txGroup, err := tx.GetTxGroup()
   156  	if err != nil {
   157  		msg.Data = err
   158  		return msg
   159  	}
   160  	if txGroup == nil {
   161  		temtxlist.Txs = append(temtxlist.Txs, tx.Tx())
   162  	} else {
   163  		temtxlist.Txs = append(temtxlist.Txs, txGroup.GetTxs()...)
   164  	}
   165  	temtxlist.Height = lastheader.Height
   166  	newtxs, err := util.CheckDupTx(mem.client, temtxlist.Txs, temtxlist.Height)
   167  	if err != nil {
   168  		msg.Data = err
   169  		return msg
   170  	}
   171  	if len(newtxs) != len(temtxlist.Txs) {
   172  		msg.Data = types.ErrDupTx
   173  		return msg
   174  	}
   175  
   176  	//exec模块检查效率影响系统性能, 支持关闭
   177  	if !mem.cfg.DisableExecCheck {
   178  		txlist := &types.ExecTxList{}
   179  		txlist.Txs = append(txlist.Txs, tx.Tx())
   180  		txlist.BlockTime = lastheader.BlockTime
   181  		txlist.Height = lastheader.Height
   182  		txlist.StateHash = lastheader.StateHash
   183  		// 增加这个属性,在执行器中会使用到
   184  		txlist.Difficulty = uint64(lastheader.Difficulty)
   185  		txlist.IsMempool = true
   186  
   187  		result, err := mem.checkTxListRemote(txlist)
   188  
   189  		if err == nil && result.Errs[0] != "" {
   190  			err = errors.New(result.Errs[0])
   191  		}
   192  		if err != nil {
   193  			mlog.Error("checkTxRemote", "txHash", common.ToHex(tx.Tx().Hash()), "checkTxListRemoteErr", err)
   194  			msg.Data = err
   195  			return msg
   196  		}
   197  	}
   198  
   199  	err = mem.PushTx(tx.Tx())
   200  	if err != nil {
   201  		mlog.Error("checkTxRemote", "push err", err)
   202  		msg.Data = err
   203  	}
   204  	return msg
   205  }