Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions triedb/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ type Config struct {
IsVerkle bool // Flag whether the db is holding a verkle tree
HashDB *hashdb.Config // Configs for hash-based scheme
PathDB *pathdb.Config // Configs for experimental path-based scheme

DBOverride BackendConstructor // Injects an arbitrary backend implementation
}

// HashDefaults represents a config for using hash-based scheme with
Expand Down Expand Up @@ -119,13 +121,16 @@ func NewDatabase(diskdb ethdb.Database, config *Config) *Database {
}
db.backend = hashdb.New(diskdb, config.HashDB, resolver)
}
db.overrideBackend(diskdb, config)
return db
}

// Reader returns a reader for accessing all trie nodes with provided state root.
// An error will be returned if the requested state is not available.
func (db *Database) Reader(blockRoot common.Hash) (database.Reader, error) {
switch b := db.backend.(type) {
case ReaderProvider:
return b.Reader(blockRoot)
case *hashdb.Database:
return b.Reader(blockRoot)
case *pathdb.Database:
Expand Down Expand Up @@ -221,7 +226,7 @@ func (db *Database) InsertPreimage(preimages map[common.Hash][]byte) {
//
// It's only supported by hash-based database and will return an error for others.
func (db *Database) Cap(limit common.StorageSize) error {
hdb, ok := db.backend.(*hashdb.Database)
hdb, ok := db.backend.(HashBackend)
if !ok {
return errors.New("not supported")
}
Expand All @@ -237,7 +242,7 @@ func (db *Database) Cap(limit common.StorageSize) error {
//
// It's only supported by hash-based database and will return an error for others.
func (db *Database) Reference(root common.Hash, parent common.Hash) error {
hdb, ok := db.backend.(*hashdb.Database)
hdb, ok := db.backend.(HashBackend)
if !ok {
return errors.New("not supported")
}
Expand All @@ -248,7 +253,7 @@ func (db *Database) Reference(root common.Hash, parent common.Hash) error {
// Dereference removes an existing reference from a root node. It's only
// supported by hash-based database and will return an error for others.
func (db *Database) Dereference(root common.Hash) error {
hdb, ok := db.backend.(*hashdb.Database)
hdb, ok := db.backend.(HashBackend)
if !ok {
return errors.New("not supported")
}
Expand All @@ -261,7 +266,7 @@ func (db *Database) Dereference(root common.Hash) error {
// corresponding trie histories are existent. It's only supported by path-based
// database and will return an error for others.
func (db *Database) Recover(target common.Hash) error {
pdb, ok := db.backend.(*pathdb.Database)
pdb, ok := db.backend.(PathBackend)
if !ok {
return errors.New("not supported")
}
Expand All @@ -279,7 +284,7 @@ func (db *Database) Recover(target common.Hash) error {
// recovered. It's only supported by path-based database and will return an
// error for others.
func (db *Database) Recoverable(root common.Hash) (bool, error) {
pdb, ok := db.backend.(*pathdb.Database)
pdb, ok := db.backend.(PathBackend)
if !ok {
return false, errors.New("not supported")
}
Expand All @@ -292,7 +297,7 @@ func (db *Database) Recoverable(root common.Hash) (bool, error) {
//
// It's only supported by path-based database and will return an error for others.
func (db *Database) Disable() error {
pdb, ok := db.backend.(*pathdb.Database)
pdb, ok := db.backend.(PathBackend)
if !ok {
return errors.New("not supported")
}
Expand All @@ -302,7 +307,7 @@ func (db *Database) Disable() error {
// Enable activates database and resets the state tree with the provided persistent
// state root once the state sync is finished.
func (db *Database) Enable(root common.Hash) error {
pdb, ok := db.backend.(*pathdb.Database)
pdb, ok := db.backend.(PathBackend)
if !ok {
return errors.New("not supported")
}
Expand All @@ -314,7 +319,7 @@ func (db *Database) Enable(root common.Hash) error {
// flattening everything down (bad for reorgs). It's only supported by path-based
// database and will return an error for others.
func (db *Database) Journal(root common.Hash) error {
pdb, ok := db.backend.(*pathdb.Database)
pdb, ok := db.backend.(PathBackend)
if !ok {
return errors.New("not supported")
}
Expand All @@ -325,7 +330,7 @@ func (db *Database) Journal(root common.Hash) error {
// It's only supported by path-based database and will return an error for
// others.
func (db *Database) SetBufferSize(size int) error {
pdb, ok := db.backend.(*pathdb.Database)
pdb, ok := db.backend.(PathBackend)
if !ok {
return errors.New("not supported")
}
Expand Down
96 changes: 96 additions & 0 deletions triedb/database.libevm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright 2024 the libevm authors.
//
// The libevm additions to go-ethereum are free software: you can redistribute
// them and/or modify them under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// The libevm additions are distributed in the hope that they will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
// General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see
// <http://www.gnu.org/licenses/>.

package triedb

import (
"github.com/ava-labs/libevm/common"
"github.com/ava-labs/libevm/ethdb"
"github.com/ava-labs/libevm/log"
"github.com/ava-labs/libevm/trie/triestate"
"github.com/ava-labs/libevm/triedb/database"
"github.com/ava-labs/libevm/triedb/hashdb"
"github.com/ava-labs/libevm/triedb/pathdb"
)

// Backend defines the intersection of methods shared by [hashdb.Database] and
// [pathdb.Database].
type Backend backend

// A ReaderProvider exposes its underlying Reader as an interface. Both
// [hashdb.Database] and [pathdb.Database] return concrete types so Go's lack of
// support for [covariant types] means that this method can't be defined on
// [Backend].
//
// [covariant types]: https://go.dev/doc/faq#covariant_types
type ReaderProvider interface {
Reader(common.Hash) (database.Reader, error)
}

// A BackendConstructor constructs alternative backend implementations.
type BackendConstructor func(ethdb.Database, *Config) BackendOverride

// A BackendOverride is an arbitrary implementation of a [Database] backend. It
// MUST be either a [HashBackend] or a [PathBackend].
type BackendOverride interface {
Backend
ReaderProvider
}

func (db *Database) overrideBackend(diskdb ethdb.Database, config *Config) {
if config.DBOverride == nil {
return
}
if config.HashDB != nil || config.PathDB != nil {
log.Crit("Database override provided when 'hash' or 'path' mode are configured")
}
db.backend.Close() //nolint:gosec // geth defaults to hashdb instances, which always return nil from Close()

db.backend = config.DBOverride(diskdb, config)
switch db.backend.(type) {
case HashBackend:
case PathBackend:
default:
log.Crit("Database override is neither hash- nor path-based")
}
}

var (
// If either of these break then the respective interface SHOULD be updated.
_ HashBackend = (*hashdb.Database)(nil)
_ PathBackend = (*pathdb.Database)(nil)
)

// A HashBackend mirrors the functionality of a [hashdb.Database].
type HashBackend interface {
Backend

Cap(limit common.StorageSize) error
Reference(root common.Hash, parent common.Hash)
Dereference(root common.Hash)
}

// A PathBackend mirrors the functionality of a [pathdb.Database].
type PathBackend interface {
Backend

Recover(root common.Hash, loader triestate.TrieLoader) error
Recoverable(root common.Hash) bool
Disable() error
Enable(root common.Hash) error
Journal(root common.Hash) error
SetBufferSize(size int) error
}
54 changes: 54 additions & 0 deletions triedb/database.libevm_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright 2024 the libevm authors.
//
// The libevm additions to go-ethereum are free software: you can redistribute
// them and/or modify them under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// The libevm additions are distributed in the hope that they will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
// General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see
// <http://www.gnu.org/licenses/>.

package triedb

import (
"testing"

"github.com/stretchr/testify/require"

"github.com/ava-labs/libevm/common"
"github.com/ava-labs/libevm/ethdb"
"github.com/ava-labs/libevm/triedb/database"
)

func TestDBOverride(t *testing.T) {
config := &Config{
DBOverride: func(d ethdb.Database, c *Config) BackendOverride {
return override{}
},
}

db := NewDatabase(nil, config)
got, err := db.Reader(common.Hash{})
require.NoError(t, err)
if _, ok := got.(reader); !ok {
t.Errorf("with non-nil %T.DBOverride, %T.Reader() got concrete type %T; want %T", config, db, got, reader{})
}
}

type override struct {
PathBackend
}

type reader struct {
database.Reader
}

func (override) Reader(common.Hash) (database.Reader, error) {
return reader{}, nil
}