Skip to content

Commit 6a1f344

Browse files
committed
all: implement EIP-compliant verkle trees
verkle: Implement Trie, NodeIterator and Database ifs Fix crash in TestDump Fix TestDump Fix TrieCopy remove unnecessary traces fix: Error() returned errIteratorEnd in verkle node iterator rewrite the iterator and change the signature of OpenStorageTrie add the adapter to reuse the account trie for storage don't try to deserialize a storage leaf into an account Fix statedb unit tests (#14) * debug code * Fix more unit tests * remove traces * Go back to the full range One tree to rule them all remove updateRoot, there is no root to update store code inside the account leaf fix build save current state for Sina Update go-verkle to latest Charge WITNESS_*_COST gas on storage loads Add witness costs for SSTORE as well Charge witness gas in the case of code execution corresponding code deletion add a --verkle flag to separate verkle experiments from regular geth operations use the snapshot to get data stateless execution from block witness AccessWitness functions Add block generation test + genesis snapshot generation test stateless block execution (#18) * test stateless block execution * Force tree resolution before generating the proof increased coverage in stateless test execution (#19) * test stateless block execution * Force tree resolution before generating the proof * increase coverage in stateless test execution ensure geth compiles fix issues in tests with verkle trees deactivated Ensure stateless data is available when executing statelessly (#20) * Ensure stateless data is available when executing statelessly * Actual execution of a statless block * bugfixes in stateless block execution * code cleanup - Reduce PR footprint by reverting NewEVM to its original signature - Move the access witness to the block context - prepare for a change in AW semantics Need to store the initial values. - Use the touch helper function, DRY * revert the signature of MustCommit to its original form (#21) fix leaf proofs in stateless execution (#22) * Fixes in witness pre-state * Add the recipient's nonce to the witness * reduce PR footprint and investigate issue in root state calculation * quick build fix cleanup: Remove extra parameter in ToBlock revert ToBlock to its older signature fix import cycle in vm tests fix linter issue fix appveyor build fix nil pointers in tests Add indices, yis and Cis to the block's Verkle proof upgrade geth dependency to drop geth's common dep fix cmd/devp2p tests fix rebase issues quell an appveyor warning fix address touching in SLOAD and SSTORE fix access witness for code size touch target account data before calling make sure the proper locations get touched in (ext)codecopy touch all code pages in execution add pushdata to witness remove useless code in genesis snapshot generation testnet: fix some of the rebase/drift issues Fix verkle proof generation in block fix an issue occuring when chunking past the code size fix: ensure the code copy doesn't extend past the code size
1 parent e9294a7 commit 6a1f344

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1731
-65
lines changed

accounts/abi/bind/bind_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1983,7 +1983,7 @@ func TestGolangBindings(t *testing.T) {
19831983
t.Fatalf("failed to tidy Go module file: %v\n%s", err, out)
19841984
}
19851985
// Test the entire package and report any failures
1986-
cmd := exec.Command(gocmd, "test", "-v", "-count", "1")
1986+
cmd := exec.Command(gocmd, "test", "-tags=bignum_kilic", "-v", "-count", "1")
19871987
cmd.Dir = pkg
19881988
if out, err := cmd.CombinedOutput(); err != nil {
19891989
t.Fatalf("failed to run binding test: %v\n%s", err, out)

cmd/geth/chaincmd.go

+5
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ var (
4949
ArgsUsage: "<genesisPath>",
5050
Flags: []cli.Flag{
5151
utils.DataDirFlag,
52+
utils.VerkleFlag,
5253
},
5354
Category: "BLOCKCHAIN COMMANDS",
5455
Description: `
@@ -205,6 +206,10 @@ func initGenesis(ctx *cli.Context) error {
205206
stack, _ := makeConfigNode(ctx)
206207
defer stack.Close()
207208

209+
if ctx.GlobalBool(utils.VerkleFlag.Name) {
210+
genesis.Config.UseVerkle = true
211+
}
212+
208213
for _, name := range []string{"chaindata", "lightchaindata"} {
209214
chaindb, err := stack.OpenDatabase(name, 0, 0, "", false)
210215
if err != nil {

cmd/geth/main.go

+1
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ var (
156156
utils.MinerNotifyFullFlag,
157157
configFileFlag,
158158
utils.CatalystFlag,
159+
utils.VerkleFlag,
159160
}
160161

161162
rpcFlags = []cli.Flag{

cmd/geth/snapshot.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ func verifyState(ctx *cli.Context) error {
220220
log.Error("Failed to load head block")
221221
return errors.New("no head block")
222222
}
223-
snaptree, err := snapshot.New(chaindb, trie.NewDatabase(chaindb), 256, headBlock.Root(), false, false, false)
223+
snaptree, err := snapshot.New(chaindb, trie.NewDatabase(chaindb), 256, headBlock.Root(), false, false, false, false)
224224
if err != nil {
225225
log.Error("Failed to open snapshot tree", "err", err)
226226
return err
@@ -472,7 +472,7 @@ func dumpState(ctx *cli.Context) error {
472472
if err != nil {
473473
return err
474474
}
475-
snaptree, err := snapshot.New(db, trie.NewDatabase(db), 256, root, false, false, false)
475+
snaptree, err := snapshot.New(db, trie.NewDatabase(db), 256, root, false, false, false, false)
476476
if err != nil {
477477
return err
478478
}

cmd/geth/usage.go

+1
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ var AppHelpFlagGroups = []flags.FlagGroup{
229229
utils.BloomFilterSizeFlag,
230230
cli.HelpFlag,
231231
utils.CatalystFlag,
232+
utils.VerkleFlag,
232233
},
233234
},
234235
}

cmd/utils/flags.go

+16
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,11 @@ var (
784784
Name: "catalyst",
785785
Usage: "Catalyst mode (eth2 integration testing)",
786786
}
787+
788+
VerkleFlag = cli.BoolFlag{
789+
Name: "verkle",
790+
Usage: "Enable geth with verkle trees (EXPERIMENTAL)",
791+
}
787792
)
788793

789794
// MakeDataDir retrieves the currently requested data directory, terminating
@@ -1465,7 +1470,11 @@ func CheckExclusive(ctx *cli.Context, args ...interface{}) {
14651470
// SetEthConfig applies eth-related command line flags to the config.
14661471
func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
14671472
// Avoid conflicting network flags
1473+
<<<<<<< HEAD
14681474
CheckExclusive(ctx, MainnetFlag, DeveloperFlag, RopstenFlag, RinkebyFlag, GoerliFlag, SepoliaFlag)
1475+
=======
1476+
CheckExclusive(ctx, MainnetFlag, DeveloperFlag, RopstenFlag, RinkebyFlag, GoerliFlag, VerkleFlag)
1477+
>>>>>>> 00ed1c501 (all: implement EIP-compliant verkle trees)
14691478
CheckExclusive(ctx, LightServeFlag, SyncModeFlag, "light")
14701479
CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer
14711480
if ctx.GlobalString(GCModeFlag.Name) == "archive" && ctx.GlobalUint64(TxLookupLimitFlag.Name) != 0 {
@@ -1603,6 +1612,13 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
16031612
}
16041613
cfg.Genesis = core.DefaultGenesisBlock()
16051614
SetDNSDiscoveryDefaults(cfg, params.MainnetGenesisHash)
1615+
case ctx.GlobalBool(VerkleFlag.Name):
1616+
if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
1617+
cfg.NetworkId = 86 // 'V'
1618+
}
1619+
cfg.Genesis = core.DefaultVerkleGenesisBlock()
1620+
cfg.Genesis.Config.UseVerkle = true
1621+
SetDNSDiscoveryDefaults(cfg, params.MainnetGenesisHash)
16061622
case ctx.GlobalBool(RopstenFlag.Name):
16071623
if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
16081624
cfg.NetworkId = 3

core/blockchain.go

+18-2
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
236236
Cache: cacheConfig.TrieCleanLimit,
237237
Journal: cacheConfig.TrieCleanJournal,
238238
Preimages: cacheConfig.Preimages,
239+
UseVerkle: chainConfig.UseVerkle,
239240
}),
240241
quit: make(chan struct{}),
241242
chainmu: syncx.NewClosableMutex(),
@@ -377,7 +378,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
377378
log.Warn("Enabling snapshot recovery", "chainhead", head.NumberU64(), "diskbase", *layer)
378379
recover = true
379380
}
380-
bc.snaps, _ = snapshot.New(bc.db, bc.stateCache.TrieDB(), bc.cacheConfig.SnapshotLimit, head.Root(), !bc.cacheConfig.SnapshotWait, true, recover)
381+
bc.snaps, _ = snapshot.New(bc.db, bc.stateCache.TrieDB(), bc.cacheConfig.SnapshotLimit, head.Root(), !bc.cacheConfig.SnapshotWait, true, recover, bc.Config().UseVerkle)
381382
}
382383

383384
// Start future block processor.
@@ -1607,7 +1608,22 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
16071608

16081609
// Process block using the parent state as reference point
16091610
substart := time.Now()
1610-
receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig)
1611+
var (
1612+
usedGas uint64
1613+
receipts types.Receipts
1614+
logs []*types.Log
1615+
)
1616+
if len(block.Header().VerkleProof) == 0 {
1617+
receipts, logs, _, usedGas, err = bc.processor.Process(block, statedb, bc.vmConfig)
1618+
} else {
1619+
var leaves map[common.Hash]common.Hash
1620+
_, _, _, leaves, err = trie.DeserializeAndVerifyVerkleProof(block.Header().VerkleProof)
1621+
if err != nil {
1622+
return it.index, err
1623+
}
1624+
statedb.SetStateless(leaves)
1625+
receipts, logs, usedGas, err = bc.processor.ProcessStateless(block, statedb, bc.vmConfig, leaves)
1626+
}
16111627
if err != nil {
16121628
bc.reportBlock(block, receipts, err)
16131629
atomic.StoreUint32(&followupInterrupt, 1)

core/blockchain_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
157157
if err != nil {
158158
return err
159159
}
160-
receipts, _, usedGas, err := blockchain.processor.Process(block, statedb, vm.Config{})
160+
receipts, _, _, usedGas, err := blockchain.processor.Process(block, statedb, vm.Config{})
161161
if err != nil {
162162
blockchain.reportBlock(block, receipts, err)
163163
return err

core/chain_makers.go

+94-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"github.com/ethereum/go-ethereum/core/vm"
2929
"github.com/ethereum/go-ethereum/ethdb"
3030
"github.com/ethereum/go-ethereum/params"
31+
"github.com/ethereum/go-ethereum/trie"
3132
)
3233

3334
// BlockGen creates blocks for testing.
@@ -43,6 +44,7 @@ type BlockGen struct {
4344
txs []*types.Transaction
4445
receipts []*types.Receipt
4546
uncles []*types.Header
47+
witness *types.AccessWitness
4648

4749
config *params.ChainConfig
4850
engine consensus.Engine
@@ -103,10 +105,17 @@ func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) {
103105
b.SetCoinbase(common.Address{})
104106
}
105107
b.statedb.Prepare(tx.Hash(), len(b.txs))
106-
receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{})
108+
receipt, accesses, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{})
107109
if err != nil {
108110
panic(err)
109111
}
112+
if accesses != nil {
113+
if b.witness != nil {
114+
b.witness.Merge(accesses)
115+
} else {
116+
b.witness = accesses
117+
}
118+
}
110119
b.txs = append(b.txs, tx)
111120
b.receipts = append(b.receipts, receipt)
112121
}
@@ -250,6 +259,90 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
250259
return blocks, receipts
251260
}
252261

262+
func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine consensus.Engine, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) {
263+
if config == nil {
264+
config = params.TestChainConfig
265+
}
266+
blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
267+
chainreader := &fakeChainReader{config: config}
268+
genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) {
269+
b := &BlockGen{i: i, chain: blocks, parent: parent, statedb: statedb, config: config, engine: engine, witness: types.NewAccessWitness()}
270+
b.header = makeHeader(chainreader, parent, statedb, b.engine)
271+
272+
// Mutate the state and block according to any hard-fork specs
273+
if daoBlock := config.DAOForkBlock; daoBlock != nil {
274+
limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange)
275+
if b.header.Number.Cmp(daoBlock) >= 0 && b.header.Number.Cmp(limit) < 0 {
276+
if config.DAOForkSupport {
277+
b.header.Extra = common.CopyBytes(params.DAOForkBlockExtra)
278+
}
279+
}
280+
}
281+
if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(b.header.Number) == 0 {
282+
misc.ApplyDAOHardFork(statedb)
283+
}
284+
// Execute any user modifications to the block
285+
if gen != nil {
286+
gen(i, b)
287+
}
288+
if b.engine != nil {
289+
// Finalize and seal the block
290+
block, err := b.engine.FinalizeAndAssemble(chainreader, b.header, statedb, b.txs, b.uncles, b.receipts)
291+
if err != nil {
292+
panic(err)
293+
}
294+
295+
// Write state changes to db
296+
root, err := statedb.Commit(config.IsEIP158(b.header.Number))
297+
if err != nil {
298+
panic(fmt.Sprintf("state write error: %v", err))
299+
}
300+
if err := statedb.Database().TrieDB().Commit(root, false, nil); err != nil {
301+
panic(fmt.Sprintf("trie write error: %v", err))
302+
}
303+
304+
// Generate an associated verkle proof
305+
if tr := statedb.GetTrie(); tr.IsVerkle() {
306+
vtr := tr.(*trie.VerkleTrie)
307+
// Generate the proof if we are using a verkle tree
308+
// WORKAROUND: make sure all keys are resolved
309+
// before building the proof. Ultimately, node
310+
// resolution can be done with a prefetcher or
311+
// from GetCommitmentsAlongPath.
312+
keys := b.witness.Keys()
313+
for _, key := range keys {
314+
out, err := vtr.TryGet(key)
315+
if err != nil {
316+
panic(err)
317+
}
318+
if len(out) == 0 {
319+
panic(fmt.Sprintf("%x should be present in the tree", key))
320+
}
321+
}
322+
vtr.Hash()
323+
_, err := vtr.ProveAndSerialize(keys, b.witness.KeyVals())
324+
//block.SetVerkleProof(p)
325+
if err != nil {
326+
panic(err)
327+
}
328+
}
329+
return block, b.receipts
330+
}
331+
return nil, nil
332+
}
333+
for i := 0; i < n; i++ {
334+
statedb, err := state.New(parent.Root(), state.NewDatabaseWithConfig(db, &trie.Config{UseVerkle: true}), nil)
335+
if err != nil {
336+
panic(err)
337+
}
338+
block, receipt := genblock(i, parent, statedb)
339+
blocks[i] = block
340+
receipts[i] = receipt
341+
parent = block
342+
}
343+
return blocks, receipts
344+
}
345+
253346
func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.StateDB, engine consensus.Engine) *types.Header {
254347
var time uint64
255348
if parent.Time() == 0 {

core/evm.go

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ func NewEVMTxContext(msg Message) vm.TxContext {
6969
return vm.TxContext{
7070
Origin: msg.From(),
7171
GasPrice: new(big.Int).Set(msg.GasPrice()),
72+
Accesses: types.NewAccessWitness(),
7273
}
7374
}
7475

core/genesis.go

+27-2
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,11 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override
180180
// We have the genesis block in database(perhaps in ancient database)
181181
// but the corresponding state is missing.
182182
header := rawdb.ReadHeader(db, stored, 0)
183-
if _, err := state.New(header.Root, state.NewDatabaseWithConfig(db, nil), nil); err != nil {
183+
var cfg *trie.Config = nil
184+
if genesis.Config.UseVerkle {
185+
cfg = &trie.Config{UseVerkle: true}
186+
}
187+
if _, err := state.New(header.Root, state.NewDatabaseWithConfig(db, cfg), nil); err != nil {
184188
if genesis == nil {
185189
genesis = DefaultGenesisBlock()
186190
}
@@ -261,7 +265,11 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
261265
if db == nil {
262266
db = rawdb.NewMemoryDatabase()
263267
}
264-
statedb, err := state.New(common.Hash{}, state.NewDatabase(db), nil)
268+
var trieCfg *trie.Config
269+
if g.Config != nil {
270+
trieCfg = &trie.Config{UseVerkle: g.Config.UseVerkle}
271+
}
272+
statedb, err := state.New(common.Hash{}, state.NewDatabaseWithConfig(db, trieCfg), nil)
265273
if err != nil {
266274
panic(err)
267275
}
@@ -303,6 +311,9 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
303311
}
304312
statedb.Commit(false)
305313
statedb.Database().TrieDB().Commit(root, true, nil)
314+
if err := statedb.Cap(root); err != nil {
315+
panic(err)
316+
}
306317

307318
return types.NewBlock(head, nil, nil, nil, trie.NewStackTrie(nil))
308319
}
@@ -354,6 +365,20 @@ func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big
354365
return g.MustCommit(db)
355366
}
356367

368+
func DefaultVerkleGenesisBlock() *Genesis {
369+
return &Genesis{
370+
Config: params.VerkleChainConfig,
371+
Nonce: 86,
372+
GasLimit: 0x2fefd8,
373+
Difficulty: big.NewInt(1),
374+
Alloc: map[common.Address]GenesisAccount{
375+
common.BytesToAddress([]byte{97, 118, 97, 209, 72, 165, 43, 239, 81, 162, 104, 199, 40, 179, 162, 27, 88, 249, 67, 6}): {
376+
Balance: big.NewInt(0).Lsh(big.NewInt(1), 27),
377+
},
378+
},
379+
}
380+
}
381+
357382
// DefaultGenesisBlock returns the Ethereum main net genesis block.
358383
func DefaultGenesisBlock() *Genesis {
359384
return &Genesis{

0 commit comments

Comments
 (0)