github.com/number571/tendermint@v0.34.11-gost/internal/mempool/v1/tx.go (about) 1 package v1 2 3 import ( 4 "sort" 5 "time" 6 7 "github.com/number571/tendermint/internal/libs/clist" 8 tmsync "github.com/number571/tendermint/internal/libs/sync" 9 "github.com/number571/tendermint/internal/mempool" 10 "github.com/number571/tendermint/types" 11 ) 12 13 // WrappedTx defines a wrapper around a raw transaction with additional metadata 14 // that is used for indexing. 15 type WrappedTx struct { 16 // tx represents the raw binary transaction data 17 tx types.Tx 18 19 // hash defines the transaction hash and the primary key used in the mempool 20 hash [mempool.TxKeySize]byte 21 22 // height defines the height at which the transaction was validated at 23 height int64 24 25 // gasWanted defines the amount of gas the transaction sender requires 26 gasWanted int64 27 28 // priority defines the transaction's priority as specified by the application 29 // in the ResponseCheckTx response. 30 priority int64 31 32 // sender defines the transaction's sender as specified by the application in 33 // the ResponseCheckTx response. 34 sender string 35 36 // timestamp is the time at which the node first received the transaction from 37 // a peer. It is used as a second dimension is prioritizing transactions when 38 // two transactions have the same priority. 39 timestamp time.Time 40 41 // peers records a mapping of all peers that sent a given transaction 42 peers map[uint16]struct{} 43 44 // heapIndex defines the index of the item in the heap 45 heapIndex int 46 47 // gossipEl references the linked-list element in the gossip index 48 gossipEl *clist.CElement 49 50 // removed marks the transaction as removed from the mempool. This is set 51 // during RemoveTx and is needed due to the fact that a given existing 52 // transaction in the mempool can be evicted when it is simultaneously having 53 // a reCheckTx callback executed. 54 removed bool 55 } 56 57 func (wtx *WrappedTx) Size() int { 58 return len(wtx.tx) 59 } 60 61 // TxStore implements a thread-safe mapping of valid transaction(s). 62 // 63 // NOTE: 64 // - Concurrent read-only access to a *WrappedTx object is OK. However, mutative 65 // access is not allowed. Regardless, it is not expected for the mempool to 66 // need mutative access. 67 type TxStore struct { 68 mtx tmsync.RWMutex 69 hashTxs map[[mempool.TxKeySize]byte]*WrappedTx // primary index 70 senderTxs map[string]*WrappedTx // sender is defined by the ABCI application 71 } 72 73 func NewTxStore() *TxStore { 74 return &TxStore{ 75 senderTxs: make(map[string]*WrappedTx), 76 hashTxs: make(map[[mempool.TxKeySize]byte]*WrappedTx), 77 } 78 } 79 80 // Size returns the total number of transactions in the store. 81 func (txs *TxStore) Size() int { 82 txs.mtx.RLock() 83 defer txs.mtx.RUnlock() 84 85 return len(txs.hashTxs) 86 } 87 88 // GetAllTxs returns all the transactions currently in the store. 89 func (txs *TxStore) GetAllTxs() []*WrappedTx { 90 txs.mtx.RLock() 91 defer txs.mtx.RUnlock() 92 93 wTxs := make([]*WrappedTx, len(txs.hashTxs)) 94 i := 0 95 for _, wtx := range txs.hashTxs { 96 wTxs[i] = wtx 97 i++ 98 } 99 100 return wTxs 101 } 102 103 // GetTxBySender returns a *WrappedTx by the transaction's sender property 104 // defined by the ABCI application. 105 func (txs *TxStore) GetTxBySender(sender string) *WrappedTx { 106 txs.mtx.RLock() 107 defer txs.mtx.RUnlock() 108 109 return txs.senderTxs[sender] 110 } 111 112 // GetTxByHash returns a *WrappedTx by the transaction's hash. 113 func (txs *TxStore) GetTxByHash(hash [mempool.TxKeySize]byte) *WrappedTx { 114 txs.mtx.RLock() 115 defer txs.mtx.RUnlock() 116 117 return txs.hashTxs[hash] 118 } 119 120 // IsTxRemoved returns true if a transaction by hash is marked as removed and 121 // false otherwise. 122 func (txs *TxStore) IsTxRemoved(hash [mempool.TxKeySize]byte) bool { 123 txs.mtx.RLock() 124 defer txs.mtx.RUnlock() 125 126 wtx, ok := txs.hashTxs[hash] 127 if ok { 128 return wtx.removed 129 } 130 131 return false 132 } 133 134 // SetTx stores a *WrappedTx by it's hash. If the transaction also contains a 135 // non-empty sender, we additionally store the transaction by the sender as 136 // defined by the ABCI application. 137 func (txs *TxStore) SetTx(wtx *WrappedTx) { 138 txs.mtx.Lock() 139 defer txs.mtx.Unlock() 140 141 if len(wtx.sender) > 0 { 142 txs.senderTxs[wtx.sender] = wtx 143 } 144 145 txs.hashTxs[mempool.TxKey(wtx.tx)] = wtx 146 } 147 148 // RemoveTx removes a *WrappedTx from the transaction store. It deletes all 149 // indexes of the transaction. 150 func (txs *TxStore) RemoveTx(wtx *WrappedTx) { 151 txs.mtx.Lock() 152 defer txs.mtx.Unlock() 153 154 if len(wtx.sender) > 0 { 155 delete(txs.senderTxs, wtx.sender) 156 } 157 158 delete(txs.hashTxs, mempool.TxKey(wtx.tx)) 159 wtx.removed = true 160 } 161 162 // TxHasPeer returns true if a transaction by hash has a given peer ID and false 163 // otherwise. If the transaction does not exist, false is returned. 164 func (txs *TxStore) TxHasPeer(hash [mempool.TxKeySize]byte, peerID uint16) bool { 165 txs.mtx.RLock() 166 defer txs.mtx.RUnlock() 167 168 wtx := txs.hashTxs[hash] 169 if wtx == nil { 170 return false 171 } 172 173 _, ok := wtx.peers[peerID] 174 return ok 175 } 176 177 // GetOrSetPeerByTxHash looks up a WrappedTx by transaction hash and adds the 178 // given peerID to the WrappedTx's set of peers that sent us this transaction. 179 // We return true if we've already recorded the given peer for this transaction 180 // and false otherwise. If the transaction does not exist by hash, we return 181 // (nil, false). 182 func (txs *TxStore) GetOrSetPeerByTxHash(hash [mempool.TxKeySize]byte, peerID uint16) (*WrappedTx, bool) { 183 txs.mtx.Lock() 184 defer txs.mtx.Unlock() 185 186 wtx := txs.hashTxs[hash] 187 if wtx == nil { 188 return nil, false 189 } 190 191 if wtx.peers == nil { 192 wtx.peers = make(map[uint16]struct{}) 193 } 194 195 if _, ok := wtx.peers[peerID]; ok { 196 return wtx, true 197 } 198 199 wtx.peers[peerID] = struct{}{} 200 return wtx, false 201 } 202 203 // WrappedTxList implements a thread-safe list of *WrappedTx objects that can be 204 // used to build generic transaction indexes in the mempool. It accepts a 205 // comparator function, less(a, b *WrappedTx) bool, that compares two WrappedTx 206 // references which is used during Insert in order to determine sorted order. If 207 // less returns true, a <= b. 208 type WrappedTxList struct { 209 mtx tmsync.RWMutex 210 txs []*WrappedTx 211 less func(*WrappedTx, *WrappedTx) bool 212 } 213 214 func NewWrappedTxList(less func(*WrappedTx, *WrappedTx) bool) *WrappedTxList { 215 return &WrappedTxList{ 216 txs: make([]*WrappedTx, 0), 217 less: less, 218 } 219 } 220 221 // Size returns the number of WrappedTx objects in the list. 222 func (wtl *WrappedTxList) Size() int { 223 wtl.mtx.RLock() 224 defer wtl.mtx.RUnlock() 225 226 return len(wtl.txs) 227 } 228 229 // Reset resets the list of transactions to an empty list. 230 func (wtl *WrappedTxList) Reset() { 231 wtl.mtx.Lock() 232 defer wtl.mtx.Unlock() 233 234 wtl.txs = make([]*WrappedTx, 0) 235 } 236 237 // Insert inserts a WrappedTx reference into the sorted list based on the list's 238 // comparator function. 239 func (wtl *WrappedTxList) Insert(wtx *WrappedTx) { 240 wtl.mtx.Lock() 241 defer wtl.mtx.Unlock() 242 243 i := sort.Search(len(wtl.txs), func(i int) bool { 244 return wtl.less(wtl.txs[i], wtx) 245 }) 246 247 if i == len(wtl.txs) { 248 // insert at the end 249 wtl.txs = append(wtl.txs, wtx) 250 return 251 } 252 253 // Make space for the inserted element by shifting values at the insertion 254 // index up one index. 255 // 256 // NOTE: The call to append does not allocate memory when cap(wtl.txs) > len(wtl.txs). 257 wtl.txs = append(wtl.txs[:i+1], wtl.txs[i:]...) 258 wtl.txs[i] = wtx 259 } 260 261 // Remove attempts to remove a WrappedTx from the sorted list. 262 func (wtl *WrappedTxList) Remove(wtx *WrappedTx) { 263 wtl.mtx.Lock() 264 defer wtl.mtx.Unlock() 265 266 i := sort.Search(len(wtl.txs), func(i int) bool { 267 return wtl.less(wtl.txs[i], wtx) 268 }) 269 270 // Since the list is sorted, we evaluate all elements starting at i. Note, if 271 // the element does not exist, we may potentially evaluate the entire remainder 272 // of the list. However, a caller should not be expected to call Remove with a 273 // non-existing element. 274 for i < len(wtl.txs) { 275 if wtl.txs[i] == wtx { 276 wtl.txs = append(wtl.txs[:i], wtl.txs[i+1:]...) 277 return 278 } 279 280 i++ 281 } 282 }