Skip to content

Commit 4d0e694

Browse files
committed
Allow using MPT
1 parent 447fed2 commit 4d0e694

38 files changed

+931
-83
lines changed

cmd/geth/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ var (
150150
utils.ScrollAlphaFlag,
151151
utils.ScrollSepoliaFlag,
152152
utils.ScrollFlag,
153+
utils.ScrollMPTFlag,
153154
utils.VMEnableDebugFlag,
154155
utils.NetworkIdFlag,
155156
utils.EthStatsURLFlag,

cmd/geth/usage.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ var AppHelpFlagGroups = []flags.FlagGroup{
5050
utils.ScrollAlphaFlag,
5151
utils.ScrollSepoliaFlag,
5252
utils.ScrollFlag,
53+
utils.ScrollMPTFlag,
5354
utils.SyncModeFlag,
5455
utils.ExitWhenSyncedFlag,
5556
utils.GCModeFlag,

cmd/utils/flags.go

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,10 @@ var (
183183
Name: "scroll",
184184
Usage: "Scroll mainnet",
185185
}
186+
ScrollMPTFlag = cli.BoolFlag{
187+
Name: "scroll-mpt",
188+
Usage: "Use MPT trie for state storage",
189+
}
186190
DeveloperFlag = cli.BoolFlag{
187191
Name: "dev",
188192
Usage: "Ephemeral proof-of-authority network with a pre-funded developer account, mining enabled",
@@ -1879,12 +1883,15 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
18791883
stack.Config().L1Confirmations = rpc.FinalizedBlockNumber
18801884
log.Info("Setting flag", "--l1.sync.startblock", "4038000")
18811885
stack.Config().L1DeploymentBlock = 4038000
1882-
// disable pruning
1883-
if ctx.GlobalString(GCModeFlag.Name) != GCModeArchive {
1884-
log.Crit("Must use --gcmode=archive")
1886+
cfg.Genesis.Config.Scroll.UseZktrie = !ctx.GlobalBool(ScrollMPTFlag.Name)
1887+
if cfg.Genesis.Config.Scroll.UseZktrie {
1888+
// disable pruning
1889+
if ctx.GlobalString(GCModeFlag.Name) != GCModeArchive {
1890+
log.Crit("Must use --gcmode=archive")
1891+
}
1892+
log.Info("Pruning disabled")
1893+
cfg.NoPruning = true
18851894
}
1886-
log.Info("Pruning disabled")
1887-
cfg.NoPruning = true
18881895
case ctx.GlobalBool(ScrollFlag.Name):
18891896
if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
18901897
cfg.NetworkId = 534352
@@ -1895,12 +1902,15 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
18951902
stack.Config().L1Confirmations = rpc.FinalizedBlockNumber
18961903
log.Info("Setting flag", "--l1.sync.startblock", "18306000")
18971904
stack.Config().L1DeploymentBlock = 18306000
1898-
// disable pruning
1899-
if ctx.GlobalString(GCModeFlag.Name) != GCModeArchive {
1900-
log.Crit("Must use --gcmode=archive")
1905+
cfg.Genesis.Config.Scroll.UseZktrie = !ctx.GlobalBool(ScrollMPTFlag.Name)
1906+
if cfg.Genesis.Config.Scroll.UseZktrie {
1907+
// disable pruning
1908+
if ctx.GlobalString(GCModeFlag.Name) != GCModeArchive {
1909+
log.Crit("Must use --gcmode=archive")
1910+
}
1911+
log.Info("Pruning disabled")
1912+
cfg.NoPruning = true
19011913
}
1902-
log.Info("Pruning disabled")
1903-
cfg.NoPruning = true
19041914
case ctx.GlobalBool(DeveloperFlag.Name):
19051915
if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
19061916
cfg.NetworkId = 1337

core/block_validator.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,8 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
226226
}
227227
// Validate the state root against the received state root and throw
228228
// an error if they don't match.
229-
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
229+
shouldValidateStateRoot := v.config.Scroll.UseZktrie != v.config.IsEuclid(header.Time)
230+
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); shouldValidateStateRoot && header.Root != root {
230231
return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root)
231232
}
232233
return nil

core/blockchain.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1318,6 +1318,9 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
13181318
return NonStatTy, err
13191319
}
13201320
triedb := bc.stateCache.TrieDB()
1321+
if block.Root() != root {
1322+
rawdb.WriteDiskStateRoot(bc.db, block.Root(), root)
1323+
}
13211324

13221325
// If we're running an archive node, always flush
13231326
if bc.cacheConfig.TrieDirtyDisabled {
@@ -1677,7 +1680,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
16771680
}
16781681

16791682
// Enable prefetching to pull in trie node paths while processing transactions
1680-
statedb.StartPrefetcher("chain")
1683+
statedb.StartPrefetcher("chain", nil)
16811684
activeState = statedb
16821685

16831686
// If we have a followup block, run that against the current state to pre-cache
@@ -1814,7 +1817,7 @@ func (bc *BlockChain) BuildAndWriteBlock(parentBlock *types.Block, header *types
18141817
return NonStatTy, err
18151818
}
18161819

1817-
statedb.StartPrefetcher("l1sync")
1820+
statedb.StartPrefetcher("l1sync", nil)
18181821
defer statedb.StopPrefetcher()
18191822

18201823
header.ParentHash = parentBlock.Hash()

core/blockchain_test.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3032,15 +3032,16 @@ func TestPoseidonCodeHash(t *testing.T) {
30323032
var callCreate2Code = common.Hex2Bytes("f4754f660000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000005c6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220707985753fcb6578098bb16f3709cf6d012993cba6dd3712661cf8f57bbc0d4d64736f6c6343000807003300000000")
30333033

30343034
var (
3035-
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
3036-
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
3037-
db = rawdb.NewMemoryDatabase()
3038-
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}}
3039-
genesis = gspec.MustCommit(db)
3040-
signer = types.LatestSigner(gspec.Config)
3041-
engine = ethash.NewFaker()
3042-
blockchain, _ = NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil)
3035+
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
3036+
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
3037+
db = rawdb.NewMemoryDatabase()
3038+
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}}
3039+
signer = types.LatestSigner(gspec.Config)
3040+
engine = ethash.NewFaker()
30433041
)
3042+
gspec.Config.Scroll.UseZktrie = true
3043+
genesis := gspec.MustCommit(db)
3044+
blockchain, _ := NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil)
30443045

30453046
defer blockchain.Stop()
30463047

@@ -3724,6 +3725,7 @@ func TestCurieTransition(t *testing.T) {
37243725
config.CurieBlock = big.NewInt(2)
37253726
config.DarwinTime = nil
37263727
config.DarwinV2Time = nil
3728+
config.Scroll.UseZktrie = true
37273729

37283730
var (
37293731
db = rawdb.NewMemoryDatabase()
@@ -3748,7 +3750,7 @@ func TestCurieTransition(t *testing.T) {
37483750
number := block.Number().Uint64()
37493751
baseFee := block.BaseFee()
37503752

3751-
statedb, _ := state.New(block.Root(), state.NewDatabase(db), nil)
3753+
statedb, _ := state.New(block.Root(), state.NewDatabaseWithConfig(db, &trie.Config{Zktrie: gspec.Config.Scroll.UseZktrie}), nil)
37523754

37533755
code := statedb.GetCode(rcfg.L1GasPriceOracleAddress)
37543756
codeSize := statedb.GetCodeSize(rcfg.L1GasPriceOracleAddress)

core/chain_makers.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/scroll-tech/go-ethereum/ethdb"
3030
"github.com/scroll-tech/go-ethereum/params"
3131
"github.com/scroll-tech/go-ethereum/rollup/fees"
32+
"github.com/scroll-tech/go-ethereum/trie"
3233
)
3334

3435
// BlockGen creates blocks for testing.
@@ -264,7 +265,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
264265
return nil, nil
265266
}
266267
for i := 0; i < n; i++ {
267-
statedb, err := state.New(parent.Root(), state.NewDatabase(db), nil)
268+
statedb, err := state.New(parent.Root(), state.NewDatabaseWithConfig(db, &trie.Config{Zktrie: config.Scroll.ZktrieEnabled()}), nil)
268269
if err != nil {
269270
panic(err)
270271
}

core/genesis.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,10 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
322322
}
323323
statedb.Commit(false)
324324
statedb.Database().TrieDB().Commit(root, true, nil)
325-
325+
if g.Config != nil && g.Config.Scroll.GenesisStateRoot != nil {
326+
head.Root = *g.Config.Scroll.GenesisStateRoot
327+
rawdb.WriteDiskStateRoot(db, head.Root, root)
328+
}
326329
return types.NewBlock(head, nil, nil, nil, trie.NewStackTrie(nil))
327330
}
328331

core/rawdb/accessors_state.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,17 @@ func DeleteTrieNode(db ethdb.KeyValueWriter, hash common.Hash) {
9494
log.Crit("Failed to delete trie node", "err", err)
9595
}
9696
}
97+
98+
func WriteDiskStateRoot(db ethdb.KeyValueWriter, headerRoot, diskRoot common.Hash) {
99+
if err := db.Put(diskStateRootKey(headerRoot), diskRoot.Bytes()); err != nil {
100+
log.Crit("Failed to store disk state root", "err", err)
101+
}
102+
}
103+
104+
func ReadDiskStateRoot(db ethdb.KeyValueReader, headerRoot common.Hash) (common.Hash, error) {
105+
data, err := db.Get(diskStateRootKey(headerRoot))
106+
if err != nil {
107+
return common.Hash{}, err
108+
}
109+
return common.BytesToHash(data), nil
110+
}

core/rawdb/schema.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ var (
127127

128128
// Scroll da syncer store
129129
daSyncedL1BlockNumberKey = []byte("LastDASyncedL1BlockNumber")
130+
131+
diskStateRootPrefix = []byte("disk-state-root")
130132
)
131133

132134
// Use the updated "L1" prefix on all new networks
@@ -312,3 +314,7 @@ func batchMetaKey(batchIndex uint64) []byte {
312314
func committedBatchMetaKey(batchIndex uint64) []byte {
313315
return append(committedBatchMetaPrefix, encodeBigEndian(batchIndex)...)
314316
}
317+
318+
func diskStateRootKey(headerRoot common.Hash) []byte {
319+
return append(diskStateRootPrefix, headerRoot.Bytes()...)
320+
}

core/state/database.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ type Trie interface {
105105
// nodes of the longest existing prefix of the key (at least the root), ending
106106
// with the node that proves the absence of the key.
107107
Prove(key []byte, fromLevel uint, proofDb ethdb.KeyValueWriter) error
108+
109+
// Witness returns a set containing all trie nodes that have been accessed.
110+
Witness() map[string]struct{}
108111
}
109112

110113
// NewDatabase creates a backing store for state. The returned database is safe for
@@ -136,6 +139,9 @@ type cachingDB struct {
136139

137140
// OpenTrie opens the main account trie at a specific root hash.
138141
func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
142+
if diskRoot, err := rawdb.ReadDiskStateRoot(db.db.DiskDB(), root); err == nil {
143+
root = diskRoot
144+
}
139145
if db.zktrie {
140146
tr, err := trie.NewZkTrie(root, trie.NewZktrieDatabaseFromTriedb(db.db))
141147
if err != nil {

core/state/snapshot/generate.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -618,8 +618,8 @@ func (dl *diskLayer) generate(stats *generatorStats) {
618618
Balance *big.Int
619619
Root common.Hash
620620
KeccakCodeHash []byte
621-
PoseidonCodeHash []byte
622-
CodeSize uint64
621+
PoseidonCodeHash []byte `rlp:"-"`
622+
CodeSize uint64 `rlp:"-"`
623623
}
624624
if err := rlp.DecodeBytes(val, &acc); err != nil {
625625
log.Crit("Invalid account encountered during snapshot creation", "err", err)

core/state/state_object.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -500,8 +500,18 @@ func (s *stateObject) Code(db Database) []byte {
500500
// CodeSize returns the size of the contract code associated with this object,
501501
// or zero if none. This method is an almost mirror of Code, but uses a cache
502502
// inside the database to avoid loading codes seen recently.
503-
func (s *stateObject) CodeSize() uint64 {
504-
return s.data.CodeSize
503+
func (s *stateObject) CodeSize(db Database) uint64 {
504+
if s.code != nil {
505+
return uint64(len(s.code))
506+
}
507+
if bytes.Equal(s.KeccakCodeHash(), emptyKeccakCodeHash) {
508+
return 0
509+
}
510+
size, err := db.ContractCodeSize(s.addrHash, common.BytesToHash(s.KeccakCodeHash()))
511+
if err != nil {
512+
s.setError(fmt.Errorf("can't load code size %x: %v", s.KeccakCodeHash(), err))
513+
}
514+
return uint64(size)
505515
}
506516

507517
func (s *stateObject) SetCode(code []byte) {
@@ -534,6 +544,9 @@ func (s *stateObject) setNonce(nonce uint64) {
534544
}
535545

536546
func (s *stateObject) PoseidonCodeHash() []byte {
547+
if !s.db.IsZktrie() {
548+
panic("PoseidonCodeHash is only available in zktrie mode")
549+
}
537550
return s.data.PoseidonCodeHash
538551
}
539552

core/state/state_test.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,8 @@ func TestSnapshotEmpty(t *testing.T) {
155155
}
156156

157157
func TestSnapshot2(t *testing.T) {
158-
state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil)
158+
stateDb := NewDatabase(rawdb.NewMemoryDatabase())
159+
state, _ := New(common.Hash{}, stateDb, nil)
159160

160161
stateobjaddr0 := common.BytesToAddress([]byte("so0"))
161162
stateobjaddr1 := common.BytesToAddress([]byte("so1"))
@@ -201,7 +202,7 @@ func TestSnapshot2(t *testing.T) {
201202
so0Restored.GetState(state.db, storageaddr)
202203
so0Restored.Code(state.db)
203204
// non-deleted is equal (restored)
204-
compareStateObjects(so0Restored, so0, t)
205+
compareStateObjects(so0Restored, so0, stateDb, t)
205206

206207
// deleted should be nil, both before and after restore of state copy
207208
so1Restored := state.getStateObject(stateobjaddr1)
@@ -210,7 +211,7 @@ func TestSnapshot2(t *testing.T) {
210211
}
211212
}
212213

213-
func compareStateObjects(so0, so1 *stateObject, t *testing.T) {
214+
func compareStateObjects(so0, so1 *stateObject, db Database, t *testing.T) {
214215
if so0.Address() != so1.Address() {
215216
t.Fatalf("Address mismatch: have %v, want %v", so0.address, so1.address)
216217
}
@@ -229,8 +230,8 @@ func compareStateObjects(so0, so1 *stateObject, t *testing.T) {
229230
if !bytes.Equal(so0.PoseidonCodeHash(), so1.PoseidonCodeHash()) {
230231
t.Fatalf("PoseidonCodeHash mismatch: have %v, want %v", so0.PoseidonCodeHash(), so1.PoseidonCodeHash())
231232
}
232-
if so0.CodeSize() != so1.CodeSize() {
233-
t.Fatalf("CodeSize mismatch: have %v, want %v", so0.CodeSize(), so1.CodeSize())
233+
if so0.CodeSize(db) != so1.CodeSize(db) {
234+
t.Fatalf("CodeSize mismatch: have %v, want %v", so0.CodeSize(db), so1.CodeSize(db))
234235
}
235236
if !bytes.Equal(so0.code, so1.code) {
236237
t.Fatalf("Code mismatch: have %v, want %v", so0.code, so1.code)

0 commit comments

Comments
 (0)