|
|
|
@ -217,12 +217,13 @@ type LegacyPool struct { |
|
|
|
|
locals *accountSet // Set of local transaction to exempt from eviction rules
|
|
|
|
|
journal *journal // Journal of local transaction to back up to disk
|
|
|
|
|
|
|
|
|
|
reserve txpool.AddressReserver // Address reserver to ensure exclusivity across subpools
|
|
|
|
|
pending map[common.Address]*list // All currently processable transactions
|
|
|
|
|
queue map[common.Address]*list // Queued but non-processable transactions
|
|
|
|
|
beats map[common.Address]time.Time // Last heartbeat from each known account
|
|
|
|
|
all *lookup // All transactions to allow lookups
|
|
|
|
|
priced *pricedList // All transactions sorted by price
|
|
|
|
|
reserve txpool.AddressReserver // Address reserver to ensure exclusivity across subpools
|
|
|
|
|
pending map[common.Address]*list // All currently processable transactions
|
|
|
|
|
queue map[common.Address]*list // Queued but non-processable transactions
|
|
|
|
|
beats map[common.Address]time.Time // Last heartbeat from each known account
|
|
|
|
|
all *lookup // All transactions to allow lookups
|
|
|
|
|
priced *pricedList // All transactions sorted by price
|
|
|
|
|
auths map[common.Address]*types.Transaction // All accounts with a pooled authorization
|
|
|
|
|
|
|
|
|
|
reqResetCh chan *txpoolResetRequest |
|
|
|
|
reqPromoteCh chan *accountSet |
|
|
|
@ -254,6 +255,7 @@ func New(config Config, chain BlockChain) *LegacyPool { |
|
|
|
|
pending: make(map[common.Address]*list), |
|
|
|
|
queue: make(map[common.Address]*list), |
|
|
|
|
beats: make(map[common.Address]time.Time), |
|
|
|
|
auths: make(map[common.Address]*types.Transaction), |
|
|
|
|
all: newLookup(), |
|
|
|
|
reqResetCh: make(chan *txpoolResetRequest), |
|
|
|
|
reqPromoteCh: make(chan *accountSet), |
|
|
|
@ -611,7 +613,8 @@ func (pool *LegacyPool) validateTxBasics(tx *types.Transaction, local bool) erro |
|
|
|
|
Accept: 0 | |
|
|
|
|
1<<types.LegacyTxType | |
|
|
|
|
1<<types.AccessListTxType | |
|
|
|
|
1<<types.DynamicFeeTxType, |
|
|
|
|
1<<types.DynamicFeeTxType | |
|
|
|
|
1<<types.SetCodeTxType, |
|
|
|
|
MaxSize: txMaxSize, |
|
|
|
|
MinTip: pool.gasTip.Load().ToBig(), |
|
|
|
|
} |
|
|
|
@ -639,6 +642,14 @@ func (pool *LegacyPool) validateTx(tx *types.Transaction) error { |
|
|
|
|
if list := pool.queue[addr]; list != nil { |
|
|
|
|
have += list.Len() |
|
|
|
|
} |
|
|
|
|
// Limit the number of setcode tranasactions per account
|
|
|
|
|
if pool.currentState.GetCode(addr) != nil { |
|
|
|
|
if have >= 1 { |
|
|
|
|
return have, 0 |
|
|
|
|
} else { |
|
|
|
|
return have, 1 - have |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return have, math.MaxInt |
|
|
|
|
}, |
|
|
|
|
ExistingExpenditure: func(addr common.Address) *big.Int { |
|
|
|
@ -655,6 +666,28 @@ func (pool *LegacyPool) validateTx(tx *types.Transaction) error { |
|
|
|
|
} |
|
|
|
|
return nil |
|
|
|
|
}, |
|
|
|
|
KnownConflicts: func(sender common.Address, addrs []common.Address) []common.Address { |
|
|
|
|
var conflicts []common.Address |
|
|
|
|
if _, ok := pool.auths[sender]; ok { |
|
|
|
|
conflicts = append(conflicts, sender) |
|
|
|
|
} |
|
|
|
|
for _, addr := range addrs { |
|
|
|
|
var known bool |
|
|
|
|
if list := pool.pending[addr]; list != nil { |
|
|
|
|
known = true |
|
|
|
|
} |
|
|
|
|
if list := pool.queue[addr]; list != nil { |
|
|
|
|
known = true |
|
|
|
|
} |
|
|
|
|
if _, ok := pool.auths[addr]; ok { |
|
|
|
|
known = true |
|
|
|
|
} |
|
|
|
|
if known { |
|
|
|
|
conflicts = append(conflicts, addr) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return conflicts |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
if err := txpool.ValidateTransactionWithState(tx, pool.signer, opts); err != nil { |
|
|
|
|
return err |
|
|
|
@ -692,6 +725,7 @@ func (pool *LegacyPool) add(tx *types.Transaction, local bool) (replaced bool, e |
|
|
|
|
|
|
|
|
|
// If the address is not yet known, request exclusivity to track the account
|
|
|
|
|
// only by this subpool until all transactions are evicted
|
|
|
|
|
// TODO: need to track every authority from setcode txs
|
|
|
|
|
var ( |
|
|
|
|
_, hasPending = pool.pending[from] |
|
|
|
|
_, hasQueued = pool.queue[from] |
|
|
|
@ -786,12 +820,16 @@ func (pool *LegacyPool) add(tx *types.Transaction, local bool) (replaced bool, e |
|
|
|
|
if old != nil { |
|
|
|
|
pool.all.Remove(old.Hash()) |
|
|
|
|
pool.priced.Removed(1) |
|
|
|
|
pool.removeAuthorities(old) |
|
|
|
|
pendingReplaceMeter.Mark(1) |
|
|
|
|
} |
|
|
|
|
pool.all.Add(tx, isLocal) |
|
|
|
|
pool.priced.Put(tx, isLocal) |
|
|
|
|
pool.journalTx(from, tx) |
|
|
|
|
pool.queueTxEvent(tx) |
|
|
|
|
for _, addr := range tx.Authorities() { |
|
|
|
|
pool.auths[addr] = tx |
|
|
|
|
} |
|
|
|
|
log.Trace("Pooled new executable transaction", "hash", hash, "from", from, "to", tx.To()) |
|
|
|
|
|
|
|
|
|
// Successful promotion, bump the heartbeat
|
|
|
|
@ -813,6 +851,9 @@ func (pool *LegacyPool) add(tx *types.Transaction, local bool) (replaced bool, e |
|
|
|
|
localGauge.Inc(1) |
|
|
|
|
} |
|
|
|
|
pool.journalTx(from, tx) |
|
|
|
|
for _, addr := range tx.Authorities() { |
|
|
|
|
pool.auths[addr] = tx |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
log.Trace("Pooled new future transaction", "hash", hash, "from", from, "to", tx.To()) |
|
|
|
|
return replaced, nil |
|
|
|
@ -860,6 +901,7 @@ func (pool *LegacyPool) enqueueTx(hash common.Hash, tx *types.Transaction, local |
|
|
|
|
// Discard any previous transaction and mark this
|
|
|
|
|
if old != nil { |
|
|
|
|
pool.all.Remove(old.Hash()) |
|
|
|
|
pool.removeAuthorities(old) |
|
|
|
|
pool.priced.Removed(1) |
|
|
|
|
queuedReplaceMeter.Mark(1) |
|
|
|
|
} else { |
|
|
|
@ -879,6 +921,10 @@ func (pool *LegacyPool) enqueueTx(hash common.Hash, tx *types.Transaction, local |
|
|
|
|
if _, exist := pool.beats[from]; !exist { |
|
|
|
|
pool.beats[from] = time.Now() |
|
|
|
|
} |
|
|
|
|
for _, auth := range tx.SetCodeAuthorizations() { |
|
|
|
|
addr, _ := auth.Authority() |
|
|
|
|
pool.auths[addr] = tx |
|
|
|
|
} |
|
|
|
|
return old != nil, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -909,6 +955,7 @@ func (pool *LegacyPool) promoteTx(addr common.Address, hash common.Hash, tx *typ |
|
|
|
|
if !inserted { |
|
|
|
|
// An older transaction was better, discard this
|
|
|
|
|
pool.all.Remove(hash) |
|
|
|
|
pool.removeAuthorities(tx) |
|
|
|
|
pool.priced.Removed(1) |
|
|
|
|
pendingDiscardMeter.Mark(1) |
|
|
|
|
return false |
|
|
|
@ -916,6 +963,7 @@ func (pool *LegacyPool) promoteTx(addr common.Address, hash common.Hash, tx *typ |
|
|
|
|
// Otherwise discard any previous transaction and mark this
|
|
|
|
|
if old != nil { |
|
|
|
|
pool.all.Remove(old.Hash()) |
|
|
|
|
pool.removeAuthorities(old) |
|
|
|
|
pool.priced.Removed(1) |
|
|
|
|
pendingReplaceMeter.Mark(1) |
|
|
|
|
} else { |
|
|
|
@ -1129,6 +1177,9 @@ func (pool *LegacyPool) removeTx(hash common.Hash, outofbound bool, unreserve bo |
|
|
|
|
if pool.locals.contains(addr) { |
|
|
|
|
localGauge.Dec(1) |
|
|
|
|
} |
|
|
|
|
// Remove any authorities the pool was tracking.
|
|
|
|
|
pool.removeAuthorities(tx) |
|
|
|
|
|
|
|
|
|
// Remove the transaction from the pending lists and reset the account nonce
|
|
|
|
|
if pending := pool.pending[addr]; pending != nil { |
|
|
|
|
if removed, invalids := pending.Remove(tx); removed { |
|
|
|
@ -1162,6 +1213,12 @@ func (pool *LegacyPool) removeTx(hash common.Hash, outofbound bool, unreserve bo |
|
|
|
|
return 0 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (pool *LegacyPool) removeAuthorities(tx *types.Transaction) { |
|
|
|
|
for _, addr := range tx.Authorities() { |
|
|
|
|
delete(pool.auths, addr) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// requestReset requests a pool reset to the new head block.
|
|
|
|
|
// The returned channel is closed when the reset has occurred.
|
|
|
|
|
func (pool *LegacyPool) requestReset(oldHead *types.Header, newHead *types.Header) chan struct{} { |
|
|
|
@ -1461,15 +1518,15 @@ func (pool *LegacyPool) promoteExecutables(accounts []common.Address) []*types.T |
|
|
|
|
// Drop all transactions that are deemed too old (low nonce)
|
|
|
|
|
forwards := list.Forward(pool.currentState.GetNonce(addr)) |
|
|
|
|
for _, tx := range forwards { |
|
|
|
|
hash := tx.Hash() |
|
|
|
|
pool.all.Remove(hash) |
|
|
|
|
pool.all.Remove(tx.Hash()) |
|
|
|
|
pool.removeAuthorities(tx) |
|
|
|
|
} |
|
|
|
|
log.Trace("Removed old queued transactions", "count", len(forwards)) |
|
|
|
|
// Drop all transactions that are too costly (low balance or out of gas)
|
|
|
|
|
drops, _ := list.Filter(pool.currentState.GetBalance(addr), gasLimit) |
|
|
|
|
for _, tx := range drops { |
|
|
|
|
hash := tx.Hash() |
|
|
|
|
pool.all.Remove(hash) |
|
|
|
|
pool.all.Remove(tx.Hash()) |
|
|
|
|
pool.removeAuthorities(tx) |
|
|
|
|
} |
|
|
|
|
log.Trace("Removed unpayable queued transactions", "count", len(drops)) |
|
|
|
|
queuedNofundsMeter.Mark(int64(len(drops))) |
|
|
|
@ -1492,6 +1549,7 @@ func (pool *LegacyPool) promoteExecutables(accounts []common.Address) []*types.T |
|
|
|
|
for _, tx := range caps { |
|
|
|
|
hash := tx.Hash() |
|
|
|
|
pool.all.Remove(hash) |
|
|
|
|
pool.removeAuthorities(tx) |
|
|
|
|
log.Trace("Removed cap-exceeding queued transaction", "hash", hash) |
|
|
|
|
} |
|
|
|
|
queuedRateLimitMeter.Mark(int64(len(caps))) |
|
|
|
@ -1557,6 +1615,7 @@ func (pool *LegacyPool) truncatePending() { |
|
|
|
|
// Drop the transaction from the global pools too
|
|
|
|
|
hash := tx.Hash() |
|
|
|
|
pool.all.Remove(hash) |
|
|
|
|
pool.removeAuthorities(tx) |
|
|
|
|
|
|
|
|
|
// Update the account nonce to the dropped transaction
|
|
|
|
|
pool.pendingNonces.setIfLower(offenders[i], tx.Nonce()) |
|
|
|
@ -1584,6 +1643,7 @@ func (pool *LegacyPool) truncatePending() { |
|
|
|
|
// Drop the transaction from the global pools too
|
|
|
|
|
hash := tx.Hash() |
|
|
|
|
pool.all.Remove(hash) |
|
|
|
|
pool.removeAuthorities(tx) |
|
|
|
|
|
|
|
|
|
// Update the account nonce to the dropped transaction
|
|
|
|
|
pool.pendingNonces.setIfLower(addr, tx.Nonce()) |
|
|
|
@ -1664,14 +1724,16 @@ func (pool *LegacyPool) demoteUnexecutables() { |
|
|
|
|
for _, tx := range olds { |
|
|
|
|
hash := tx.Hash() |
|
|
|
|
pool.all.Remove(hash) |
|
|
|
|
pool.removeAuthorities(tx) |
|
|
|
|
log.Trace("Removed old pending transaction", "hash", hash) |
|
|
|
|
} |
|
|
|
|
// Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later
|
|
|
|
|
drops, invalids := list.Filter(pool.currentState.GetBalance(addr), gasLimit) |
|
|
|
|
for _, tx := range drops { |
|
|
|
|
hash := tx.Hash() |
|
|
|
|
log.Trace("Removed unpayable pending transaction", "hash", hash) |
|
|
|
|
pool.all.Remove(hash) |
|
|
|
|
pool.removeAuthorities(tx) |
|
|
|
|
log.Trace("Removed unpayable pending transaction", "hash", hash) |
|
|
|
|
} |
|
|
|
|
pendingNofundsMeter.Mark(int64(len(drops))) |
|
|
|
|
|
|
|
|
@ -1995,6 +2057,7 @@ func (pool *LegacyPool) Clear() { |
|
|
|
|
pool.pending = make(map[common.Address]*list) |
|
|
|
|
pool.queue = make(map[common.Address]*list) |
|
|
|
|
pool.pendingNonces = newNoncer(pool.currentState) |
|
|
|
|
pool.auths = make(map[common.Address]*types.Transaction) |
|
|
|
|
|
|
|
|
|
if !pool.config.NoLocals && pool.config.Journal != "" { |
|
|
|
|
pool.journal = newTxJournal(pool.config.Journal) |
|
|
|
|