github.com/turingchain2020/turingchain@v1.1.21/system/mempool/base.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 mempool
     6  
     7  import (
     8  	"sync"
     9  	"sync/atomic"
    10  	"time"
    11  
    12  	"github.com/turingchain2020/turingchain/common"
    13  	log "github.com/turingchain2020/turingchain/common/log/log15"
    14  	"github.com/turingchain2020/turingchain/queue"
    15  	"github.com/turingchain2020/turingchain/types"
    16  )
    17  
    18  var mlog = log.New("module", "mempool.base")
    19  
    20  //Mempool mempool 基础类
    21  type Mempool struct {
    22  	proxyMtx          sync.Mutex
    23  	in                chan *queue.Message
    24  	out               <-chan *queue.Message
    25  	client            queue.Client
    26  	header            *types.Header
    27  	sync              bool
    28  	cfg               *types.Mempool
    29  	poolHeader        chan struct{}
    30  	isclose           int32
    31  	wg                sync.WaitGroup
    32  	done              chan struct{}
    33  	removeBlockTicket *time.Ticker
    34  	cache             *txCache
    35  }
    36  
    37  //GetSync 判断是否mempool 同步
    38  func (mem *Mempool) getSync() bool {
    39  	mem.proxyMtx.Lock()
    40  	defer mem.proxyMtx.Unlock()
    41  	return mem.sync
    42  }
    43  
    44  //NewMempool 新建mempool 实例
    45  func NewMempool(cfg *types.Mempool) *Mempool {
    46  	pool := &Mempool{}
    47  	if cfg.MaxTxNumPerAccount == 0 {
    48  		cfg.MaxTxNumPerAccount = maxTxNumPerAccount
    49  	}
    50  	if cfg.MaxTxLast == 0 {
    51  		cfg.MaxTxLast = maxTxLast
    52  	}
    53  	if cfg.PoolCacheSize == 0 {
    54  		cfg.PoolCacheSize = poolCacheSize
    55  	}
    56  	pool.in = make(chan *queue.Message)
    57  	pool.out = make(<-chan *queue.Message)
    58  	pool.done = make(chan struct{})
    59  	pool.cfg = cfg
    60  	pool.poolHeader = make(chan struct{}, 2)
    61  	pool.removeBlockTicket = time.NewTicker(time.Minute)
    62  	pool.cache = newCache(cfg.MaxTxNumPerAccount, cfg.MaxTxLast, cfg.PoolCacheSize)
    63  	return pool
    64  }
    65  
    66  //Close 关闭mempool
    67  func (mem *Mempool) Close() {
    68  	if mem.isClose() {
    69  		return
    70  	}
    71  	atomic.StoreInt32(&mem.isclose, 1)
    72  	close(mem.done)
    73  	if mem.client != nil {
    74  		mem.client.Close()
    75  	}
    76  	mem.removeBlockTicket.Stop()
    77  	mlog.Info("mempool module closing")
    78  	mem.wg.Wait()
    79  	mlog.Info("mempool module closed")
    80  }
    81  
    82  //SetQueueClient 初始化mempool模块
    83  func (mem *Mempool) SetQueueClient(client queue.Client) {
    84  	mem.client = client
    85  	mem.client.Sub("mempool")
    86  	mem.wg.Add(1)
    87  	go mem.pollLastHeader()
    88  	mem.wg.Add(1)
    89  	go mem.checkSync()
    90  	mem.wg.Add(1)
    91  	go mem.removeBlockedTxs()
    92  
    93  	mem.wg.Add(1)
    94  	go mem.eventProcess()
    95  }
    96  
    97  // Size 返回mempool中txCache大小
    98  func (mem *Mempool) Size() int {
    99  	mem.proxyMtx.Lock()
   100  	defer mem.proxyMtx.Unlock()
   101  	return mem.cache.Size()
   102  }
   103  
   104  // SetMinFee 设置最小交易费用
   105  func (mem *Mempool) SetMinFee(fee int64) {
   106  	mem.proxyMtx.Lock()
   107  	mem.cfg.MinTxFeeRate = fee
   108  	mem.proxyMtx.Unlock()
   109  }
   110  
   111  //SetQueueCache 设置排队策略
   112  func (mem *Mempool) SetQueueCache(qcache QueueCache) {
   113  	mem.cache.SetQueueCache(qcache)
   114  }
   115  
   116  // GetTxList 从txCache中返回给定数目的tx
   117  func (mem *Mempool) getTxList(filterList *types.TxHashList) (txs []*types.Transaction) {
   118  	mem.proxyMtx.Lock()
   119  	defer mem.proxyMtx.Unlock()
   120  	count := filterList.GetCount()
   121  	dupMap := make(map[string]bool)
   122  	for i := 0; i < len(filterList.GetHashes()); i++ {
   123  		dupMap[string(filterList.GetHashes()[i])] = true
   124  	}
   125  	return mem.filterTxList(count, dupMap, false)
   126  }
   127  
   128  func (mem *Mempool) filterTxList(count int64, dupMap map[string]bool, isAll bool) (txs []*types.Transaction) {
   129  	//mempool中的交易都是未打包的,需要用下一个区块的高度和时间作为交易过期判定
   130  	height := mem.header.GetHeight() + 1
   131  	blockTime := mem.header.GetBlockTime()
   132  	types.AssertConfig(mem.client)
   133  	cfg := mem.client.GetConfig()
   134  	//由于mempool可能存在过期交易,先遍历所有,满足目标交易数再退出,否则存在无法获取到实际交易情况
   135  	mem.cache.Walk(0, func(tx *Item) bool {
   136  		if len(dupMap) > 0 {
   137  			if _, ok := dupMap[string(tx.Value.Hash())]; ok {
   138  				return true
   139  			}
   140  		}
   141  		if isExpired(cfg, tx, height, blockTime) && !isAll {
   142  			return true
   143  		}
   144  		txs = append(txs, tx.Value)
   145  		//达到设定的交易数,退出循环, count为0获取所有
   146  		if count > 0 && len(txs) == int(count) {
   147  			return false
   148  		}
   149  		return true
   150  	})
   151  	return txs
   152  }
   153  
   154  // RemoveTxs 从mempool中删除给定Hash的txs
   155  func (mem *Mempool) RemoveTxs(hashList *types.TxHashList) error {
   156  	mem.proxyMtx.Lock()
   157  	defer mem.proxyMtx.Unlock()
   158  	mem.removeTxs(hashList.Hashes)
   159  	return nil
   160  }
   161  
   162  func (mem *Mempool) removeTxs(hashes [][]byte) {
   163  
   164  	for _, hash := range hashes {
   165  		exist := mem.cache.Exist(string(hash))
   166  		if exist {
   167  			mem.cache.Remove(string(hash))
   168  		}
   169  	}
   170  }
   171  
   172  // PushTx 将交易推入mempool,并返回结果(error)
   173  func (mem *Mempool) PushTx(tx *types.Transaction) error {
   174  	mem.proxyMtx.Lock()
   175  	defer mem.proxyMtx.Unlock()
   176  	err := mem.cache.Push(tx)
   177  	return err
   178  }
   179  
   180  //  setHeader设置mempool.header
   181  func (mem *Mempool) setHeader(h *types.Header) {
   182  	mem.proxyMtx.Lock()
   183  	mem.header = h
   184  	mem.proxyMtx.Unlock()
   185  }
   186  
   187  // GetHeader 获取Mempool.header
   188  func (mem *Mempool) GetHeader() *types.Header {
   189  	mem.proxyMtx.Lock()
   190  	defer mem.proxyMtx.Unlock()
   191  	return mem.header
   192  }
   193  
   194  //IsClose 判断是否mempool 关闭
   195  func (mem *Mempool) isClose() bool {
   196  	return atomic.LoadInt32(&mem.isclose) == 1
   197  }
   198  
   199  // GetLastHeader 获取LastHeader的height和blockTime
   200  func (mem *Mempool) GetLastHeader() (interface{}, error) {
   201  	if mem.client == nil {
   202  		panic("client not bind message queue.")
   203  	}
   204  	msg := mem.client.NewMessage("blockchain", types.EventGetLastHeader, nil)
   205  	err := mem.client.Send(msg, true)
   206  	if err != nil {
   207  		mlog.Error("blockchain closed", "err", err.Error())
   208  		return nil, err
   209  	}
   210  	return mem.client.Wait(msg)
   211  }
   212  
   213  // GetAccTxs 用来获取对应账户地址(列表)中的全部交易详细信息
   214  func (mem *Mempool) GetAccTxs(addrs *types.ReqAddrs) *types.TransactionDetails {
   215  	mem.proxyMtx.Lock()
   216  	defer mem.proxyMtx.Unlock()
   217  	return mem.cache.GetAccTxs(addrs)
   218  }
   219  
   220  // TxNumOfAccount 返回账户在mempool中交易数量
   221  func (mem *Mempool) TxNumOfAccount(addr string) int64 {
   222  	mem.proxyMtx.Lock()
   223  	defer mem.proxyMtx.Unlock()
   224  	return int64(mem.cache.TxNumOfAccount(addr))
   225  }
   226  
   227  // GetLatestTx 返回最新十条加入到mempool的交易
   228  func (mem *Mempool) GetLatestTx() []*types.Transaction {
   229  	mem.proxyMtx.Lock()
   230  	defer mem.proxyMtx.Unlock()
   231  	return mem.cache.GetLatestTx()
   232  }
   233  
   234  // GetTotalCacheBytes 获取缓存交易的总占用空间
   235  func (mem *Mempool) GetTotalCacheBytes() int64 {
   236  	mem.proxyMtx.Lock()
   237  	defer mem.proxyMtx.Unlock()
   238  	return mem.cache.qcache.GetCacheBytes()
   239  }
   240  
   241  // pollLastHeader 在初始化后循环获取LastHeader,直到获取成功后,返回
   242  func (mem *Mempool) pollLastHeader() {
   243  	defer mem.wg.Done()
   244  	defer func() {
   245  		mlog.Info("pollLastHeader quit")
   246  		mem.poolHeader <- struct{}{}
   247  	}()
   248  	for {
   249  		if mem.isClose() {
   250  			return
   251  		}
   252  		lastHeader, err := mem.GetLastHeader()
   253  		if err != nil {
   254  			mlog.Error(err.Error())
   255  			time.Sleep(time.Second)
   256  			continue
   257  		}
   258  		h := lastHeader.(*queue.Message).Data.(*types.Header)
   259  		mem.setHeader(h)
   260  		return
   261  	}
   262  }
   263  
   264  func (mem *Mempool) removeExpired() {
   265  	mem.proxyMtx.Lock()
   266  	defer mem.proxyMtx.Unlock()
   267  	types.AssertConfig(mem.client)
   268  	//mempool的header是当前高度,而交易将被下一个区块打包,过期判定采用下一个区块的高度和时间
   269  	mem.cache.removeExpiredTx(mem.client.GetConfig(), mem.header.GetHeight()+1, mem.header.GetBlockTime())
   270  }
   271  
   272  // removeBlockedTxs 每隔1分钟清理一次已打包的交易
   273  func (mem *Mempool) removeBlockedTxs() {
   274  	defer mem.wg.Done()
   275  	defer mlog.Info("RemoveBlockedTxs quit")
   276  	if mem.client == nil {
   277  		panic("client not bind message queue.")
   278  	}
   279  	for {
   280  		select {
   281  		case <-mem.removeBlockTicket.C:
   282  			if mem.isClose() {
   283  				return
   284  			}
   285  			mem.removeExpired()
   286  		case <-mem.done:
   287  			return
   288  		}
   289  	}
   290  }
   291  
   292  // RemoveTxsOfBlock 移除mempool中已被Blockchain打包的tx
   293  func (mem *Mempool) RemoveTxsOfBlock(block *types.Block) bool {
   294  	mem.proxyMtx.Lock()
   295  	defer mem.proxyMtx.Unlock()
   296  	for _, tx := range block.Txs {
   297  		hash := tx.Hash()
   298  		exist := mem.cache.Exist(string(hash))
   299  		if exist {
   300  			mem.cache.Remove(string(hash))
   301  		}
   302  	}
   303  	return true
   304  }
   305  func (mem *Mempool) getCacheFeeRate() int64 {
   306  	if mem.cache.qcache == nil {
   307  		return 0
   308  	}
   309  	feeRate := mem.cache.qcache.GetProperFee()
   310  
   311  	//控制精度
   312  	unitFee := mem.cfg.MinTxFeeRate
   313  	if unitFee != 0 && feeRate%unitFee > 0 {
   314  		feeRate = (feeRate/unitFee + 1) * unitFee
   315  	}
   316  	if feeRate > mem.cfg.MaxTxFeeRate {
   317  		feeRate = mem.cfg.MaxTxFeeRate
   318  	}
   319  	return feeRate
   320  }
   321  
   322  // GetProperFeeRate 获取合适的手续费率
   323  func (mem *Mempool) GetProperFeeRate(req *types.ReqProperFee) int64 {
   324  	if req == nil || req.TxCount == 0 {
   325  		req = &types.ReqProperFee{TxCount: 20}
   326  	}
   327  	if req.TxSize == 0 {
   328  		req.TxSize = 10240
   329  	}
   330  	feeRate := mem.getCacheFeeRate()
   331  	if mem.cfg.IsLevelFee {
   332  		levelFeeRate := mem.getLevelFeeRate(mem.cfg.MinTxFeeRate, req.TxCount, req.TxSize)
   333  		if levelFeeRate > feeRate {
   334  			feeRate = levelFeeRate
   335  		}
   336  	}
   337  	return feeRate
   338  }
   339  
   340  // getLevelFeeRate 获取合适的阶梯手续费率, 可以外部传入count, size进行前瞻性估计
   341  func (mem *Mempool) getLevelFeeRate(baseFeeRate int64, appendCount, appendSize int32) int64 {
   342  	var feeRate int64
   343  	sumByte := mem.GetTotalCacheBytes() + int64(appendSize)
   344  	types.AssertConfig(mem.client)
   345  	cfg := mem.client.GetConfig()
   346  	maxTxNumber := cfg.GetP(mem.Height()).MaxTxNumber
   347  	memSize := mem.Size()
   348  	switch {
   349  	case sumByte >= int64(types.MaxBlockSize/20) || int64(memSize+int(appendCount)) >= maxTxNumber/2:
   350  		feeRate = 100 * baseFeeRate
   351  	case sumByte >= int64(types.MaxBlockSize/100) || int64(memSize+int(appendCount)) >= maxTxNumber/10:
   352  		feeRate = 10 * baseFeeRate
   353  	default:
   354  		feeRate = baseFeeRate
   355  	}
   356  	if feeRate > mem.cfg.MaxTxFeeRate {
   357  		feeRate = mem.cfg.MaxTxFeeRate
   358  	}
   359  	return feeRate
   360  }
   361  
   362  // Mempool.DelBlock将回退的区块内的交易重新加入mempool中
   363  func (mem *Mempool) delBlock(block *types.Block) {
   364  	if len(block.Txs) <= 0 {
   365  		return
   366  	}
   367  	blkTxs := block.Txs
   368  	header := mem.GetHeader()
   369  	types.AssertConfig(mem.client)
   370  	cfg := mem.client.GetConfig()
   371  	for i := 0; i < len(blkTxs); i++ {
   372  		tx := blkTxs[i]
   373  		//当前包括ticket和平行链的第一笔挖矿交易,统一actionName为miner
   374  		if i == 0 && tx.ActionName() == types.MinerAction {
   375  			continue
   376  		}
   377  		groupCount := int(tx.GetGroupCount())
   378  		if groupCount > 1 && i+groupCount <= len(blkTxs) {
   379  			group := types.Transactions{Txs: blkTxs[i : i+groupCount]}
   380  			tx = group.Tx()
   381  			i = i + groupCount - 1
   382  		}
   383  		err := tx.Check(cfg, header.GetHeight(), mem.cfg.MinTxFeeRate, mem.cfg.MaxTxFee)
   384  		if err != nil {
   385  			continue
   386  		}
   387  		if !mem.checkExpireValid(tx) {
   388  			continue
   389  		}
   390  		err = mem.PushTx(tx)
   391  		if err != nil {
   392  			mlog.Error("mem", "push tx err", err)
   393  		}
   394  	}
   395  }
   396  
   397  // Height 获取区块高度
   398  func (mem *Mempool) Height() int64 {
   399  	mem.proxyMtx.Lock()
   400  	defer mem.proxyMtx.Unlock()
   401  	if mem.header == nil {
   402  		return -1
   403  	}
   404  	return mem.header.GetHeight()
   405  }
   406  
   407  // Wait wait mempool ready
   408  func (mem *Mempool) Wait() {
   409  	<-mem.poolHeader
   410  	//wait sync
   411  	<-mem.poolHeader
   412  }
   413  
   414  // SendTxToP2P 向"p2p"发送消息
   415  func (mem *Mempool) sendTxToP2P(tx *types.Transaction) {
   416  	if mem.client == nil {
   417  		panic("client not bind message queue.")
   418  	}
   419  	msg := mem.client.NewMessage("p2p", types.EventTxBroadcast, tx)
   420  	err := mem.client.Send(msg, false)
   421  	if err != nil {
   422  		mlog.Error("tx sent to p2p", "tx.Hash", common.ToHex(tx.Hash()))
   423  		return
   424  	}
   425  	//mlog.Debug("tx sent to p2p", "tx.Hash", common.ToHex(tx.Hash()))
   426  }
   427  
   428  // Mempool.checkSync检查并获取mempool同步状态
   429  func (mem *Mempool) checkSync() {
   430  	defer func() {
   431  		mlog.Info("getsync quit")
   432  		mem.poolHeader <- struct{}{}
   433  	}()
   434  	defer mem.wg.Done()
   435  	if mem.getSync() {
   436  		return
   437  	}
   438  	if mem.cfg.ForceAccept {
   439  		mem.setSync(true)
   440  	}
   441  	for {
   442  		if mem.isClose() {
   443  			return
   444  		}
   445  		if mem.client == nil {
   446  			panic("client not bind message queue.")
   447  		}
   448  		msg := mem.client.NewMessage("blockchain", types.EventIsSync, nil)
   449  		err := mem.client.Send(msg, true)
   450  		if err != nil {
   451  			time.Sleep(time.Second)
   452  			continue
   453  		}
   454  		resp, err := mem.client.Wait(msg)
   455  		if err != nil {
   456  			time.Sleep(time.Second)
   457  			continue
   458  		}
   459  		if resp.GetData().(*types.IsCaughtUp).GetIscaughtup() {
   460  			mem.setSync(true)
   461  			return
   462  		}
   463  		time.Sleep(time.Second)
   464  		continue
   465  	}
   466  }
   467  
   468  func (mem *Mempool) setSync(status bool) {
   469  	mem.proxyMtx.Lock()
   470  	mem.sync = status
   471  	mem.proxyMtx.Unlock()
   472  }
   473  
   474  // getTxListByHash 从qcache或者SHashTxCache中获取hash对应的tx交易列表
   475  func (mem *Mempool) getTxListByHash(hashList *types.ReqTxHashList) *types.ReplyTxList {
   476  	mem.proxyMtx.Lock()
   477  	defer mem.proxyMtx.Unlock()
   478  
   479  	var replyTxList types.ReplyTxList
   480  
   481  	//通过短hash来获取tx交易
   482  	if hashList.GetIsShortHash() {
   483  		for _, sHash := range hashList.GetHashes() {
   484  			tx := mem.cache.GetSHashTxCache(sHash)
   485  			replyTxList.Txs = append(replyTxList.Txs, tx)
   486  		}
   487  		return &replyTxList
   488  	}
   489  	//通过hash来获取tx交易
   490  	for _, hash := range hashList.GetHashes() {
   491  		tx := mem.cache.getTxByHash(hash)
   492  		replyTxList.Txs = append(replyTxList.Txs, tx)
   493  	}
   494  	return &replyTxList
   495  }