From 831264e5ac9ef6d51357bb72f6d6b4c45c2fa105 Mon Sep 17 00:00:00 2001 From: BZO95 Date: Tue, 17 Mar 2026 17:28:26 +0800 Subject: [PATCH] cmd/geth, cmd/utils, core/rawdb: test state.scheme migration Add regression coverage for state.scheme default/reuse/conflict migration paths in geth genesis startup, align ParseStateScheme comments and CLI wording with path-as-default behavior. --- cmd/geth/genesis_test.go | 80 ++++++++++++++++++++++++++++++++++++ cmd/utils/flags.go | 2 +- core/rawdb/accessors_trie.go | 2 +- 3 files changed, 82 insertions(+), 2 deletions(-) diff --git a/cmd/geth/genesis_test.go b/cmd/geth/genesis_test.go index f5d21cc00b..40530f0a1b 100644 --- a/cmd/geth/genesis_test.go +++ b/cmd/geth/genesis_test.go @@ -196,3 +196,83 @@ func TestCustomBackend(t *testing.T) { } } } + +// TestStateScheme that the state scheme selection and compatibility checks work +// properly for new and existing datadirs. +func TestStateScheme(t *testing.T) { + t.Parallel() + genesis := `{ + "alloc" : { + "0x0000000000000000000000000000000000000001": { + "balance": "0x1" + } + }, + "coinbase" : "0x0000000000000000000000000000000000000000", + "difficulty" : "0x20000", + "extraData" : "", + "gasLimit" : "0x2fefd8", + "nonce" : "0x0000000000001338", + "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "timestamp" : "0x00", + "config": { + "terminalTotalDifficulty": 0 + } + }` + type schemeTest struct { + initArgs []string + execArgs []string + execExpect string + } + testfunc := func(t *testing.T, tt schemeTest) error { + // Create a temporary data directory to use and inspect later + datadir := t.TempDir() + + // Initialize the data directory with the custom genesis block + json := filepath.Join(datadir, "genesis.json") + if err := os.WriteFile(json, []byte(genesis), 0600); err != nil { + return fmt.Errorf("failed to write genesis file: %v", err) + } + { // Init + args := append(tt.initArgs, "--datadir", datadir, "init", json) + geth := runGeth(t, args...) + geth.ExpectExit() + } + { // Exec + query + args := append(tt.execArgs, "--networkid", "1337", "--syncmode=full", "--cache", "16", + "--datadir", datadir, "--maxpeers", "0", "--port", "0", "--authrpc.port", "0", + "--nodiscover", "--nat", "none", "--ipcdisable", + "--exec", "eth.getBlock(0).nonce", "console") + geth := runGeth(t, args...) + geth.ExpectRegexp(tt.execExpect) + geth.ExpectExit() + } + return nil + } + for i, tt := range []schemeTest{ + { // New datadir defaults to path scheme. + execExpect: "0x0000000000001338", + }, + { // Explicit path first, then autodiscover. + initArgs: []string{"--state.scheme", "path"}, + execExpect: "0x0000000000001338", + }, + { // Explicit hash first, then autodiscover. + initArgs: []string{"--state.scheme", "hash"}, + execExpect: "0x0000000000001338", + }, + { // Can't start hash on top of existing path database. + execArgs: []string{"--state.scheme", "hash"}, + execExpect: `Fatal: Failed to register the Ethereum service: incompatible state scheme, stored: path, provided: hash`, + }, + { // Can't start path on top of existing hash database. + initArgs: []string{"--state.scheme", "hash"}, + execArgs: []string{"--state.scheme", "path"}, + execExpect: `Fatal: Failed to register the Ethereum service: incompatible state scheme, stored: hash, provided: path`, + }, + } { + if err := testfunc(t, tt); err != nil { + t.Fatalf("test %d-state-scheme: %v", i, err) + } + } +} diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 792e0e55ab..b684ee0cf6 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -284,7 +284,7 @@ var ( } StateSchemeFlag = &cli.StringFlag{ Name: "state.scheme", - Usage: "Scheme to use for storing ethereum state ('hash' or 'path')", + Usage: "Scheme to use for storing ethereum state ('hash' or 'path', defaults to 'path' for new datadirs)", Category: flags.StateCategory, } StateSizeTrackingFlag = &cli.BoolFlag{ diff --git a/core/rawdb/accessors_trie.go b/core/rawdb/accessors_trie.go index 7d8b266c15..0939e0fbd5 100644 --- a/core/rawdb/accessors_trie.go +++ b/core/rawdb/accessors_trie.go @@ -267,7 +267,7 @@ func ReadStateScheme(db ethdb.Database) string { // compatible with persistent state scheme. func ParseStateScheme(provided string, disk ethdb.Database) (string, error) { // If state scheme is not specified, use the scheme consistent - // with persistent state, or fallback to hash mode if database + // with persistent state, or fallback to path mode if database // is empty. stored := ReadStateScheme(disk) if provided == "" {