mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-23 23:24:30 +00:00
Wire the NOMT binary merkle trie engine into geth's triedb/state framework. This adds two new packages: - triedb/nomtdb: backend implementing triedb.backend interface, manages flat state persistence in ethdb and delegates trie ops to nomt/db - trie/nomttrie: NomtTrie implementing state.Trie, accumulates LeafOps during block execution and flushes to NOMT engine on Hash()/Commit() Key design choices: - Single flat keyspace: accounts use keccak256(addr), storage uses keccak256(keccak256(addr) || keccak256(slot)) as 256-bit trie paths - OpenStorageTrie returns the account trie itself (no separate tries) - Flat state (account/storage values) stored in ethdb with prefixed keys - NOMT trie stores only hashes; reads delegate to ethdb flat state Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
84 lines
2.6 KiB
Go
84 lines
2.6 KiB
Go
package nomtdb
|
|
|
|
import (
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/ethereum/go-ethereum/ethdb"
|
|
"github.com/ethereum/go-ethereum/nomt/db"
|
|
"github.com/ethereum/go-ethereum/rlp"
|
|
)
|
|
|
|
// Key prefixes for NOMT flat state in ethdb.
|
|
const (
|
|
nomtAccountPrefix byte = 0x01
|
|
nomtStoragePrefix byte = 0x02
|
|
)
|
|
|
|
// NomtAccountKey returns the ethdb key for an account's flat state.
|
|
// Format: 0x01 || accountHash (32 bytes)
|
|
func NomtAccountKey(accountHash common.Hash) []byte {
|
|
key := make([]byte, 1+common.HashLength)
|
|
key[0] = nomtAccountPrefix
|
|
copy(key[1:], accountHash[:])
|
|
return key
|
|
}
|
|
|
|
// NomtStorageKey returns the ethdb key for a storage slot's flat state.
|
|
// Format: 0x02 || accountHash (32 bytes) || slotHash (32 bytes)
|
|
func NomtStorageKey(accountHash, slotHash common.Hash) []byte {
|
|
key := make([]byte, 1+2*common.HashLength)
|
|
key[0] = nomtStoragePrefix
|
|
copy(key[1:], accountHash[:])
|
|
copy(key[1+common.HashLength:], slotHash[:])
|
|
return key
|
|
}
|
|
|
|
// nodeReader implements database.NodeReader backed by the NOMT page store.
|
|
//
|
|
// In NOMT, trie data is stored as pages (126 nodes each), not individual nodes.
|
|
// This reader extracts individual nodes from pages for compatibility with
|
|
// geth's node-oriented interfaces.
|
|
type nodeReader struct {
|
|
nomt *db.DB
|
|
}
|
|
|
|
// Node retrieves a trie node blob. For NOMT, this is a compatibility shim —
|
|
// the NomtTrie accesses pages directly rather than going through NodeReader.
|
|
func (r *nodeReader) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) {
|
|
// NOMT trie operations go through the page-based engine directly.
|
|
// This reader exists to satisfy the interface; the NomtTrie doesn't
|
|
// use it for normal trie operations.
|
|
return nil, nil
|
|
}
|
|
|
|
// stateReader implements database.StateReader backed by NOMT's flat state
|
|
// stored in geth's ethdb.
|
|
type stateReader struct {
|
|
diskdb ethdb.Database
|
|
}
|
|
|
|
// Account retrieves an account from NOMT's flat state storage.
|
|
func (r *stateReader) Account(hash common.Hash) (*types.SlimAccount, error) {
|
|
data, err := r.diskdb.Get(NomtAccountKey(hash))
|
|
if err != nil {
|
|
// Key not found is not an error — return nil account.
|
|
return nil, nil
|
|
}
|
|
if len(data) == 0 {
|
|
return nil, nil
|
|
}
|
|
account := new(types.SlimAccount)
|
|
if err := rlp.DecodeBytes(data, account); err != nil {
|
|
return nil, err
|
|
}
|
|
return account, nil
|
|
}
|
|
|
|
// Storage retrieves a storage slot from NOMT's flat state storage.
|
|
func (r *stateReader) Storage(accountHash, storageHash common.Hash) ([]byte, error) {
|
|
data, err := r.diskdb.Get(NomtStorageKey(accountHash, storageHash))
|
|
if err != nil {
|
|
return nil, nil
|
|
}
|
|
return data, nil
|
|
}
|