github.com/bencicandrej/quorum@v2.2.6-0.20190909091323-878cab86f711+incompatible/core/tx_pool.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "errors" 21 "fmt" 22 "math" 23 "math/big" 24 "sort" 25 "sync" 26 "time" 27 28 "github.com/ethereum/go-ethereum/common" 29 "github.com/ethereum/go-ethereum/common/prque" 30 "github.com/ethereum/go-ethereum/core/state" 31 "github.com/ethereum/go-ethereum/core/types" 32 "github.com/ethereum/go-ethereum/event" 33 "github.com/ethereum/go-ethereum/log" 34 "github.com/ethereum/go-ethereum/metrics" 35 "github.com/ethereum/go-ethereum/params" 36 ) 37 38 const ( 39 // chainHeadChanSize is the size of channel listening to ChainHeadEvent. 40 chainHeadChanSize = 10 41 ) 42 43 var ( 44 // ErrInvalidSender is returned if the transaction contains an invalid signature. 45 ErrInvalidSender = errors.New("invalid sender") 46 47 // ErrNonceTooLow is returned if the nonce of a transaction is lower than the 48 // one present in the local chain. 49 ErrNonceTooLow = errors.New("nonce too low") 50 51 // ErrUnderpriced is returned if a transaction's gas price is below the minimum 52 // configured for the transaction pool. 53 ErrUnderpriced = errors.New("transaction underpriced") 54 55 // ErrReplaceUnderpriced is returned if a transaction is attempted to be replaced 56 // with a different one without the required price bump. 57 ErrReplaceUnderpriced = errors.New("replacement transaction underpriced") 58 59 // ErrInsufficientFunds is returned if the total cost of executing a transaction 60 // is higher than the balance of the user's account. 61 ErrInsufficientFunds = errors.New("insufficient funds for gas * price + value") 62 63 // ErrIntrinsicGas is returned if the transaction is specified to use less gas 64 // than required to start the invocation. 65 ErrIntrinsicGas = errors.New("intrinsic gas too low") 66 67 // ErrGasLimit is returned if a transaction's requested gas limit exceeds the 68 // maximum allowance of the current block. 69 ErrGasLimit = errors.New("exceeds block gas limit") 70 71 // ErrNegativeValue is a sanity error to ensure noone is able to specify a 72 // transaction with a negative value. 73 ErrNegativeValue = errors.New("negative value") 74 75 // ErrOversizedData is returned if the input data of a transaction is greater 76 // than some meaningful limit a user might use. This is not a consensus error 77 // making the transaction invalid, rather a DOS protection. 78 ErrOversizedData = errors.New("oversized data") 79 80 ErrInvalidGasPrice = errors.New("Gas price not 0") 81 82 // ErrEtherValueUnsupported is returned if a transaction specifies an Ether Value 83 // for a private Quorum transaction. 84 ErrEtherValueUnsupported = errors.New("ether value is not supported for private transactions") 85 ) 86 87 var ( 88 evictionInterval = time.Minute // Time interval to check for evictable transactions 89 statsReportInterval = 8 * time.Second // Time interval to report transaction pool stats 90 ) 91 92 var ( 93 // Metrics for the pending pool 94 pendingDiscardCounter = metrics.NewRegisteredCounter("txpool/pending/discard", nil) 95 pendingReplaceCounter = metrics.NewRegisteredCounter("txpool/pending/replace", nil) 96 pendingRateLimitCounter = metrics.NewRegisteredCounter("txpool/pending/ratelimit", nil) // Dropped due to rate limiting 97 pendingNofundsCounter = metrics.NewRegisteredCounter("txpool/pending/nofunds", nil) // Dropped due to out-of-funds 98 99 // Metrics for the queued pool 100 queuedDiscardCounter = metrics.NewRegisteredCounter("txpool/queued/discard", nil) 101 queuedReplaceCounter = metrics.NewRegisteredCounter("txpool/queued/replace", nil) 102 queuedRateLimitCounter = metrics.NewRegisteredCounter("txpool/queued/ratelimit", nil) // Dropped due to rate limiting 103 queuedNofundsCounter = metrics.NewRegisteredCounter("txpool/queued/nofunds", nil) // Dropped due to out-of-funds 104 105 // General tx metrics 106 invalidTxCounter = metrics.NewRegisteredCounter("txpool/invalid", nil) 107 underpricedTxCounter = metrics.NewRegisteredCounter("txpool/underpriced", nil) 108 ) 109 110 // TxStatus is the current status of a transaction as seen by the pool. 111 type TxStatus uint 112 113 const ( 114 TxStatusUnknown TxStatus = iota 115 TxStatusQueued 116 TxStatusPending 117 TxStatusIncluded 118 ) 119 120 // blockChain provides the state of blockchain and current gas limit to do 121 // some pre checks in tx pool and event subscribers. 122 type blockChain interface { 123 CurrentBlock() *types.Block 124 GetBlock(hash common.Hash, number uint64) *types.Block 125 StateAt(root common.Hash) (*state.StateDB, *state.StateDB, error) 126 127 SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription 128 } 129 130 // TxPoolConfig are the configuration parameters of the transaction pool. 131 type TxPoolConfig struct { 132 Locals []common.Address // Addresses that should be treated by default as local 133 NoLocals bool // Whether local transaction handling should be disabled 134 Journal string // Journal of local transactions to survive node restarts 135 Rejournal time.Duration // Time interval to regenerate the local transaction journal 136 137 TransactionSizeLimit uint64 // Maximum size allowed for valid transaction (in KB) 138 MaxCodeSize uint64 // Maximum size allowed of contract code that can be deployed (in KB) 139 140 PriceLimit uint64 // Minimum gas price to enforce for acceptance into the pool 141 PriceBump uint64 // Minimum price bump percentage to replace an already existing transaction (nonce) 142 143 AccountSlots uint64 // Number of executable transaction slots guaranteed per account 144 GlobalSlots uint64 // Maximum number of executable transaction slots for all accounts 145 AccountQueue uint64 // Maximum number of non-executable transaction slots permitted per account 146 GlobalQueue uint64 // Maximum number of non-executable transaction slots for all accounts 147 148 Lifetime time.Duration // Maximum amount of time non-executable transaction are queued 149 } 150 151 // DefaultTxPoolConfig contains the default configurations for the transaction 152 // pool. 153 var DefaultTxPoolConfig = TxPoolConfig{ 154 Journal: "transactions.rlp", 155 Rejournal: time.Hour, 156 157 TransactionSizeLimit: 64, 158 MaxCodeSize: 24, 159 160 PriceLimit: 1, 161 PriceBump: 10, 162 163 AccountSlots: 16, 164 GlobalSlots: 4096, 165 AccountQueue: 64, 166 GlobalQueue: 1024, 167 168 Lifetime: 3 * time.Hour, 169 } 170 171 // sanitize checks the provided user configurations and changes anything that's 172 // unreasonable or unworkable. 173 func (config *TxPoolConfig) sanitize() TxPoolConfig { 174 conf := *config 175 if conf.Rejournal < time.Second { 176 log.Warn("Sanitizing invalid txpool journal time", "provided", conf.Rejournal, "updated", time.Second) 177 conf.Rejournal = time.Second 178 } 179 if conf.PriceLimit < 1 { 180 log.Warn("Sanitizing invalid txpool price limit", "provided", conf.PriceLimit, "updated", DefaultTxPoolConfig.PriceLimit) 181 conf.PriceLimit = DefaultTxPoolConfig.PriceLimit 182 } 183 if conf.PriceBump < 1 { 184 log.Warn("Sanitizing invalid txpool price bump", "provided", conf.PriceBump, "updated", DefaultTxPoolConfig.PriceBump) 185 conf.PriceBump = DefaultTxPoolConfig.PriceBump 186 } 187 return conf 188 } 189 190 // TxPool contains all currently known transactions. Transactions 191 // enter the pool when they are received from the network or submitted 192 // locally. They exit the pool when they are included in the blockchain. 193 // 194 // The pool separates processable transactions (which can be applied to the 195 // current state) and future transactions. Transactions move between those 196 // two states over time as they are received and processed. 197 type TxPool struct { 198 config TxPoolConfig 199 chainconfig *params.ChainConfig 200 chain blockChain 201 gasPrice *big.Int 202 txFeed event.Feed 203 scope event.SubscriptionScope 204 chainHeadCh chan ChainHeadEvent 205 chainHeadSub event.Subscription 206 signer types.Signer 207 mu sync.RWMutex 208 209 currentState *state.StateDB // Current state in the blockchain head 210 pendingState *state.ManagedState // Pending state tracking virtual nonces 211 currentMaxGas uint64 // Current gas limit for transaction caps 212 213 locals *accountSet // Set of local transaction to exempt from eviction rules 214 journal *txJournal // Journal of local transaction to back up to disk 215 216 pending map[common.Address]*txList // All currently processable transactions 217 queue map[common.Address]*txList // Queued but non-processable transactions 218 beats map[common.Address]time.Time // Last heartbeat from each known account 219 all *txLookup // All transactions to allow lookups 220 priced *txPricedList // All transactions sorted by price 221 222 wg sync.WaitGroup // for shutdown sync 223 224 homestead bool 225 } 226 227 // NewTxPool creates a new transaction pool to gather, sort and filter inbound 228 // transactions from the network. 229 func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain blockChain) *TxPool { 230 // Sanitize the input to ensure no vulnerable gas prices are set 231 config = (&config).sanitize() 232 233 // Create the transaction pool with its initial settings 234 pool := &TxPool{ 235 config: config, 236 chainconfig: chainconfig, 237 chain: chain, 238 signer: types.NewEIP155Signer(chainconfig.ChainID), 239 pending: make(map[common.Address]*txList), 240 queue: make(map[common.Address]*txList), 241 beats: make(map[common.Address]time.Time), 242 all: newTxLookup(), 243 chainHeadCh: make(chan ChainHeadEvent, chainHeadChanSize), 244 gasPrice: new(big.Int).SetUint64(config.PriceLimit), 245 } 246 pool.locals = newAccountSet(pool.signer) 247 for _, addr := range config.Locals { 248 log.Info("Setting new local account", "address", addr) 249 pool.locals.add(addr) 250 } 251 pool.priced = newTxPricedList(pool.all) 252 pool.reset(nil, chain.CurrentBlock().Header()) 253 254 // If local transactions and journaling is enabled, load from disk 255 if !config.NoLocals && config.Journal != "" { 256 pool.journal = newTxJournal(config.Journal) 257 258 if err := pool.journal.load(pool.AddLocals); err != nil { 259 log.Warn("Failed to load transaction journal", "err", err) 260 } 261 if err := pool.journal.rotate(pool.local()); err != nil { 262 log.Warn("Failed to rotate transaction journal", "err", err) 263 } 264 } 265 // Subscribe events from blockchain 266 pool.chainHeadSub = pool.chain.SubscribeChainHeadEvent(pool.chainHeadCh) 267 268 // Start the event loop and return 269 pool.wg.Add(1) 270 go pool.loop() 271 272 return pool 273 } 274 275 // loop is the transaction pool's main event loop, waiting for and reacting to 276 // outside blockchain events as well as for various reporting and transaction 277 // eviction events. 278 func (pool *TxPool) loop() { 279 defer pool.wg.Done() 280 281 // Start the stats reporting and transaction eviction tickers 282 var prevPending, prevQueued, prevStales int 283 284 report := time.NewTicker(statsReportInterval) 285 defer report.Stop() 286 287 evict := time.NewTicker(evictionInterval) 288 defer evict.Stop() 289 290 journal := time.NewTicker(pool.config.Rejournal) 291 defer journal.Stop() 292 293 // Track the previous head headers for transaction reorgs 294 head := pool.chain.CurrentBlock() 295 296 // Keep waiting for and reacting to the various events 297 for { 298 select { 299 // Handle ChainHeadEvent 300 case ev := <-pool.chainHeadCh: 301 if ev.Block != nil { 302 pool.mu.Lock() 303 if pool.chainconfig.IsHomestead(ev.Block.Number()) { 304 pool.homestead = true 305 } 306 pool.reset(head.Header(), ev.Block.Header()) 307 head = ev.Block 308 309 pool.mu.Unlock() 310 } 311 // Be unsubscribed due to system stopped 312 case <-pool.chainHeadSub.Err(): 313 return 314 315 // Handle stats reporting ticks 316 case <-report.C: 317 pool.mu.RLock() 318 pending, queued := pool.stats() 319 stales := pool.priced.stales 320 pool.mu.RUnlock() 321 322 if pending != prevPending || queued != prevQueued || stales != prevStales { 323 log.Debug("Transaction pool status report", "executable", pending, "queued", queued, "stales", stales) 324 prevPending, prevQueued, prevStales = pending, queued, stales 325 } 326 327 // Handle inactive account transaction eviction 328 case <-evict.C: 329 pool.mu.Lock() 330 for addr := range pool.queue { 331 // Skip local transactions from the eviction mechanism 332 if pool.locals.contains(addr) { 333 continue 334 } 335 // Any non-locals old enough should be removed 336 if time.Since(pool.beats[addr]) > pool.config.Lifetime { 337 for _, tx := range pool.queue[addr].Flatten() { 338 pool.removeTx(tx.Hash(), true) 339 } 340 } 341 } 342 pool.mu.Unlock() 343 344 // Handle local transaction journal rotation 345 case <-journal.C: 346 if pool.journal != nil { 347 pool.mu.Lock() 348 if err := pool.journal.rotate(pool.local()); err != nil { 349 log.Warn("Failed to rotate local tx journal", "err", err) 350 } 351 pool.mu.Unlock() 352 } 353 } 354 } 355 } 356 357 // lockedReset is a wrapper around reset to allow calling it in a thread safe 358 // manner. This method is only ever used in the tester! 359 func (pool *TxPool) lockedReset(oldHead, newHead *types.Header) { 360 pool.mu.Lock() 361 defer pool.mu.Unlock() 362 363 pool.reset(oldHead, newHead) 364 } 365 366 // reset retrieves the current state of the blockchain and ensures the content 367 // of the transaction pool is valid with regard to the chain state. 368 func (pool *TxPool) reset(oldHead, newHead *types.Header) { 369 // If we're reorging an old state, reinject all dropped transactions 370 var reinject types.Transactions 371 372 if oldHead != nil && oldHead.Hash() != newHead.ParentHash { 373 // If the reorg is too deep, avoid doing it (will happen during fast sync) 374 oldNum := oldHead.Number.Uint64() 375 newNum := newHead.Number.Uint64() 376 377 if depth := uint64(math.Abs(float64(oldNum) - float64(newNum))); depth > 64 { 378 log.Debug("Skipping deep transaction reorg", "depth", depth) 379 } else { 380 // Reorg seems shallow enough to pull in all transactions into memory 381 var discarded, included types.Transactions 382 383 var ( 384 rem = pool.chain.GetBlock(oldHead.Hash(), oldHead.Number.Uint64()) 385 add = pool.chain.GetBlock(newHead.Hash(), newHead.Number.Uint64()) 386 ) 387 for rem.NumberU64() > add.NumberU64() { 388 discarded = append(discarded, rem.Transactions()...) 389 if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil { 390 log.Error("Unrooted old chain seen by tx pool", "block", oldHead.Number, "hash", oldHead.Hash()) 391 return 392 } 393 } 394 for add.NumberU64() > rem.NumberU64() { 395 included = append(included, add.Transactions()...) 396 if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil { 397 log.Error("Unrooted new chain seen by tx pool", "block", newHead.Number, "hash", newHead.Hash()) 398 return 399 } 400 } 401 for rem.Hash() != add.Hash() { 402 discarded = append(discarded, rem.Transactions()...) 403 if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil { 404 log.Error("Unrooted old chain seen by tx pool", "block", oldHead.Number, "hash", oldHead.Hash()) 405 return 406 } 407 included = append(included, add.Transactions()...) 408 if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil { 409 log.Error("Unrooted new chain seen by tx pool", "block", newHead.Number, "hash", newHead.Hash()) 410 return 411 } 412 } 413 reinject = types.TxDifference(discarded, included) 414 } 415 } 416 // Initialize the internal state to the current head 417 if newHead == nil { 418 newHead = pool.chain.CurrentBlock().Header() // Special case during testing 419 } 420 statedb, _, err := pool.chain.StateAt(newHead.Root) 421 if err != nil { 422 log.Error("Failed to reset txpool state", "err", err) 423 return 424 } 425 pool.currentState = statedb 426 pool.pendingState = state.ManageState(statedb) 427 pool.currentMaxGas = newHead.GasLimit 428 429 // Inject any transactions discarded due to reorgs 430 log.Debug("Reinjecting stale transactions", "count", len(reinject)) 431 senderCacher.recover(pool.signer, reinject) 432 pool.addTxsLocked(reinject, false) 433 434 // validate the pool of pending transactions, this will remove 435 // any transactions that have been included in the block or 436 // have been invalidated because of another transaction (e.g. 437 // higher gas price) 438 pool.demoteUnexecutables() 439 440 // Update all accounts to the latest known pending nonce 441 for addr, list := range pool.pending { 442 txs := list.Flatten() // Heavy but will be cached and is needed by the miner anyway 443 pool.pendingState.SetNonce(addr, txs[len(txs)-1].Nonce()+1) 444 } 445 // Check the queue and move transactions over to the pending if possible 446 // or remove those that have become invalid 447 pool.promoteExecutables(nil) 448 } 449 450 // Stop terminates the transaction pool. 451 func (pool *TxPool) Stop() { 452 // Unsubscribe all subscriptions registered from txpool 453 pool.scope.Close() 454 455 // Unsubscribe subscriptions registered from blockchain 456 pool.chainHeadSub.Unsubscribe() 457 pool.wg.Wait() 458 459 if pool.journal != nil { 460 pool.journal.close() 461 } 462 log.Info("Transaction pool stopped") 463 } 464 465 // SubscribeNewTxsEvent registers a subscription of NewTxsEvent and 466 // starts sending event to the given channel. 467 func (pool *TxPool) SubscribeNewTxsEvent(ch chan<- NewTxsEvent) event.Subscription { 468 return pool.scope.Track(pool.txFeed.Subscribe(ch)) 469 } 470 471 // GasPrice returns the current gas price enforced by the transaction pool. 472 func (pool *TxPool) GasPrice() *big.Int { 473 pool.mu.RLock() 474 defer pool.mu.RUnlock() 475 476 return new(big.Int).Set(pool.gasPrice) 477 } 478 479 // SetGasPrice updates the minimum price required by the transaction pool for a 480 // new transaction, and drops all transactions below this threshold. 481 func (pool *TxPool) SetGasPrice(price *big.Int) { 482 pool.mu.Lock() 483 defer pool.mu.Unlock() 484 485 pool.gasPrice = price 486 for _, tx := range pool.priced.Cap(price, pool.locals) { 487 pool.removeTx(tx.Hash(), false) 488 } 489 log.Info("Transaction pool price threshold updated", "price", price) 490 } 491 492 // State returns the virtual managed state of the transaction pool. 493 func (pool *TxPool) State() *state.ManagedState { 494 pool.mu.RLock() 495 defer pool.mu.RUnlock() 496 497 return pool.pendingState 498 } 499 500 // Stats retrieves the current pool stats, namely the number of pending and the 501 // number of queued (non-executable) transactions. 502 func (pool *TxPool) Stats() (int, int) { 503 pool.mu.RLock() 504 defer pool.mu.RUnlock() 505 506 return pool.stats() 507 } 508 509 // stats retrieves the current pool stats, namely the number of pending and the 510 // number of queued (non-executable) transactions. 511 func (pool *TxPool) stats() (int, int) { 512 pending := 0 513 for _, list := range pool.pending { 514 pending += list.Len() 515 } 516 queued := 0 517 for _, list := range pool.queue { 518 queued += list.Len() 519 } 520 return pending, queued 521 } 522 523 // Content retrieves the data content of the transaction pool, returning all the 524 // pending as well as queued transactions, grouped by account and sorted by nonce. 525 func (pool *TxPool) Content() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) { 526 pool.mu.Lock() 527 defer pool.mu.Unlock() 528 529 pending := make(map[common.Address]types.Transactions) 530 for addr, list := range pool.pending { 531 pending[addr] = list.Flatten() 532 } 533 queued := make(map[common.Address]types.Transactions) 534 for addr, list := range pool.queue { 535 queued[addr] = list.Flatten() 536 } 537 return pending, queued 538 } 539 540 // Pending retrieves all currently processable transactions, grouped by origin 541 // account and sorted by nonce. The returned transaction set is a copy and can be 542 // freely modified by calling code. 543 func (pool *TxPool) Pending() (map[common.Address]types.Transactions, error) { 544 pool.mu.Lock() 545 defer pool.mu.Unlock() 546 547 pending := make(map[common.Address]types.Transactions) 548 for addr, list := range pool.pending { 549 pending[addr] = list.Flatten() 550 } 551 return pending, nil 552 } 553 554 // Locals retrieves the accounts currently considered local by the pool. 555 func (pool *TxPool) Locals() []common.Address { 556 pool.mu.Lock() 557 defer pool.mu.Unlock() 558 559 return pool.locals.flatten() 560 } 561 562 // local retrieves all currently known local transactions, grouped by origin 563 // account and sorted by nonce. The returned transaction set is a copy and can be 564 // freely modified by calling code. 565 func (pool *TxPool) local() map[common.Address]types.Transactions { 566 txs := make(map[common.Address]types.Transactions) 567 for addr := range pool.locals.accounts { 568 if pending := pool.pending[addr]; pending != nil { 569 txs[addr] = append(txs[addr], pending.Flatten()...) 570 } 571 if queued := pool.queue[addr]; queued != nil { 572 txs[addr] = append(txs[addr], queued.Flatten()...) 573 } 574 } 575 return txs 576 } 577 578 // validateTx checks whether a transaction is valid according to the consensus 579 // rules and adheres to some heuristic limits of the local node (price and size). 580 func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { 581 isQuorum := pool.chainconfig.IsQuorum 582 sizeLimit := pool.chainconfig.TransactionSizeLimit 583 if sizeLimit == 0 { 584 sizeLimit = DefaultTxPoolConfig.TransactionSizeLimit 585 } 586 587 if isQuorum && tx.GasPrice().Cmp(common.Big0) != 0 { 588 return ErrInvalidGasPrice 589 } 590 // Reject transactions over 32KB (or manually set limit) to prevent DOS attacks 591 if float64(tx.Size()) > float64(sizeLimit*1024) { 592 return ErrOversizedData 593 } 594 // Transactions can't be negative. This may never happen using RLP decoded 595 // transactions but may occur if you create a transaction using the RPC. 596 if tx.Value().Sign() < 0 { 597 return ErrNegativeValue 598 } 599 // Ensure the transaction doesn't exceed the current block limit gas. 600 if pool.currentMaxGas < tx.Gas() { 601 return ErrGasLimit 602 } 603 // Make sure the transaction is signed properly 604 from, err := types.Sender(pool.signer, tx) 605 if err != nil { 606 return ErrInvalidSender 607 } 608 // Drop non-local transactions under our own minimal accepted gas price 609 local = local || pool.locals.contains(from) // account may be local even if the transaction arrived from the network 610 if !isQuorum && !local && pool.gasPrice.Cmp(tx.GasPrice()) > 0 { 611 return ErrUnderpriced 612 } 613 // Ensure the transaction adheres to nonce ordering 614 if pool.currentState.GetNonce(from) > tx.Nonce() { 615 return ErrNonceTooLow 616 } 617 // Ether value is not currently supported on private transactions 618 if tx.IsPrivate() && (len(tx.Data()) == 0 || tx.Value().Sign() != 0) { 619 return ErrEtherValueUnsupported 620 } 621 // Transactor should have enough funds to cover the costs 622 // cost == V + GP * GL 623 if pool.currentState.GetBalance(from).Cmp(tx.Cost()) < 0 { 624 return ErrInsufficientFunds 625 } 626 intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead) 627 if err != nil { 628 return err 629 } 630 if tx.Gas() < intrGas { 631 return ErrIntrinsicGas 632 } 633 return nil 634 } 635 636 // add validates a transaction and inserts it into the non-executable queue for 637 // later pending promotion and execution. If the transaction is a replacement for 638 // an already pending or queued one, it overwrites the previous and returns this 639 // so outer code doesn't uselessly call promote. 640 // 641 // If a newly added transaction is marked as local, its sending account will be 642 // whitelisted, preventing any associated transaction from being dropped out of 643 // the pool due to pricing constraints. 644 func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) { 645 // If the transaction is already known, discard it 646 hash := tx.Hash() 647 if pool.all.Get(hash) != nil { 648 log.Trace("Discarding already known transaction", "hash", hash) 649 return false, fmt.Errorf("known transaction: %x", hash) 650 } 651 // If the transaction fails basic validation, discard it 652 if err := pool.validateTx(tx, local); err != nil { 653 log.Trace("Discarding invalid transaction", "hash", hash, "err", err) 654 invalidTxCounter.Inc(1) 655 return false, err 656 } 657 // If the transaction pool is full, discard underpriced transactions 658 if uint64(pool.all.Count()) >= pool.config.GlobalSlots+pool.config.GlobalQueue { 659 // If the new transaction is underpriced, don't accept it 660 if !pool.chainconfig.IsQuorum && !local && pool.priced.Underpriced(tx, pool.locals) { 661 log.Trace("Discarding underpriced transaction", "hash", hash, "price", tx.GasPrice()) 662 underpricedTxCounter.Inc(1) 663 return false, ErrUnderpriced 664 } 665 // New transaction is better than our worse ones, make room for it 666 drop := pool.priced.Discard(pool.all.Count()-int(pool.config.GlobalSlots+pool.config.GlobalQueue-1), pool.locals) 667 for _, tx := range drop { 668 log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "price", tx.GasPrice()) 669 underpricedTxCounter.Inc(1) 670 pool.removeTx(tx.Hash(), false) 671 } 672 } 673 // If the transaction is replacing an already pending one, do directly 674 from, _ := types.Sender(pool.signer, tx) // already validated 675 if list := pool.pending[from]; list != nil && list.Overlaps(tx) { 676 // Nonce already pending, check if required price bump is met 677 inserted, old := list.Add(tx, pool.config.PriceBump) 678 if !inserted { 679 pendingDiscardCounter.Inc(1) 680 return false, ErrReplaceUnderpriced 681 } 682 // New transaction is better, replace old one 683 if old != nil { 684 pool.all.Remove(old.Hash()) 685 pool.priced.Removed() 686 pendingReplaceCounter.Inc(1) 687 } 688 pool.all.Add(tx) 689 pool.priced.Put(tx) 690 pool.journalTx(from, tx) 691 692 log.Trace("Pooled new executable transaction", "hash", hash, "from", from, "to", tx.To()) 693 694 // We've directly injected a replacement transaction, notify subsystems 695 go pool.txFeed.Send(NewTxsEvent{types.Transactions{tx}}) 696 697 return old != nil, nil 698 } 699 // New transaction isn't replacing a pending one, push into queue 700 replace, err := pool.enqueueTx(hash, tx) 701 if err != nil { 702 return false, err 703 } 704 // Mark local addresses and journal local transactions 705 if local { 706 if !pool.locals.contains(from) { 707 log.Info("Setting new local account", "address", from) 708 pool.locals.add(from) 709 } 710 } 711 pool.journalTx(from, tx) 712 713 log.Trace("Pooled new future transaction", "hash", hash, "from", from, "to", tx.To()) 714 return replace, nil 715 } 716 717 // enqueueTx inserts a new transaction into the non-executable transaction queue. 718 // 719 // Note, this method assumes the pool lock is held! 720 func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) (bool, error) { 721 // Try to insert the transaction into the future queue 722 from, _ := types.Sender(pool.signer, tx) // already validated 723 if pool.queue[from] == nil { 724 pool.queue[from] = newTxList(false) 725 } 726 inserted, old := pool.queue[from].Add(tx, pool.config.PriceBump) 727 if !inserted { 728 // An older transaction was better, discard this 729 queuedDiscardCounter.Inc(1) 730 return false, ErrReplaceUnderpriced 731 } 732 // Discard any previous transaction and mark this 733 if old != nil { 734 pool.all.Remove(old.Hash()) 735 pool.priced.Removed() 736 queuedReplaceCounter.Inc(1) 737 } 738 if pool.all.Get(hash) == nil { 739 pool.all.Add(tx) 740 pool.priced.Put(tx) 741 } 742 return old != nil, nil 743 } 744 745 // journalTx adds the specified transaction to the local disk journal if it is 746 // deemed to have been sent from a local account. 747 func (pool *TxPool) journalTx(from common.Address, tx *types.Transaction) { 748 // Only journal if it's enabled and the transaction is local 749 if pool.journal == nil || !pool.locals.contains(from) { 750 return 751 } 752 if err := pool.journal.insert(tx); err != nil { 753 log.Warn("Failed to journal local transaction", "err", err) 754 } 755 } 756 757 // promoteTx adds a transaction to the pending (processable) list of transactions 758 // and returns whether it was inserted or an older was better. 759 // 760 // Note, this method assumes the pool lock is held! 761 func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) bool { 762 // Try to insert the transaction into the pending queue 763 if pool.pending[addr] == nil { 764 pool.pending[addr] = newTxList(true) 765 } 766 list := pool.pending[addr] 767 768 inserted, old := list.Add(tx, pool.config.PriceBump) 769 if !inserted { 770 // An older transaction was better, discard this 771 pool.all.Remove(hash) 772 pool.priced.Removed() 773 774 pendingDiscardCounter.Inc(1) 775 return false 776 } 777 // Otherwise discard any previous transaction and mark this 778 if old != nil { 779 pool.all.Remove(old.Hash()) 780 pool.priced.Removed() 781 782 pendingReplaceCounter.Inc(1) 783 } 784 // Failsafe to work around direct pending inserts (tests) 785 if pool.all.Get(hash) == nil { 786 pool.all.Add(tx) 787 pool.priced.Put(tx) 788 } 789 // Set the potentially new pending nonce and notify any subsystems of the new tx 790 pool.beats[addr] = time.Now() 791 pool.pendingState.SetNonce(addr, tx.Nonce()+1) 792 793 return true 794 } 795 796 // AddLocal enqueues a single transaction into the pool if it is valid, marking 797 // the sender as a local one in the mean time, ensuring it goes around the local 798 // pricing constraints. 799 func (pool *TxPool) AddLocal(tx *types.Transaction) error { 800 return pool.addTx(tx, !pool.config.NoLocals) 801 } 802 803 // AddRemote enqueues a single transaction into the pool if it is valid. If the 804 // sender is not among the locally tracked ones, full pricing constraints will 805 // apply. 806 func (pool *TxPool) AddRemote(tx *types.Transaction) error { 807 return pool.addTx(tx, false) 808 } 809 810 // AddLocals enqueues a batch of transactions into the pool if they are valid, 811 // marking the senders as a local ones in the mean time, ensuring they go around 812 // the local pricing constraints. 813 func (pool *TxPool) AddLocals(txs []*types.Transaction) []error { 814 return pool.addTxs(txs, !pool.config.NoLocals) 815 } 816 817 // AddRemotes enqueues a batch of transactions into the pool if they are valid. 818 // If the senders are not among the locally tracked ones, full pricing constraints 819 // will apply. 820 func (pool *TxPool) AddRemotes(txs []*types.Transaction) []error { 821 return pool.addTxs(txs, false) 822 } 823 824 // addTx enqueues a single transaction into the pool if it is valid. 825 func (pool *TxPool) addTx(tx *types.Transaction, local bool) error { 826 pool.mu.Lock() 827 defer pool.mu.Unlock() 828 829 // Try to inject the transaction and update any state 830 replace, err := pool.add(tx, local) 831 if err != nil { 832 return err 833 } 834 // If we added a new transaction, run promotion checks and return 835 if !replace { 836 from, _ := types.Sender(pool.signer, tx) // already validated 837 pool.promoteExecutables([]common.Address{from}) 838 } 839 return nil 840 } 841 842 // addTxs attempts to queue a batch of transactions if they are valid. 843 func (pool *TxPool) addTxs(txs []*types.Transaction, local bool) []error { 844 pool.mu.Lock() 845 defer pool.mu.Unlock() 846 847 return pool.addTxsLocked(txs, local) 848 } 849 850 // addTxsLocked attempts to queue a batch of transactions if they are valid, 851 // whilst assuming the transaction pool lock is already held. 852 func (pool *TxPool) addTxsLocked(txs []*types.Transaction, local bool) []error { 853 // Add the batch of transactions, tracking the accepted ones 854 dirty := make(map[common.Address]struct{}) 855 errs := make([]error, len(txs)) 856 857 for i, tx := range txs { 858 var replace bool 859 if replace, errs[i] = pool.add(tx, local); errs[i] == nil && !replace { 860 from, _ := types.Sender(pool.signer, tx) // already validated 861 dirty[from] = struct{}{} 862 } 863 } 864 // Only reprocess the internal state if something was actually added 865 if len(dirty) > 0 { 866 addrs := make([]common.Address, 0, len(dirty)) 867 for addr := range dirty { 868 addrs = append(addrs, addr) 869 } 870 pool.promoteExecutables(addrs) 871 } 872 return errs 873 } 874 875 // Status returns the status (unknown/pending/queued) of a batch of transactions 876 // identified by their hashes. 877 func (pool *TxPool) Status(hashes []common.Hash) []TxStatus { 878 pool.mu.RLock() 879 defer pool.mu.RUnlock() 880 881 status := make([]TxStatus, len(hashes)) 882 for i, hash := range hashes { 883 if tx := pool.all.Get(hash); tx != nil { 884 from, _ := types.Sender(pool.signer, tx) // already validated 885 if pool.pending[from] != nil && pool.pending[from].txs.items[tx.Nonce()] != nil { 886 status[i] = TxStatusPending 887 } else { 888 status[i] = TxStatusQueued 889 } 890 } 891 } 892 return status 893 } 894 895 // Get returns a transaction if it is contained in the pool 896 // and nil otherwise. 897 func (pool *TxPool) Get(hash common.Hash) *types.Transaction { 898 return pool.all.Get(hash) 899 } 900 901 // removeTx removes a single transaction from the queue, moving all subsequent 902 // transactions back to the future queue. 903 func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) { 904 // Fetch the transaction we wish to delete 905 tx := pool.all.Get(hash) 906 if tx == nil { 907 return 908 } 909 addr, _ := types.Sender(pool.signer, tx) // already validated during insertion 910 911 // Remove it from the list of known transactions 912 pool.all.Remove(hash) 913 if outofbound { 914 pool.priced.Removed() 915 } 916 // Remove the transaction from the pending lists and reset the account nonce 917 if pending := pool.pending[addr]; pending != nil { 918 if removed, invalids := pending.Remove(tx); removed { 919 // If no more pending transactions are left, remove the list 920 if pending.Empty() { 921 delete(pool.pending, addr) 922 delete(pool.beats, addr) 923 } 924 // Postpone any invalidated transactions 925 for _, tx := range invalids { 926 pool.enqueueTx(tx.Hash(), tx) 927 } 928 // Update the account nonce if needed 929 if nonce := tx.Nonce(); pool.pendingState.GetNonce(addr) > nonce { 930 pool.pendingState.SetNonce(addr, nonce) 931 } 932 return 933 } 934 } 935 // Transaction is in the future queue 936 if future := pool.queue[addr]; future != nil { 937 future.Remove(tx) 938 if future.Empty() { 939 delete(pool.queue, addr) 940 } 941 } 942 } 943 944 // promoteExecutables moves transactions that have become processable from the 945 // future queue to the set of pending transactions. During this process, all 946 // invalidated transactions (low nonce, low balance) are deleted. 947 func (pool *TxPool) promoteExecutables(accounts []common.Address) { 948 isQuorum := pool.chainconfig.IsQuorum 949 // Init delayed since tx pool could have been started before any state sync 950 if isQuorum && pool.pendingState == nil { 951 pool.reset(nil, nil) 952 } 953 var promoted []*types.Transaction 954 // Gather all the accounts potentially needing updates 955 if accounts == nil { 956 accounts = make([]common.Address, 0, len(pool.queue)) 957 for addr := range pool.queue { 958 accounts = append(accounts, addr) 959 } 960 } 961 // Iterate over all accounts and promote any executable transactions 962 for _, addr := range accounts { 963 list := pool.queue[addr] 964 if list == nil { 965 continue // Just in case someone calls with a non existing account 966 } 967 // Drop all transactions that are deemed too old (low nonce) 968 for _, tx := range list.Forward(pool.currentState.GetNonce(addr)) { 969 hash := tx.Hash() 970 log.Trace("Removed old queued transaction", "hash", hash) 971 pool.all.Remove(hash) 972 pool.priced.Removed() 973 } 974 if !isQuorum { 975 // Drop all transactions that are too costly (low balance or out of gas) 976 drops, _ := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas) 977 for _, tx := range drops { 978 hash := tx.Hash() 979 log.Trace("Removed unpayable queued transaction", "hash", hash) 980 pool.all.Remove(hash) 981 pool.priced.Removed() 982 queuedNofundsCounter.Inc(1) 983 } 984 } 985 // Gather all executable transactions and promote them 986 for _, tx := range list.Ready(pool.pendingState.GetNonce(addr)) { 987 hash := tx.Hash() 988 log.Trace("Promoting queued transaction", "hash", hash) 989 if pool.promoteTx(addr, hash, tx) { 990 log.Trace("Promoting queued transaction", "hash", hash) 991 promoted = append(promoted, tx) 992 } 993 } 994 // Drop all transactions over the allowed limit 995 if !pool.locals.contains(addr) { 996 for _, tx := range list.Cap(int(pool.config.AccountQueue)) { 997 hash := tx.Hash() 998 pool.all.Remove(hash) 999 pool.priced.Removed() 1000 queuedRateLimitCounter.Inc(1) 1001 log.Trace("Removed cap-exceeding queued transaction", "hash", hash) 1002 } 1003 } 1004 // Delete the entire queue entry if it became empty. 1005 if list.Empty() { 1006 delete(pool.queue, addr) 1007 } 1008 } 1009 // Notify subsystem for new promoted transactions. 1010 if len(promoted) > 0 { 1011 go pool.txFeed.Send(NewTxsEvent{promoted}) 1012 } 1013 // If the pending limit is overflown, start equalizing allowances 1014 pending := uint64(0) 1015 for _, list := range pool.pending { 1016 pending += uint64(list.Len()) 1017 } 1018 if pending > pool.config.GlobalSlots { 1019 pendingBeforeCap := pending 1020 // Assemble a spam order to penalize large transactors first 1021 spammers := prque.New(nil) 1022 for addr, list := range pool.pending { 1023 // Only evict transactions from high rollers 1024 if !pool.locals.contains(addr) && uint64(list.Len()) > pool.config.AccountSlots { 1025 spammers.Push(addr, int64(list.Len())) 1026 } 1027 } 1028 // Gradually drop transactions from offenders 1029 offenders := []common.Address{} 1030 for pending > pool.config.GlobalSlots && !spammers.Empty() { 1031 // Retrieve the next offender if not local address 1032 offender, _ := spammers.Pop() 1033 offenders = append(offenders, offender.(common.Address)) 1034 1035 // Equalize balances until all the same or below threshold 1036 if len(offenders) > 1 { 1037 // Calculate the equalization threshold for all current offenders 1038 threshold := pool.pending[offender.(common.Address)].Len() 1039 1040 // Iteratively reduce all offenders until below limit or threshold reached 1041 for pending > pool.config.GlobalSlots && pool.pending[offenders[len(offenders)-2]].Len() > threshold { 1042 for i := 0; i < len(offenders)-1; i++ { 1043 list := pool.pending[offenders[i]] 1044 for _, tx := range list.Cap(list.Len() - 1) { 1045 // Drop the transaction from the global pools too 1046 hash := tx.Hash() 1047 pool.all.Remove(hash) 1048 pool.priced.Removed() 1049 1050 // Update the account nonce to the dropped transaction 1051 if nonce := tx.Nonce(); pool.pendingState.GetNonce(offenders[i]) > nonce { 1052 pool.pendingState.SetNonce(offenders[i], nonce) 1053 } 1054 log.Trace("Removed fairness-exceeding pending transaction", "hash", hash) 1055 } 1056 pending-- 1057 } 1058 } 1059 } 1060 } 1061 // If still above threshold, reduce to limit or min allowance 1062 if pending > pool.config.GlobalSlots && len(offenders) > 0 { 1063 for pending > pool.config.GlobalSlots && uint64(pool.pending[offenders[len(offenders)-1]].Len()) > pool.config.AccountSlots { 1064 for _, addr := range offenders { 1065 list := pool.pending[addr] 1066 for _, tx := range list.Cap(list.Len() - 1) { 1067 // Drop the transaction from the global pools too 1068 hash := tx.Hash() 1069 pool.all.Remove(hash) 1070 pool.priced.Removed() 1071 1072 // Update the account nonce to the dropped transaction 1073 if nonce := tx.Nonce(); pool.pendingState.GetNonce(addr) > nonce { 1074 pool.pendingState.SetNonce(addr, nonce) 1075 } 1076 log.Trace("Removed fairness-exceeding pending transaction", "hash", hash) 1077 } 1078 pending-- 1079 } 1080 } 1081 } 1082 pendingRateLimitCounter.Inc(int64(pendingBeforeCap - pending)) 1083 } 1084 // If we've queued more transactions than the hard limit, drop oldest ones 1085 queued := uint64(0) 1086 for _, list := range pool.queue { 1087 queued += uint64(list.Len()) 1088 } 1089 if queued > pool.config.GlobalQueue { 1090 // Sort all accounts with queued transactions by heartbeat 1091 addresses := make(addressesByHeartbeat, 0, len(pool.queue)) 1092 for addr := range pool.queue { 1093 if !pool.locals.contains(addr) { // don't drop locals 1094 addresses = append(addresses, addressByHeartbeat{addr, pool.beats[addr]}) 1095 } 1096 } 1097 sort.Sort(addresses) 1098 1099 // Drop transactions until the total is below the limit or only locals remain 1100 for drop := queued - pool.config.GlobalQueue; drop > 0 && len(addresses) > 0; { 1101 addr := addresses[len(addresses)-1] 1102 list := pool.queue[addr.address] 1103 1104 addresses = addresses[:len(addresses)-1] 1105 1106 // Drop all transactions if they are less than the overflow 1107 if size := uint64(list.Len()); size <= drop { 1108 for _, tx := range list.Flatten() { 1109 pool.removeTx(tx.Hash(), true) 1110 } 1111 drop -= size 1112 queuedRateLimitCounter.Inc(int64(size)) 1113 continue 1114 } 1115 // Otherwise drop only last few transactions 1116 txs := list.Flatten() 1117 for i := len(txs) - 1; i >= 0 && drop > 0; i-- { 1118 pool.removeTx(txs[i].Hash(), true) 1119 drop-- 1120 queuedRateLimitCounter.Inc(1) 1121 } 1122 } 1123 } 1124 } 1125 1126 // demoteUnexecutables removes invalid and processed transactions from the pools 1127 // executable/pending queue and any subsequent transactions that become unexecutable 1128 // are moved back into the future queue. 1129 func (pool *TxPool) demoteUnexecutables() { 1130 // Iterate over all accounts and demote any non-executable transactions 1131 for addr, list := range pool.pending { 1132 nonce := pool.currentState.GetNonce(addr) 1133 1134 // Drop all transactions that are deemed too old (low nonce) 1135 for _, tx := range list.Forward(nonce) { 1136 hash := tx.Hash() 1137 log.Trace("Removed old pending transaction", "hash", hash) 1138 pool.all.Remove(hash) 1139 pool.priced.Removed() 1140 } 1141 // Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later 1142 drops, invalids := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas) 1143 for _, tx := range drops { 1144 hash := tx.Hash() 1145 log.Trace("Removed unpayable pending transaction", "hash", hash) 1146 pool.all.Remove(hash) 1147 pool.priced.Removed() 1148 pendingNofundsCounter.Inc(1) 1149 } 1150 for _, tx := range invalids { 1151 hash := tx.Hash() 1152 log.Trace("Demoting pending transaction", "hash", hash) 1153 pool.enqueueTx(hash, tx) 1154 } 1155 // If there's a gap in front, warn (should never happen) and postpone all transactions 1156 if list.Len() > 0 && list.txs.Get(nonce) == nil { 1157 for _, tx := range list.Cap(0) { 1158 hash := tx.Hash() 1159 log.Error("Demoting invalidated transaction", "hash", hash) 1160 pool.enqueueTx(hash, tx) 1161 } 1162 } 1163 // Delete the entire queue entry if it became empty. 1164 if list.Empty() { 1165 delete(pool.pending, addr) 1166 delete(pool.beats, addr) 1167 } 1168 } 1169 } 1170 1171 // addressByHeartbeat is an account address tagged with its last activity timestamp. 1172 type addressByHeartbeat struct { 1173 address common.Address 1174 heartbeat time.Time 1175 } 1176 1177 type addressesByHeartbeat []addressByHeartbeat 1178 1179 func (a addressesByHeartbeat) Len() int { return len(a) } 1180 func (a addressesByHeartbeat) Less(i, j int) bool { return a[i].heartbeat.Before(a[j].heartbeat) } 1181 func (a addressesByHeartbeat) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 1182 1183 // accountSet is simply a set of addresses to check for existence, and a signer 1184 // capable of deriving addresses from transactions. 1185 type accountSet struct { 1186 accounts map[common.Address]struct{} 1187 signer types.Signer 1188 cache *[]common.Address 1189 } 1190 1191 // newAccountSet creates a new address set with an associated signer for sender 1192 // derivations. 1193 func newAccountSet(signer types.Signer) *accountSet { 1194 return &accountSet{ 1195 accounts: make(map[common.Address]struct{}), 1196 signer: signer, 1197 } 1198 } 1199 1200 // contains checks if a given address is contained within the set. 1201 func (as *accountSet) contains(addr common.Address) bool { 1202 _, exist := as.accounts[addr] 1203 return exist 1204 } 1205 1206 // containsTx checks if the sender of a given tx is within the set. If the sender 1207 // cannot be derived, this method returns false. 1208 func (as *accountSet) containsTx(tx *types.Transaction) bool { 1209 if addr, err := types.Sender(as.signer, tx); err == nil { 1210 return as.contains(addr) 1211 } 1212 return false 1213 } 1214 1215 // add inserts a new address into the set to track. 1216 func (as *accountSet) add(addr common.Address) { 1217 as.accounts[addr] = struct{}{} 1218 as.cache = nil 1219 } 1220 1221 // flatten returns the list of addresses within this set, also caching it for later 1222 // reuse. The returned slice should not be changed! 1223 func (as *accountSet) flatten() []common.Address { 1224 if as.cache == nil { 1225 accounts := make([]common.Address, 0, len(as.accounts)) 1226 for account := range as.accounts { 1227 accounts = append(accounts, account) 1228 } 1229 as.cache = &accounts 1230 } 1231 return *as.cache 1232 } 1233 1234 // txLookup is used internally by TxPool to track transactions while allowing lookup without 1235 // mutex contention. 1236 // 1237 // Note, although this type is properly protected against concurrent access, it 1238 // is **not** a type that should ever be mutated or even exposed outside of the 1239 // transaction pool, since its internal state is tightly coupled with the pools 1240 // internal mechanisms. The sole purpose of the type is to permit out-of-bound 1241 // peeking into the pool in TxPool.Get without having to acquire the widely scoped 1242 // TxPool.mu mutex. 1243 type txLookup struct { 1244 all map[common.Hash]*types.Transaction 1245 lock sync.RWMutex 1246 } 1247 1248 // newTxLookup returns a new txLookup structure. 1249 func newTxLookup() *txLookup { 1250 return &txLookup{ 1251 all: make(map[common.Hash]*types.Transaction), 1252 } 1253 } 1254 1255 // Range calls f on each key and value present in the map. 1256 func (t *txLookup) Range(f func(hash common.Hash, tx *types.Transaction) bool) { 1257 t.lock.RLock() 1258 defer t.lock.RUnlock() 1259 1260 for key, value := range t.all { 1261 if !f(key, value) { 1262 break 1263 } 1264 } 1265 } 1266 1267 // Get returns a transaction if it exists in the lookup, or nil if not found. 1268 func (t *txLookup) Get(hash common.Hash) *types.Transaction { 1269 t.lock.RLock() 1270 defer t.lock.RUnlock() 1271 1272 return t.all[hash] 1273 } 1274 1275 // Count returns the current number of items in the lookup. 1276 func (t *txLookup) Count() int { 1277 t.lock.RLock() 1278 defer t.lock.RUnlock() 1279 1280 return len(t.all) 1281 } 1282 1283 // Add adds a transaction to the lookup. 1284 func (t *txLookup) Add(tx *types.Transaction) { 1285 t.lock.Lock() 1286 defer t.lock.Unlock() 1287 1288 t.all[tx.Hash()] = tx 1289 } 1290 1291 // Remove removes a transaction from the lookup. 1292 func (t *txLookup) Remove(hash common.Hash) { 1293 t.lock.Lock() 1294 defer t.lock.Unlock() 1295 1296 delete(t.all, hash) 1297 }