From b126eda14eadada5e94077cdc3478785ffce136a Mon Sep 17 00:00:00 2001 From: Scott Fairclough Date: Thu, 14 Nov 2024 10:02:09 +0000 Subject: [PATCH] purge routine for txpool --- cmd/txpool/main.go | 8 ++++- cmd/utils/flags.go | 16 +++++++++ core/vm/contracts_zkevm.go | 3 +- erigon-lib/txpool/txpoolcfg/txpoolcfg.go | 5 +++ eth/ethconfig/tx_pool.go | 4 +++ turbo/cli/default_flags.go | 2 ++ zk/txpool/pool.go | 43 +++++++++++++++++++++++- 7 files changed, 78 insertions(+), 3 deletions(-) diff --git a/cmd/txpool/main.go b/cmd/txpool/main.go index 385842cc89f..c373c85d520 100644 --- a/cmd/txpool/main.go +++ b/cmd/txpool/main.go @@ -59,7 +59,9 @@ var ( noTxGossip bool - commitEvery time.Duration + commitEvery time.Duration + purgeEvery time.Duration + purgeDistance time.Duration ) func init() { @@ -85,6 +87,8 @@ func init() { rootCmd.PersistentFlags().Uint64Var(&priceBump, "txpool.pricebump", txpoolcfg.DefaultConfig.PriceBump, "Price bump percentage to replace an already existing transaction") rootCmd.PersistentFlags().Uint64Var(&blobPriceBump, "txpool.blobpricebump", txpoolcfg.DefaultConfig.BlobPriceBump, "Price bump percentage to replace an existing blob (type-3) transaction") rootCmd.PersistentFlags().DurationVar(&commitEvery, utils.TxPoolCommitEveryFlag.Name, utils.TxPoolCommitEveryFlag.Value, utils.TxPoolCommitEveryFlag.Usage) + rootCmd.PersistentFlags().DurationVar(&purgeEvery, utils.TxpoolPurgeEveryFlag.Name, utils.TxpoolPurgeEveryFlag.Value, utils.TxpoolPurgeEveryFlag.Usage) + rootCmd.PersistentFlags().DurationVar(&purgeDistance, utils.TxpoolPurgeDistanceFlag.Name, utils.TxpoolPurgeDistanceFlag.Value, utils.TxpoolPurgeDistanceFlag.Usage) rootCmd.PersistentFlags().BoolVar(&noTxGossip, utils.TxPoolGossipDisableFlag.Name, utils.TxPoolGossipDisableFlag.Value, utils.TxPoolGossipDisableFlag.Usage) rootCmd.Flags().StringSliceVar(&traceSenders, utils.TxPoolTraceSendersFlag.Name, []string{}, utils.TxPoolTraceSendersFlag.Usage) } @@ -144,6 +148,8 @@ func doTxpool(ctx context.Context, logger log.Logger) error { cfg.DBDir = dirs.TxPool cfg.CommitEvery = common2.RandomizeDuration(commitEvery) + cfg.PurgeEvery = common2.RandomizeDuration(purgeEvery) + cfg.PurgeDistance = purgeDistance cfg.PendingSubPoolLimit = pendingPoolLimit cfg.BaseFeeSubPoolLimit = baseFeePoolLimit cfg.QueuedSubPoolLimit = queuedPoolLimit diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 59936ed948a..87b02432c57 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -237,6 +237,16 @@ var ( Usage: "How often transactions should be committed to the storage", Value: txpoolcfg.DefaultConfig.CommitEvery, } + TxpoolPurgeEveryFlag = cli.DurationFlag{ + Name: "txpool.purge.every", + Usage: "How often transactions should be purged from the storage", + Value: txpoolcfg.DefaultConfig.PurgeEvery, + } + TxpoolPurgeDistanceFlag = cli.DurationFlag{ + Name: "txpool.purge.distance", + Usage: "Transactions older than this distance will be purged", + Value: txpoolcfg.DefaultConfig.PurgeDistance, + } // Miner settings MiningEnabledFlag = cli.BoolFlag{ Name: "mine", @@ -1914,6 +1924,12 @@ func setTxPool(ctx *cli.Context, fullCfg *ethconfig.Config) { fullCfg.TxPool.BlobPriceBump = ctx.Uint64(TxPoolBlobPriceBumpFlag.Name) } cfg.CommitEvery = common2.RandomizeDuration(ctx.Duration(TxPoolCommitEveryFlag.Name)) + + purgeEvery := ctx.Duration(TxpoolPurgeEveryFlag.Name) + purgeDistance := ctx.Duration(TxpoolPurgeDistanceFlag.Name) + + fullCfg.TxPool.PurgeEvery = common2.RandomizeDuration(purgeEvery) + fullCfg.TxPool.PurgeDistance = purgeDistance } func setEthash(ctx *cli.Context, datadir string, cfg *ethconfig.Config) { diff --git a/core/vm/contracts_zkevm.go b/core/vm/contracts_zkevm.go index 037f2bc7c42..68671d3b70c 100644 --- a/core/vm/contracts_zkevm.go +++ b/core/vm/contracts_zkevm.go @@ -77,7 +77,7 @@ var PrecompiledContractsForkID8Elderberry = map[libcommon.Address]PrecompiledCon libcommon.BytesToAddress([]byte{2}): &sha256hash_zkevm{enabled: true}, libcommon.BytesToAddress([]byte{3}): &ripemd160hash_zkevm{enabled: false}, libcommon.BytesToAddress([]byte{4}): &dataCopy_zkevm{enabled: true}, - libcommon.BytesToAddress([]byte{5}): &bigModExp_zkevm{enabled: false, eip2565: true}, + libcommon.BytesToAddress([]byte{5}): &bigModExp_zkevm{enabled: true, eip2565: true}, libcommon.BytesToAddress([]byte{6}): &bn256AddIstanbul_zkevm{enabled: true}, libcommon.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul_zkevm{enabled: true}, libcommon.BytesToAddress([]byte{8}): &bn256PairingIstanbul_zkevm{enabled: true}, @@ -316,6 +316,7 @@ func (c *bigModExp_zkevm) RequiredGas(input []byte) uint64 { // - if neither of the above are true we check for reverts and return 0 gas fee if modBitLen == 0 { + return 0 // consume as normal - will return 0 } else if baseBitLen == 0 { if modBitLen > 8192 { diff --git a/erigon-lib/txpool/txpoolcfg/txpoolcfg.go b/erigon-lib/txpool/txpoolcfg/txpoolcfg.go index 54f5e0dfa9a..0ee6d97bed5 100644 --- a/erigon-lib/txpool/txpoolcfg/txpoolcfg.go +++ b/erigon-lib/txpool/txpoolcfg/txpoolcfg.go @@ -52,6 +52,7 @@ type Config struct { ProcessRemoteTxsEvery time.Duration CommitEvery time.Duration LogEvery time.Duration + PurgeEvery time.Duration //txpool db MdbxPageSize datasize.ByteSize @@ -59,6 +60,8 @@ type Config struct { MdbxGrowthStep datasize.ByteSize NoGossip bool // this mode doesn't broadcast any txs, and if receive remote-txn - skip it + + PurgeDistance time.Duration } var DefaultConfig = Config{ @@ -66,6 +69,8 @@ var DefaultConfig = Config{ ProcessRemoteTxsEvery: 100 * time.Millisecond, CommitEvery: 15 * time.Second, LogEvery: 30 * time.Second, + PurgeEvery: 1 * time.Minute, + PurgeDistance: 24 * time.Hour, PendingSubPoolLimit: 10_000, BaseFeeSubPoolLimit: 10_000, diff --git a/eth/ethconfig/tx_pool.go b/eth/ethconfig/tx_pool.go index 8909339f822..de4789dd05a 100644 --- a/eth/ethconfig/tx_pool.go +++ b/eth/ethconfig/tx_pool.go @@ -73,9 +73,13 @@ var DefaultTxPool2Config = func(fullCfg *Config) txpoolcfg.Config { cfg.BlobSlots = fullCfg.TxPool.BlobSlots cfg.TotalBlobPoolLimit = fullCfg.TxPool.TotalBlobPoolLimit cfg.LogEvery = 3 * time.Minute + cfg.PurgeEvery = 1 * time.Minute + cfg.PurgeDistance = 24 * time.Hour cfg.CommitEvery = 5 * time.Minute cfg.TracedSenders = pool1Cfg.TracedSenders cfg.CommitEvery = pool1Cfg.CommitEvery + cfg.PurgeEvery = fullCfg.TxPool.PurgeEvery + cfg.PurgeDistance = fullCfg.TxPool.PurgeDistance return cfg } diff --git a/turbo/cli/default_flags.go b/turbo/cli/default_flags.go index ffc404728dd..fd7e59e4b44 100644 --- a/turbo/cli/default_flags.go +++ b/turbo/cli/default_flags.go @@ -29,6 +29,8 @@ var DefaultFlags = []cli.Flag{ &utils.TxPoolLifetimeFlag, &utils.TxPoolTraceSendersFlag, &utils.TxPoolCommitEveryFlag, + &utils.TxpoolPurgeEveryFlag, + &utils.TxpoolPurgeDistanceFlag, &PruneFlag, &PruneHistoryFlag, &PruneReceiptFlag, diff --git a/zk/txpool/pool.go b/zk/txpool/pool.go index d7662eb980c..995e62dd84b 100644 --- a/zk/txpool/pool.go +++ b/zk/txpool/pool.go @@ -147,6 +147,7 @@ const ( DiscardByLimbo DiscardReason = 27 SmartContractDeploymentDisabled DiscardReason = 28 // to == null not allowed, config set to block smart contract deployment GasLimitTooHigh DiscardReason = 29 // gas limit is too high + Expired DiscardReason = 30 // used when a transaction is purged from the pool ) func (r DiscardReason) String() string { @@ -226,13 +227,14 @@ type metaTx struct { bestIndex int worstIndex int timestamp uint64 // when it was added to pool + created uint64 // unix timestamp of creation subPool SubPoolMarker currentSubPool SubPoolType alreadyYielded bool } func newMetaTx(slot *types.TxSlot, isLocal bool, timestmap uint64) *metaTx { - mt := &metaTx{Tx: slot, worstIndex: -1, bestIndex: -1, timestamp: timestmap} + mt := &metaTx{Tx: slot, worstIndex: -1, bestIndex: -1, timestamp: timestmap, created: uint64(time.Now().Unix())} if isLocal { mt.subPool = IsLocal } @@ -1391,6 +1393,8 @@ func MainLoop(ctx context.Context, db kv.RwDB, coreDB kv.RoDB, p *TxPool, newTxs defer commitEvery.Stop() logEvery := time.NewTicker(p.cfg.LogEvery) defer logEvery.Stop() + purgeEvery := time.NewTicker(p.cfg.PurgeEvery) + defer purgeEvery.Stop() for { select { @@ -1520,6 +1524,8 @@ func MainLoop(ctx context.Context, db kv.RwDB, coreDB kv.RoDB, p *TxPool, newTxs types, sizes, hashes = p.AppendAllAnnouncements(types, sizes, hashes[:0]) go send.PropagatePooledTxsToPeersList(newPeers, types, sizes, hashes) propagateToNewPeerTimer.UpdateDuration(t) + case <-purgeEvery.C: + p.purge() } } } @@ -1833,6 +1839,41 @@ func (p *TxPool) deprecatedForEach(_ context.Context, f func(rlp []byte, sender }) } +func (p *TxPool) purge() { + p.lock.Lock() + defer p.lock.Unlock() + + // go through all transactions and remove the ones that have a timestamp older than the purge time in config + cutOff := uint64(time.Now().Add(-p.cfg.PurgeDistance).Unix()) + log.Debug("[txpool] purging", "cutOff", cutOff) + + toDelete := make([]*metaTx, 0) + + p.all.ascendAll(func(mt *metaTx) bool { + if mt.created < cutOff { + toDelete = append(toDelete, mt) + } + + return false + }) + + for _, mt := range toDelete { + p.discardLocked(mt, Expired) + // do not hold on to the discard reason as we're purging it completely from the pool + p.discardReasonsLRU.Remove(string(mt.Tx.IDHash[:])) + + // get the address of the sender + addr := common.Address{} + if checkAddr, ok := p.senders.senderID2Addr[mt.Tx.SenderID]; ok { + addr = checkAddr + } + log.Debug("[txpool] purge", + "sender", addr, + "hash", hex.EncodeToString(mt.Tx.IDHash[:]), + "ts", mt.created) + } +} + // CalcIntrinsicGas computes the 'intrinsic gas' for a message with the given data. func CalcIntrinsicGas(dataLen, dataNonZeroLen uint64, accessList types.AccessList, isContractCreation, isHomestead, isEIP2028, isShanghai bool) (uint64, DiscardReason) { // Set the starting gas for the raw transaction