diff --git a/eth/api_admin.go b/eth/api_admin.go index 4a3ccb84e82d..6fa3f4decbc3 100644 --- a/eth/api_admin.go +++ b/eth/api_admin.go @@ -141,3 +141,15 @@ func (api *AdminAPI) ImportChain(file string) (bool, error) { } return true, nil } + +// ClearTxpool clears all transactions from the transaction pool. +// This method removes all pending and queued transactions from both the +// legacy transaction pool and the blob transaction pool. +// +// Note: This operation invokes Sync() internally and should be used with +// caution as it can be susceptible to DoS vectors. It's primarily intended +// for testing and administrative purposes. +func (api *AdminAPI) ClearTxpool() error { + api.eth.TxPool().Clear() + return nil +} diff --git a/eth/api_admin_test.go b/eth/api_admin_test.go new file mode 100644 index 000000000000..9aef2de51e88 --- /dev/null +++ b/eth/api_admin_test.go @@ -0,0 +1,101 @@ +// Copyright 2024 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package eth + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/beacon" + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/txpool" + "github.com/ethereum/go-ethereum/core/txpool/blobpool" + "github.com/ethereum/go-ethereum/core/txpool/legacypool" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" +) + +func TestAdminAPI_ClearTxpool(t *testing.T) { + // Create test key and genesis + testKey, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + testAddress := crypto.PubkeyToAddress(testKey.PublicKey) + testFunds := big.NewInt(1000_000_000_000_000) + testGspec := &core.Genesis{ + Config: params.MergedTestChainConfig, + Alloc: types.GenesisAlloc{ + testAddress: {Balance: testFunds}, + }, + Difficulty: common.Big0, + BaseFee: big.NewInt(params.InitialBaseFee), + } + testSigner := types.LatestSignerForChainID(testGspec.Config.ChainID) + + // Initialize backend + db := rawdb.NewMemoryDatabase() + engine := beacon.New(ethash.NewFaker()) + chain, _ := core.NewBlockChain(db, testGspec, engine, nil) + + txconfig := legacypool.DefaultConfig + txconfig.Journal = "" // Don't litter the disk with test journals + + blobPool := blobpool.New(blobpool.Config{Datadir: ""}, chain, nil) + legacyPool := legacypool.New(txconfig, chain) + pool, _ := txpool.New(txconfig.PriceLimit, chain, []txpool.SubPool{legacyPool, blobPool}) + + eth := &Ethereum{ + blockchain: chain, + txPool: pool, + } + + // Create admin API + api := NewAdminAPI(eth) + + // Create and add a test transaction + tx := types.NewTransaction(0, common.Address{1}, big.NewInt(1000), params.TxGas, big.NewInt(params.InitialBaseFee), nil) + signedTx, err := types.SignTx(tx, testSigner, testKey) + if err != nil { + t.Fatalf("Failed to sign transaction: %v", err) + } + + // Add transaction to pool + errs := pool.Add([]*types.Transaction{signedTx}, true) + if errs[0] != nil { + t.Logf("Note: Transaction addition returned: %v (this may be expected)", errs[0]) + } + + // Verify we tried to add a transaction + t.Logf("Transaction added to pool from: %s", testAddress.Hex()) + + // Clear the transaction pool + err = api.ClearTxpool() + if err != nil { + t.Fatalf("ClearTxpool failed: %v", err) + } + + // Verify the pool is empty after clear + pool.Sync() + pending := pool.Pending(txpool.PendingFilter{}) + if len(pending) > 0 { + t.Errorf("Expected empty pool after clear, but found %d accounts with pending transactions", len(pending)) + } + + t.Log("Successfully cleared transaction pool") +} diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 0aedffe2307a..35a5c0167ba3 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -158,6 +158,11 @@ web3._extend({ name: 'stopWS', call: 'admin_stopWS' }), + new web3._extend.Method({ + name: 'clearTxpool', + call: 'admin_clearTxpool', + params: 0 + }), ], properties: [ new web3._extend.Property({