cmd/evm, core/state: add callback to blockrunner, fix dump with missing preimages

This changes makes it so that the block test executor takes a callback, just like
the state test executor already does. This callback can be used to examine the
post-execution state, e.g. to aid debugging of test failures.

This change also modifies the mechanics of Dump: previously, all accounts for which
we did not have the preimage (address) were silently discarded.

Now they are output instead like this:
```
{
    "root": "3ef447699d08e3160c448903e77bd092c67ce3faeba773a3f83c500ab80f2400",
    "accounts": {
        "pre(0x03601462093b5945d1676df093446790fd31b20e7b12a2e8e5e09d068109616b)": {
            "balance": "10780210",
            "nonce": 1,
```
This commit is contained in:
Martin Holst Swende 2023-11-10 08:54:01 +01:00
parent 984f82629c
commit 7df4ebd5ec
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
4 changed files with 25 additions and 10 deletions

View file

@ -24,6 +24,7 @@ import (
"regexp"
"sort"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/tracers/logger"
@ -85,7 +86,13 @@ func blockTestCmd(ctx *cli.Context) error {
continue
}
test := tests[name]
if err := test.Run(false, rawdb.HashScheme, tracer); err != nil {
if err := test.Run(false, rawdb.HashScheme, tracer, func(res error, chain *core.BlockChain) {
if ctx.Bool(DumpFlag.Name) {
if state, _ := chain.State(); state != nil {
fmt.Println(string(state.Dump(nil)))
}
}
}); err != nil {
return fmt.Errorf("test %v: %w", name, err)
}
}

View file

@ -62,8 +62,8 @@ type DumpAccount struct {
// Dump represents the full dump in a collected format, as one large map.
type Dump struct {
Root string `json:"root"`
Accounts map[common.Address]DumpAccount `json:"accounts"`
Root string `json:"root"`
Accounts map[string]DumpAccount `json:"accounts"`
}
// OnRoot implements DumpCollector interface
@ -73,8 +73,11 @@ func (d *Dump) OnRoot(root common.Hash) {
// OnAccount implements DumpCollector interface
func (d *Dump) OnAccount(addr *common.Address, account DumpAccount) {
if addr == nil {
d.Accounts[fmt.Sprintf("pre(%s)", account.SecureKey)] = account
}
if addr != nil {
d.Accounts[*addr] = account
d.Accounts[(*addr).String()] = account
}
}
@ -223,7 +226,7 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey []
// RawDump returns the entire state an a single large object
func (s *StateDB) RawDump(opts *DumpConfig) Dump {
dump := &Dump{
Accounts: make(map[common.Address]DumpAccount),
Accounts: make(map[string]DumpAccount),
}
s.DumpToCollector(dump, opts)
return *dump

View file

@ -74,19 +74,19 @@ func TestExecutionSpec(t *testing.T) {
}
func execBlockTest(t *testing.T, bt *testMatcher, test *BlockTest) {
if err := bt.checkFailure(t, test.Run(false, rawdb.HashScheme, nil)); err != nil {
if err := bt.checkFailure(t, test.Run(false, rawdb.HashScheme, nil, nil)); err != nil {
t.Errorf("test in hash mode without snapshotter failed: %v", err)
return
}
if err := bt.checkFailure(t, test.Run(true, rawdb.HashScheme, nil)); err != nil {
if err := bt.checkFailure(t, test.Run(true, rawdb.HashScheme, nil, nil)); err != nil {
t.Errorf("test in hash mode with snapshotter failed: %v", err)
return
}
if err := bt.checkFailure(t, test.Run(false, rawdb.PathScheme, nil)); err != nil {
if err := bt.checkFailure(t, test.Run(false, rawdb.PathScheme, nil, nil)); err != nil {
t.Errorf("test in path mode without snapshotter failed: %v", err)
return
}
if err := bt.checkFailure(t, test.Run(true, rawdb.PathScheme, nil)); err != nil {
if err := bt.checkFailure(t, test.Run(true, rawdb.PathScheme, nil, nil)); err != nil {
t.Errorf("test in path mode with snapshotter failed: %v", err)
return
}

View file

@ -108,7 +108,7 @@ type btHeaderMarshaling struct {
ExcessBlobGas *math.HexOrDecimal64
}
func (t *BlockTest) Run(snapshotter bool, scheme string, tracer vm.EVMLogger) error {
func (t *BlockTest) Run(snapshotter bool, scheme string, tracer vm.EVMLogger, postCheck func(error, *core.BlockChain)) (result error) {
config, ok := Forks[t.json.Network]
if !ok {
return UnsupportedForkError{t.json.Network}
@ -158,6 +158,11 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, tracer vm.EVMLogger) er
if err != nil {
return err
}
// Import succeeded: regardless of whether the _test_ succeeds or not, schedule
// the post-check to run
defer func() {
postCheck(result, chain)
}()
cmlast := chain.CurrentBlock().Hash()
if common.Hash(t.json.BestBlock) != cmlast {
return fmt.Errorf("last block hash validation mismatch: want: %x, have: %x", t.json.BestBlock, cmlast)