diff --git a/cmd/workload/README.md b/cmd/workload/README.md
index 1b84dd05db9..ee1d6acbc96 100644
--- a/cmd/workload/README.md
+++ b/cmd/workload/README.md
@@ -34,4 +34,5 @@ the following commands (in this directory) against a synced mainnet node:
> go run . filtergen --queries queries/filter_queries_mainnet.json http://host:8545
> go run . historygen --history-tests queries/history_mainnet.json http://host:8545
> go run . tracegen --trace-tests queries/trace_mainnet.json --trace-start 4000000 --trace-end 4000100 http://host:8545
+> go run . proofgen --proof-tests queries/proof_mainnet.json --proof-states 3000 http://host:8545
```
diff --git a/cmd/workload/main.go b/cmd/workload/main.go
index 32618d6a79b..0b890594648 100644
--- a/cmd/workload/main.go
+++ b/cmd/workload/main.go
@@ -48,6 +48,7 @@ func init() {
historyGenerateCommand,
filterGenerateCommand,
traceGenerateCommand,
+ proofGenerateCommand,
filterPerfCommand,
}
}
diff --git a/cmd/workload/prooftest.go b/cmd/workload/prooftest.go
new file mode 100644
index 00000000000..dcc063d30e5
--- /dev/null
+++ b/cmd/workload/prooftest.go
@@ -0,0 +1,105 @@
+// 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 .
+
+package main
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "math/big"
+ "os"
+ "strings"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/internal/utesting"
+ "github.com/urfave/cli/v2"
+)
+
+// proofTest is the content of a state-proof test.
+type proofTest struct {
+ BlockNumbers []uint64 `json:"blockNumbers"`
+ Addresses [][]common.Address `json:"addresses"`
+ StorageKeys [][][]string `json:"storageKeys"`
+ Results [][]common.Hash `json:"results"`
+}
+
+type proofTestSuite struct {
+ cfg testConfig
+ tests proofTest
+ invalidDir string
+}
+
+func newProofTestSuite(cfg testConfig, ctx *cli.Context) *proofTestSuite {
+ s := &proofTestSuite{
+ cfg: cfg,
+ invalidDir: ctx.String(proofTestInvalidOutputFlag.Name),
+ }
+ if err := s.loadTests(); err != nil {
+ exit(err)
+ }
+ return s
+}
+
+func (s *proofTestSuite) loadTests() error {
+ file, err := s.cfg.fsys.Open(s.cfg.proofTestFile)
+ if err != nil {
+ // If not found in embedded FS, try to load it from disk
+ if !os.IsNotExist(err) {
+ return err
+ }
+ file, err = os.OpenFile(s.cfg.proofTestFile, os.O_RDONLY, 0666)
+ if err != nil {
+ return fmt.Errorf("can't open proofTestFile: %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.proofTestFile, err)
+ }
+ if len(s.tests.BlockNumbers) == 0 {
+ return fmt.Errorf("proofTestFile %s has no test data", s.cfg.proofTestFile)
+ }
+ return nil
+}
+
+func (s *proofTestSuite) allTests() []workloadTest {
+ return []workloadTest{
+ newArchiveWorkloadTest("Proof/GetProof", s.getProof),
+ }
+}
+
+func (s *proofTestSuite) getProof(t *utesting.T) {
+ ctx := context.Background()
+ for i, blockNumber := range s.tests.BlockNumbers {
+ for j := 0; j < len(s.tests.Addresses[i]); j++ {
+ res, err := s.cfg.client.Geth.GetProof(ctx, s.tests.Addresses[i][j], s.tests.StorageKeys[i][j], big.NewInt(int64(blockNumber)))
+ if err != nil {
+ t.Errorf("State proving fails, blockNumber: %d, address: %x, keys: %v, err: %v\n", blockNumber, s.tests.Addresses[i][j], strings.Join(s.tests.StorageKeys[i][j], " "), err)
+ continue
+ }
+ blob, err := json.Marshal(res)
+ if err != nil {
+ t.Fatalf("State proving fails: error %v", err)
+ continue
+ }
+ if crypto.Keccak256Hash(blob) != s.tests.Results[i][j] {
+ t.Errorf("State proof mismatch, %d, number: %d, address: %x, keys: %v: invalid result", i, blockNumber, s.tests.Addresses[i][j], strings.Join(s.tests.StorageKeys[i][j], " "))
+ }
+ }
+ }
+}
diff --git a/cmd/workload/prooftestgen.go b/cmd/workload/prooftestgen.go
new file mode 100644
index 00000000000..a22da4df859
--- /dev/null
+++ b/cmd/workload/prooftestgen.go
@@ -0,0 +1,333 @@
+// 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
+
+package main
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "math/big"
+ "math/rand"
+ "os"
+ "path/filepath"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/eth/tracers"
+ "github.com/ethereum/go-ethereum/eth/tracers/native"
+ "github.com/ethereum/go-ethereum/internal/flags"
+ "github.com/ethereum/go-ethereum/internal/testrand"
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/urfave/cli/v2"
+)
+
+var (
+ proofGenerateCommand = &cli.Command{
+ Name: "proofgen",
+ Usage: "Generates tests for state proof verification",
+ ArgsUsage: "",
+ Action: generateProofTests,
+ Flags: []cli.Flag{
+ proofTestFileFlag,
+ proofTestResultOutputFlag,
+ proofTestStatesFlag,
+ },
+ }
+
+ proofTestFileFlag = &cli.StringFlag{
+ Name: "proof-tests",
+ Usage: "JSON file containing proof test queries",
+ Value: "proof_tests.json",
+ Category: flags.TestingCategory,
+ }
+ proofTestResultOutputFlag = &cli.StringFlag{
+ Name: "proof-output",
+ Usage: "Folder containing detailed trace output files",
+ Value: "",
+ Category: flags.TestingCategory,
+ }
+ proofTestStatesFlag = &cli.Int64Flag{
+ Name: "proof-states",
+ Usage: "Number of states to generate proof against",
+ Value: 10000,
+ Category: flags.TestingCategory,
+ }
+ proofTestInvalidOutputFlag = &cli.StringFlag{
+ Name: "proof-invalid",
+ Usage: "Folder containing the mismatched state proof output files",
+ Value: "",
+ Category: flags.TestingCategory,
+ }
+)
+
+type proofGenerator func(cli *client, head uint64, number int) ([]uint64, [][]common.Address, [][][]string, error)
+
+func genAccountProof(cli *client, head uint64, number int) ([]uint64, [][]common.Address, [][][]string, error) {
+ var (
+ blockNumbers []uint64
+ accountAddresses [][]common.Address
+ storageKeys [][][]string
+ nAccounts int
+ ctx = context.Background()
+ start = time.Now()
+ )
+ chainID, err := cli.Eth.ChainID(ctx)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ signer := types.LatestSignerForChainID(chainID)
+
+ for {
+ if nAccounts >= number {
+ break
+ }
+ blockNumber := rand.Intn(int(head)) + 1
+
+ block, err := cli.Eth.BlockByNumber(context.Background(), big.NewInt(int64(blockNumber)))
+ if err != nil {
+ continue
+ }
+ var (
+ addresses []common.Address
+ keys [][]string
+ gather = func(address common.Address) {
+ addresses = append(addresses, address)
+ keys = append(keys, nil)
+ nAccounts++
+ }
+ )
+ for _, tx := range block.Transactions() {
+ if nAccounts >= number {
+ break
+ }
+ sender, err := signer.Sender(tx)
+ if err != nil {
+ log.Error("Failed to resolve the sender address", "hash", tx.Hash(), "err", err)
+ continue
+ }
+ gather(sender)
+
+ if tx.To() != nil {
+ gather(*tx.To())
+ }
+ }
+ blockNumbers = append(blockNumbers, uint64(blockNumber))
+ accountAddresses = append(accountAddresses, addresses)
+ storageKeys = append(storageKeys, keys)
+ }
+ log.Info("Generated tests for account proof", "blocks", len(blockNumbers), "accounts", nAccounts, "elapsed", common.PrettyDuration(time.Since(start)))
+ return blockNumbers, accountAddresses, storageKeys, nil
+}
+
+func genNonExistentAccountProof(cli *client, head uint64, number int) ([]uint64, [][]common.Address, [][][]string, error) {
+ var (
+ blockNumbers []uint64
+ accountAddresses [][]common.Address
+ storageKeys [][][]string
+ total int
+ )
+ for i := 0; i < number/5; i++ {
+ var (
+ addresses []common.Address
+ keys [][]string
+ blockNumber = uint64(rand.Intn(int(head))) + 1
+ )
+ for j := 0; j < 5; j++ {
+ addresses = append(addresses, testrand.Address())
+ keys = append(keys, nil)
+ }
+ total += len(addresses)
+ blockNumbers = append(blockNumbers, blockNumber)
+ accountAddresses = append(accountAddresses, addresses)
+ storageKeys = append(storageKeys, keys)
+ }
+ log.Info("Generated tests for non-existing account proof", "blocks", len(blockNumbers), "accounts", total)
+ return blockNumbers, accountAddresses, storageKeys, nil
+}
+
+func genStorageProof(cli *client, head uint64, number int) ([]uint64, [][]common.Address, [][][]string, error) {
+ var (
+ blockNumbers []uint64
+ accountAddresses [][]common.Address
+ storageKeys [][][]string
+
+ nAccounts int
+ nStorages int
+ start = time.Now()
+ )
+ for {
+ if nAccounts+nStorages >= number {
+ break
+ }
+ blockNumber := rand.Intn(int(head)) + 1
+
+ block, err := cli.Eth.BlockByNumber(context.Background(), big.NewInt(int64(blockNumber)))
+ if err != nil {
+ continue
+ }
+ var (
+ addresses []common.Address
+ slots [][]string
+ tracer = "prestateTracer"
+ configBlob, _ = json.Marshal(native.PrestateTracerConfig{
+ DiffMode: false,
+ DisableCode: true,
+ DisableStorage: false,
+ })
+ )
+ for _, tx := range block.Transactions() {
+ if nAccounts+nStorages >= number {
+ break
+ }
+ if tx.To() == nil {
+ continue
+ }
+ ret, err := cli.Geth.TraceTransaction(context.Background(), tx.Hash(), &tracers.TraceConfig{
+ Tracer: &tracer,
+ TracerConfig: configBlob,
+ })
+ if err != nil {
+ log.Error("Failed to trace the transaction", "blockNumber", blockNumber, "hash", tx.Hash(), "err", err)
+ continue
+ }
+ blob, err := json.Marshal(ret)
+ if err != nil {
+ log.Error("Failed to marshal data", "err", err)
+ continue
+ }
+ var accounts map[common.Address]*native.PrestateAccount
+ if err := json.Unmarshal(blob, &accounts); err != nil {
+ log.Error("Failed to decode trace result", "blockNumber", blockNumber, "hash", tx.Hash(), "err", err)
+ continue
+ }
+ for addr, account := range accounts {
+ if len(account.Storage) == 0 {
+ continue
+ }
+ addresses = append(addresses, addr)
+ nAccounts += 1
+
+ var keys []string
+ for k := range account.Storage {
+ keys = append(keys, k.Hex())
+ }
+ nStorages += len(keys)
+
+ var emptyKeys []string
+ for i := 0; i < 3; i++ {
+ emptyKeys = append(emptyKeys, testrand.Hash().Hex())
+ }
+ nStorages += len(emptyKeys)
+
+ slots = append(slots, append(keys, emptyKeys...))
+ }
+ }
+ blockNumbers = append(blockNumbers, uint64(blockNumber))
+ accountAddresses = append(accountAddresses, addresses)
+ storageKeys = append(storageKeys, slots)
+ }
+ log.Info("Generated tests for account proof", "blocks", len(blockNumbers), "accounts", nAccounts, "storages", nStorages, "elapsed", common.PrettyDuration(time.Since(start)))
+ return blockNumbers, accountAddresses, storageKeys, nil
+}
+
+func genProofRequests(cli *client, head uint64, states int) (*proofTest, error) {
+ var (
+ blockNumbers []uint64
+ accountAddresses [][]common.Address
+ storageKeys [][][]string
+ )
+ ratio := []float64{0.2, 0.1, 0.7}
+ for i, fn := range []proofGenerator{genAccountProof, genNonExistentAccountProof, genStorageProof} {
+ numbers, addresses, keys, err := fn(cli, head, int(float64(states)*ratio[i]))
+ if err != nil {
+ return nil, err
+ }
+ blockNumbers = append(blockNumbers, numbers...)
+ accountAddresses = append(accountAddresses, addresses...)
+ storageKeys = append(storageKeys, keys...)
+ }
+ return &proofTest{
+ BlockNumbers: blockNumbers,
+ Addresses: accountAddresses,
+ StorageKeys: storageKeys,
+ }, nil
+}
+
+func generateProofTests(clictx *cli.Context) error {
+ var (
+ client = makeClient(clictx)
+ ctx = context.Background()
+ states = clictx.Int(proofTestStatesFlag.Name)
+ outputFile = clictx.String(proofTestFileFlag.Name)
+ outputDir = clictx.String(proofTestResultOutputFlag.Name)
+ )
+ head, err := client.Eth.BlockNumber(ctx)
+ if err != nil {
+ exit(err)
+ }
+ test, err := genProofRequests(client, head, states)
+ if err != nil {
+ exit(err)
+ }
+ for i, blockNumber := range test.BlockNumbers {
+ var hashes []common.Hash
+ for j := 0; j < len(test.Addresses[i]); j++ {
+ res, err := client.Geth.GetProof(ctx, test.Addresses[i][j], test.StorageKeys[i][j], big.NewInt(int64(blockNumber)))
+ if err != nil {
+ log.Error("Failed to prove the state", "number", blockNumber, "address", test.Addresses[i][j], "slots", len(test.StorageKeys[i][j]), "err", err)
+ continue
+ }
+ blob, err := json.Marshal(res)
+ if err != nil {
+ return err
+ }
+ hashes = append(hashes, crypto.Keccak256Hash(blob))
+
+ writeStateProof(outputDir, blockNumber, test.Addresses[i][j], res)
+ }
+ test.Results = append(test.Results, hashes)
+ }
+ writeJSON(outputFile, test)
+ return nil
+}
+
+func writeStateProof(dir string, blockNumber uint64, address common.Address, result any) {
+ if dir == "" {
+ return
+ }
+ // Ensure the directory exists
+ if err := os.MkdirAll(dir, os.ModePerm); err != nil {
+ exit(fmt.Errorf("failed to create directories: %w", err))
+ }
+ fname := fmt.Sprintf("%d-%x", blockNumber, address)
+ name := filepath.Join(dir, fname)
+ file, err := os.Create(name)
+ if err != nil {
+ exit(fmt.Errorf("error creating %s: %v", name, err))
+ return
+ }
+ defer file.Close()
+
+ data, _ := json.MarshalIndent(result, "", " ")
+ _, err = file.Write(data)
+ if err != nil {
+ exit(fmt.Errorf("error writing %s: %v", name, err))
+ return
+ }
+}
diff --git a/cmd/workload/testsuite.go b/cmd/workload/testsuite.go
index 39eeb8e3c20..e9477ceb4eb 100644
--- a/cmd/workload/testsuite.go
+++ b/cmd/workload/testsuite.go
@@ -50,7 +50,9 @@ var (
filterQueryFileFlag,
historyTestFileFlag,
traceTestFileFlag,
+ proofTestFileFlag,
traceTestInvalidOutputFlag,
+ proofTestInvalidOutputFlag,
},
}
testPatternFlag = &cli.StringFlag{
@@ -95,6 +97,7 @@ type testConfig struct {
historyTestFile string
historyPruneBlock *uint64
traceTestFile string
+ proofTestFile string
}
var errPrunedHistory = fmt.Errorf("attempt to access pruned history")
@@ -145,6 +148,12 @@ func testConfigFromCLI(ctx *cli.Context) (cfg testConfig) {
} else {
cfg.traceTestFile = "queries/trace_mainnet.json"
}
+ if ctx.IsSet(proofTestFileFlag.Name) {
+ cfg.proofTestFile = ctx.String(proofTestFileFlag.Name)
+ } else {
+ cfg.proofTestFile = "queries/proof_mainnet.json"
+ }
+
cfg.historyPruneBlock = new(uint64)
*cfg.historyPruneBlock = history.PrunePoints[params.MainnetGenesisHash].BlockNumber
case ctx.Bool(testSepoliaFlag.Name):
@@ -164,6 +173,12 @@ func testConfigFromCLI(ctx *cli.Context) (cfg testConfig) {
} else {
cfg.traceTestFile = "queries/trace_sepolia.json"
}
+ if ctx.IsSet(proofTestFileFlag.Name) {
+ cfg.proofTestFile = ctx.String(proofTestFileFlag.Name)
+ } else {
+ cfg.proofTestFile = "queries/proof_sepolia.json"
+ }
+
cfg.historyPruneBlock = new(uint64)
*cfg.historyPruneBlock = history.PrunePoints[params.SepoliaGenesisHash].BlockNumber
default:
@@ -171,6 +186,7 @@ func testConfigFromCLI(ctx *cli.Context) (cfg testConfig) {
cfg.filterQueryFile = ctx.String(filterQueryFileFlag.Name)
cfg.historyTestFile = ctx.String(historyTestFileFlag.Name)
cfg.traceTestFile = ctx.String(traceTestFileFlag.Name)
+ cfg.proofTestFile = ctx.String(proofTestFileFlag.Name)
}
return cfg
}
@@ -222,11 +238,13 @@ func runTestCmd(ctx *cli.Context) error {
filterSuite := newFilterTestSuite(cfg)
historySuite := newHistoryTestSuite(cfg)
traceSuite := newTraceTestSuite(cfg, ctx)
+ proofSuite := newProofTestSuite(cfg, ctx)
// Filter test cases.
tests := filterSuite.allTests()
tests = append(tests, historySuite.allTests()...)
tests = append(tests, traceSuite.allTests()...)
+ tests = append(tests, proofSuite.allTests()...)
utests := filterTests(tests, ctx.String(testPatternFlag.Name), func(t workloadTest) bool {
if t.Slow && !ctx.Bool(testSlowFlag.Name) {
diff --git a/eth/tracers/native/gen_account_json.go b/eth/tracers/native/gen_account_json.go
index 4c39cbc38cd..911456c5d59 100644
--- a/eth/tracers/native/gen_account_json.go
+++ b/eth/tracers/native/gen_account_json.go
@@ -13,44 +13,44 @@ import (
var _ = (*accountMarshaling)(nil)
// MarshalJSON marshals as JSON.
-func (a account) MarshalJSON() ([]byte, error) {
- type account struct {
+func (p PrestateAccount) MarshalJSON() ([]byte, error) {
+ type PrestateAccount struct {
Balance *hexutil.Big `json:"balance,omitempty"`
Code hexutil.Bytes `json:"code,omitempty"`
Nonce uint64 `json:"nonce,omitempty"`
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
}
- var enc account
- enc.Balance = (*hexutil.Big)(a.Balance)
- enc.Code = a.Code
- enc.Nonce = a.Nonce
- enc.Storage = a.Storage
+ var enc PrestateAccount
+ enc.Balance = (*hexutil.Big)(p.Balance)
+ enc.Code = p.Code
+ enc.Nonce = p.Nonce
+ enc.Storage = p.Storage
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
-func (a *account) UnmarshalJSON(input []byte) error {
- type account struct {
+func (p *PrestateAccount) UnmarshalJSON(input []byte) error {
+ type PrestateAccount struct {
Balance *hexutil.Big `json:"balance,omitempty"`
Code *hexutil.Bytes `json:"code,omitempty"`
Nonce *uint64 `json:"nonce,omitempty"`
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
}
- var dec account
+ var dec PrestateAccount
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.Balance != nil {
- a.Balance = (*big.Int)(dec.Balance)
+ p.Balance = (*big.Int)(dec.Balance)
}
if dec.Code != nil {
- a.Code = *dec.Code
+ p.Code = *dec.Code
}
if dec.Nonce != nil {
- a.Nonce = *dec.Nonce
+ p.Nonce = *dec.Nonce
}
if dec.Storage != nil {
- a.Storage = dec.Storage
+ p.Storage = dec.Storage
}
return nil
}
diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go
index 57c66ae3272..765d8df464b 100644
--- a/eth/tracers/native/prestate.go
+++ b/eth/tracers/native/prestate.go
@@ -35,15 +35,15 @@ import (
"github.com/ethereum/go-ethereum/params"
)
-//go:generate go run github.com/fjl/gencodec -type account -field-override accountMarshaling -out gen_account_json.go
+//go:generate go run github.com/fjl/gencodec -type PrestateAccount -field-override accountMarshaling -out gen_account_json.go
func init() {
tracers.DefaultDirectory.Register("prestateTracer", newPrestateTracer, false)
}
-type stateMap = map[common.Address]*account
+type stateMap = map[common.Address]*PrestateAccount
-type account struct {
+type PrestateAccount struct {
Balance *big.Int `json:"balance,omitempty"`
Code []byte `json:"code,omitempty"`
Nonce uint64 `json:"nonce,omitempty"`
@@ -51,7 +51,7 @@ type account struct {
empty bool
}
-func (a *account) exists() bool {
+func (a *PrestateAccount) exists() bool {
return a.Nonce > 0 || len(a.Code) > 0 || len(a.Storage) > 0 || (a.Balance != nil && a.Balance.Sign() != 0)
}
@@ -65,7 +65,7 @@ type prestateTracer struct {
pre stateMap
post stateMap
to common.Address
- config prestateTracerConfig
+ config PrestateTracerConfig
chainConfig *params.ChainConfig
interrupt atomic.Bool // Atomic flag to signal execution interruption
reason error // Textual reason for the interruption
@@ -73,7 +73,7 @@ type prestateTracer struct {
deleted map[common.Address]bool
}
-type prestateTracerConfig struct {
+type PrestateTracerConfig struct {
DiffMode bool `json:"diffMode"` // If true, this tracer will return state modifications
DisableCode bool `json:"disableCode"` // If true, this tracer will not return the contract code
DisableStorage bool `json:"disableStorage"` // If true, this tracer will not return the contract storage
@@ -81,7 +81,7 @@ type prestateTracerConfig struct {
}
func newPrestateTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
- var config prestateTracerConfig
+ var config PrestateTracerConfig
if err := json.Unmarshal(cfg, &config); err != nil {
return nil, err
}
@@ -244,7 +244,7 @@ func (t *prestateTracer) processDiffState() {
continue
}
modified := false
- postAccount := &account{Storage: make(map[common.Hash]common.Hash)}
+ postAccount := &PrestateAccount{Storage: make(map[common.Hash]common.Hash)}
newBalance := t.env.StateDB.GetBalance(addr).ToBig()
newNonce := t.env.StateDB.GetNonce(addr)
@@ -300,7 +300,7 @@ func (t *prestateTracer) lookupAccount(addr common.Address) {
return
}
- acc := &account{
+ acc := &PrestateAccount{
Balance: t.env.StateDB.GetBalance(addr).ToBig(),
Nonce: t.env.StateDB.GetNonce(addr),
Code: t.env.StateDB.GetCode(addr),
diff --git a/ethclient/gethclient/gethclient.go b/ethclient/gethclient/gethclient.go
index d030878e546..a55fe4f777f 100644
--- a/ethclient/gethclient/gethclient.go
+++ b/ethclient/gethclient/gethclient.go
@@ -105,7 +105,10 @@ func (ec *Client) GetProof(ctx context.Context, account common.Address, keys []s
var res accountResult
err := ec.c.CallContext(ctx, &res, "eth_getProof", account, keys, toBlockNumArg(blockNumber))
- // Turn hexutils back to normal datatypes
+ if err != nil {
+ return nil, err
+ }
+ // Turn hexutils back to normal data types
storageResults := make([]StorageResult, 0, len(res.StorageProof))
for _, st := range res.StorageProof {
storageResults = append(storageResults, StorageResult{
@@ -123,7 +126,7 @@ func (ec *Client) GetProof(ctx context.Context, account common.Address, keys []s
StorageHash: res.StorageHash,
StorageProof: storageResults,
}
- return &result, err
+ return &result, nil
}
// CallContract executes a message call transaction, which is directly executed in the VM