Skip to content

Commit c0825a7

Browse files
gballetjsign
andcommitted
cmd/evm/internal/t8ntool: support for verkle-at-genesis
Co-authored-by: Ignacio Hagopian <[email protected]>
1 parent 4906c99 commit c0825a7

File tree

8 files changed

+195
-25
lines changed

8 files changed

+195
-25
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
name: Execution Spec Tests - Consume (stable)
2+
3+
on:
4+
push:
5+
branches: [master]
6+
pull_request:
7+
branches: [master, kaustinen-with-shapella]
8+
workflow_dispatch:
9+
10+
env:
11+
FIXTURES_TAG: "[email protected]"
12+
13+
jobs:
14+
setup:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Checkout go-ethereum
18+
uses: actions/checkout@v4
19+
20+
- name: Setup Python
21+
uses: actions/setup-python@v5
22+
with:
23+
python-version: "3.12.4"
24+
25+
- name: Set up Go
26+
uses: actions/setup-go@v5
27+
with:
28+
go-version: 1.22.4
29+
30+
- name: Build geth evm
31+
run: |
32+
go build -v ./cmd/evm
33+
mkdir -p ${{ github.workspace }}/bin
34+
mv evm ${{ github.workspace }}/bin/evm
35+
chmod +x ${{ github.workspace }}/bin/evm
36+
37+
- name: Archive built evm
38+
uses: actions/upload-artifact@v4
39+
with:
40+
name: evm
41+
path: ${{ github.workspace }}/bin/evm
42+
43+
consume:
44+
runs-on: ubuntu-latest
45+
needs: setup
46+
strategy:
47+
matrix:
48+
filename:
49+
[
50+
fixtures_verkle-genesis.tar.gz,
51+
]
52+
steps:
53+
- name: Download geth evm
54+
uses: actions/download-artifact@v4
55+
with:
56+
name: evm
57+
path: ./bin
58+
59+
- name: Make evm binary executable and add to PATH
60+
run: |
61+
chmod +x ./bin/evm
62+
echo "${{ github.workspace }}/bin" >> $GITHUB_PATH
63+
64+
- name: Download fixtures
65+
uses: robinraju/release-downloader@v1
66+
with:
67+
repository: "ethereum/execution-spec-tests"
68+
tag: "${{ env.FIXTURES_TAG }}"
69+
fileName: "${{ matrix.filename }}"
70+
extract: true
71+
- name: Clone execution-spec-tests and consume tests
72+
run: |
73+
curl -LsSf https://astral.sh/uv/install.sh | sh
74+
git clone https://github.com/ethereum/execution-spec-tests -b ${{ env.FIXTURES_TAG }} --depth 1
75+
cd execution-spec-tests
76+
uv run consume direct --evm-bin="${{ github.workspace }}/bin/evm" --input=../fixtures -n auto
77+
shell: bash

cmd/evm/internal/t8ntool/execution.go

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ import (
4444
)
4545

4646
type Prestate struct {
47-
Env stEnv `json:"env"`
48-
Pre types.GenesisAlloc `json:"pre"`
47+
Env stEnv `json:"env"`
48+
Pre types.GenesisAlloc `json:"pre"`
49+
VKT map[common.Hash]hexutil.Bytes `json:"vkt,omitempty"`
4950
}
5051

5152
//go:generate go run github.com/fjl/gencodec -type ExecutionResult -field-override executionResultMarshaling -out gen_execresult.go
@@ -143,7 +144,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
143144
return h
144145
}
145146
var (
146-
statedb = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre)
147+
statedb = MakePreState(rawdb.NewMemoryDatabase(), chainConfig, pre, chainConfig.IsVerkle(big.NewInt(int64(pre.Env.Number)), pre.Env.Timestamp))
147148
signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp)
148149
gaspool = new(core.GasPool)
149150
blockHash = common.Hash{0x13, 0x37}
@@ -165,6 +166,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
165166
GasLimit: pre.Env.GasLimit,
166167
GetHash: getHash,
167168
}
169+
168170
// If currentBaseFee is defined, add it to the vmContext.
169171
if pre.Env.BaseFee != nil {
170172
vmContext.BaseFee = new(big.Int).Set(pre.Env.BaseFee)
@@ -251,6 +253,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
251253
}
252254
}
253255
statedb.SetTxContext(tx.Hash(), txIndex)
256+
evm.AccessEvents = state.NewAccessEvents(evm.StateDB.PointCache())
254257
var (
255258
snapshot = statedb.Snapshot()
256259
prevGas = gaspool.Gas()
@@ -315,7 +318,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
315318
evm.Config.Tracer.OnTxEnd(receipt, nil)
316319
}
317320
}
318-
321+
statedb.AccessEvents().Merge(evm.AccessEvents)
319322
txIndex++
320323
}
321324
statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber))
@@ -348,6 +351,8 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
348351
// Amount is in gwei, turn into wei
349352
amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei))
350353
statedb.AddBalance(w.Address, uint256.MustFromBig(amount), tracing.BalanceIncreaseWithdrawal)
354+
355+
statedb.AccessEvents().AddAccount(w.Address, true)
351356
}
352357

353358
// Gather the execution-layer triggered requests.
@@ -414,11 +419,12 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
414419
return statedb, execRs, body, nil
415420
}
416421

417-
func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB {
422+
func MakePreState(db ethdb.Database, chainConfig *params.ChainConfig, pre *Prestate, verkle bool) *state.StateDB {
418423
tdb := triedb.NewDatabase(db, &triedb.Config{Preimages: true})
419424
sdb := state.NewDatabase(tdb, nil)
425+
420426
statedb, _ := state.New(types.EmptyRootHash, sdb)
421-
for addr, a := range accounts {
427+
for addr, a := range pre.Pre {
422428
statedb.SetCode(addr, a.Code)
423429
statedb.SetNonce(addr, a.Nonce, tracing.NonceChangeGenesis)
424430
statedb.SetBalance(addr, uint256.MustFromBig(a.Balance), tracing.BalanceIncreaseGenesisBalance)
@@ -427,12 +433,21 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB
427433
}
428434
}
429435
// Commit and re-open to start with a clean state.
430-
root, _ := statedb.Commit(0, false, false)
431-
statedb, _ = state.New(root, sdb)
436+
mptRoot, err := statedb.Commit(0, false, false)
437+
if err != nil {
438+
panic(err)
439+
}
440+
// If verkle mode started, establish the conversion
441+
if verkle {
442+
if _, ok := statedb.GetTrie().(*trie.VerkleTrie); ok {
443+
return statedb
444+
}
445+
}
446+
statedb, _ = state.New(mptRoot, sdb)
432447
return statedb
433448
}
434449

435-
func rlpHash(x interface{}) (h common.Hash) {
450+
func rlpHash(x any) (h common.Hash) {
436451
hw := sha3.NewLegacyKeccak256()
437452
rlp.Encode(hw, x)
438453
hw.Sum(h[:0])

cmd/evm/internal/t8ntool/flags.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,22 @@ var (
8888
"\t<file> - into the file <file> ",
8989
Value: "block.json",
9090
}
91+
OutputVKTFlag = &cli.StringFlag{
92+
Name: "output.vkt",
93+
Usage: "Determines where to put the `VKT` of the post-state.\n" +
94+
"\t`stdout` - into the stdout output\n" +
95+
"\t`stderr` - into the stderr output\n" +
96+
"\t<file> - into the file <file> ",
97+
Value: "vkt.json",
98+
}
99+
OutputWitnessFlag = &cli.StringFlag{
100+
Name: "output.witness",
101+
Usage: "Determines where to put the `witness` of the post-state.\n" +
102+
"\t`stdout` - into the stdout output\n" +
103+
"\t`stderr` - into the stderr output\n" +
104+
"\t<file> - into the file <file> ",
105+
Value: "witness.json",
106+
}
91107
InputAllocFlag = &cli.StringFlag{
92108
Name: "input.alloc",
93109
Usage: "`stdin` or file name of where to find the prestate alloc to use.",
@@ -123,6 +139,10 @@ var (
123139
Usage: "`stdin` or file name of where to find the transactions list in RLP form.",
124140
Value: "txs.rlp",
125141
}
142+
InputVKTFlag = &cli.StringFlag{
143+
Name: "input.vkt",
144+
Usage: "`stdin` or file name of where to find the prestate VKT.",
145+
}
126146
SealCliqueFlag = &cli.StringFlag{
127147
Name: "seal.clique",
128148
Usage: "Seal block with Clique. `stdin` or file name of where to find the Clique sealing data.",

cmd/evm/internal/t8ntool/transition.go

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,11 @@ var (
7575
)
7676

7777
type input struct {
78-
Alloc types.GenesisAlloc `json:"alloc,omitempty"`
79-
Env *stEnv `json:"env,omitempty"`
80-
Txs []*txWithKey `json:"txs,omitempty"`
81-
TxRlp string `json:"txsRlp,omitempty"`
78+
Alloc types.GenesisAlloc `json:"alloc,omitempty"`
79+
Env *stEnv `json:"env,omitempty"`
80+
VKT map[common.Hash]hexutil.Bytes `json:"vkt,omitempty"`
81+
Txs []*txWithKey `json:"txs,omitempty"`
82+
TxRlp string `json:"txsRlp,omitempty"`
8283
}
8384

8485
func Transition(ctx *cli.Context) error {
@@ -90,16 +91,16 @@ func Transition(ctx *cli.Context) error {
9091
// stdin input or in files.
9192
// Check if anything needs to be read from stdin
9293
var (
93-
prestate Prestate
94-
txIt txIterator // txs to apply
95-
allocStr = ctx.String(InputAllocFlag.Name)
96-
94+
prestate Prestate
95+
txIt txIterator // txs to apply
96+
allocStr = ctx.String(InputAllocFlag.Name)
97+
vktStr = ctx.String(InputVKTFlag.Name)
9798
envStr = ctx.String(InputEnvFlag.Name)
9899
txStr = ctx.String(InputTxsFlag.Name)
99100
inputData = &input{}
100101
)
101102
// Figure out the prestate alloc
102-
if allocStr == stdinSelector || envStr == stdinSelector || txStr == stdinSelector {
103+
if allocStr == stdinSelector || vktStr == stdinSelector || envStr == stdinSelector || txStr == stdinSelector {
103104
decoder := json.NewDecoder(os.Stdin)
104105
if err := decoder.Decode(inputData); err != nil {
105106
return NewError(ErrorJson, fmt.Errorf("failed unmarshalling stdin: %v", err))
@@ -110,8 +111,18 @@ func Transition(ctx *cli.Context) error {
110111
return err
111112
}
112113
}
114+
if vktStr != stdinSelector {
115+
if err := readFile(vktStr, "VKT", &inputData.Alloc); err != nil {
116+
return err
117+
}
118+
}
113119
prestate.Pre = inputData.Alloc
114-
120+
if vktStr != stdinSelector && vktStr != "" {
121+
if err := readFile(vktStr, "VKT", &inputData.VKT); err != nil {
122+
return err
123+
}
124+
}
125+
prestate.VKT = inputData.VKT
115126
// Set the block environment
116127
if envStr != stdinSelector {
117128
var env stEnv
@@ -183,8 +194,14 @@ func Transition(ctx *cli.Context) error {
183194
}
184195
// Dump the execution result
185196
collector := make(Alloc)
186-
s.DumpToCollector(collector, nil)
187-
return dispatchOutput(ctx, baseDir, result, collector, body)
197+
var vktleaves map[common.Hash]hexutil.Bytes
198+
if !chainConfig.IsVerkle(big.NewInt(int64(prestate.Env.Number)), prestate.Env.Timestamp) {
199+
s.DumpToCollector(collector, nil)
200+
} else {
201+
vktleaves = make(map[common.Hash]hexutil.Bytes)
202+
s.DumpVKTLeaves(vktleaves)
203+
}
204+
return dispatchOutput(ctx, baseDir, result, collector, body, vktleaves)
188205
}
189206

190207
func applyLondonChecks(env *stEnv, chainConfig *params.ChainConfig) error {
@@ -306,7 +323,7 @@ func saveFile(baseDir, filename string, data interface{}) error {
306323

307324
// dispatchOutput writes the output data to either stderr or stdout, or to the specified
308325
// files
309-
func dispatchOutput(ctx *cli.Context, baseDir string, result *ExecutionResult, alloc Alloc, body hexutil.Bytes) error {
326+
func dispatchOutput(ctx *cli.Context, baseDir string, result *ExecutionResult, alloc Alloc, body hexutil.Bytes, vkt map[common.Hash]hexutil.Bytes) error {
310327
stdOutObject := make(map[string]interface{})
311328
stdErrObject := make(map[string]interface{})
312329
dispatch := func(baseDir, fName, name string, obj interface{}) error {
@@ -333,6 +350,11 @@ func dispatchOutput(ctx *cli.Context, baseDir string, result *ExecutionResult, a
333350
if err := dispatch(baseDir, ctx.String(OutputBodyFlag.Name), "body", body); err != nil {
334351
return err
335352
}
353+
if vkt != nil {
354+
if err := dispatch(baseDir, ctx.String(OutputVKTFlag.Name), "vkt", vkt); err != nil {
355+
return err
356+
}
357+
}
336358
if len(stdOutObject) > 0 {
337359
b, err := json.MarshalIndent(stdOutObject, "", " ")
338360
if err != nil {

cmd/evm/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,13 @@ var (
146146
t8ntool.TraceEnableCallFramesFlag,
147147
t8ntool.OutputBasedir,
148148
t8ntool.OutputAllocFlag,
149+
t8ntool.OutputVKTFlag,
150+
t8ntool.OutputWitnessFlag,
149151
t8ntool.OutputResultFlag,
150152
t8ntool.OutputBodyFlag,
151153
t8ntool.InputAllocFlag,
152154
t8ntool.InputEnvFlag,
155+
t8ntool.InputVKTFlag,
153156
t8ntool.InputTxsFlag,
154157
t8ntool.ForknameFlag,
155158
t8ntool.ChainIDFlag,

core/state/dump.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,18 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey []
208208
return nextKey
209209
}
210210

211+
func (s *StateDB) DumpVKTLeaves(collector map[common.Hash]hexutil.Bytes) {
212+
it, err := s.trie.(*trie.VerkleTrie).NodeIterator(nil)
213+
if err != nil {
214+
panic(err)
215+
}
216+
for it.Next(true) {
217+
if it.Leaf() {
218+
collector[common.BytesToHash(it.LeafKey())] = it.LeafBlob()
219+
}
220+
}
221+
}
222+
211223
// RawDump returns the state. If the processing is aborted e.g. due to options
212224
// reaching Max, the `Next` key is set on the returned Dump.
213225
func (s *StateDB) RawDump(opts *DumpConfig) Dump {

tests/block_test_util.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,19 +117,20 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, tracer *t
117117
return UnsupportedForkError{t.json.Network}
118118
}
119119
// import pre accounts & construct test genesis block & state root
120+
// Commit genesis state
121+
gspec := t.genesis(config)
120122
var (
121123
db = rawdb.NewMemoryDatabase()
122124
tconf = &triedb.Config{
123125
Preimages: true,
126+
IsVerkle: gspec.Config.VerkleTime != nil && *gspec.Config.VerkleTime <= gspec.Timestamp,
124127
}
125128
)
126-
if scheme == rawdb.PathScheme {
129+
if scheme == rawdb.PathScheme || tconf.IsVerkle {
127130
tconf.PathDB = pathdb.Defaults
128131
} else {
129132
tconf.HashDB = hashdb.Defaults
130133
}
131-
// Commit genesis state
132-
gspec := t.genesis(config)
133134

134135
// if ttd is not specified, set an arbitrary huge value
135136
if gspec.Config.TerminalTotalDifficulty == nil {

tests/init.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,26 @@ var Forks = map[string]*params.ChainConfig{
464464
Osaka: params.DefaultOsakaBlobConfig,
465465
},
466466
},
467+
468+
"Verkle": {
469+
ChainID: big.NewInt(1),
470+
HomesteadBlock: big.NewInt(0),
471+
EIP150Block: big.NewInt(0),
472+
EIP155Block: big.NewInt(0),
473+
EIP158Block: big.NewInt(0),
474+
ByzantiumBlock: big.NewInt(0),
475+
ConstantinopleBlock: big.NewInt(0),
476+
PetersburgBlock: big.NewInt(0),
477+
IstanbulBlock: big.NewInt(0),
478+
MuirGlacierBlock: big.NewInt(0),
479+
BerlinBlock: big.NewInt(0),
480+
LondonBlock: big.NewInt(0),
481+
ArrowGlacierBlock: big.NewInt(0),
482+
MergeNetsplitBlock: big.NewInt(0),
483+
TerminalTotalDifficulty: big.NewInt(0),
484+
ShanghaiTime: u64(0),
485+
VerkleTime: u64(0),
486+
},
467487
}
468488

469489
// AvailableForks returns the set of defined fork names

0 commit comments

Comments
 (0)