9 "github.com/bytom/protocol/bc"
10 "github.com/bytom/protocol/bc/legacy"
11 "github.com/golang/groupcache/lru"
15 maxCachedErrTxs = 1000
17 // ErrTransactionNotExist is the pre-defined error message
18 ErrTransactionNotExist = errors.New("transaction are not existed in the mempool")
21 // TxDesc store tx and related info for mining strategy
31 // TxPool is use for store the unconfirmed transaction
35 pool map[bc.Hash]*TxDesc
37 newTxCh chan *legacy.Tx
40 // NewTxPool init a new TxPool
41 func NewTxPool() *TxPool {
43 lastUpdated: time.Now().Unix(),
44 pool: make(map[bc.Hash]*TxDesc),
45 errCache: lru.New(maxCachedErrTxs),
46 newTxCh: make(chan *legacy.Tx, maxNewTxChSize),
50 // GetNewTxCh return a unconfirmed transaction feed channel
51 func (mp *TxPool) GetNewTxCh() chan *legacy.Tx {
55 // AddTransaction add a verified transaction to pool
56 func (mp *TxPool) AddTransaction(tx *legacy.Tx, height, fee uint64) *TxDesc {
60 Weight: tx.TxData.SerializedSize,
63 FeePerKB: fee * 1000 / tx.TxHeader.SerializedSize,
69 mp.pool[tx.Tx.ID] = txD
70 atomic.StoreInt64(&mp.lastUpdated, time.Now().Unix())
76 // AddErrCache add a failed transaction record to lru cache
77 func (mp *TxPool) AddErrCache(txHash *bc.Hash, err error) {
81 mp.errCache.Add(txHash, err)
84 // GetErrCache return the error of the transaction
85 func (mp *TxPool) GetErrCache(txHash *bc.Hash) error {
89 v, ok := mp.errCache.Get(txHash)
96 // RemoveTransaction remove a transaction from the pool
97 func (mp *TxPool) RemoveTransaction(txHash *bc.Hash) {
101 if _, ok := mp.pool[*txHash]; ok {
102 delete(mp.pool, *txHash)
103 atomic.StoreInt64(&mp.lastUpdated, time.Now().Unix())
107 // GetTransaction return the TxDesc by hash
108 func (mp *TxPool) GetTransaction(txHash *bc.Hash) (*TxDesc, error) {
110 defer mp.mtx.RUnlock()
112 if txD, ok := mp.pool[*txHash]; ok {
116 return nil, ErrTransactionNotExist
119 // GetTransactions return all the transactions in the pool
120 func (mp *TxPool) GetTransactions() []*TxDesc {
122 defer mp.mtx.RUnlock()
124 txDs := make([]*TxDesc, len(mp.pool))
126 for _, desc := range mp.pool {
133 // IsTransactionInPool check wheather a transaction in pool or not
134 func (mp *TxPool) IsTransactionInPool(txHash *bc.Hash) bool {
136 defer mp.mtx.RUnlock()
138 if _, ok := mp.pool[*txHash]; ok {
144 // IsTransactionInErrCache check wheather a transaction in errCache or not
145 func (mp *TxPool) IsTransactionInErrCache(txHash *bc.Hash) bool {
147 defer mp.mtx.RUnlock()
149 _, ok := mp.errCache.Get(txHash)
153 // HaveTransaction IsTransactionInErrCache check is transaction in errCache or pool
154 func (mp *TxPool) HaveTransaction(txHash *bc.Hash) bool {
155 return mp.IsTransactionInPool(txHash) || mp.IsTransactionInErrCache(txHash)
158 // Count return number of transcation in pool
159 func (mp *TxPool) Count() int {
161 defer mp.mtx.RUnlock()
163 count := len(mp.pool)