cmd/evm: add state transition tool for testing (#20958)
This PR implements the EVM state transition tool, which is intended to be the replacement for our retesteth client implementation. Documentation is present in the cmd/evm/README.md file. Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
committed by
GitHub
parent
dd91c7ce6a
commit
e376d2fb31
@ -27,6 +27,14 @@ import (
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
)
|
||||
|
||||
// DumpCollector interface which the state trie calls during iteration
|
||||
type DumpCollector interface {
|
||||
// OnRoot is called with the state root
|
||||
OnRoot(common.Hash)
|
||||
// OnAccount is called once for each account in the trie
|
||||
OnAccount(common.Address, DumpAccount)
|
||||
}
|
||||
|
||||
// DumpAccount represents an account in the state.
|
||||
type DumpAccount struct {
|
||||
Balance string `json:"balance"`
|
||||
@ -46,9 +54,14 @@ type Dump struct {
|
||||
Accounts map[common.Address]DumpAccount `json:"accounts"`
|
||||
}
|
||||
|
||||
// iterativeDump is a 'collector'-implementation which dump output line-by-line iteratively.
|
||||
type iterativeDump struct {
|
||||
*json.Encoder
|
||||
// OnRoot implements DumpCollector interface
|
||||
func (d *Dump) OnRoot(root common.Hash) {
|
||||
d.Root = fmt.Sprintf("%x", root)
|
||||
}
|
||||
|
||||
// OnAccount implements DumpCollector interface
|
||||
func (d *Dump) OnAccount(addr common.Address, account DumpAccount) {
|
||||
d.Accounts[addr] = account
|
||||
}
|
||||
|
||||
// IteratorDump is an implementation for iterating over data.
|
||||
@ -58,28 +71,23 @@ type IteratorDump struct {
|
||||
Next []byte `json:"next,omitempty"` // nil if no more accounts
|
||||
}
|
||||
|
||||
// Collector interface which the state trie calls during iteration
|
||||
type collector interface {
|
||||
onRoot(common.Hash)
|
||||
onAccount(common.Address, DumpAccount)
|
||||
}
|
||||
|
||||
func (d *Dump) onRoot(root common.Hash) {
|
||||
// OnRoot implements DumpCollector interface
|
||||
func (d *IteratorDump) OnRoot(root common.Hash) {
|
||||
d.Root = fmt.Sprintf("%x", root)
|
||||
}
|
||||
|
||||
func (d *Dump) onAccount(addr common.Address, account DumpAccount) {
|
||||
d.Accounts[addr] = account
|
||||
}
|
||||
func (d *IteratorDump) onRoot(root common.Hash) {
|
||||
d.Root = fmt.Sprintf("%x", root)
|
||||
}
|
||||
|
||||
func (d *IteratorDump) onAccount(addr common.Address, account DumpAccount) {
|
||||
// OnAccount implements DumpCollector interface
|
||||
func (d *IteratorDump) OnAccount(addr common.Address, account DumpAccount) {
|
||||
d.Accounts[addr] = account
|
||||
}
|
||||
|
||||
func (d iterativeDump) onAccount(addr common.Address, account DumpAccount) {
|
||||
// iterativeDump is a DumpCollector-implementation which dumps output line-by-line iteratively.
|
||||
type iterativeDump struct {
|
||||
*json.Encoder
|
||||
}
|
||||
|
||||
// OnAccount implements DumpCollector interface
|
||||
func (d iterativeDump) OnAccount(addr common.Address, account DumpAccount) {
|
||||
dumpAccount := &DumpAccount{
|
||||
Balance: account.Balance,
|
||||
Nonce: account.Nonce,
|
||||
@ -96,15 +104,16 @@ func (d iterativeDump) onAccount(addr common.Address, account DumpAccount) {
|
||||
d.Encode(dumpAccount)
|
||||
}
|
||||
|
||||
func (d iterativeDump) onRoot(root common.Hash) {
|
||||
// OnRoot implements DumpCollector interface
|
||||
func (d iterativeDump) OnRoot(root common.Hash) {
|
||||
d.Encode(struct {
|
||||
Root common.Hash `json:"root"`
|
||||
}{root})
|
||||
}
|
||||
|
||||
func (s *StateDB) dump(c collector, excludeCode, excludeStorage, excludeMissingPreimages bool, start []byte, maxResults int) (nextKey []byte) {
|
||||
func (s *StateDB) DumpToCollector(c DumpCollector, excludeCode, excludeStorage, excludeMissingPreimages bool, start []byte, maxResults int) (nextKey []byte) {
|
||||
missingPreimages := 0
|
||||
c.onRoot(s.trie.Hash())
|
||||
c.OnRoot(s.trie.Hash())
|
||||
|
||||
var count int
|
||||
it := trie.NewIterator(s.trie.NodeIterator(start))
|
||||
@ -145,7 +154,7 @@ func (s *StateDB) dump(c collector, excludeCode, excludeStorage, excludeMissingP
|
||||
account.Storage[common.BytesToHash(s.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(content)
|
||||
}
|
||||
}
|
||||
c.onAccount(addr, account)
|
||||
c.OnAccount(addr, account)
|
||||
count++
|
||||
if maxResults > 0 && count >= maxResults {
|
||||
if it.Next() {
|
||||
@ -166,7 +175,7 @@ func (s *StateDB) RawDump(excludeCode, excludeStorage, excludeMissingPreimages b
|
||||
dump := &Dump{
|
||||
Accounts: make(map[common.Address]DumpAccount),
|
||||
}
|
||||
s.dump(dump, excludeCode, excludeStorage, excludeMissingPreimages, nil, 0)
|
||||
s.DumpToCollector(dump, excludeCode, excludeStorage, excludeMissingPreimages, nil, 0)
|
||||
return *dump
|
||||
}
|
||||
|
||||
@ -175,14 +184,14 @@ func (s *StateDB) Dump(excludeCode, excludeStorage, excludeMissingPreimages bool
|
||||
dump := s.RawDump(excludeCode, excludeStorage, excludeMissingPreimages)
|
||||
json, err := json.MarshalIndent(dump, "", " ")
|
||||
if err != nil {
|
||||
fmt.Println("dump err", err)
|
||||
fmt.Println("Dump err", err)
|
||||
}
|
||||
return json
|
||||
}
|
||||
|
||||
// IterativeDump dumps out accounts as json-objects, delimited by linebreaks on stdout
|
||||
func (s *StateDB) IterativeDump(excludeCode, excludeStorage, excludeMissingPreimages bool, output *json.Encoder) {
|
||||
s.dump(iterativeDump{output}, excludeCode, excludeStorage, excludeMissingPreimages, nil, 0)
|
||||
s.DumpToCollector(iterativeDump{output}, excludeCode, excludeStorage, excludeMissingPreimages, nil, 0)
|
||||
}
|
||||
|
||||
// IteratorDump dumps out a batch of accounts starts with the given start key
|
||||
@ -190,6 +199,6 @@ func (s *StateDB) IteratorDump(excludeCode, excludeStorage, excludeMissingPreima
|
||||
iterator := &IteratorDump{
|
||||
Accounts: make(map[common.Address]DumpAccount),
|
||||
}
|
||||
iterator.Next = s.dump(iterator, excludeCode, excludeStorage, excludeMissingPreimages, start, maxResults)
|
||||
iterator.Next = s.DumpToCollector(iterator, excludeCode, excludeStorage, excludeMissingPreimages, start, maxResults)
|
||||
return *iterator
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ func TestDump(t *testing.T) {
|
||||
s.state.updateStateObject(obj2)
|
||||
s.state.Commit(false)
|
||||
|
||||
// check that dump contains the state objects that are in trie
|
||||
// check that DumpToCollector contains the state objects that are in trie
|
||||
got := string(s.state.Dump(false, false, true))
|
||||
want := `{
|
||||
"root": "71edff0130dd2385947095001c73d9e28d862fc286fca2b922ca6f6f3cddfdd2",
|
||||
@ -83,7 +83,7 @@ func TestDump(t *testing.T) {
|
||||
}
|
||||
}`
|
||||
if got != want {
|
||||
t.Errorf("dump mismatch:\ngot: %s\nwant: %s\n", got, want)
|
||||
t.Errorf("DumpToCollector mismatch:\ngot: %s\nwant: %s\n", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,30 +18,44 @@ package vm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
var activators = map[int]func(*JumpTable){
|
||||
2200: enable2200,
|
||||
1884: enable1884,
|
||||
1344: enable1344,
|
||||
2315: enable2315,
|
||||
}
|
||||
|
||||
// EnableEIP enables the given EIP on the config.
|
||||
// This operation writes in-place, and callers need to ensure that the globally
|
||||
// defined jump tables are not polluted.
|
||||
func EnableEIP(eipNum int, jt *JumpTable) error {
|
||||
switch eipNum {
|
||||
case 2200:
|
||||
enable2200(jt)
|
||||
case 1884:
|
||||
enable1884(jt)
|
||||
case 1344:
|
||||
enable1344(jt)
|
||||
case 2315:
|
||||
enable2315(jt)
|
||||
default:
|
||||
enablerFn, ok := activators[eipNum]
|
||||
if !ok {
|
||||
return fmt.Errorf("undefined eip %d", eipNum)
|
||||
}
|
||||
enablerFn(jt)
|
||||
return nil
|
||||
}
|
||||
|
||||
func ValidEip(eipNum int) bool {
|
||||
_, ok := activators[eipNum]
|
||||
return ok
|
||||
}
|
||||
func ActivateableEips() []string {
|
||||
var nums []string
|
||||
for k := range activators {
|
||||
nums = append(nums, fmt.Sprintf("%d", k))
|
||||
}
|
||||
sort.Strings(nums)
|
||||
return nums
|
||||
}
|
||||
|
||||
// enable1884 applies EIP-1884 to the given jump table:
|
||||
// - Increase cost of BALANCE to 700
|
||||
// - Increase cost of EXTCODEHASH to 700
|
||||
|
Reference in New Issue
Block a user