From 2196aa11588916629c901ded249eaa7079800639 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Tue, 22 Apr 2025 18:17:18 +0200 Subject: [PATCH] cmd/evm/internal/t8ntool: support for verkle-at-genesis testnets Co-authored-by: Ignacio Hagopian --- .github/workflows/stable-spec-tests.yml | 77 +++++++++++++++++++++ cmd/evm/blockrunner.go | 2 +- cmd/evm/internal/t8ntool/execution.go | 90 ++++++++++++++++++++----- cmd/evm/internal/t8ntool/flags.go | 20 ++++++ cmd/evm/internal/t8ntool/gen_stenv.go | 6 ++ cmd/evm/internal/t8ntool/transition.go | 48 +++++++++---- cmd/evm/main.go | 3 + cmd/geth/snapshot.go | 80 ++++++++++++++++++++++ core/state/dump.go | 12 ++++ tests/block_test_util.go | 7 +- tests/init.go | 39 +++++++++++ 11 files changed, 349 insertions(+), 35 deletions(-) create mode 100644 .github/workflows/stable-spec-tests.yml diff --git a/.github/workflows/stable-spec-tests.yml b/.github/workflows/stable-spec-tests.yml new file mode 100644 index 0000000000..3c5477150e --- /dev/null +++ b/.github/workflows/stable-spec-tests.yml @@ -0,0 +1,77 @@ +name: Execution Spec Tests - Consume (stable) + +on: + push: + branches: [master] + pull_request: + branches: [master, kaustinen-with-shapella] + workflow_dispatch: + +env: + FIXTURES_TAG: "verkle@v0.0.9-alpha-1" + +jobs: + setup: + runs-on: ubuntu-latest + steps: + - name: Checkout go-ethereum + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.12.4" + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: 1.22.4 + + - name: Build geth evm + run: | + go build -v ./cmd/evm + mkdir -p ${{ github.workspace }}/bin + mv evm ${{ github.workspace }}/bin/evm + chmod +x ${{ github.workspace }}/bin/evm + + - name: Archive built evm + uses: actions/upload-artifact@v4 + with: + name: evm + path: ${{ github.workspace }}/bin/evm + + consume: + runs-on: ubuntu-latest + needs: setup + strategy: + matrix: + filename: + [ + fixtures_verkle-genesis.tar.gz, + ] + steps: + - name: Download geth evm + uses: actions/download-artifact@v4 + with: + name: evm + path: ./bin + + - name: Make evm binary executable and add to PATH + run: | + chmod +x ./bin/evm + echo "${{ github.workspace }}/bin" >> $GITHUB_PATH + + - name: Download fixtures + uses: robinraju/release-downloader@v1 + with: + repository: "ethereum/execution-spec-tests" + tag: "${{ env.FIXTURES_TAG }}" + fileName: "${{ matrix.filename }}" + extract: true + - name: Clone execution-spec-tests and consume tests + run: | + curl -LsSf https://astral.sh/uv/install.sh | sh + git clone https://github.com/ethereum/execution-spec-tests -b ${{ env.FIXTURES_TAG }} --depth 1 + cd execution-spec-tests + uv run consume direct --evm-bin="${{ github.workspace }}/bin/evm" --input=../fixtures -n auto + shell: bash diff --git a/cmd/evm/blockrunner.go b/cmd/evm/blockrunner.go index 31d1ba5ba1..f6538b1356 100644 --- a/cmd/evm/blockrunner.go +++ b/cmd/evm/blockrunner.go @@ -89,7 +89,7 @@ func runBlockTest(ctx *cli.Context, fname string) ([]testResult, error) { continue } result := &testResult{Name: name, Pass: true} - if err := tests[name].Run(false, rawdb.HashScheme, ctx.Bool(WitnessCrossCheckFlag.Name), tracer, func(res error, chain *core.BlockChain) { + if err := tests[name].Run(false, rawdb.PathScheme, ctx.Bool(WitnessCrossCheckFlag.Name), tracer, func(res error, chain *core.BlockChain) { if ctx.Bool(DumpFlag.Name) { if s, _ := chain.State(); s != nil { result.State = dump(s) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 7de1eb6949..35993759e3 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -39,13 +39,15 @@ import ( "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/triedb" + "github.com/ethereum/go-verkle" "github.com/holiman/uint256" "golang.org/x/crypto/sha3" ) type Prestate struct { - Env stEnv `json:"env"` - Pre types.GenesisAlloc `json:"pre"` + Env stEnv `json:"env"` + Pre types.GenesisAlloc `json:"pre"` + VKT map[common.Hash]hexutil.Bytes `json:"vkt,omitempty"` } //go:generate go run github.com/fjl/gencodec -type ExecutionResult -field-override executionResultMarshaling -out gen_execresult.go @@ -68,6 +70,11 @@ type ExecutionResult struct { CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"` RequestsHash *common.Hash `json:"requestsHash,omitempty"` Requests [][]byte `json:"requests"` + + // Verkle witness + VerkleProof *verkle.VerkleProof `json:"verkleProof,omitempty"` + StateDiff verkle.StateDiff `json:"stateDiff,omitempty"` + ParentRoot common.Hash `json:"parentStateRoot,omitempty"` } type executionResultMarshaling struct { @@ -101,6 +108,7 @@ type stEnv struct { ParentExcessBlobGas *uint64 `json:"parentExcessBlobGas,omitempty"` ParentBlobGasUsed *uint64 `json:"parentBlobGasUsed,omitempty"` ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"` + ParentHash *common.Hash `json:"parentHash,omitempty"` } type stEnvMarshaling struct { @@ -143,16 +151,17 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, return h } var ( - statedb = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre) - signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp) - gaspool = new(core.GasPool) - blockHash = common.Hash{0x13, 0x37} - rejectedTxs []*rejectedTx - includedTxs types.Transactions - gasUsed = uint64(0) - blobGasUsed = uint64(0) - receipts = make(types.Receipts, 0) - txIndex = 0 + parentStateRoot, statedb = MakePreState(rawdb.NewMemoryDatabase(), chainConfig, pre, chainConfig.IsVerkle(big.NewInt(int64(pre.Env.Number)), pre.Env.Timestamp)) + signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp) + gaspool = new(core.GasPool) + blockHash = common.Hash{0x13, 0x37} + rejectedTxs []*rejectedTx + includedTxs types.Transactions + gasUsed = uint64(0) + blobGasUsed = uint64(0) + receipts = make(types.Receipts, 0) + txIndex = 0 + vtrpre *trie.VerkleTrie ) gaspool.AddGas(pre.Env.GasLimit) vmContext := vm.BlockContext{ @@ -165,6 +174,14 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, GasLimit: pre.Env.GasLimit, GetHash: getHash, } + + // We save the current state of the Verkle Tree before applying the transactions. + // Note that if the Verkle fork isn't active, this will be a noop. + switch tr := statedb.GetTrie().(type) { + case *trie.VerkleTrie: + vtrpre = tr.Copy() + } + // If currentBaseFee is defined, add it to the vmContext. if pre.Env.BaseFee != nil { vmContext.BaseFee = new(big.Int).Set(pre.Env.BaseFee) @@ -251,6 +268,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } } statedb.SetTxContext(tx.Hash(), txIndex) + evm.AccessEvents = state.NewAccessEvents(evm.StateDB.PointCache()) var ( snapshot = statedb.Snapshot() prevGas = gaspool.Gas() @@ -315,7 +333,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, evm.Config.Tracer.OnTxEnd(receipt, nil) } } - + statedb.AccessEvents().Merge(evm.AccessEvents) txIndex++ } statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber)) @@ -348,6 +366,8 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, // Amount is in gwei, turn into wei amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei)) statedb.AddBalance(w.Address, uint256.MustFromBig(amount), tracing.BalanceIncreaseWithdrawal) + + statedb.AccessEvents().AddAccount(w.Address, true) } // Gather the execution-layer triggered requests. @@ -373,6 +393,25 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, if err != nil { return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not commit state: %v", err)) } + // Add the witness to the execution result + var vktProof *verkle.VerkleProof + var vktStateDiff verkle.StateDiff + if chainConfig.IsVerkle(big.NewInt(int64(pre.Env.Number)), pre.Env.Timestamp) { + keys := statedb.AccessEvents().Keys() + if len(keys) > 0 && vtrpre != nil { + var proofTrie *trie.VerkleTrie + switch tr := statedb.GetTrie().(type) { + case *trie.VerkleTrie: + proofTrie = tr + default: + return nil, nil, nil, fmt.Errorf("invalid tree type in proof generation: %v", tr) + } + vktProof, vktStateDiff, err = vtrpre.Proof(proofTrie, keys) + if err != nil { + return nil, nil, nil, fmt.Errorf("error generating verkle proof for block %d: %w", pre.Env.Number, err) + } + } + } execRs := &ExecutionResult{ StateRoot: root, TxRoot: types.DeriveSha(includedTxs, trie.NewStackTrie(nil)), @@ -384,6 +423,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, Difficulty: (*math.HexOrDecimal256)(vmContext.Difficulty), GasUsed: (math.HexOrDecimal64)(gasUsed), BaseFee: (*math.HexOrDecimal256)(vmContext.BaseFee), + VerkleProof: vktProof, + StateDiff: vktStateDiff, + ParentRoot: parentStateRoot, } if pre.Env.Withdrawals != nil { h := types.DeriveSha(types.Withdrawals(pre.Env.Withdrawals), trie.NewStackTrie(nil)) @@ -414,11 +456,13 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, return statedb, execRs, body, nil } -func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB { +// XXX peut-etre pas besoin de changer les parametres tant qu'on n'a pas la conversion +func MakePreState(db ethdb.Database, chainConfig *params.ChainConfig, pre *Prestate, verkle bool) (common.Hash, *state.StateDB) { tdb := triedb.NewDatabase(db, &triedb.Config{Preimages: true}) sdb := state.NewDatabase(tdb, nil) + statedb, _ := state.New(types.EmptyRootHash, sdb) - for addr, a := range accounts { + for addr, a := range pre.Pre { statedb.SetCode(addr, a.Code) statedb.SetNonce(addr, a.Nonce, tracing.NonceChangeGenesis) statedb.SetBalance(addr, uint256.MustFromBig(a.Balance), tracing.BalanceIncreaseGenesisBalance) @@ -427,9 +471,19 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB } } // Commit and re-open to start with a clean state. - root, _ := statedb.Commit(0, false, false) - statedb, _ = state.New(root, sdb) - return statedb + mptRoot, err := statedb.Commit(0, false, false) + if err != nil { + panic(err) + } + parentRoot := mptRoot + // If verkle mode started, establish the conversion + if verkle { + if _, ok := statedb.GetTrie().(*trie.VerkleTrie); ok { + return parentRoot, statedb + } + } + statedb, _ = state.New(mptRoot, sdb) + return parentRoot, statedb } func rlpHash(x interface{}) (h common.Hash) { diff --git a/cmd/evm/internal/t8ntool/flags.go b/cmd/evm/internal/t8ntool/flags.go index f2606c86d1..52f7b05a20 100644 --- a/cmd/evm/internal/t8ntool/flags.go +++ b/cmd/evm/internal/t8ntool/flags.go @@ -88,6 +88,22 @@ var ( "\t - into the file ", Value: "block.json", } + OutputVKTFlag = &cli.StringFlag{ + Name: "output.vkt", + Usage: "Determines where to put the `VKT` of the post-state.\n" + + "\t`stdout` - into the stdout output\n" + + "\t`stderr` - into the stderr output\n" + + "\t - into the file ", + Value: "vkt.json", + } + OutputWitnessFlag = &cli.StringFlag{ + Name: "output.witness", + Usage: "Determines where to put the `witness` of the post-state.\n" + + "\t`stdout` - into the stdout output\n" + + "\t`stderr` - into the stderr output\n" + + "\t - into the file ", + Value: "witness.json", + } InputAllocFlag = &cli.StringFlag{ Name: "input.alloc", Usage: "`stdin` or file name of where to find the prestate alloc to use.", @@ -123,6 +139,10 @@ var ( Usage: "`stdin` or file name of where to find the transactions list in RLP form.", Value: "txs.rlp", } + InputVKTFlag = &cli.StringFlag{ + Name: "input.vkt", + Usage: "`stdin` or file name of where to find the prestate VKT.", + } SealCliqueFlag = &cli.StringFlag{ Name: "seal.clique", Usage: "Seal block with Clique. `stdin` or file name of where to find the Clique sealing data.", diff --git a/cmd/evm/internal/t8ntool/gen_stenv.go b/cmd/evm/internal/t8ntool/gen_stenv.go index d47db4a876..0c296395e2 100644 --- a/cmd/evm/internal/t8ntool/gen_stenv.go +++ b/cmd/evm/internal/t8ntool/gen_stenv.go @@ -37,6 +37,7 @@ func (s stEnv) MarshalJSON() ([]byte, error) { ParentExcessBlobGas *math.HexOrDecimal64 `json:"parentExcessBlobGas,omitempty"` ParentBlobGasUsed *math.HexOrDecimal64 `json:"parentBlobGasUsed,omitempty"` ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"` + ParentHash *common.Hash `json:"parentHash,omitempty"` } var enc stEnv enc.Coinbase = common.UnprefixedAddress(s.Coinbase) @@ -59,6 +60,7 @@ func (s stEnv) MarshalJSON() ([]byte, error) { enc.ParentExcessBlobGas = (*math.HexOrDecimal64)(s.ParentExcessBlobGas) enc.ParentBlobGasUsed = (*math.HexOrDecimal64)(s.ParentBlobGasUsed) enc.ParentBeaconBlockRoot = s.ParentBeaconBlockRoot + enc.ParentHash = s.ParentHash return json.Marshal(&enc) } @@ -85,6 +87,7 @@ func (s *stEnv) UnmarshalJSON(input []byte) error { ParentExcessBlobGas *math.HexOrDecimal64 `json:"parentExcessBlobGas,omitempty"` ParentBlobGasUsed *math.HexOrDecimal64 `json:"parentBlobGasUsed,omitempty"` ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"` + ParentHash *common.Hash `json:"parentHash,omitempty"` } var dec stEnv if err := json.Unmarshal(input, &dec); err != nil { @@ -154,5 +157,8 @@ func (s *stEnv) UnmarshalJSON(input []byte) error { if dec.ParentBeaconBlockRoot != nil { s.ParentBeaconBlockRoot = dec.ParentBeaconBlockRoot } + if dec.ParentHash != nil { + s.ParentHash = dec.ParentHash + } return nil } diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index e946ccddd5..6036f868b2 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -75,10 +75,11 @@ var ( ) type input struct { - Alloc types.GenesisAlloc `json:"alloc,omitempty"` - Env *stEnv `json:"env,omitempty"` - Txs []*txWithKey `json:"txs,omitempty"` - TxRlp string `json:"txsRlp,omitempty"` + Alloc types.GenesisAlloc `json:"alloc,omitempty"` + Env *stEnv `json:"env,omitempty"` + VKT map[common.Hash]hexutil.Bytes `json:"vkt,omitempty"` + Txs []*txWithKey `json:"txs,omitempty"` + TxRlp string `json:"txsRlp,omitempty"` } func Transition(ctx *cli.Context) error { @@ -90,16 +91,16 @@ func Transition(ctx *cli.Context) error { // stdin input or in files. // Check if anything needs to be read from stdin var ( - prestate Prestate - txIt txIterator // txs to apply - allocStr = ctx.String(InputAllocFlag.Name) - + prestate Prestate + txIt txIterator // txs to apply + allocStr = ctx.String(InputAllocFlag.Name) + vktStr = ctx.String(InputVKTFlag.Name) envStr = ctx.String(InputEnvFlag.Name) txStr = ctx.String(InputTxsFlag.Name) inputData = &input{} ) // Figure out the prestate alloc - if allocStr == stdinSelector || envStr == stdinSelector || txStr == stdinSelector { + if allocStr == stdinSelector || vktStr == stdinSelector || envStr == stdinSelector || txStr == stdinSelector { decoder := json.NewDecoder(os.Stdin) if err := decoder.Decode(inputData); err != nil { return NewError(ErrorJson, fmt.Errorf("failed unmarshalling stdin: %v", err)) @@ -110,8 +111,18 @@ func Transition(ctx *cli.Context) error { return err } } + if vktStr != stdinSelector { + if err := readFile(vktStr, "VKT", &inputData.Alloc); err != nil { + return err + } + } prestate.Pre = inputData.Alloc - + if vktStr != stdinSelector && vktStr != "" { + if err := readFile(vktStr, "VKT", &inputData.VKT); err != nil { + return err + } + } + prestate.VKT = inputData.VKT // Set the block environment if envStr != stdinSelector { var env stEnv @@ -183,8 +194,14 @@ func Transition(ctx *cli.Context) error { } // Dump the execution result collector := make(Alloc) - s.DumpToCollector(collector, nil) - return dispatchOutput(ctx, baseDir, result, collector, body) + var vktleaves map[common.Hash]hexutil.Bytes + if !chainConfig.IsVerkle(big.NewInt(int64(prestate.Env.Number)), prestate.Env.Timestamp) { + s.DumpToCollector(collector, nil) + } else { + vktleaves = make(map[common.Hash]hexutil.Bytes) + s.DumpVKTLeaves(vktleaves) + } + return dispatchOutput(ctx, baseDir, result, collector, body, vktleaves) } func applyLondonChecks(env *stEnv, chainConfig *params.ChainConfig) error { @@ -306,7 +323,7 @@ func saveFile(baseDir, filename string, data interface{}) error { // dispatchOutput writes the output data to either stderr or stdout, or to the specified // files -func dispatchOutput(ctx *cli.Context, baseDir string, result *ExecutionResult, alloc Alloc, body hexutil.Bytes) error { +func dispatchOutput(ctx *cli.Context, baseDir string, result *ExecutionResult, alloc Alloc, body hexutil.Bytes, vkt map[common.Hash]hexutil.Bytes) error { stdOutObject := make(map[string]interface{}) stdErrObject := make(map[string]interface{}) dispatch := func(baseDir, fName, name string, obj interface{}) error { @@ -333,6 +350,11 @@ func dispatchOutput(ctx *cli.Context, baseDir string, result *ExecutionResult, a if err := dispatch(baseDir, ctx.String(OutputBodyFlag.Name), "body", body); err != nil { return err } + if vkt != nil { + if err := dispatch(baseDir, ctx.String(OutputVKTFlag.Name), "vkt", vkt); err != nil { + return err + } + } if len(stdOutObject) > 0 { b, err := json.MarshalIndent(stdOutObject, "", " ") if err != nil { diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 61e46aa50e..7f405a7df1 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -146,10 +146,13 @@ var ( t8ntool.TraceEnableCallFramesFlag, t8ntool.OutputBasedir, t8ntool.OutputAllocFlag, + t8ntool.OutputVKTFlag, + t8ntool.OutputWitnessFlag, t8ntool.OutputResultFlag, t8ntool.OutputBodyFlag, t8ntool.InputAllocFlag, t8ntool.InputEnvFlag, + t8ntool.InputVKTFlag, t8ntool.InputTxsFlag, t8ntool.ForknameFlag, t8ntool.ChainIDFlag, diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index f0be52a0df..cfe0a5e689 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -98,6 +98,17 @@ data, and verifies that all snapshot storage data has a corresponding account. Description: ` geth snapshot inspect-account
checks all snapshot layers and prints out information about the specified address. +`, + }, + { + Name: "inspect-garys-account", + Usage: "Check all snapshot layers for the specific account", + ArgsUsage: "
", + Action: checkGarysAccounts, + Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags), + Description: ` +geth snapshot inspect-account
checks all snapshot layers and prints out +information about the specified address. `, }, { @@ -692,3 +703,72 @@ func checkAccount(ctx *cli.Context) error { log.Info("Checked the snapshot journalled storage", "time", common.PrettyDuration(time.Since(start))) return nil } + +func checkGarysAccounts(ctx *cli.Context) error { + stack, _ := makeConfigNode(ctx) + defer stack.Close() + + chaindb := utils.MakeChainDatabase(ctx, stack, true) + defer chaindb.Close() + + triedb := utils.MakeTrieDatabase(ctx, chaindb, false, true, false) + defer triedb.Close() + + var root common.Hash + if ctx.NArg() == 1 { + rootBytes := common.FromHex(ctx.Args().Get(1)) + if len(rootBytes) != common.HashLength { + return fmt.Errorf("invalid hash: %s", ctx.Args().Get(1)) + } + root = common.BytesToHash(rootBytes) + } else { + headBlock := rawdb.ReadHeadBlock(chaindb) + if headBlock == nil { + log.Error("Failed to load head block") + return errors.New("no head block") + } + root = headBlock.Root() + } + snapConfig := snapshot.Config{ + CacheSize: 256, + Recovery: false, + NoBuild: true, + AsyncBuild: false, + } + snaptree, err := snapshot.New(snapConfig, chaindb, triedb, root) + if err != nil { + return err + } + accIt, err := snaptree.AccountIterator(root, common.Hash{}) + if err != nil { + log.Error("Failed to create account iterator", "error", err) + return err + } + defer accIt.Release() + + // Open the file in append mode, create it if it doesn't exist + file, err := os.OpenFile("weird_contracts.csv", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return err + } + defer file.Close() + file.WriteString("account hash,nonce,code hash,root hash,balance\n") + + var weird int + for accIt.Next() { + acc, err := types.FullAccount(accIt.Account()) + if err != nil { + log.Error("Failed to get full account", "error", err) + return err + } + + if acc.Nonce == 0 && bytes.Equal(acc.CodeHash, types.EmptyCodeHash[:]) && acc.Root != types.EmptyRootHash { + weird++ + if _, err = file.WriteString(fmt.Sprintf("%x,%d,%x,%x,%s\n", accIt.Hash(), acc.Nonce, acc.CodeHash, acc.Root, acc.Balance.String())); err != nil { + return err + } + } + } + log.Info("sweep completed", "count", weird) + return nil +} diff --git a/core/state/dump.go b/core/state/dump.go index c9aad4f8e2..3005c0810b 100644 --- a/core/state/dump.go +++ b/core/state/dump.go @@ -208,6 +208,18 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey [] return nextKey } +func (s *StateDB) DumpVKTLeaves(collector map[common.Hash]hexutil.Bytes) { + it, err := s.trie.(*trie.VerkleTrie).NodeIterator(nil) + if err != nil { + panic(err) + } + for it.Next(true) { + if it.Leaf() { + collector[common.BytesToHash(it.LeafKey())] = it.LeafBlob() + } + } +} + // RawDump returns the state. If the processing is aborted e.g. due to options // reaching Max, the `Next` key is set on the returned Dump. func (s *StateDB) RawDump(opts *DumpConfig) Dump { diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 77bf945e40..e42e69ad72 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -117,19 +117,20 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, tracer *t return UnsupportedForkError{t.json.Network} } // import pre accounts & construct test genesis block & state root + // Commit genesis state + gspec := t.genesis(config) var ( db = rawdb.NewMemoryDatabase() tconf = &triedb.Config{ Preimages: true, + IsVerkle: gspec.Config.VerkleTime != nil && *gspec.Config.VerkleTime <= gspec.Timestamp, } ) - if scheme == rawdb.PathScheme { + if scheme == rawdb.PathScheme || tconf.IsVerkle { tconf.PathDB = pathdb.Defaults } else { tconf.HashDB = hashdb.Defaults } - // Commit genesis state - gspec := t.genesis(config) // if ttd is not specified, set an arbitrary huge value if gspec.Config.TerminalTotalDifficulty == nil { diff --git a/tests/init.go b/tests/init.go index a8bc424fa2..2db7ca1b75 100644 --- a/tests/init.go +++ b/tests/init.go @@ -464,6 +464,45 @@ var Forks = map[string]*params.ChainConfig{ Osaka: params.DefaultOsakaBlobConfig, }, }, + + "Verkle": { + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ArrowGlacierBlock: big.NewInt(0), + MergeNetsplitBlock: big.NewInt(0), + TerminalTotalDifficulty: big.NewInt(0), + ShanghaiTime: u64(0), + VerkleTime: u64(0), + }, + "ShanghaiToVerkleAtTime32": { + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ArrowGlacierBlock: big.NewInt(0), + MergeNetsplitBlock: big.NewInt(0), + TerminalTotalDifficulty: big.NewInt(0), + ShanghaiTime: u64(0), + VerkleTime: u64(32), + }, } // AvailableForks returns the set of defined fork names