mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 23:26:44 +00:00
cmd/workload: implement history tests
This commit is contained in:
parent
9a7d8cd216
commit
2823ee96da
5 changed files with 325 additions and 29 deletions
|
|
@ -48,8 +48,8 @@ func newFilterTestSuite(cfg testConfig) *filterTestSuite {
|
|||
func (s *filterTestSuite) allTests() []utesting.Test {
|
||||
return []utesting.Test{
|
||||
{Name: "Filter/ShortRange", Fn: s.filterShortRange},
|
||||
{Name: "Filter/LongRange", Fn: s.filterLongRange},
|
||||
{Name: "Filter/FullRange", Fn: s.filterFullRange},
|
||||
{Name: "Filter/LongRange", Fn: s.filterLongRange, Slow: true},
|
||||
{Name: "Filter/FullRange", Fn: s.filterFullRange, Slow: true},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -162,7 +162,6 @@ func (s *filterTestSuite) loadQueries() error {
|
|||
if count == 0 {
|
||||
return fmt.Errorf("filterQueryFile %s is empty", s.cfg.filterQueryFile)
|
||||
}
|
||||
fmt.Println("Loaded", count, "filter test queries")
|
||||
s.queries = queries
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
305
cmd/workload/historytest.go
Normal file
305
cmd/workload/historytest.go
Normal file
|
|
@ -0,0 +1,305 @@
|
|||
// Copyright 2025 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 (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/internal/utesting"
|
||||
)
|
||||
|
||||
// historyTest is the content of a history test.
|
||||
type historyTest struct {
|
||||
BlockNumbers []uint64 `json:"blockNumbers"`
|
||||
BlockHashes []common.Hash `json:"blockHashes"`
|
||||
TxCounts []int `json:"txCounts"`
|
||||
TxHashIndex []int `json:"txHashIndex"`
|
||||
TxHashes []*common.Hash `json:"txHashes"`
|
||||
ReceiptsHashes []common.Hash `json:"blockReceiptsHashes"`
|
||||
}
|
||||
|
||||
type historyTestSuite struct {
|
||||
cfg testConfig
|
||||
tests historyTest
|
||||
}
|
||||
|
||||
func newHistoryTestSuite(cfg testConfig) *historyTestSuite {
|
||||
s := &historyTestSuite{cfg: cfg}
|
||||
if err := s.loadTests(); err != nil {
|
||||
exit(err)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *historyTestSuite) loadTests() error {
|
||||
file, err := s.cfg.fsys.Open(s.cfg.historyTestFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't open historyTestFile: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
if err := json.NewDecoder(file).Decode(&s.tests); err != nil {
|
||||
return fmt.Errorf("invalid JSON in %s: %v", s.cfg.historyTestFile, err)
|
||||
}
|
||||
if len(s.tests.BlockNumbers) == 0 {
|
||||
return fmt.Errorf("historyTestFile %s has no test data", s.cfg.historyTestFile)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *historyTestSuite) allTests() []utesting.Test {
|
||||
return []utesting.Test{
|
||||
{
|
||||
Name: "History/getBlockByHash",
|
||||
Fn: s.testGetBlockByHash,
|
||||
},
|
||||
{
|
||||
Name: "History/getBlockByNumber",
|
||||
Fn: s.testGetBlockByNumber,
|
||||
},
|
||||
{
|
||||
Name: "History/getBlockReceiptsByHash",
|
||||
Fn: s.testGetBlockReceiptsByHash,
|
||||
},
|
||||
{
|
||||
Name: "History/getBlockReceiptsByNumber",
|
||||
Fn: s.testGetBlockReceiptsByNumber,
|
||||
},
|
||||
{
|
||||
Name: "History/getBlockTransactionCountByHash",
|
||||
Fn: s.testGetBlockTransactionCountByHash,
|
||||
},
|
||||
{
|
||||
Name: "History/getBlockTransactionCountByNumber",
|
||||
Fn: s.testGetBlockTransactionCountByNumber,
|
||||
},
|
||||
{
|
||||
Name: "History/getTransactionByBlockHashAndIndex",
|
||||
Fn: s.testGetTransactionByBlockHashAndIndex,
|
||||
},
|
||||
{
|
||||
Name: "History/getTransactionByBlockNumberAndIndex",
|
||||
Fn: s.testGetTransactionByBlockNumberAndIndex,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *historyTestSuite) testGetBlockByHash(t *utesting.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
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 b == nil {
|
||||
t.Fatalf("block %d (hash %v): not found", num, bhash)
|
||||
}
|
||||
if b.Hash != bhash || uint64(b.Number) != num {
|
||||
t.Errorf("block %d (hash %v): invalid number/hash", num, bhash)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *historyTestSuite) testGetBlockByNumber(t *utesting.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
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 b == nil {
|
||||
t.Fatalf("block %d (hash %v): not found", num, bhash)
|
||||
}
|
||||
if b.Hash != bhash || uint64(b.Number) != num {
|
||||
t.Errorf("block %d (hash %v): invalid number/hash", num, bhash)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *historyTestSuite) testGetBlockTransactionCountByHash(t *utesting.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
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)
|
||||
}
|
||||
expectedCount := uint64(s.tests.TxCounts[i])
|
||||
if count != expectedCount {
|
||||
t.Errorf("block %d (hash %v): wrong txcount %d, want %d", count, expectedCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *historyTestSuite) testGetBlockTransactionCountByNumber(t *utesting.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
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)
|
||||
}
|
||||
expectedCount := uint64(s.tests.TxCounts[i])
|
||||
if count != expectedCount {
|
||||
t.Errorf("block %d (hash %v): wrong txcount %d, want %d", count, expectedCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *historyTestSuite) testGetBlockReceiptsByHash(t *utesting.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
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)
|
||||
}
|
||||
hash := calcReceiptsHash(receipts)
|
||||
expectedHash := s.tests.ReceiptsHashes[i]
|
||||
if hash != expectedHash {
|
||||
t.Errorf("block %d (hash %v): wrong receipts hash %v, want %v", num, bhash, hash, expectedHash)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *historyTestSuite) testGetBlockReceiptsByNumber(t *utesting.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
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)
|
||||
}
|
||||
hash := calcReceiptsHash(receipts)
|
||||
expectedHash := s.tests.ReceiptsHashes[i]
|
||||
if hash != expectedHash {
|
||||
t.Errorf("block %d (hash %v): wrong receipts hash %v, want %v", num, bhash, hash, expectedHash)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *historyTestSuite) testGetTransactionByBlockHashAndIndex(t *utesting.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
for i, num := range s.tests.BlockNumbers {
|
||||
bhash := s.tests.BlockHashes[i]
|
||||
txIndex := s.tests.TxHashIndex[i]
|
||||
expectedHash := s.tests.TxHashes[i]
|
||||
if expectedHash == nil {
|
||||
continue // no txs in block
|
||||
}
|
||||
|
||||
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 tx == nil {
|
||||
t.Errorf("block %d (hash %v): txIndex %d not found", num, bhash, txIndex)
|
||||
}
|
||||
if tx.Hash != *expectedHash || uint64(tx.TransactionIndex) != uint64(txIndex) {
|
||||
t.Errorf("block %d (hash %v): txIndex %d has wrong txHash/Index", num, bhash, txIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *historyTestSuite) testGetTransactionByBlockNumberAndIndex(t *utesting.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
for i, num := range s.tests.BlockNumbers {
|
||||
bhash := s.tests.BlockHashes[i]
|
||||
txIndex := s.tests.TxHashIndex[i]
|
||||
expectedHash := s.tests.TxHashes[i]
|
||||
if expectedHash == nil {
|
||||
continue // no txs in block
|
||||
}
|
||||
|
||||
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 tx == nil {
|
||||
t.Errorf("block %d (hash %v): txIndex %d not found", num, bhash, txIndex)
|
||||
}
|
||||
if tx.Hash != *expectedHash || uint64(tx.TransactionIndex) != uint64(txIndex) {
|
||||
t.Errorf("block %d (hash %v): txIndex %d has wrong txHash/Index", num, bhash, txIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type simpleBlock struct {
|
||||
Number hexutil.Uint64 `json:"number"`
|
||||
Hash common.Hash `json:"hash"`
|
||||
}
|
||||
|
||||
type simpleTransaction struct {
|
||||
Hash common.Hash `json:"hash"`
|
||||
TransactionIndex hexutil.Uint64 `json:"transactionIndex"`
|
||||
}
|
||||
|
||||
func (c *client) getBlockByHash(ctx context.Context, arg common.Hash, fullTx bool) (*simpleBlock, error) {
|
||||
var r *simpleBlock
|
||||
err := c.RPC.CallContext(ctx, &r, "eth_getBlockByHash", arg, fullTx)
|
||||
return r, err
|
||||
}
|
||||
|
||||
func (c *client) getBlockByNumber(ctx context.Context, arg uint64, fullTx bool) (*simpleBlock, error) {
|
||||
var r *simpleBlock
|
||||
err := c.RPC.CallContext(ctx, &r, "eth_getBlockByNumber", hexutil.Uint64(arg), fullTx)
|
||||
return r, err
|
||||
}
|
||||
|
||||
func (c *client) getTransactionByBlockHashAndIndex(ctx context.Context, block common.Hash, index uint64) (*simpleTransaction, error) {
|
||||
var r *simpleTransaction
|
||||
err := c.RPC.CallContext(ctx, &r, "eth_getTransactionByBlockHashAndIndex", block, hexutil.Uint64(index))
|
||||
return r, err
|
||||
}
|
||||
|
||||
func (c *client) getTransactionByBlockNumberAndIndex(ctx context.Context, block uint64, index uint64) (*simpleTransaction, error) {
|
||||
var r *simpleTransaction
|
||||
err := c.RPC.CallContext(ctx, &r, "eth_getTransactionByBlockNumberAndIndex", hexutil.Uint64(block), hexutil.Uint64(index))
|
||||
return r, err
|
||||
}
|
||||
|
||||
func (c *client) getBlockTransactionCountByHash(ctx context.Context, block common.Hash) (uint64, error) {
|
||||
var r hexutil.Uint64
|
||||
err := c.RPC.CallContext(ctx, &r, "eth_getBlockTransactionCountByHash", block)
|
||||
return uint64(r), err
|
||||
}
|
||||
|
||||
func (c *client) getBlockTransactionCountByNumber(ctx context.Context, block uint64) (uint64, error) {
|
||||
var r hexutil.Uint64
|
||||
err := c.RPC.CallContext(ctx, &r, "eth_getBlockTransactionCountByNumber", block)
|
||||
return uint64(r), err
|
||||
}
|
||||
|
||||
func (c *client) getBlockReceipts(ctx context.Context, arg any) ([]*types.Receipt, error) {
|
||||
var result []*types.Receipt
|
||||
err := c.RPC.CallContext(ctx, &result, "eth_getBlockReceipts", arg)
|
||||
return result, err
|
||||
}
|
||||
|
|
@ -31,14 +31,6 @@ import (
|
|||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// eth_getBlockByHash
|
||||
// eth_getBlockByNumber
|
||||
// eth_getBlockReceipts
|
||||
// eth_getBlockTransactionCountByHash
|
||||
// eth_getBlockTransactionCountByNumber
|
||||
// eth_getTransactionByBlockHashAndIndex
|
||||
// eth_getTransactionByBlockNumberAndIndex
|
||||
|
||||
var (
|
||||
historyGenerateCommand = &cli.Command{
|
||||
Name: "historygen",
|
||||
|
|
@ -64,16 +56,6 @@ var (
|
|||
}
|
||||
)
|
||||
|
||||
// historyTest is the content of a history test.
|
||||
type historyTest struct {
|
||||
BlockNumbers []uint64 `json:"blockNumbers"`
|
||||
BlockHashes []common.Hash `json:"blockHashes"`
|
||||
TxCounts []int `json:"txCounts"`
|
||||
TxHashIndex []int `json:"txHashIndex"`
|
||||
TxHashes []*common.Hash `json:"txHashes"`
|
||||
ReceiptsHashes []common.Hash `json:"blockReceiptsHashes"`
|
||||
}
|
||||
|
||||
const historyTestBlockCount = 2000
|
||||
|
||||
func generateHistoryTests(clictx *cli.Context) error {
|
||||
|
|
@ -147,12 +129,6 @@ func generateHistoryTests(clictx *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *client) getBlockReceipts(ctx context.Context, arg any) ([]*types.Receipt, error) {
|
||||
var result []*types.Receipt
|
||||
err := c.RPC.CallContext(ctx, &result, "eth_getBlockReceipts", arg)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func calcReceiptsHash(rcpt []*types.Receipt) common.Hash {
|
||||
h := crypto.NewKeccakState()
|
||||
rlp.Encode(h, rcpt)
|
||||
|
|
|
|||
1
cmd/workload/queries/history_sepolia.json
Normal file
1
cmd/workload/queries/history_sepolia.json
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -20,6 +20,7 @@ import (
|
|||
"embed"
|
||||
"io/fs"
|
||||
"os"
|
||||
"slices"
|
||||
|
||||
"github.com/ethereum/go-ethereum/internal/flags"
|
||||
"github.com/ethereum/go-ethereum/internal/utesting"
|
||||
|
|
@ -39,6 +40,7 @@ var (
|
|||
Flags: []cli.Flag{
|
||||
testPatternFlag,
|
||||
testTAPFlag,
|
||||
testSlowFlag,
|
||||
testSepoliaFlag,
|
||||
testMainnetFlag,
|
||||
filterQueryFileFlag,
|
||||
|
|
@ -54,6 +56,12 @@ var (
|
|||
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",
|
||||
|
|
@ -103,13 +111,20 @@ func testConfigFromCLI(ctx *cli.Context) (cfg testConfig) {
|
|||
|
||||
func runTestCmd(ctx *cli.Context) error {
|
||||
cfg := testConfigFromCLI(ctx)
|
||||
s := newFilterTestSuite(cfg)
|
||||
filterSuite := newFilterTestSuite(cfg)
|
||||
historySuite := newHistoryTestSuite(cfg)
|
||||
|
||||
// Filter test cases.
|
||||
tests := s.allTests()
|
||||
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") {
|
||||
|
|
|
|||
Loading…
Reference in a new issue