diff --git a/tests/block_test.go b/tests/block_test.go index 0f087967bb..ba2e71c499 100644 --- a/tests/block_test.go +++ b/tests/block_test.go @@ -24,6 +24,65 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" ) +func TestBlockchainBAL(t *testing.T) { + bt := new(testMatcher) + + // We are running most of GeneralStatetests to tests witness support, even + // though they are ran as state tests too. Still, the performance tests are + // less about state andmore about EVM number crunching, so skip those. + bt.skipLoad(`^GeneralStateTests/VMTests/vmPerformance`) + + // Skip random failures due to selfish mining test + bt.skipLoad(`.*bcForgedTest/bcForkUncle\.json`) + + // Slow tests + bt.slow(`.*bcExploitTest/DelegateCallSpam.json`) + bt.slow(`.*bcExploitTest/ShanghaiLove.json`) + bt.slow(`.*bcExploitTest/SuicideIssue.json`) + bt.slow(`.*/bcForkStressTest/`) + bt.slow(`.*/bcGasPricerTest/RPC_API_Test.json`) + bt.slow(`.*/bcWalletTest/`) + + // Very slow test + bt.skipLoad(`.*/stTimeConsuming/.*`) + // test takes a lot for time and goes easily OOM because of sha3 calculation on a huge range, + // using 4.6 TGas + bt.skipLoad(`.*randomStatetest94.json.*`) + + // After the merge we would accept side chains as canonical even if they have lower td + bt.skipLoad(`.*bcMultiChainTest/ChainAtoChainB_difficultyB.json`) + bt.skipLoad(`.*bcMultiChainTest/CallContractFromNotBestBlock.json`) + bt.skipLoad(`.*bcTotalDifficultyTest/uncleBlockAtBlock3afterBlock4.json`) + bt.skipLoad(`.*bcTotalDifficultyTest/lotsOfBranchesOverrideAtTheMiddle.json`) + bt.skipLoad(`.*bcTotalDifficultyTest/sideChainWithMoreTransactions.json`) + bt.skipLoad(`.*bcForkStressTest/ForkStressTest.json`) + bt.skipLoad(`.*bcMultiChainTest/lotsOfLeafs.json`) + bt.skipLoad(`.*bcFrontierToHomestead/blockChainFrontierWithLargerTDvsHomesteadBlockchain.json`) + bt.skipLoad(`.*bcFrontierToHomestead/blockChainFrontierWithLargerTDvsHomesteadBlockchain2.json`) + + // With chain history removal, TDs become unavailable, this transition tests based on TTD are unrunnable + bt.skipLoad(`.*bcArrowGlacierToParis/powToPosBlockRejection.json`) + + // This directory contains no test. + bt.skipLoad(`.*\.meta/.*`) + + bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) { + config, ok := Forks[test.json.Network] + if !ok { + t.Fatalf("unsupported fork: %s\n", test.json.Network) + } + gspec := test.genesis(config) + // skip any tests which are not past the cancun fork (selfdestruct removal) + if gspec.Config.CancunTime == nil || *gspec.Config.CancunTime != 0 { + return + } + execBlockTest(t, bt, test, true) + }) + // There is also a LegacyTests folder, containing blockchain tests generated + // prior to Istanbul. However, they are all derived from GeneralStateTests, + // which run natively, so there's no reason to run them here. +} + func TestBlockchain(t *testing.T) { bt := new(testMatcher) @@ -66,24 +125,17 @@ func TestBlockchain(t *testing.T) { // This directory contains no test. bt.skipLoad(`.*\.meta/.*`) - // Broken tests - bt.skipLoad(`RevertInCreateInInit`) - bt.skipLoad(`InitCollisionParis`) - bt.skipLoad(`dynamicAccountOverwriteEmpty_Paris`) - bt.skipLoad(`create2collisionStorageParis`) - bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) { - execBlockTest(t, bt, test) + execBlockTest(t, bt, test, false) }) // There is also a LegacyTests folder, containing blockchain tests generated // prior to Istanbul. However, they are all derived from GeneralStateTests, // which run natively, so there's no reason to run them here. } -// TestExecutionSpecBlocktests runs the test fixtures from execution-spec-tests. -func TestExecutionSpecBlocktests(t *testing.T) { - if !common.FileExist(executionSpecBlockchainTestDir) { - t.Skipf("directory %s does not exist", executionSpecBlockchainTestDir) +func testExecutionSpecBlocktests(t *testing.T, testDir string) { + if !common.FileExist(testDir) { + t.Skipf("directory %s does not exist", testDir) } bt := new(testMatcher) @@ -91,18 +143,24 @@ func TestExecutionSpecBlocktests(t *testing.T) { bt.skipLoad(".*prague/eip7251_consolidations/test_system_contract_deployment.json") bt.skipLoad(".*prague/eip7002_el_triggerable_withdrawals/test_system_contract_deployment.json") - // Broken tests - bt.skipLoad(`RevertInCreateInInit`) - bt.skipLoad(`InitCollisionParis`) - bt.skipLoad(`dynamicAccountOverwriteEmpty_Paris`) - bt.skipLoad(`create2collisionStorageParis`) - - bt.walk(t, executionSpecBlockchainTestDir, func(t *testing.T, name string, test *BlockTest) { - execBlockTest(t, bt, test) + bt.walk(t, testDir, func(t *testing.T, name string, test *BlockTest) { + execBlockTest(t, bt, test, true) }) } -func execBlockTest(t *testing.T, bt *testMatcher, test *BlockTest) { +// TestExecutionSpecBlocktests runs the test fixtures from execution-spec-tests. +func TestExecutionSpecBlocktests(t *testing.T) { + testExecutionSpecBlocktests(t, executionSpecBlockchainTestDir) +} + +// TestExecutionSpecBlocktestsBAL runs the BAL release test fixtures from execution-spec-tests. +func TestExecutionSpecBlocktestsBAL(t *testing.T) { + testExecutionSpecBlocktests(t, executionSpecBALBlockchainTestDir) +} + +var failures = 0 + +func execBlockTest(t *testing.T, bt *testMatcher, test *BlockTest, buildAndVerifyBAL bool) { // Define all the different flag combinations we should run the tests with, // picking only one for short tests. // @@ -118,7 +176,13 @@ func execBlockTest(t *testing.T, bt *testMatcher, test *BlockTest) { } for _, snapshot := range snapshotConf { for _, dbscheme := range dbschemeConf { - if err := bt.checkFailure(t, test.Run(snapshot, dbscheme, true, nil, nil)); err != nil { + if err := bt.checkFailure(t, test.Run(snapshot, dbscheme, true, buildAndVerifyBAL, nil, nil)); err != nil { + failures++ + /* + if failures > 10 { + panic("adsf") + } + */ t.Errorf("test with config {snapshotter:%v, scheme:%v} failed: %v", snapshot, dbscheme, err) return } diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 900b108623..d047732c03 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -26,6 +26,7 @@ import ( "math/big" "os" "reflect" + "strings" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -37,6 +38,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/types/bal" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -71,6 +73,7 @@ type btBlock struct { ExpectException string Rlp string UncleHeaders []*btHeader + AccessList *bal.BlockAccessList `json:"blockAccessList,omitempty"` } //go:generate go run github.com/fjl/gencodec -type btHeader -field-override btHeaderMarshaling -out gen_btheader.go @@ -97,8 +100,8 @@ type btHeader struct { BlobGasUsed *uint64 ExcessBlobGas *uint64 ParentBeaconBlockRoot *common.Hash - SlotNumber *uint64 BlockAccessListHash *common.Hash + SlotNumber *uint64 } type btHeaderMarshaling struct { @@ -114,27 +117,20 @@ type btHeaderMarshaling struct { SlotNumber *math.HexOrDecimal64 } -func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, tracer *tracing.Hooks, postCheck func(error, *core.BlockChain)) (result error) { - config, ok := Forks[t.json.Network] - if !ok { - return UnsupportedForkError{t.json.Network} - } - +func (t *BlockTest) createTestBlockChain(config *params.ChainConfig, snapshotter bool, scheme string, witness, createAndVerifyBAL bool, tracer *tracing.Hooks) (*core.BlockChain, error) { // import pre accounts & construct test genesis block & state root - // Commit genesis state var ( - gspec = t.genesis(config) db = rawdb.NewMemoryDatabase() tconf = &triedb.Config{ Preimages: true, - IsUBT: gspec.Config.UBTTime != nil && *gspec.Config.UBTTime <= gspec.Timestamp, } ) - if scheme == rawdb.PathScheme || tconf.IsUBT { + if scheme == rawdb.PathScheme { tconf.PathDB = pathdb.Defaults } else { tconf.HashDB = hashdb.Defaults } + gspec := t.genesis(config) // if ttd is not specified, set an arbitrary huge value if gspec.Config.TerminalTotalDifficulty == nil { @@ -143,15 +139,15 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, tracer *t triedb := triedb.NewDatabase(db, tconf) gblock, err := gspec.Commit(db, triedb, nil) if err != nil { - return err + return nil, err } triedb.Close() // close the db to prevent memory leak if gblock.Hash() != t.json.Genesis.Hash { - return fmt.Errorf("genesis block hash doesn't match test: computed=%x, test=%x", gblock.Hash().Bytes()[:6], t.json.Genesis.Hash[:6]) + return nil, fmt.Errorf("genesis block hash doesn't match test: computed=%x, test=%x", gblock.Hash().Bytes()[:6], t.json.Genesis.Hash[:6]) } if gblock.Root() != t.json.Genesis.StateRoot { - return fmt.Errorf("genesis block state root does not match test: computed=%x, test=%x", gblock.Root().Bytes()[:6], t.json.Genesis.StateRoot[:6]) + return nil, fmt.Errorf("genesis block state root does not match test: computed=%x, test=%x", gblock.Root().Bytes()[:6], t.json.Genesis.StateRoot[:6]) } // Wrap the original engine within the beacon-engine engine := beacon.New(ethash.NewFaker()) @@ -165,12 +161,27 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, tracer *t Tracer: tracer, }, StatelessSelfValidation: witness, + NoPrefetch: true, } if snapshotter { options.SnapshotLimit = 1 options.SnapshotWait = true } chain, err := core.NewBlockChain(db, gspec, engine, options) + if err != nil { + return nil, err + } + return chain, nil +} + +func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, createAndVerifyBAL bool, tracer *tracing.Hooks, postCheck func(error, *core.BlockChain)) (result error) { + config, ok := Forks[t.json.Network] + if !ok { + return UnsupportedForkError{t.json.Network} + } + // import pre accounts & construct test genesis block & state root + + chain, err := t.createTestBlockChain(config, snapshotter, scheme, witness, createAndVerifyBAL, tracer) if err != nil { return err } @@ -204,7 +215,50 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, tracer *t } } } - return t.validateImportedHeaders(chain, validBlocks) + err = t.validateImportedHeaders(chain, validBlocks) + if err != nil { + return err + } + + if createAndVerifyBAL { + newChain, _ := t.createTestBlockChain(config, snapshotter, scheme, witness, createAndVerifyBAL, tracer) + defer newChain.Stop() + + var blocksWithBAL types.Blocks + for i := uint64(1); i <= chain.CurrentBlock().Number.Uint64(); i++ { + block := chain.GetBlockByNumber(i) + if chain.Config().IsAmsterdam(block.Number(), block.Time()) && block.AccessList() == nil { + return fmt.Errorf("block %d missing BAL", block.NumberU64()) + } + blocksWithBAL = append(blocksWithBAL, block) + } + + amt, err := newChain.InsertChain(blocksWithBAL) + if err != nil { + return err + } + _ = amt + newDB, err := newChain.State() + if err != nil { + return err + } + if err = t.validatePostState(newDB); err != nil { + return fmt.Errorf("post state validation failed: %v", err) + } + // Cross-check the snapshot-to-hash against the trie hash + if snapshotter { + if newChain.Snapshots() != nil { + if err := chain.Snapshots().Verify(chain.CurrentBlock().Root); err != nil { + return err + } + } + } + err = t.validateImportedHeaders(newChain, validBlocks) + if err != nil { + return err + } + } + return nil } // Network returns the network/fork name for this test. @@ -228,8 +282,8 @@ func (t *BlockTest) genesis(config *params.ChainConfig) *core.Genesis { BaseFee: t.json.Genesis.BaseFeePerGas, BlobGasUsed: t.json.Genesis.BlobGasUsed, ExcessBlobGas: t.json.Genesis.ExcessBlobGas, - SlotNumber: t.json.Genesis.SlotNumber, BlockAccessListHash: t.json.Genesis.BlockAccessListHash, + SlotNumber: t.json.Genesis.SlotNumber, } } @@ -259,6 +313,16 @@ func (t *BlockTest) insertBlocks(blockchain *core.BlockChain) ([]btBlock, error) return nil, fmt.Errorf("block RLP decoding failed when expected to succeed: %v", err) } } + + // check that if we encode the same block, it will result in the same RLP + var enc bytes.Buffer + if err := rlp.Encode(&enc, cb); err != nil { + return nil, err + } + expected := common.Hex2Bytes(strings.TrimLeft(b.Rlp, "0x")) + if !bytes.Equal(enc.Bytes(), expected) { + return nil, fmt.Errorf("mismatch. expected\n%s\ngot\n%x\n", expected, enc.Bytes()) + } // RLP decoding worked, try to insert into chain: blocks := types.Blocks{cb} i, err := blockchain.InsertChain(blocks) @@ -271,7 +335,7 @@ func (t *BlockTest) insertBlocks(blockchain *core.BlockChain) ([]btBlock, error) } if b.BlockHeader == nil { if data, err := json.MarshalIndent(cb.Header(), "", " "); err == nil { - fmt.Fprintf(os.Stdout, "block (index %d) insertion should have failed due to: %v:\n%v\n", + fmt.Fprintf(os.Stderr, "block (index %d) insertion should have failed due to: %v:\n%v\n", bi, b.ExpectException, string(data)) } return nil, fmt.Errorf("block (index %d) insertion should have failed due to: %v", diff --git a/tests/init_test.go b/tests/init_test.go index b933c9808c..2f2e4101f8 100644 --- a/tests/init_test.go +++ b/tests/init_test.go @@ -34,17 +34,18 @@ import ( ) var ( - baseDir = filepath.Join(".", "testdata") - blockTestDir = filepath.Join(baseDir, "BlockchainTests") - stateTestDir = filepath.Join(baseDir, "GeneralStateTests") - legacyStateTestDir = filepath.Join(baseDir, "LegacyTests", "Constantinople", "GeneralStateTests") - transactionTestDir = filepath.Join(baseDir, "TransactionTests") - rlpTestDir = filepath.Join(baseDir, "RLPTests") - difficultyTestDir = filepath.Join(baseDir, "BasicTests") - executionSpecBlockchainTestDir = filepath.Join(".", "spec-tests", "fixtures", "blockchain_tests") - executionSpecStateTestDir = filepath.Join(".", "spec-tests", "fixtures", "state_tests") - executionSpecTransactionTestDir = filepath.Join(".", "spec-tests", "fixtures", "transaction_tests") - benchmarksDir = filepath.Join(".", "evm-benchmarks", "benchmarks") + baseDir = filepath.Join(".", "testdata") + blockTestDir = filepath.Join(baseDir, "BlockchainTests") + stateTestDir = filepath.Join(baseDir, "GeneralStateTests") + legacyStateTestDir = filepath.Join(baseDir, "LegacyTests", "Constantinople", "GeneralStateTests") + transactionTestDir = filepath.Join(baseDir, "TransactionTests") + rlpTestDir = filepath.Join(baseDir, "RLPTests") + difficultyTestDir = filepath.Join(baseDir, "BasicTests") + executionSpecBlockchainTestDir = filepath.Join(".", "spec-tests", "fixtures", "blockchain_tests") + executionSpecStateTestDir = filepath.Join(".", "spec-tests", "fixtures", "state_tests") + executionSpecTransactionTestDir = filepath.Join(".", "spec-tests", "fixtures", "transaction_tests") + benchmarksDir = filepath.Join(".", "evm-benchmarks", "benchmarks") + executionSpecBALBlockchainTestDir = filepath.Join(".", "spec-tests-bal", "fixtures", "blockchain_tests") ) func readJSON(reader io.Reader, value interface{}) error {