1
0
Fork 0
forked from forks/go-ethereum
go-ethereum-modded-tocallarg/cmd/workload/testsuite.go
Felix Lange 48ec86abbb
core: initialize history pruning in BlockChain (#31636)
I added the history mode configuration in eth/ethconfig initially, since
it seemed like the logical place. But it turns out we need access to the
intended pruning setting at a deeper level, and it actually needs to be
integrated with the blockchain startup procedure.

With this change applied, if a node previously had its history pruned,
and is subsequently restarted **without** the `--history.chain
postmerge` flag, the `BlockChain` initialization code will now verify
the freezer tail against the known pruning point of the predefined
network and will restore pruning status. Note that this logic is quite
restrictive, we allow non-zero tail only for known networks, and only
for the specific pruning point that is defined.
2025-04-15 14:32:46 +02:00

174 lines
5.2 KiB
Go

// Copyright 2020 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"embed"
"fmt"
"io/fs"
"os"
"slices"
"github.com/ethereum/go-ethereum/core/history"
"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"
)
//go:embed queries
var builtinTestFiles embed.FS
var (
runTestCommand = &cli.Command{
Name: "test",
Usage: "Runs workload tests against an RPC endpoint",
ArgsUsage: "<RPC endpoint URL>",
Action: runTestCmd,
Flags: []cli.Flag{
testPatternFlag,
testTAPFlag,
testSlowFlag,
testSepoliaFlag,
testMainnetFlag,
filterQueryFileFlag,
historyTestFileFlag,
},
}
testPatternFlag = &cli.StringFlag{
Name: "run",
Usage: "Pattern of test suite(s) to run",
Category: flags.TestingCategory,
}
testTAPFlag = &cli.BoolFlag{
Name: "tap",
Usage: "Output test results in TAP format",
Category: flags.TestingCategory,
}
testSlowFlag = &cli.BoolFlag{
Name: "slow",
Usage: "Enable slow tests",
Value: false,
Category: flags.TestingCategory,
}
testSepoliaFlag = &cli.BoolFlag{
Name: "sepolia",
Usage: "Use test cases for sepolia network",
Category: flags.TestingCategory,
}
testMainnetFlag = &cli.BoolFlag{
Name: "mainnet",
Usage: "Use test cases for mainnet network",
Category: flags.TestingCategory,
}
)
// testConfig holds the parameters for testing.
type testConfig struct {
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) {
flags.CheckExclusive(ctx, testMainnetFlag, testSepoliaFlag)
if (ctx.IsSet(testMainnetFlag.Name) || ctx.IsSet(testSepoliaFlag.Name)) && ctx.IsSet(filterQueryFileFlag.Name) {
exit(filterQueryFileFlag.Name + " cannot be used with " + testMainnetFlag.Name + " or " + testSepoliaFlag.Name)
}
// configure ethclient
cfg.client = makeClient(ctx)
// configure test files
switch {
case ctx.Bool(testMainnetFlag.Name):
cfg.fsys = builtinTestFiles
cfg.filterQueryFile = "queries/filter_queries_mainnet.json"
cfg.historyTestFile = "queries/history_mainnet.json"
cfg.historyPruneBlock = new(uint64)
*cfg.historyPruneBlock = history.PrunePoints[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 = history.PrunePoints[params.SepoliaGenesisHash].BlockNumber
default:
cfg.fsys = os.DirFS(".")
cfg.filterQueryFile = ctx.String(filterQueryFileFlag.Name)
cfg.historyTestFile = ctx.String(historyTestFileFlag.Name)
}
return cfg
}
func runTestCmd(ctx *cli.Context) error {
cfg := testConfigFromCLI(ctx)
filterSuite := newFilterTestSuite(cfg)
historySuite := newHistoryTestSuite(cfg)
// Filter test cases.
tests := filterSuite.allTests()
tests = append(tests, historySuite.allTests()...)
if ctx.IsSet(testPatternFlag.Name) {
tests = utesting.MatchTests(tests, ctx.String(testPatternFlag.Name))
}
if !ctx.Bool(testSlowFlag.Name) {
tests = slices.DeleteFunc(tests, func(test utesting.Test) bool {
return test.Slow
})
}
// Disable logging unless explicitly enabled.
if !ctx.IsSet("verbosity") && !ctx.IsSet("vmodule") {
log.SetDefault(log.NewLogger(log.DiscardHandler()))
}
// Run the tests.
var run = utesting.RunTests
if ctx.Bool(testTAPFlag.Name) {
run = utesting.RunTAP
}
results := run(tests, os.Stdout)
if utesting.CountFailures(results) > 0 {
os.Exit(1)
}
return nil
}