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>
109 lines
3.1 KiB
Go
109 lines
3.1 KiB
Go
package nomtdb
|
|
|
|
import (
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/ethdb"
|
|
"github.com/ethereum/go-ethereum/log"
|
|
"github.com/ethereum/go-ethereum/nomt/db"
|
|
"github.com/ethereum/go-ethereum/triedb/database"
|
|
)
|
|
|
|
// Database is the NOMT triedb backend. It manages the NOMT trie engine for
|
|
// page-based merkle storage and delegates flat state to geth's ethdb.
|
|
type Database struct {
|
|
diskdb ethdb.Database // geth's existing PebbleDB for flat state + metadata
|
|
nomt *db.DB // NOMT trie engine (Bitbox page storage)
|
|
config *Config
|
|
}
|
|
|
|
// New creates a new NOMT backend. The diskdb is used for flat state storage
|
|
// (accounts, storage slots) and NOMT metadata. The NOMT engine opens its own
|
|
// Bitbox files under config.DataDir.
|
|
func New(diskdb ethdb.Database, config *Config) *Database {
|
|
if config.HTCapacity == 0 {
|
|
config.HTCapacity = Defaults.HTCapacity
|
|
}
|
|
nomtDB, err := db.Open(config.DataDir, db.Config{
|
|
HTCapacity: config.HTCapacity,
|
|
})
|
|
if err != nil {
|
|
log.Crit("Failed to open NOMT database", "err", err)
|
|
}
|
|
return &Database{
|
|
diskdb: diskdb,
|
|
nomt: nomtDB,
|
|
config: config,
|
|
}
|
|
}
|
|
|
|
// NomtDB returns the underlying NOMT trie engine.
|
|
func (d *Database) NomtDB() *db.DB {
|
|
return d.nomt
|
|
}
|
|
|
|
// DiskDB returns the underlying ethdb for flat state access.
|
|
func (d *Database) DiskDB() ethdb.Database {
|
|
return d.diskdb
|
|
}
|
|
|
|
// NodeReader returns a reader for accessing trie nodes within the specified state.
|
|
func (d *Database) NodeReader(root common.Hash) (database.NodeReader, error) {
|
|
return &nodeReader{nomt: d.nomt}, nil
|
|
}
|
|
|
|
// StateReader returns a reader for accessing flat states within the specified state.
|
|
func (d *Database) StateReader(root common.Hash) (database.StateReader, error) {
|
|
return &stateReader{diskdb: d.diskdb}, nil
|
|
}
|
|
|
|
// Size returns the current storage size of the NOMT database.
|
|
// First return is diff layer size (always 0 for NOMT), second is disk size.
|
|
func (d *Database) Size() (common.StorageSize, common.StorageSize) {
|
|
return 0, 0
|
|
}
|
|
|
|
// Commit is a no-op for NOMT — pages are synced during trie Hash()/Commit().
|
|
func (d *Database) Commit(root common.Hash, report bool) error {
|
|
return nil
|
|
}
|
|
|
|
// Close closes the NOMT database backend.
|
|
func (d *Database) Close() error {
|
|
return d.nomt.Close()
|
|
}
|
|
|
|
// Update writes flat state changes to ethdb. The trie pages have already been
|
|
// persisted by the NomtTrie during Hash()/Commit().
|
|
func (d *Database) Update(accounts map[common.Hash][]byte, storages map[common.Hash]map[common.Hash][]byte) error {
|
|
batch := d.diskdb.NewBatch()
|
|
|
|
for accountHash, data := range accounts {
|
|
key := NomtAccountKey(accountHash)
|
|
if len(data) == 0 {
|
|
if err := batch.Delete(key); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
if err := batch.Put(key, data); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
for accountHash, slots := range storages {
|
|
for slotHash, value := range slots {
|
|
key := NomtStorageKey(accountHash, slotHash)
|
|
if len(value) == 0 {
|
|
if err := batch.Delete(key); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
if err := batch.Put(key, value); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return batch.Write()
|
|
}
|