feat(tx-pool): fast reject known skipped txs (#1004)

* feat(tx-pool): fast reject known skipped txs (#1001)

* feat(tx-pool): fast reject known skipped txs

* fix make lint

* add miner flag to tx pool

* bump version
This commit is contained in:
colin 2024-08-26 22:48:44 +08:00 committed by GitHub
parent ff23c5272a
commit c252ee1ee0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 51 additions and 6 deletions

View file

@ -441,6 +441,7 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend) {
// Set the gas price to the limits from the CLI and start mining // Set the gas price to the limits from the CLI and start mining
gasprice := utils.GlobalBig(ctx, utils.MinerGasPriceFlag.Name) gasprice := utils.GlobalBig(ctx, utils.MinerGasPriceFlag.Name)
ethBackend.TxPool().SetGasPrice(gasprice) ethBackend.TxPool().SetGasPrice(gasprice)
ethBackend.TxPool().SetIsMiner(true)
// start mining // start mining
threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name) threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name)
if err := ethBackend.StartMining(threads); err != nil { if err := ethBackend.StartMining(threads); err != nil {

View file

@ -158,6 +158,16 @@ func ReadSkippedTransaction(db ethdb.Reader, txHash common.Hash) *SkippedTransac
return &stxV2 return &stxV2
} }
// IsSkippedTransaction checks if a transaction exists as a skipped transaction in the database.
func IsSkippedTransaction(db ethdb.Reader, txHash common.Hash) bool {
exists, err := db.Has(SkippedTransactionKey(txHash))
if err != nil {
log.Error("Failed to check skipped transaction", "hash", txHash.String(), "err", err)
return false
}
return exists
}
// writeSkippedTransactionHash writes the hash of a skipped transaction to the database. // writeSkippedTransactionHash writes the hash of a skipped transaction to the database.
func writeSkippedTransactionHash(db ethdb.KeyValueWriter, index uint64, txHash common.Hash) { func writeSkippedTransactionHash(db ethdb.KeyValueWriter, index uint64, txHash common.Hash) {
if err := db.Put(SkippedTransactionHashKey(index), txHash[:]); err != nil { if err := db.Put(SkippedTransactionHashKey(index), txHash[:]); err != nil {

View file

@ -29,8 +29,10 @@ import (
"github.com/scroll-tech/go-ethereum/common" "github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/common/prque" "github.com/scroll-tech/go-ethereum/common/prque"
"github.com/scroll-tech/go-ethereum/consensus/misc" "github.com/scroll-tech/go-ethereum/consensus/misc"
"github.com/scroll-tech/go-ethereum/core/rawdb"
"github.com/scroll-tech/go-ethereum/core/state" "github.com/scroll-tech/go-ethereum/core/state"
"github.com/scroll-tech/go-ethereum/core/types" "github.com/scroll-tech/go-ethereum/core/types"
"github.com/scroll-tech/go-ethereum/ethdb"
"github.com/scroll-tech/go-ethereum/event" "github.com/scroll-tech/go-ethereum/event"
"github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/log"
"github.com/scroll-tech/go-ethereum/metrics" "github.com/scroll-tech/go-ethereum/metrics"
@ -110,6 +112,7 @@ var (
// General tx metrics // General tx metrics
knownTxMeter = metrics.NewRegisteredMeter("txpool/known", nil) knownTxMeter = metrics.NewRegisteredMeter("txpool/known", nil)
knownSkippedTxMeter = metrics.NewRegisteredMeter("txpool/known/skipped", nil)
validTxMeter = metrics.NewRegisteredMeter("txpool/valid", nil) validTxMeter = metrics.NewRegisteredMeter("txpool/valid", nil)
invalidTxMeter = metrics.NewRegisteredMeter("txpool/invalid", nil) invalidTxMeter = metrics.NewRegisteredMeter("txpool/invalid", nil)
underpricedTxMeter = metrics.NewRegisteredMeter("txpool/underpriced", nil) underpricedTxMeter = metrics.NewRegisteredMeter("txpool/underpriced", nil)
@ -154,6 +157,8 @@ type blockChain interface {
StateAt(root common.Hash) (*state.StateDB, error) StateAt(root common.Hash) (*state.StateDB, error)
SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription
Database() ethdb.Database
} }
// TxPoolConfig are the configuration parameters of the transaction pool. // TxPoolConfig are the configuration parameters of the transaction pool.
@ -279,6 +284,8 @@ type TxPool struct {
initDoneCh chan struct{} // is closed once the pool is initialized (for tests) initDoneCh chan struct{} // is closed once the pool is initialized (for tests)
changesSinceReorg int // A counter for how many drops we've performed in-between reorg. changesSinceReorg int // A counter for how many drops we've performed in-between reorg.
isMiner atomic.Bool
} }
type txpoolResetRequest struct { type txpoolResetRequest struct {
@ -492,6 +499,17 @@ func (pool *TxPool) SetGasPrice(price *big.Int) {
log.Info("Transaction pool price threshold updated", "price", price) log.Info("Transaction pool price threshold updated", "price", price)
} }
// SetIsMiner updates the miner status of the node.
func (pool *TxPool) SetIsMiner(isMiner bool) {
pool.isMiner.Store(isMiner)
log.Info("Transaction pool miner status updated", "isMiner", isMiner)
}
// IsMiner returns the current miner status of the node.
func (pool *TxPool) IsMiner() bool {
return pool.isMiner.Load()
}
// Nonce returns the next nonce of an account, with all transactions executable // Nonce returns the next nonce of an account, with all transactions executable
// by the pool already applied on top. // by the pool already applied on top.
func (pool *TxPool) Nonce(addr common.Address) uint64 { func (pool *TxPool) Nonce(addr common.Address) uint64 {
@ -767,6 +785,13 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
knownTxMeter.Mark(1) knownTxMeter.Mark(1)
return false, ErrAlreadyKnown return false, ErrAlreadyKnown
} }
if pool.IsMiner() && rawdb.IsSkippedTransaction(pool.chain.Database(), hash) {
log.Trace("Discarding already known skipped transaction", "hash", hash)
knownSkippedTxMeter.Mark(1)
return false, ErrAlreadyKnown
}
// Make the local flag. If it's from local source or it's from the network but // Make the local flag. If it's from local source or it's from the network but
// the sender is marked as local previously, treat it as the local transaction. // the sender is marked as local previously, treat it as the local transaction.
isLocal := local || pool.locals.containsTx(tx) isLocal := local || pool.locals.containsTx(tx)

View file

@ -35,6 +35,7 @@ import (
"github.com/scroll-tech/go-ethereum/core/state" "github.com/scroll-tech/go-ethereum/core/state"
"github.com/scroll-tech/go-ethereum/core/types" "github.com/scroll-tech/go-ethereum/core/types"
"github.com/scroll-tech/go-ethereum/crypto" "github.com/scroll-tech/go-ethereum/crypto"
"github.com/scroll-tech/go-ethereum/ethdb"
"github.com/scroll-tech/go-ethereum/event" "github.com/scroll-tech/go-ethereum/event"
"github.com/scroll-tech/go-ethereum/params" "github.com/scroll-tech/go-ethereum/params"
"github.com/scroll-tech/go-ethereum/trie" "github.com/scroll-tech/go-ethereum/trie"
@ -97,6 +98,10 @@ func (bc *testBlockChain) SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) even
return bc.chainHeadFeed.Subscribe(ch) return bc.chainHeadFeed.Subscribe(ch)
} }
func (bc *testBlockChain) Database() ethdb.Database {
return nil
}
func transaction(nonce uint64, gaslimit uint64, key *ecdsa.PrivateKey) *types.Transaction { func transaction(nonce uint64, gaslimit uint64, key *ecdsa.PrivateKey) *types.Transaction {
return pricedTransaction(nonce, gaslimit, big.NewInt(1), key) return pricedTransaction(nonce, gaslimit, big.NewInt(1), key)
} }

View file

@ -91,6 +91,10 @@ func (bc *testBlockChain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent)
return bc.chainHeadFeed.Subscribe(ch) return bc.chainHeadFeed.Subscribe(ch)
} }
func (bc *testBlockChain) Database() ethdb.Database {
return nil
}
func TestMiner(t *testing.T) { func TestMiner(t *testing.T) {
miner, mux := createMiner(t) miner, mux := createMiner(t)
miner.Start(common.HexToAddress("0x12345")) miner.Start(common.HexToAddress("0x12345"))

View file

@ -24,7 +24,7 @@ import (
const ( const (
VersionMajor = 5 // Major version component of the current release VersionMajor = 5 // Major version component of the current release
VersionMinor = 7 // Minor version component of the current release VersionMinor = 7 // Minor version component of the current release
VersionPatch = 0 // Patch version component of the current release VersionPatch = 1 // Patch version component of the current release
VersionMeta = "mainnet" // Version metadata to append to the version string VersionMeta = "mainnet" // Version metadata to append to the version string
) )