core/txpool/localpool: add basic test and benchmark

This commit is contained in:
Marius van der Wijden 2023-11-12 22:51:29 +01:00
parent 6bbe856697
commit a4f2744da2
3 changed files with 162 additions and 3 deletions

View file

@ -0,0 +1,39 @@
package localpool
import (
"errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
)
type MockBC struct {
currentBlock *types.Header
dbs map[common.Hash]*state.StateDB
}
func (m *MockBC) Config() *params.ChainConfig {
return params.AllDevChainProtocolChanges
}
func (m *MockBC) CurrentBlock() *types.Header {
return m.currentBlock
}
func (m *MockBC) GetBlock(hash common.Hash, number uint64) *types.Block {
return nil
}
func (m *MockBC) StateAt(root common.Hash) (*state.StateDB, error) {
state, ok := m.dbs[root]
if !ok {
return nil, errors.New("not found")
}
return state, nil
}
func (m *MockBC) SetState(root common.Hash, db *state.StateDB) {
m.dbs[root] = db
}

View file

@ -87,7 +87,7 @@ func (l *LocalPool) Init(gasTip *big.Int, head *types.Header, reserve txpool.Add
l.reserver = reserve
// TODO load transactions.rlp
l.Reset(nil, head)
return errors.New("not implemented")
return nil
}
func (l *LocalPool) Close() error {
@ -149,7 +149,7 @@ func (l *LocalPool) Add(txs []*types.Transaction, local bool, sync bool) []error
}
// notify all listeners about successfully added txs
l.txFeed.Send(core.NewTxsEvent{Txs: successfulTxs})
return nil
return errs
}
func (l *LocalPool) add(tx *types.Transaction) error {

View file

@ -1,6 +1,17 @@
package localpool
import "errors"
import (
"errors"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
)
func (l *LocalPool) verifyConsistency() error {
for _, list := range l.allAccounts {
@ -25,3 +36,112 @@ func (l *LocalPool) verifyConsistency() error {
}
return nil
}
func TestReset(t *testing.T) {
// Generate a faucet
key, err := crypto.GenerateKey()
if err != nil {
t.Fatal(err)
}
addr := crypto.PubkeyToAddress(key.PublicKey)
// Setup a mock blockchain
bc := &MockBC{
currentBlock: &types.Header{Root: common.Hash{}},
dbs: make(map[common.Hash]*state.StateDB),
}
initialDB, err := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
if err != nil {
t.Fatal(err)
}
initialDB.CreateAccount(addr)
initialDB.SetBalance(addr, big.NewInt(1_000_000_000_000_000_000))
bc.SetState(common.Hash{}, initialDB)
// Setup the txpool
pool, err := NewLocalPool(bc, types.LatestSigner(params.AllDevChainProtocolChanges))
if err != nil {
t.Fatal(err)
}
if err := pool.Init(nil, &types.Header{Root: common.Hash{}, GasLimit: 200_000}, func(addr common.Address, reserve bool) error { return nil }); err != nil {
t.Fatal(err)
}
// Queue transactions
// TODO there might be an off-by-one error here
for i := 1; i < 100; i++ {
tx := types.NewTransaction(uint64(i), common.Address{}, new(big.Int), 100000, big.NewInt(1234), nil)
signer := types.LatestSigner(params.AllDevChainProtocolChanges)
signed, err := types.SignTx(tx, signer, key)
if err != nil {
t.Fatal(err)
}
if errs := pool.Add([]*types.Transaction{signed}, true, false); errs[0] != nil {
t.Fatal(errs[0])
}
}
// Verify integrity
if err := pool.verifyConsistency(); err != nil {
t.Fatal(err)
}
pending, queued := pool.ContentFrom(addr)
if len(pending) != 99 || len(queued) != 0 {
t.Fatal(len(pending), len(queued))
}
// Reset the pool
newDB := initialDB.Copy()
newDB.SetNonce(addr, uint64(100+1))
bc.SetState(common.Hash{1}, newDB)
pool.Reset(nil, &types.Header{Root: common.Hash{1}})
// Verify post state
if err := pool.verifyConsistency(); err != nil {
t.Fatal(err)
}
pending, queued = pool.ContentFrom(addr)
if len(pending) != 0 || len(queued) != 0 {
t.Fatal(pending, queued)
}
}
func BenchmarkReorg(b *testing.B) {
// Generate a faucet
key, err := crypto.GenerateKey()
if err != nil {
b.Fatal(err)
}
addr := crypto.PubkeyToAddress(key.PublicKey)
// Setup a mock blockchain
bc := &MockBC{
currentBlock: &types.Header{Root: common.Hash{}},
dbs: make(map[common.Hash]*state.StateDB),
}
initialDB, err := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
if err != nil {
b.Fatal(err)
}
initialDB.CreateAccount(addr)
initialDB.SetBalance(addr, big.NewInt(1_000_000_000_000_000_000))
bc.SetState(common.Hash{}, initialDB)
// Setup the txpool
pool, err := NewLocalPool(bc, types.LatestSigner(params.AllDevChainProtocolChanges))
if err != nil {
b.Fatal(err)
}
if err := pool.Init(nil, &types.Header{Root: common.Hash{}, GasLimit: 200_000}, func(addr common.Address, reserve bool) error { return nil }); err != nil {
b.Fatal(err)
}
// Queue transactions
for i := 0; i < b.N; i++ {
tx := types.NewTransaction(uint64(i), common.Address{}, new(big.Int), 100000, big.NewInt(1234), nil)
signer := types.LatestSigner(params.AllDevChainProtocolChanges)
signed, err := types.SignTx(tx, signer, key)
if err != nil {
b.Fatal(err)
}
if errs := pool.Add([]*types.Transaction{signed}, true, false); errs[0] != nil {
b.Fatal(errs[0])
}
}
newDB := initialDB.Copy()
newDB.SetNonce(addr, uint64(b.N+1))
bc.SetState(common.Hash{1}, newDB)
b.ResetTimer()
pool.Reset(nil, &types.Header{Root: common.Hash{1}})
}