github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/chain/core/tx_pool.go (about) 1 package core 2 3 import ( 4 "errors" 5 "fmt" 6 "math" 7 "math/big" 8 "sort" 9 "sync" 10 "time" 11 12 "github.com/neatlab/neatio/chain/core/state" 13 "github.com/neatlab/neatio/chain/core/types" 14 "github.com/neatlab/neatio/chain/log" 15 neatAbi "github.com/neatlab/neatio/neatabi/abi" 16 "github.com/neatlab/neatio/params" 17 "github.com/neatlab/neatio/utilities/common" 18 "github.com/neatlab/neatio/utilities/common/prque" 19 "github.com/neatlab/neatio/utilities/event" 20 "github.com/neatlab/neatio/utilities/metrics" 21 ) 22 23 const ( 24 chainHeadChanSize = 10 25 ) 26 27 var ( 28 ErrInvalidSender = errors.New("invalid sender") 29 30 ErrInvalidAddress = errors.New("invalid address") 31 32 ErrNonceTooLow = errors.New("nonce too low") 33 34 ErrUnderpriced = errors.New("transaction underpriced") 35 36 ErrReplaceUnderpriced = errors.New("replacement transaction underpriced") 37 38 ErrInsufficientFunds = errors.New("insufficient funds for gas * price + value") 39 40 ErrIntrinsicGas = errors.New("intrinsic gas too low") 41 42 ErrGasLimit = errors.New("exceeds block gas limit") 43 44 ErrNegativeValue = errors.New("negative value") 45 46 ErrOversizedData = errors.New("oversized data") 47 ) 48 49 var ( 50 evictionInterval = time.Minute 51 statsReportInterval = 8 * time.Second 52 ) 53 54 var ( 55 pendingDiscardCounter = metrics.NewRegisteredCounter("txpool/pending/discard", nil) 56 pendingReplaceCounter = metrics.NewRegisteredCounter("txpool/pending/replace", nil) 57 pendingRateLimitCounter = metrics.NewRegisteredCounter("txpool/pending/ratelimit", nil) 58 pendingNofundsCounter = metrics.NewRegisteredCounter("txpool/pending/nofunds", nil) 59 60 queuedDiscardCounter = metrics.NewRegisteredCounter("txpool/queued/discard", nil) 61 queuedReplaceCounter = metrics.NewRegisteredCounter("txpool/queued/replace", nil) 62 queuedRateLimitCounter = metrics.NewRegisteredCounter("txpool/queued/ratelimit", nil) 63 queuedNofundsCounter = metrics.NewRegisteredCounter("txpool/queued/nofunds", nil) 64 65 invalidTxCounter = metrics.NewRegisteredCounter("txpool/invalid", nil) 66 underpricedTxCounter = metrics.NewRegisteredCounter("txpool/underpriced", nil) 67 ) 68 69 type TxStatus uint 70 71 const ( 72 TxStatusUnknown TxStatus = iota 73 TxStatusQueued 74 TxStatusPending 75 TxStatusIncluded 76 ) 77 78 type blockChain interface { 79 CurrentBlock() *types.Block 80 GetBlock(hash common.Hash, number uint64) *types.Block 81 StateAt(root common.Hash) (*state.StateDB, error) 82 83 SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription 84 } 85 86 type TxPoolConfig struct { 87 NoLocals bool 88 Journal string 89 Rejournal time.Duration 90 91 PriceLimit uint64 92 PriceBump uint64 93 94 AccountSlots uint64 95 GlobalSlots uint64 96 AccountQueue uint64 97 GlobalQueue uint64 98 99 Lifetime time.Duration 100 } 101 102 var DefaultTxPoolConfig = TxPoolConfig{ 103 Journal: "transactions.rlp", 104 Rejournal: time.Hour, 105 106 PriceLimit: 1, 107 PriceBump: 10, 108 109 AccountSlots: 16, 110 GlobalSlots: 4096, 111 AccountQueue: 64, 112 GlobalQueue: 1024, 113 114 Lifetime: 3 * time.Hour, 115 } 116 117 func (config *TxPoolConfig) sanitize() TxPoolConfig { 118 conf := *config 119 if conf.Rejournal < time.Second { 120 log.Warn("Sanitizing invalid txpool journal time", "provided", conf.Rejournal, "updated", time.Second) 121 conf.Rejournal = time.Second 122 } 123 if conf.PriceLimit < 1 { 124 log.Warn("Sanitizing invalid txpool price limit", "provided", conf.PriceLimit, "updated", DefaultTxPoolConfig.PriceLimit) 125 conf.PriceLimit = DefaultTxPoolConfig.PriceLimit 126 } 127 if conf.PriceBump < 1 { 128 log.Warn("Sanitizing invalid txpool price bump", "provided", conf.PriceBump, "updated", DefaultTxPoolConfig.PriceBump) 129 conf.PriceBump = DefaultTxPoolConfig.PriceBump 130 } 131 return conf 132 } 133 134 type TxPool struct { 135 config TxPoolConfig 136 chainconfig *params.ChainConfig 137 chain blockChain 138 gasPrice *big.Int 139 txFeed event.Feed 140 scope event.SubscriptionScope 141 chainHeadCh chan ChainHeadEvent 142 chainHeadSub event.Subscription 143 signer types.Signer 144 mu sync.RWMutex 145 146 currentState *state.StateDB 147 pendingState *state.ManagedState 148 currentMaxGas uint64 149 150 locals *accountSet 151 journal *txJournal 152 153 pending map[common.Address]*txList 154 queue map[common.Address]*txList 155 beats map[common.Address]time.Time 156 all map[common.Hash]*types.Transaction 157 priced *txPricedList 158 159 wg sync.WaitGroup 160 161 cch CrossChainHelper 162 } 163 164 var TxPoolSigner types.Signer = nil 165 166 func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain blockChain, cch CrossChainHelper) *TxPool { 167 168 config = (&config).sanitize() 169 170 pool := &TxPool{ 171 config: config, 172 chainconfig: chainconfig, 173 chain: chain, 174 signer: types.NewEIP155Signer(chainconfig.ChainId), 175 pending: make(map[common.Address]*txList), 176 queue: make(map[common.Address]*txList), 177 beats: make(map[common.Address]time.Time), 178 all: make(map[common.Hash]*types.Transaction), 179 chainHeadCh: make(chan ChainHeadEvent, chainHeadChanSize), 180 gasPrice: new(big.Int).SetUint64(config.PriceLimit), 181 cch: cch, 182 } 183 pool.locals = newAccountSet(pool.signer) 184 pool.priced = newTxPricedList(&pool.all) 185 pool.reset(nil, chain.CurrentBlock().Header()) 186 187 if !config.NoLocals && config.Journal != "" { 188 pool.journal = newTxJournal(config.Journal) 189 190 log.Debug("Load transaction journal", "journal", pool.journal) 191 if err := pool.journal.load(pool.AddLocal); err != nil { 192 log.Warn("Failed to load transaction journal", "err", err) 193 } 194 if err := pool.journal.rotate(pool.local()); err != nil { 195 log.Warn("Failed to rotate transaction journal", "err", err) 196 } 197 } 198 199 TxPoolSigner = pool.signer 200 201 pool.chainHeadSub = pool.chain.SubscribeChainHeadEvent(pool.chainHeadCh) 202 203 pool.wg.Add(1) 204 go pool.loop() 205 206 return pool 207 } 208 209 func (pool *TxPool) loop() { 210 defer pool.wg.Done() 211 212 var prevPending, prevQueued, prevStales int 213 214 report := time.NewTicker(statsReportInterval) 215 defer report.Stop() 216 217 evict := time.NewTicker(evictionInterval) 218 defer evict.Stop() 219 220 journal := time.NewTicker(pool.config.Rejournal) 221 defer journal.Stop() 222 223 head := pool.chain.CurrentBlock() 224 225 for { 226 select { 227 228 case ev := <-pool.chainHeadCh: 229 if ev.Block != nil { 230 pool.mu.Lock() 231 pool.reset(head.Header(), ev.Block.Header()) 232 head = ev.Block 233 pool.mu.Unlock() 234 } 235 236 case <-pool.chainHeadSub.Err(): 237 return 238 239 case <-report.C: 240 pool.mu.RLock() 241 pending, queued := pool.stats() 242 stales := pool.priced.stales 243 pool.mu.RUnlock() 244 245 if pending != prevPending || queued != prevQueued || stales != prevStales { 246 log.Debug("Transaction pool status report", "executable", pending, "queued", queued, "stales", stales) 247 prevPending, prevQueued, prevStales = pending, queued, stales 248 } 249 250 case <-evict.C: 251 pool.mu.Lock() 252 for addr := range pool.queue { 253 254 if pool.locals.contains(addr) { 255 continue 256 } 257 258 if time.Since(pool.beats[addr]) > pool.config.Lifetime { 259 for _, tx := range pool.queue[addr].Flatten() { 260 pool.removeTx(tx.Hash()) 261 } 262 } 263 } 264 pool.mu.Unlock() 265 266 case <-journal.C: 267 if pool.journal != nil { 268 pool.mu.Lock() 269 if err := pool.journal.rotate(pool.local()); err != nil { 270 log.Warn("Failed to rotate local tx journal", "err", err) 271 } 272 pool.mu.Unlock() 273 } 274 } 275 } 276 } 277 278 func (pool *TxPool) lockedReset(oldHead, newHead *types.Header) { 279 pool.mu.Lock() 280 defer pool.mu.Unlock() 281 282 pool.reset(oldHead, newHead) 283 } 284 285 func (pool *TxPool) reset(oldHead, newHead *types.Header) { 286 287 var reinject types.Transactions 288 289 if oldHead != nil && oldHead.Hash() != newHead.ParentHash { 290 291 oldNum := oldHead.Number.Uint64() 292 newNum := newHead.Number.Uint64() 293 294 if depth := uint64(math.Abs(float64(oldNum) - float64(newNum))); depth > 64 { 295 log.Debug("Skipping deep transaction reorg", "depth", depth) 296 } else { 297 298 var discarded, included types.Transactions 299 300 var ( 301 rem = pool.chain.GetBlock(oldHead.Hash(), oldHead.Number.Uint64()) 302 add = pool.chain.GetBlock(newHead.Hash(), newHead.Number.Uint64()) 303 ) 304 for rem.NumberU64() > add.NumberU64() { 305 discarded = append(discarded, rem.Transactions()...) 306 if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil { 307 log.Error("Unrooted old chain seen by tx pool", "block", oldHead.Number, "hash", oldHead.Hash()) 308 return 309 } 310 } 311 for add.NumberU64() > rem.NumberU64() { 312 included = append(included, add.Transactions()...) 313 if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil { 314 log.Error("Unrooted new chain seen by tx pool", "block", newHead.Number, "hash", newHead.Hash()) 315 return 316 } 317 } 318 for rem.Hash() != add.Hash() { 319 discarded = append(discarded, rem.Transactions()...) 320 if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil { 321 log.Error("Unrooted old chain seen by tx pool", "block", oldHead.Number, "hash", oldHead.Hash()) 322 return 323 } 324 included = append(included, add.Transactions()...) 325 if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil { 326 log.Error("Unrooted new chain seen by tx pool", "block", newHead.Number, "hash", newHead.Hash()) 327 return 328 } 329 } 330 reinject = types.TxDifference(discarded, included) 331 } 332 } 333 334 if newHead == nil { 335 newHead = pool.chain.CurrentBlock().Header() 336 } 337 statedb, err := pool.chain.StateAt(newHead.Root) 338 if err != nil { 339 log.Error("Failed to reset txpool state", "err", err) 340 return 341 } 342 pool.currentState = statedb 343 pool.pendingState = state.ManageState(statedb) 344 pool.currentMaxGas = newHead.GasLimit 345 346 log.Debug("Reinjecting stale transactions", "count", len(reinject)) 347 pool.addTxsLocked(reinject, false) 348 349 pool.demoteUnexecutables() 350 351 for addr, list := range pool.pending { 352 txs := list.Flatten() 353 pool.pendingState.SetNonce(addr, txs[len(txs)-1].Nonce()+1) 354 } 355 356 pool.promoteExecutables(nil) 357 } 358 359 func (pool *TxPool) Stop() { 360 361 pool.scope.Close() 362 363 pool.chainHeadSub.Unsubscribe() 364 pool.wg.Wait() 365 366 if pool.journal != nil { 367 pool.journal.close() 368 } 369 log.Info("Transaction pool stopped") 370 } 371 372 func (pool *TxPool) SubscribeTxPreEvent(ch chan<- TxPreEvent) event.Subscription { 373 return pool.scope.Track(pool.txFeed.Subscribe(ch)) 374 } 375 376 func (pool *TxPool) GasPrice() *big.Int { 377 pool.mu.RLock() 378 defer pool.mu.RUnlock() 379 380 return new(big.Int).Set(pool.gasPrice) 381 } 382 383 func (pool *TxPool) SetGasPrice(price *big.Int) { 384 pool.mu.Lock() 385 defer pool.mu.Unlock() 386 387 pool.gasPrice = price 388 for _, tx := range pool.priced.Cap(price, pool.locals) { 389 pool.removeTx(tx.Hash()) 390 } 391 log.Info("Transaction pool price threshold updated", "price", price) 392 } 393 394 func (pool *TxPool) State() *state.ManagedState { 395 pool.mu.RLock() 396 defer pool.mu.RUnlock() 397 398 return pool.pendingState 399 } 400 401 func (pool *TxPool) Stats() (int, int) { 402 pool.mu.RLock() 403 defer pool.mu.RUnlock() 404 405 return pool.stats() 406 } 407 408 func (pool *TxPool) stats() (int, int) { 409 pending := 0 410 for _, list := range pool.pending { 411 pending += list.Len() 412 } 413 queued := 0 414 for _, list := range pool.queue { 415 queued += list.Len() 416 } 417 return pending, queued 418 } 419 420 func (pool *TxPool) Content() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) { 421 pool.mu.Lock() 422 defer pool.mu.Unlock() 423 424 pending := make(map[common.Address]types.Transactions) 425 for addr, list := range pool.pending { 426 pending[addr] = list.Flatten() 427 } 428 queued := make(map[common.Address]types.Transactions) 429 for addr, list := range pool.queue { 430 queued[addr] = list.Flatten() 431 } 432 return pending, queued 433 } 434 435 func (pool *TxPool) Pending() (map[common.Address]types.Transactions, error) { 436 pool.mu.Lock() 437 defer pool.mu.Unlock() 438 439 pending := make(map[common.Address]types.Transactions) 440 for addr, list := range pool.pending { 441 pending[addr] = list.Flatten() 442 } 443 return pending, nil 444 } 445 446 func (pool *TxPool) local() map[common.Address]types.Transactions { 447 txs := make(map[common.Address]types.Transactions) 448 for addr := range pool.locals.accounts { 449 if pending := pool.pending[addr]; pending != nil { 450 txs[addr] = append(txs[addr], pending.Flatten()...) 451 } 452 if queued := pool.queue[addr]; queued != nil { 453 txs[addr] = append(txs[addr], queued.Flatten()...) 454 } 455 } 456 return txs 457 } 458 459 func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { 460 461 if tx.Size() > 32*1024 { 462 return ErrOversizedData 463 } 464 465 if tx.Value().Sign() < 0 { 466 return ErrNegativeValue 467 } 468 469 if pool.currentMaxGas < tx.Gas() { 470 return ErrGasLimit 471 } 472 473 from, err := types.Sender(pool.signer, tx) 474 if err != nil { 475 return ErrInvalidSender 476 } 477 478 local = local || pool.locals.contains(from) 479 if !local && pool.gasPrice.Cmp(tx.GasPrice()) > 0 { 480 return ErrUnderpriced 481 } 482 483 if pool.currentState.GetNonce(from) > tx.Nonce() { 484 return ErrNonceTooLow 485 } 486 487 if pool.currentState.GetBalance(from).Cmp(tx.Cost()) < 0 { 488 return ErrInsufficientFunds 489 } 490 491 if !neatAbi.IsNeatChainContractAddr(tx.To()) { 492 intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, true) 493 if err != nil { 494 return err 495 } 496 if tx.Gas() < intrGas { 497 return ErrIntrinsicGas 498 } 499 } else { 500 501 data := tx.Data() 502 function, err := neatAbi.FunctionTypeFromId(data[:4]) 503 if err != nil { 504 return err 505 } 506 507 if pool.chainconfig.IsMainChain() && !function.AllowInMainChain() { 508 return ErrNotAllowedInMainChain 509 } else if !pool.chainconfig.IsMainChain() && !function.AllowInSideChain() { 510 return ErrNotAllowedInSideChain 511 } 512 513 log.Infof("validateTx Chain Function %v", function.String()) 514 if validateCb := GetValidateCb(function); validateCb != nil { 515 if function.IsCrossChainType() { 516 if fn, ok := validateCb.(CrossChainValidateCb); ok { 517 pool.cch.GetMutex().Lock() 518 err := fn(tx, pool.currentState, pool.cch) 519 pool.cch.GetMutex().Unlock() 520 if err != nil { 521 return err 522 } 523 } else { 524 panic("callback func is wrong, this should not happened, please check the code") 525 } 526 } else { 527 if fn, ok := validateCb.(NonCrossChainValidateCb); ok { 528 if err := fn(tx, pool.currentState, pool.chain.(*BlockChain)); err != nil { 529 return err 530 } 531 } else { 532 panic("callback func is wrong, this should not happened, please check the code") 533 } 534 } 535 } 536 } 537 538 return nil 539 } 540 541 func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) { 542 543 hash := tx.Hash() 544 if pool.all[hash] != nil { 545 log.Trace("Discarding already known transaction", "hash", hash) 546 return false, fmt.Errorf("known transaction: %x", hash) 547 } 548 549 if err := pool.validateTx(tx, local); err != nil { 550 log.Trace("Discarding invalid transaction", "hash", hash, "err", err) 551 invalidTxCounter.Inc(1) 552 return false, err 553 } 554 555 if !params.GenCfg.PerfTest && 556 uint64(len(pool.all)) >= pool.config.GlobalSlots+pool.config.GlobalQueue { 557 558 if pool.priced.Underpriced(tx, pool.locals) { 559 log.Trace("Discarding underpriced transaction", "hash", hash, "price", tx.GasPrice()) 560 underpricedTxCounter.Inc(1) 561 return false, ErrUnderpriced 562 } 563 564 drop := pool.priced.Discard(len(pool.all)-int(pool.config.GlobalSlots+pool.config.GlobalQueue-1), pool.locals) 565 for _, tx := range drop { 566 log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "price", tx.GasPrice()) 567 underpricedTxCounter.Inc(1) 568 pool.removeTx(tx.Hash()) 569 } 570 } 571 572 from, _ := types.Sender(pool.signer, tx) 573 if list := pool.pending[from]; list != nil && list.Overlaps(tx) { 574 575 inserted, old := list.Add(tx, pool.config.PriceBump) 576 if !inserted { 577 pendingDiscardCounter.Inc(1) 578 return false, ErrReplaceUnderpriced 579 } 580 581 if old != nil { 582 delete(pool.all, old.Hash()) 583 pool.priced.Removed() 584 pendingReplaceCounter.Inc(1) 585 } 586 pool.all[tx.Hash()] = tx 587 pool.priced.Put(tx) 588 pool.journalTx(from, tx) 589 590 log.Trace("Pooled new executable transaction", "hash", hash, "from", from, "to", tx.To()) 591 592 go pool.txFeed.Send(TxPreEvent{tx}) 593 594 return old != nil, nil 595 } 596 597 replace, err := pool.enqueueTx(hash, tx) 598 if err != nil { 599 return false, err 600 } 601 602 if local { 603 pool.locals.add(from) 604 } 605 pool.journalTx(from, tx) 606 607 log.Trace("Pooled new future transaction", "hash", hash, "from", from, "to", tx.To()) 608 return replace, nil 609 } 610 611 func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) (bool, error) { 612 613 from, _ := types.Sender(pool.signer, tx) 614 if pool.queue[from] == nil { 615 pool.queue[from] = newTxList(false) 616 } 617 inserted, old := pool.queue[from].Add(tx, pool.config.PriceBump) 618 if !inserted { 619 620 queuedDiscardCounter.Inc(1) 621 return false, ErrReplaceUnderpriced 622 } 623 624 if old != nil { 625 delete(pool.all, old.Hash()) 626 pool.priced.Removed() 627 queuedReplaceCounter.Inc(1) 628 } 629 pool.all[hash] = tx 630 pool.priced.Put(tx) 631 return old != nil, nil 632 } 633 634 func (pool *TxPool) journalTx(from common.Address, tx *types.Transaction) { 635 636 if pool.journal == nil || !pool.locals.contains(from) { 637 return 638 } 639 if err := pool.journal.insert(tx); err != nil { 640 log.Warn("Failed to journal local transaction", "err", err) 641 } 642 } 643 644 func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) { 645 646 if pool.pending[addr] == nil { 647 pool.pending[addr] = newTxList(true) 648 } 649 list := pool.pending[addr] 650 651 inserted, old := list.Add(tx, pool.config.PriceBump) 652 if !inserted { 653 654 delete(pool.all, hash) 655 pool.priced.Removed() 656 657 pendingDiscardCounter.Inc(1) 658 return 659 } 660 661 if old != nil { 662 delete(pool.all, old.Hash()) 663 pool.priced.Removed() 664 665 pendingReplaceCounter.Inc(1) 666 } 667 668 if pool.all[hash] == nil { 669 pool.all[hash] = tx 670 pool.priced.Put(tx) 671 } 672 673 pool.beats[addr] = time.Now() 674 pool.pendingState.SetNonce(addr, tx.Nonce()+1) 675 676 go pool.txFeed.Send(TxPreEvent{tx}) 677 } 678 679 func (pool *TxPool) AddLocal(tx *types.Transaction) error { 680 return pool.addTx(tx, !pool.config.NoLocals) 681 } 682 683 func (pool *TxPool) AddRemote(tx *types.Transaction) error { 684 return pool.addTx(tx, false) 685 } 686 687 func (pool *TxPool) AddLocals(txs []*types.Transaction) []error { 688 return pool.addTxs(txs, !pool.config.NoLocals) 689 } 690 691 func (pool *TxPool) AddRemotes(txs []*types.Transaction) []error { 692 return pool.addTxs(txs, false) 693 } 694 695 func (pool *TxPool) addTx(tx *types.Transaction, local bool) error { 696 pool.mu.Lock() 697 defer pool.mu.Unlock() 698 699 replace, err := pool.add(tx, local) 700 if err != nil { 701 return err 702 } 703 704 if !replace { 705 from, _ := types.Sender(pool.signer, tx) 706 pool.promoteExecutables([]common.Address{from}) 707 } 708 return nil 709 } 710 711 func (pool *TxPool) addTxs(txs []*types.Transaction, local bool) []error { 712 pool.mu.Lock() 713 defer pool.mu.Unlock() 714 return pool.addTxsLocked(txs, local) 715 } 716 717 func (pool *TxPool) addTxsLocked(txs []*types.Transaction, local bool) []error { 718 719 dirty := make(map[common.Address]struct{}) 720 errs := make([]error, len(txs)) 721 for i, tx := range txs { 722 var replace bool 723 if replace, errs[i] = pool.add(tx, local); errs[i] == nil { 724 if !replace { 725 from, _ := types.Sender(pool.signer, tx) 726 dirty[from] = struct{}{} 727 } 728 } 729 } 730 731 if len(dirty) > 0 { 732 addrs := make([]common.Address, 0, len(dirty)) 733 for addr := range dirty { 734 addrs = append(addrs, addr) 735 } 736 pool.promoteExecutables(addrs) 737 } 738 739 return errs 740 } 741 742 func (pool *TxPool) Status(hashes []common.Hash) []TxStatus { 743 pool.mu.RLock() 744 defer pool.mu.RUnlock() 745 746 status := make([]TxStatus, len(hashes)) 747 for i, hash := range hashes { 748 if tx := pool.all[hash]; tx != nil { 749 from, _ := types.Sender(pool.signer, tx) 750 if pool.pending[from] != nil && pool.pending[from].txs.items[tx.Nonce()] != nil { 751 status[i] = TxStatusPending 752 } else { 753 status[i] = TxStatusQueued 754 } 755 } 756 } 757 return status 758 } 759 760 func (pool *TxPool) Get(hash common.Hash) *types.Transaction { 761 pool.mu.RLock() 762 defer pool.mu.RUnlock() 763 764 return pool.all[hash] 765 } 766 767 func (pool *TxPool) RemoveTxs(txs types.Transactions) { 768 pool.mu.Lock() 769 defer pool.mu.Unlock() 770 771 for _, tx := range txs { 772 pool.removeTx(tx.Hash()) 773 } 774 } 775 776 func (pool *TxPool) removeTx(hash common.Hash) { 777 778 tx, ok := pool.all[hash] 779 if !ok { 780 return 781 } 782 addr, _ := types.Sender(pool.signer, tx) 783 784 delete(pool.all, hash) 785 pool.priced.Removed() 786 787 if pending := pool.pending[addr]; pending != nil { 788 if removed, invalids := pending.Remove(tx); removed { 789 790 if pending.Empty() { 791 delete(pool.pending, addr) 792 delete(pool.beats, addr) 793 } 794 795 for _, tx := range invalids { 796 pool.enqueueTx(tx.Hash(), tx) 797 } 798 799 if nonce := tx.Nonce(); pool.pendingState.GetNonce(addr) > nonce { 800 pool.pendingState.SetNonce(addr, nonce) 801 } 802 return 803 } 804 } 805 806 if future := pool.queue[addr]; future != nil { 807 future.Remove(tx) 808 if future.Empty() { 809 delete(pool.queue, addr) 810 } 811 } 812 } 813 814 func (pool *TxPool) promoteExecutables(accounts []common.Address) { 815 816 if accounts == nil { 817 accounts = make([]common.Address, 0, len(pool.queue)) 818 for addr := range pool.queue { 819 accounts = append(accounts, addr) 820 } 821 } 822 823 for _, addr := range accounts { 824 list := pool.queue[addr] 825 if list == nil { 826 continue 827 } 828 829 for _, tx := range list.Forward(pool.currentState.GetNonce(addr)) { 830 hash := tx.Hash() 831 log.Trace("Removed old queued transaction", "hash", hash) 832 delete(pool.all, hash) 833 pool.priced.Removed() 834 } 835 836 drops, _ := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas) 837 for _, tx := range drops { 838 hash := tx.Hash() 839 log.Trace("Removed unpayable queued transaction", "hash", hash) 840 delete(pool.all, hash) 841 pool.priced.Removed() 842 queuedNofundsCounter.Inc(1) 843 } 844 845 for _, tx := range list.Ready(pool.pendingState.GetNonce(addr)) { 846 hash := tx.Hash() 847 log.Trace("Promoting queued transaction", "hash", hash) 848 pool.promoteTx(addr, hash, tx) 849 } 850 851 if !pool.locals.contains(addr) { 852 for _, tx := range list.Cap(int(pool.config.AccountQueue)) { 853 hash := tx.Hash() 854 delete(pool.all, hash) 855 pool.priced.Removed() 856 queuedRateLimitCounter.Inc(1) 857 log.Trace("Removed cap-exceeding queued transaction", "hash", hash) 858 } 859 } 860 861 if list.Empty() { 862 delete(pool.queue, addr) 863 } 864 } 865 866 pending := uint64(0) 867 for _, list := range pool.pending { 868 pending += uint64(list.Len()) 869 } 870 if pending > pool.config.GlobalSlots { 871 pendingBeforeCap := pending 872 873 spammers := prque.New(nil) 874 for addr, list := range pool.pending { 875 876 if !pool.locals.contains(addr) && uint64(list.Len()) > pool.config.AccountSlots { 877 spammers.Push(addr, int64(list.Len())) 878 } 879 } 880 881 offenders := []common.Address{} 882 for pending > pool.config.GlobalSlots && !spammers.Empty() { 883 884 offender, _ := spammers.Pop() 885 offenders = append(offenders, offender.(common.Address)) 886 887 if len(offenders) > 1 { 888 889 threshold := pool.pending[offender.(common.Address)].Len() 890 891 for pending > pool.config.GlobalSlots && pool.pending[offenders[len(offenders)-2]].Len() > threshold { 892 for i := 0; i < len(offenders)-1; i++ { 893 list := pool.pending[offenders[i]] 894 for _, tx := range list.Cap(list.Len() - 1) { 895 896 hash := tx.Hash() 897 delete(pool.all, hash) 898 pool.priced.Removed() 899 900 if nonce := tx.Nonce(); pool.pendingState.GetNonce(offenders[i]) > nonce { 901 pool.pendingState.SetNonce(offenders[i], nonce) 902 } 903 log.Trace("Removed fairness-exceeding pending transaction", "hash", hash) 904 } 905 pending-- 906 } 907 } 908 } 909 } 910 911 if pending > pool.config.GlobalSlots && len(offenders) > 0 { 912 for pending > pool.config.GlobalSlots && uint64(pool.pending[offenders[len(offenders)-1]].Len()) > pool.config.AccountSlots { 913 for _, addr := range offenders { 914 list := pool.pending[addr] 915 for _, tx := range list.Cap(list.Len() - 1) { 916 917 hash := tx.Hash() 918 delete(pool.all, hash) 919 pool.priced.Removed() 920 921 if nonce := tx.Nonce(); pool.pendingState.GetNonce(addr) > nonce { 922 pool.pendingState.SetNonce(addr, nonce) 923 } 924 log.Trace("Removed fairness-exceeding pending transaction", "hash", hash) 925 } 926 pending-- 927 } 928 } 929 } 930 pendingRateLimitCounter.Inc(int64(pendingBeforeCap - pending)) 931 } 932 933 queued := uint64(0) 934 for _, list := range pool.queue { 935 queued += uint64(list.Len()) 936 } 937 if queued > pool.config.GlobalQueue { 938 939 addresses := make(addresssByHeartbeat, 0, len(pool.queue)) 940 for addr := range pool.queue { 941 if !pool.locals.contains(addr) { 942 addresses = append(addresses, addressByHeartbeat{addr, pool.beats[addr]}) 943 } 944 } 945 sort.Sort(addresses) 946 947 for drop := queued - pool.config.GlobalQueue; drop > 0 && len(addresses) > 0; { 948 addr := addresses[len(addresses)-1] 949 list := pool.queue[addr.address] 950 951 addresses = addresses[:len(addresses)-1] 952 953 if size := uint64(list.Len()); size <= drop { 954 for _, tx := range list.Flatten() { 955 pool.removeTx(tx.Hash()) 956 } 957 drop -= size 958 queuedRateLimitCounter.Inc(int64(size)) 959 continue 960 } 961 962 txs := list.Flatten() 963 for i := len(txs) - 1; i >= 0 && drop > 0; i-- { 964 pool.removeTx(txs[i].Hash()) 965 drop-- 966 queuedRateLimitCounter.Inc(1) 967 } 968 } 969 } 970 } 971 972 func (pool *TxPool) demoteUnexecutables() { 973 974 for addr, list := range pool.pending { 975 nonce := pool.currentState.GetNonce(addr) 976 977 for _, tx := range list.Forward(nonce) { 978 hash := tx.Hash() 979 log.Trace("Removed old pending transaction", "hash", hash) 980 delete(pool.all, hash) 981 pool.priced.Removed() 982 } 983 984 drops, invalids := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas) 985 for _, tx := range drops { 986 hash := tx.Hash() 987 log.Trace("Removed unpayable pending transaction", "hash", hash) 988 delete(pool.all, hash) 989 pool.priced.Removed() 990 pendingNofundsCounter.Inc(1) 991 } 992 for _, tx := range invalids { 993 hash := tx.Hash() 994 log.Trace("Demoting pending transaction", "hash", hash) 995 pool.enqueueTx(hash, tx) 996 } 997 998 if list.Len() > 0 && list.txs.Get(nonce) == nil { 999 for _, tx := range list.Cap(0) { 1000 hash := tx.Hash() 1001 log.Error("Demoting invalidated transaction", "hash", hash) 1002 pool.enqueueTx(hash, tx) 1003 } 1004 } 1005 1006 if list.Empty() { 1007 delete(pool.pending, addr) 1008 delete(pool.beats, addr) 1009 } 1010 } 1011 } 1012 1013 type addressByHeartbeat struct { 1014 address common.Address 1015 heartbeat time.Time 1016 } 1017 1018 type addresssByHeartbeat []addressByHeartbeat 1019 1020 func (a addresssByHeartbeat) Len() int { return len(a) } 1021 func (a addresssByHeartbeat) Less(i, j int) bool { return a[i].heartbeat.Before(a[j].heartbeat) } 1022 func (a addresssByHeartbeat) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 1023 1024 type accountSet struct { 1025 accounts map[common.Address]struct{} 1026 signer types.Signer 1027 } 1028 1029 func newAccountSet(signer types.Signer) *accountSet { 1030 return &accountSet{ 1031 accounts: make(map[common.Address]struct{}), 1032 signer: signer, 1033 } 1034 } 1035 1036 func (as *accountSet) contains(addr common.Address) bool { 1037 _, exist := as.accounts[addr] 1038 return exist 1039 } 1040 1041 func (as *accountSet) containsTx(tx *types.Transaction) bool { 1042 if addr, err := types.Sender(as.signer, tx); err == nil { 1043 return as.contains(addr) 1044 } 1045 return false 1046 } 1047 1048 func (as *accountSet) add(addr common.Address) { 1049 as.accounts[addr] = struct{}{} 1050 }