cmd/workload: implement checks for history-pruned node (#31355)

Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
jwasinger 2025-03-13 15:21:47 +01:00 committed by GitHub
parent 5117f77af9
commit 444a6d007a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 85 additions and 29 deletions

View file

@ -108,7 +108,7 @@ func (s *filterTestSuite) filterFullRange(t *utesting.T) {
}
func (s *filterTestSuite) queryAndCheck(t *utesting.T, query *filterQuery) {
query.run(s.cfg.client)
query.run(s.cfg.client, s.cfg.historyPruneBlock)
if query.Err != nil {
t.Errorf("Filter query failed (fromBlock: %d toBlock: %d addresses: %v topics: %v error: %v)", query.FromBlock, query.ToBlock, query.Address, query.Topics, query.Err)
return
@ -125,7 +125,7 @@ func (s *filterTestSuite) fullRangeQueryAndCheck(t *utesting.T, query *filterQue
Address: query.Address,
Topics: query.Topics,
}
frQuery.run(s.cfg.client)
frQuery.run(s.cfg.client, s.cfg.historyPruneBlock)
if frQuery.Err != nil {
t.Errorf("Full range filter query failed (addresses: %v topics: %v error: %v)", frQuery.Address, frQuery.Topics, frQuery.Err)
return
@ -197,7 +197,7 @@ func (fq *filterQuery) calculateHash() common.Hash {
return crypto.Keccak256Hash(enc)
}
func (fq *filterQuery) run(client *client) {
func (fq *filterQuery) run(client *client, historyPruneBlock *uint64) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()
logs, err := client.Eth.FilterLogs(ctx, ethereum.FilterQuery{
@ -207,10 +207,13 @@ func (fq *filterQuery) run(client *client) {
Topics: fq.Topics,
})
if err != nil {
if err = validateHistoryPruneErr(fq.Err, uint64(fq.FromBlock), historyPruneBlock); err == errPrunedHistory {
return
} else if err != nil {
fmt.Printf("Filter query failed: fromBlock: %d toBlock: %d addresses: %v topics: %v error: %v\n",
fq.FromBlock, fq.ToBlock, fq.Address, fq.Topics, err)
}
fq.Err = err
fmt.Printf("Filter query failed: fromBlock: %d toBlock: %d addresses: %v topics: %v error: %v\n",
fq.FromBlock, fq.ToBlock, fq.Address, fq.Topics, err)
return
}
fq.results = logs
}

View file

@ -70,7 +70,7 @@ func filterGenCmd(ctx *cli.Context) error {
f.updateFinalizedBlock()
query := f.newQuery()
query.run(f.client)
query.run(f.client, nil)
if query.Err != nil {
f.errors = append(f.errors, query)
continue
@ -81,7 +81,7 @@ func filterGenCmd(ctx *cli.Context) error {
if extQuery == nil {
break
}
extQuery.run(f.client)
extQuery.run(f.client, nil)
if extQuery.Err == nil && len(extQuery.results) < len(query.results) {
extQuery.Err = fmt.Errorf("invalid result length; old range %d %d; old length %d; new range %d %d; new length %d; address %v; Topics %v",
query.FromBlock, query.ToBlock, len(query.results),

View file

@ -70,7 +70,7 @@ func filterPerfCmd(ctx *cli.Context) error {
queries[pick] = queries[len(queries)-1]
queries = queries[:len(queries)-1]
start := time.Now()
qt.query.run(cfg.client)
qt.query.run(cfg.client, cfg.historyPruneBlock)
qt.runtime = append(qt.runtime, time.Since(start))
slices.Sort(qt.runtime)
qt.medianTime = qt.runtime[len(qt.runtime)/2]

View file

@ -108,8 +108,11 @@ func (s *historyTestSuite) testGetBlockByHash(t *utesting.T) {
for i, num := range s.tests.BlockNumbers {
bhash := s.tests.BlockHashes[i]
b, err := s.cfg.client.getBlockByHash(ctx, bhash, false)
if err != nil {
t.Fatalf("block %d (hash %v): error %v", num, bhash, err)
if err = validateHistoryPruneErr(err, num, s.cfg.historyPruneBlock); err == errPrunedHistory {
continue
} else if err != nil {
t.Errorf("block %d (hash %v): error %v", num, bhash, err)
continue
}
if b == nil {
t.Errorf("block %d (hash %v): not found", num, bhash)
@ -127,8 +130,11 @@ func (s *historyTestSuite) testGetBlockByNumber(t *utesting.T) {
for i, num := range s.tests.BlockNumbers {
bhash := s.tests.BlockHashes[i]
b, err := s.cfg.client.getBlockByNumber(ctx, num, false)
if err != nil {
t.Fatalf("block %d (hash %v): error %v", num, bhash, err)
if err = validateHistoryPruneErr(err, num, s.cfg.historyPruneBlock); err == errPrunedHistory {
continue
} else if err != nil {
t.Errorf("block %d (hash %v): error %v", num, bhash, err)
continue
}
if b == nil {
t.Errorf("block %d (hash %v): not found", num, bhash)
@ -146,8 +152,11 @@ func (s *historyTestSuite) testGetBlockTransactionCountByHash(t *utesting.T) {
for i, num := range s.tests.BlockNumbers {
bhash := s.tests.BlockHashes[i]
count, err := s.cfg.client.getBlockTransactionCountByHash(ctx, bhash)
if err != nil {
t.Fatalf("block %d (hash %v): error %v", num, bhash, err)
if err = validateHistoryPruneErr(err, num, s.cfg.historyPruneBlock); err == errPrunedHistory {
continue
} else if err != nil {
t.Errorf("block %d (hash %v): error %v", num, bhash, err)
continue
}
expectedCount := uint64(s.tests.TxCounts[i])
if count != expectedCount {
@ -162,8 +171,11 @@ func (s *historyTestSuite) testGetBlockTransactionCountByNumber(t *utesting.T) {
for i, num := range s.tests.BlockNumbers {
bhash := s.tests.BlockHashes[i]
count, err := s.cfg.client.getBlockTransactionCountByNumber(ctx, num)
if err != nil {
t.Fatalf("block %d (hash %v): error %v", num, bhash, err)
if err = validateHistoryPruneErr(err, num, s.cfg.historyPruneBlock); err == errPrunedHistory {
continue
} else if err != nil {
t.Errorf("block %d (hash %v): error %v", num, bhash, err)
continue
}
expectedCount := uint64(s.tests.TxCounts[i])
if count != expectedCount {
@ -178,8 +190,11 @@ func (s *historyTestSuite) testGetBlockReceiptsByHash(t *utesting.T) {
for i, num := range s.tests.BlockNumbers {
bhash := s.tests.BlockHashes[i]
receipts, err := s.cfg.client.getBlockReceipts(ctx, bhash)
if err != nil {
t.Fatalf("block %d (hash %v): error %v", num, bhash, err)
if err = validateHistoryPruneErr(err, num, s.cfg.historyPruneBlock); err == errPrunedHistory {
continue
} else if err != nil {
t.Errorf("block %d (hash %v): error %v", num, bhash, err)
continue
}
hash := calcReceiptsHash(receipts)
expectedHash := s.tests.ReceiptsHashes[i]
@ -195,8 +210,11 @@ func (s *historyTestSuite) testGetBlockReceiptsByNumber(t *utesting.T) {
for i, num := range s.tests.BlockNumbers {
bhash := s.tests.BlockHashes[i]
receipts, err := s.cfg.client.getBlockReceipts(ctx, hexutil.Uint64(num))
if err != nil {
t.Fatalf("block %d (hash %v): error %v", num, bhash, err)
if err = validateHistoryPruneErr(err, num, s.cfg.historyPruneBlock); err == errPrunedHistory {
continue
} else if err != nil {
t.Errorf("block %d (hash %v): error %v", num, bhash, err)
continue
}
hash := calcReceiptsHash(receipts)
expectedHash := s.tests.ReceiptsHashes[i]
@ -218,8 +236,11 @@ func (s *historyTestSuite) testGetTransactionByBlockHashAndIndex(t *utesting.T)
}
tx, err := s.cfg.client.getTransactionByBlockHashAndIndex(ctx, bhash, uint64(txIndex))
if err != nil {
t.Fatalf("block %d (hash %v): error %v", num, bhash, err)
if err = validateHistoryPruneErr(err, num, s.cfg.historyPruneBlock); err == errPrunedHistory {
continue
} else if err != nil {
t.Errorf("block %d (hash %v): error %v", num, bhash, err)
continue
}
if tx == nil {
t.Errorf("block %d (hash %v): txIndex %d not found", num, bhash, txIndex)
@ -243,8 +264,11 @@ func (s *historyTestSuite) testGetTransactionByBlockNumberAndIndex(t *utesting.T
}
tx, err := s.cfg.client.getTransactionByBlockNumberAndIndex(ctx, num, uint64(txIndex))
if err != nil {
t.Fatalf("block %d (hash %v): error %v", num, bhash, err)
if err = validateHistoryPruneErr(err, num, s.cfg.historyPruneBlock); err == errPrunedHistory {
continue
} else if err != nil {
t.Errorf("block %d (hash %v): error %v", num, bhash, err)
continue
}
if tx == nil {
t.Errorf("block %d (hash %v): txIndex %d not found", num, bhash, txIndex)

View file

@ -18,13 +18,17 @@ package main
import (
"embed"
"fmt"
"io/fs"
"os"
"slices"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/internal/utesting"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
"github.com/urfave/cli/v2"
)
@ -77,10 +81,31 @@ var (
// testConfig holds the parameters for testing.
type testConfig struct {
client *client
fsys fs.FS
filterQueryFile string
historyTestFile string
client *client
fsys fs.FS
filterQueryFile string
historyTestFile string
historyPruneBlock *uint64
}
var errPrunedHistory = fmt.Errorf("attempt to access pruned history")
// validateHistoryPruneErr checks whether the given error is caused by access
// to history before the pruning threshold block (it is an rpc.Error with code 4444).
// In this case, errPrunedHistory is returned.
// If the error is a pruned history error that occurs when accessing a block past the
// historyPrune block, an error is returned.
// Otherwise, the original value of err is returned.
func validateHistoryPruneErr(err error, blockNum uint64, historyPruneBlock *uint64) error {
if err != nil {
if rpcErr, ok := err.(rpc.Error); ok && rpcErr.ErrorCode() == 4444 {
if historyPruneBlock != nil && blockNum > *historyPruneBlock {
return fmt.Errorf("pruned history error returned after pruning threshold")
}
return errPrunedHistory
}
}
return err
}
func testConfigFromCLI(ctx *cli.Context) (cfg testConfig) {
@ -98,10 +123,14 @@ func testConfigFromCLI(ctx *cli.Context) (cfg testConfig) {
cfg.fsys = builtinTestFiles
cfg.filterQueryFile = "queries/filter_queries_mainnet.json"
cfg.historyTestFile = "queries/history_mainnet.json"
cfg.historyPruneBlock = new(uint64)
*cfg.historyPruneBlock = ethconfig.HistoryPrunePoints[params.MainnetGenesisHash].BlockNumber
case ctx.Bool(testSepoliaFlag.Name):
cfg.fsys = builtinTestFiles
cfg.filterQueryFile = "queries/filter_queries_sepolia.json"
cfg.historyTestFile = "queries/history_sepolia.json"
cfg.historyPruneBlock = new(uint64)
*cfg.historyPruneBlock = ethconfig.HistoryPrunePoints[params.SepoliaGenesisHash].BlockNumber
default:
cfg.fsys = os.DirFS(".")
cfg.filterQueryFile = ctx.String(filterQueryFileFlag.Name)