|
17 | 17 | package state
|
18 | 18 |
|
19 | 19 | import (
|
| 20 | + "bytes" |
| 21 | + "encoding/gob" |
20 | 22 | "errors"
|
21 | 23 | "fmt"
|
| 24 | + "runtime/debug" |
| 25 | + "sync" |
22 | 26 |
|
23 | 27 | "github.com/ethereum/go-ethereum/common"
|
24 | 28 | "github.com/ethereum/go-ethereum/common/lru"
|
@@ -102,6 +106,10 @@ type Database interface {
|
102 | 106 | SaveTransitionState(common.Hash)
|
103 | 107 |
|
104 | 108 | LoadTransitionState(common.Hash)
|
| 109 | + |
| 110 | + LockCurrentTransitionState() |
| 111 | + |
| 112 | + UnLockCurrentTransitionState() |
105 | 113 | }
|
106 | 114 |
|
107 | 115 | // Trie is a Ethereum Merkle Patricia trie.
|
@@ -189,22 +197,24 @@ func NewDatabase(db ethdb.Database) Database {
|
189 | 197 | // large memory cache.
|
190 | 198 | func NewDatabaseWithConfig(db ethdb.Database, config *trie.Config) Database {
|
191 | 199 | return &cachingDB{
|
192 |
| - disk: db, |
193 |
| - codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), |
194 |
| - codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), |
195 |
| - triedb: trie.NewDatabaseWithConfig(db, config), |
196 |
| - addrToPoint: utils.NewPointCache(), |
| 200 | + disk: db, |
| 201 | + codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), |
| 202 | + codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), |
| 203 | + triedb: trie.NewDatabaseWithConfig(db, config), |
| 204 | + addrToPoint: utils.NewPointCache(), |
| 205 | + TransitionStatePerRoot: lru.NewBasicLRU[common.Hash, *TransitionState](100), |
197 | 206 | }
|
198 | 207 | }
|
199 | 208 |
|
200 | 209 | // NewDatabaseWithNodeDB creates a state database with an already initialized node database.
|
201 | 210 | func NewDatabaseWithNodeDB(db ethdb.Database, triedb *trie.Database) Database {
|
202 | 211 | return &cachingDB{
|
203 |
| - disk: db, |
204 |
| - codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), |
205 |
| - codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), |
206 |
| - triedb: triedb, |
207 |
| - addrToPoint: utils.NewPointCache(), |
| 212 | + disk: db, |
| 213 | + codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), |
| 214 | + codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), |
| 215 | + triedb: triedb, |
| 216 | + addrToPoint: utils.NewPointCache(), |
| 217 | + TransitionStatePerRoot: lru.NewBasicLRU[common.Hash, *TransitionState](100), |
208 | 218 | }
|
209 | 219 | }
|
210 | 220 |
|
@@ -305,12 +315,12 @@ type cachingDB struct {
|
305 | 315 | // TODO ensure that this info is in the DB
|
306 | 316 | LastMerkleRoot common.Hash // root hash of the read-only base tree
|
307 | 317 | CurrentTransitionState *TransitionState
|
308 |
| - TransitionStatePerRoot map[common.Hash]*TransitionState |
| 318 | + TransitionStatePerRoot lru.BasicLRU[common.Hash, *TransitionState] |
| 319 | + transitionStateLock sync.Mutex |
309 | 320 |
|
310 | 321 | addrToPoint *utils.PointCache
|
311 | 322 |
|
312 | 323 | baseRoot common.Hash // hash of the read-only base tree
|
313 |
| - |
314 | 324 | }
|
315 | 325 |
|
316 | 326 | func (db *cachingDB) openMPTTrie(root common.Hash) (Trie, error) {
|
@@ -543,37 +553,82 @@ func (db *cachingDB) SetLastMerkleRoot(merkleRoot common.Hash) {
|
543 | 553 | }
|
544 | 554 |
|
545 | 555 | func (db *cachingDB) SaveTransitionState(root common.Hash) {
|
546 |
| - if db.TransitionStatePerRoot == nil { |
547 |
| - db.TransitionStatePerRoot = make(map[common.Hash]*TransitionState) |
548 |
| - } |
549 |
| - |
| 556 | + db.transitionStateLock.Lock() |
| 557 | + defer db.transitionStateLock.Unlock() |
550 | 558 | if db.CurrentTransitionState != nil {
|
551 |
| - // Copy so that the address pointer isn't updated after |
552 |
| - // it has been saved. |
553 |
| - db.TransitionStatePerRoot[root] = db.CurrentTransitionState.Copy() |
| 559 | + var buf bytes.Buffer |
| 560 | + enc := gob.NewEncoder(&buf) |
| 561 | + err := enc.Encode(db.CurrentTransitionState) |
| 562 | + if err != nil { |
| 563 | + log.Error("failed to encode transition state", "err", err) |
| 564 | + return |
| 565 | + } |
| 566 | + |
| 567 | + if !db.TransitionStatePerRoot.Contains(root) { |
| 568 | + // Copy so that the address pointer isn't updated after |
| 569 | + // it has been saved. |
| 570 | + db.TransitionStatePerRoot.Add(root, db.CurrentTransitionState.Copy()) |
| 571 | + |
| 572 | + rawdb.WriteVerkleTransitionState(db.DiskDB(), root, buf.Bytes()) |
| 573 | + } |
554 | 574 |
|
555 |
| - fmt.Println("saving transition state", "storage processed", db.CurrentTransitionState.StorageProcessed, "addr", db.CurrentTransitionState.CurrentAccountAddress, "slot hash", db.CurrentTransitionState.CurrentSlotHash, "root", root, "ended", db.CurrentTransitionState.ended, "started", db.CurrentTransitionState.started) |
| 575 | + log.Debug("saving transition state", "storage processed", db.CurrentTransitionState.StorageProcessed, "addr", db.CurrentTransitionState.CurrentAccountAddress, "slot hash", db.CurrentTransitionState.CurrentSlotHash, "root", root, "ended", db.CurrentTransitionState.ended, "started", db.CurrentTransitionState.started) |
556 | 576 | }
|
557 | 577 | }
|
558 | 578 |
|
559 | 579 | func (db *cachingDB) LoadTransitionState(root common.Hash) {
|
560 |
| - if db.TransitionStatePerRoot == nil { |
561 |
| - db.TransitionStatePerRoot = make(map[common.Hash]*TransitionState) |
562 |
| - } |
| 580 | + db.transitionStateLock.Lock() |
| 581 | + defer db.transitionStateLock.Unlock() |
| 582 | + // Try to get the transition state from the cache and |
| 583 | + // the DB if it's not there. |
| 584 | + ts, ok := db.TransitionStatePerRoot.Get(root) |
| 585 | + if !ok { |
| 586 | + // Not in the cache, try getting it from the DB |
| 587 | + data, err := rawdb.ReadVerkleTransitionState(db.DiskDB(), root) |
| 588 | + if err != nil { |
| 589 | + log.Error("failed to read transition state", "err", err) |
| 590 | + return |
| 591 | + } |
| 592 | + |
| 593 | + // if a state could be read from the db, attempt to decode it |
| 594 | + if len(data) > 0 { |
| 595 | + var ( |
| 596 | + newts TransitionState |
| 597 | + buf = bytes.NewBuffer(data[:]) |
| 598 | + dec = gob.NewDecoder(buf) |
| 599 | + ) |
| 600 | + // Decode transition state |
| 601 | + err = dec.Decode(&newts) |
| 602 | + if err != nil { |
| 603 | + log.Error("failed to decode transition state", "err", err) |
| 604 | + return |
| 605 | + } |
| 606 | + ts = &newts |
| 607 | + } |
563 | 608 |
|
564 |
| - // Initialize the first transition state, with the "ended" |
565 |
| - // field set to true if the database was created |
566 |
| - // as a verkle database. |
567 |
| - ts, ok := db.TransitionStatePerRoot[root] |
568 |
| - if !ok || ts == nil { |
569 |
| - fmt.Println("could not find any transition state, starting with a fresh state", "is verkle", db.triedb.IsVerkle()) |
570 |
| - // Start with a fresh state |
571 |
| - ts = &TransitionState{ended: false} |
| 609 | + // Fallback that should only happen before the transition |
| 610 | + if ts == nil { |
| 611 | + // Initialize the first transition state, with the "ended" |
| 612 | + // field set to true if the database was created |
| 613 | + // as a verkle database. |
| 614 | + log.Debug("no transition state found, starting fresh", "is verkle", db.triedb.IsVerkle()) |
| 615 | + // Start with a fresh state |
| 616 | + ts = &TransitionState{ended: db.triedb.IsVerkle()} |
| 617 | + } |
572 | 618 | }
|
573 | 619 |
|
574 | 620 | // Copy so that the CurrentAddress pointer in the map
|
575 | 621 | // doesn't get overwritten.
|
576 | 622 | db.CurrentTransitionState = ts.Copy()
|
577 | 623 |
|
578 |
| - fmt.Println("loaded transition state", "storage processed", db.CurrentTransitionState.StorageProcessed, "addr", db.CurrentTransitionState.CurrentAccountAddress, "slot hash", db.CurrentTransitionState.CurrentSlotHash, "root", root, "ended", db.CurrentTransitionState.ended, "started", db.CurrentTransitionState.started) |
| 624 | + log.Debug("loaded transition state", "storage processed", db.CurrentTransitionState.StorageProcessed, "addr", db.CurrentTransitionState.CurrentAccountAddress, "slot hash", db.CurrentTransitionState.CurrentSlotHash, "root", root, "ended", db.CurrentTransitionState.ended, "started", db.CurrentTransitionState.started) |
| 625 | + debug.PrintStack() |
| 626 | +} |
| 627 | + |
| 628 | +func (db *cachingDB) LockCurrentTransitionState() { |
| 629 | + db.transitionStateLock.Lock() |
| 630 | +} |
| 631 | + |
| 632 | +func (db *cachingDB) UnLockCurrentTransitionState() { |
| 633 | + db.transitionStateLock.Unlock() |
579 | 634 | }
|
0 commit comments