diff --git a/core/overlay/state_transition.go b/core/overlay/state_transition.go index a52d9139c9..44cbdab11d 100644 --- a/core/overlay/state_transition.go +++ b/core/overlay/state_transition.go @@ -17,17 +17,21 @@ package overlay import ( - "bytes" - "encoding/gob" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/trie/bintrie" ) // TransitionState is a structure that holds the progress markers of the // translation process. +// TODO gballet: +// * see if I can get rid of the pointer now that this piece +// has been rewritten. +// * the conversion pointers should no longer be necessary, +// remove them when it's been confirmed. +// * we can't keep the preimage offset in the file type TransitionState struct { CurrentAccountAddress *common.Address // addresss of the last translated account CurrentSlotHash common.Hash // hash of the last translated storage slot @@ -69,38 +73,32 @@ func (ts *TransitionState) Copy() *TransitionState { return ret } +var ( + conversionProgressAddressKey = common.Hash{1} + conversionProgressSlotKey = common.Hash{2} + conversionProgressStorageProcessed = common.Hash{3} +) + // LoadTransitionState retrieves the Verkle transition state associated with // the given state root hash from the database. -func LoadTransitionState(db ethdb.KeyValueReader, root common.Hash, isVerkle bool) *TransitionState { - var ts *TransitionState - - data, _ := rawdb.ReadVerkleTransitionState(db, root) - - // if a state could be read from the db, attempt to decode it - if len(data) > 0 { - var ( - newts TransitionState - buf = bytes.NewBuffer(data[:]) - dec = gob.NewDecoder(buf) - ) - // Decode transition state - err := dec.Decode(&newts) - if err != nil { - log.Error("failed to decode transition state", "err", err) - return nil - } - ts = &newts +func LoadTransitionState(db ethdb.KeyValueReader, root common.Hash) *TransitionState { + stem := bintrie.GetBinaryTreeKeyStorageSlot(params.BinaryTransitionRegistryAddress, conversionProgressAddressKey[:]) + leaf := rawdb.ReadStorageTrieNode(db, common.Hash{}, stem[:bintrie.StemSize]) + if len(leaf) == 0 { + return &TransitionState{} } - // Fallback that should only happen before the transition - if ts == nil { - // Initialize the first transition state, with the "ended" - // field set to true if the database was created - // as a verkle database. - log.Debug("no transition state found, starting fresh", "verkle", isVerkle) - - // Start with a fresh state - ts = &TransitionState{Ended: isVerkle} + node, err := bintrie.DeserializeNode(leaf, 0) + if err != nil { + panic("could not deserialize conversion pointers contract storage") + } + leafNode := node.(*bintrie.StemNode) + currentAccount := common.BytesToAddress(leafNode.Values[65][12:]) + currentSlotHash := common.BytesToHash(leafNode.Values[66]) + storageProcessed := len(leafNode.Values[67]) > 0 && leafNode.Values[67][0] != 0 + return &TransitionState{ + CurrentAccountAddress: ¤tAccount, + CurrentSlotHash: currentSlotHash, + StorageProcessed: storageProcessed, } - return ts } diff --git a/core/state/database.go b/core/state/database.go index 4a5547d075..99a8349537 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -239,15 +239,24 @@ func (db *CachingDB) ReadersWithCacheStats(stateRoot common.Hash) (ReaderWithSta // OpenTrie opens the main account trie at a specific root hash. func (db *CachingDB) OpenTrie(root common.Hash) (Trie, error) { if db.triedb.IsVerkle() { - ts := overlay.LoadTransitionState(db.TrieDB().Disk(), root, db.triedb.IsVerkle()) - if ts.InTransition() { - panic("state tree transition isn't supported yet") + // if the transition has started, it will be present in the overlay tree, + // so we open it regardless. + bt, err := bintrie.NewBinaryTrie(root, db.triedb) + if err != nil { + return nil, fmt.Errorf("could not open the overlay tree: %w", err) } - if ts.Transitioned() { + ts := overlay.LoadTransitionState(db.TrieDB().Disk(), root) + if !ts.InTransition() { // Use BinaryTrie instead of VerkleTrie when IsVerkle is set // (IsVerkle actually means Binary Trie mode in this codebase) - return bintrie.NewBinaryTrie(root, db.triedb) + return bt, nil } + + base, err := trie.NewStateTrie(trie.StateTrieID(root), db.triedb) + if err != nil { + return nil, fmt.Errorf("could not create base trie in OpenTrie: %w", err) + } + return transitiontrie.NewTransitionTrie(base, bt, false), nil } tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.triedb) if err != nil { diff --git a/core/state/reader.go b/core/state/reader.go index 35b732173b..6191cf7944 100644 --- a/core/state/reader.go +++ b/core/state/reader.go @@ -330,7 +330,7 @@ func newTrieReader(root common.Hash, db *triedb.Database) (*trieReader, error) { // Based on the transition status, determine if the overlay // tree needs to be created, or if a single, target tree is // to be picked. - ts := overlay.LoadTransitionState(db.Disk(), root, true) + ts := overlay.LoadTransitionState(db.Disk(), root) if ts.InTransition() { mpt, err := trie.NewStateTrie(trie.StateTrieID(ts.BaseRoot), db) if err != nil { diff --git a/core/state/statedb.go b/core/state/statedb.go index 610e7173cf..294f5f719d 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -349,6 +349,17 @@ func (s *StateDB) GetStorageRoot(addr common.Address) common.Hash { return common.Hash{} } +// TransitionComplete checks if the EIP-7612 transition is complete. +func (s *StateDB) InTransition() bool { + completeKey := common.Hash{} // slot 0 for completion flag + completeValue := s.GetState(params.BinaryTransitionRegistryAddress, completeKey) + return completeValue != (common.Hash{}) +} + +func (s *StateDB) ProcessBinaryTreeTransition(maxSlot uint64) { + +} + // TxIndex returns the current transaction index set by SetTxContext. func (s *StateDB) TxIndex() int { return s.txIndex diff --git a/params/protocol_params.go b/params/protocol_params.go index bb506af015..60c0cfe51e 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -219,4 +219,7 @@ var ( // EIP-7251 - Increase the MAX_EFFECTIVE_BALANCE ConsolidationQueueAddress = common.HexToAddress("0x0000BBdDc7CE488642fb579F8B00f3a590007251") ConsolidationQueueCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd") + + // EIP-7612 - Tree transition registry contract address + BinaryTransitionRegistryAddress = common.HexToAddress("0x1622162216221622162216221622162216221622162216221622162216221622") )