diff --git a/triedb/database.go b/triedb/database.go index c1e6f9af4e..d891130b68 100644 --- a/triedb/database.go +++ b/triedb/database.go @@ -17,8 +17,6 @@ package triedb import ( - "errors" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" @@ -86,6 +84,21 @@ type backend interface { // 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. Reader(root common.Hash) (database.Reader, error) + + // These methods have a one-to-one correspondence with methods exposed by + // [Database]. Refer to the respective documentation for their behavior. + Cap(limit common.StorageSize) error + Reference(root, parent common.Hash) error + Dereference(root common.Hash) error + Recover(target common.Hash) error + Recoverable(root common.Hash) (bool, error) + Disable() error + Enable(root common.Hash) error + Journal(root common.Hash) error + SetBufferSize(int) error + AccountHistory(_ common.Address, start, end uint64) (*pathdb.HistoryStats, error) + StorageHistory(_ common.Address, slot common.Hash, start, end uint64) (*pathdb.HistoryStats, error) + HistoryRange() (uint64, uint64, error) } // Database is the wrapper of the underlying backend which is shared by different @@ -221,14 +234,10 @@ 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) - if !ok { - return errors.New("not supported") - } if db.preimages != nil { db.preimages.commit(false) } - return hdb.Cap(limit) + return db.backend.Cap(limit) } // Reference adds a new reference from a parent node to a child node. This function @@ -237,23 +246,13 @@ 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) - if !ok { - return errors.New("not supported") - } - hdb.Reference(root, parent) - return nil + return db.backend.Reference(root, parent) } // 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) - if !ok { - return errors.New("not supported") - } - hdb.Dereference(root) - return nil + return db.backend.Dereference(root) } // Recover rollbacks the database to a specified historical point. The state is @@ -261,22 +260,14 @@ 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) - if !ok { - return errors.New("not supported") - } - return pdb.Recover(target) + return db.backend.Recover(target) } // Recoverable returns the indicator if the specified state is enabled to be // 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) - if !ok { - return false, errors.New("not supported") - } - return pdb.Recoverable(root), nil + return db.backend.Recoverable(root) } // Disable deactivates the database and invalidates all available state layers @@ -285,21 +276,13 @@ 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) - if !ok { - return errors.New("not supported") - } - return pdb.Disable() + return db.backend.Disable() } // 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) - if !ok { - return errors.New("not supported") - } - return pdb.Enable(root) + return db.backend.Enable(root) } // Journal commits an entire diff hierarchy to disk into a single journal entry. @@ -307,22 +290,14 @@ 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) - if !ok { - return errors.New("not supported") - } - return pdb.Journal(root) + return db.backend.Journal(root) } // SetBufferSize sets the node buffer size to the provided value(in bytes). // 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) - if !ok { - return errors.New("not supported") - } - return pdb.SetBufferSize(size) + return db.backend.SetBufferSize(size) } // IsVerkle returns the indicator if the database is holding a verkle tree. diff --git a/triedb/hashdb/database.go b/triedb/hashdb/database.go index 4def10e338..6338d89a8a 100644 --- a/triedb/hashdb/database.go +++ b/triedb/hashdb/database.go @@ -217,12 +217,13 @@ func (db *Database) node(hash common.Hash) ([]byte, error) { // Reference adds a new reference from a parent node to a child node. // This function is used to add reference between internal trie node // and external node(e.g. storage trie root), all internal trie nodes -// are referenced together by database itself. -func (db *Database) Reference(child common.Hash, parent common.Hash) { +// are referenced together by database itself. It always returns a nil error. +func (db *Database) Reference(child common.Hash, parent common.Hash) error { db.lock.Lock() defer db.lock.Unlock() db.reference(child, parent) + return nil } // reference is the private locked version of Reference. @@ -250,12 +251,13 @@ func (db *Database) reference(child common.Hash, parent common.Hash) { db.childrenSize += common.HashLength } -// Dereference removes an existing reference from a root node. -func (db *Database) Dereference(root common.Hash) { +// Dereference removes an existing reference from a root node. It always returns +// a nil error. +func (db *Database) Dereference(root common.Hash) error { // Sanity check to ensure that the meta-root is not removed if root == (common.Hash{}) { log.Error("Attempted to dereference the trie cache meta root") - return + return nil } db.lock.Lock() defer db.lock.Unlock() @@ -273,6 +275,7 @@ func (db *Database) Dereference(root common.Hash) { log.Debug("Dereferenced trie from memory database", "nodes", nodes-len(db.dirties), "size", storage-db.dirtiesSize, "time", time.Since(start), "gcnodes", db.gcnodes, "gcsize", db.gcsize, "gctime", db.gctime, "livenodes", len(db.dirties), "livesize", db.dirtiesSize) + return nil } // dereference is the private locked version of Dereference. diff --git a/triedb/hashdb/unsupported.go b/triedb/hashdb/unsupported.go new file mode 100644 index 0000000000..043603ffcb --- /dev/null +++ b/triedb/hashdb/unsupported.go @@ -0,0 +1,60 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it 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 go-ethereum library is distributed in the hope that it 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 . + +package hashdb + +import ( + "errors" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/triedb/pathdb" +) + +// These methods are implemented by pathdb but not supported by hashdb. They are +// included for interface parity to avoid triedb having to check concrete types. + +var errUnsupported = errors.New("method not supported by hashdb") + +// Recover isn't supported and always returns an error. +func (*Database) Recover(target common.Hash) error { return errUnsupported } + +// Recoverable isn't supported and always returns an error. +func (*Database) Recoverable(root common.Hash) (bool, error) { return false, errUnsupported } + +// Disable isn't supported and always returns an error. +func (*Database) Disable() error { return errUnsupported } + +// Enable isn't supported and always returns an error. +func (*Database) Enable(root common.Hash) error { return errUnsupported } + +// Journal isn't supported and always returns an error. +func (*Database) Journal(root common.Hash) error { return errUnsupported } + +// SetBufferSize isn't supported and always returns an error. +func (*Database) SetBufferSize(int) error { return errUnsupported } + +// AccountHistory isn't supported and always returns an error. +func (*Database) AccountHistory(_ common.Address, start, end uint64) (*pathdb.HistoryStats, error) { + return nil, errUnsupported +} + +// StorageHistory isn't supported and always returns an error. +func (*Database) StorageHistory(_ common.Address, slot common.Hash, start, end uint64) (*pathdb.HistoryStats, error) { + return nil, errUnsupported +} + +// HistoryRange isn't supported and always returns an error. +func (*Database) HistoryRange() (uint64, uint64, error) { return 0, 0, errUnsupported } diff --git a/triedb/history.go b/triedb/history.go index f663cdd7c2..769196a800 100644 --- a/triedb/history.go +++ b/triedb/history.go @@ -17,8 +17,6 @@ package triedb import ( - "errors" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/triedb/pathdb" ) @@ -33,11 +31,7 @@ import ( // // This function is only supported by path mode database. func (db *Database) AccountHistory(address common.Address, start, end uint64) (*pathdb.HistoryStats, error) { - pdb, ok := db.backend.(*pathdb.Database) - if !ok { - return nil, errors.New("not supported") - } - return pdb.AccountHistory(address, start, end) + return db.backend.AccountHistory(address, start, end) } // StorageHistory inspects the storage history within the specified range. @@ -52,11 +46,7 @@ func (db *Database) AccountHistory(address common.Address, start, end uint64) (* // // This function is only supported by path mode database. func (db *Database) StorageHistory(address common.Address, slot common.Hash, start uint64, end uint64) (*pathdb.HistoryStats, error) { - pdb, ok := db.backend.(*pathdb.Database) - if !ok { - return nil, errors.New("not supported") - } - return pdb.StorageHistory(address, slot, start, end) + return db.backend.StorageHistory(address, slot, start, end) } // HistoryRange returns the block numbers associated with earliest and latest @@ -64,9 +54,5 @@ func (db *Database) StorageHistory(address common.Address, slot common.Hash, sta // // This function is only supported by path mode database. func (db *Database) HistoryRange() (uint64, uint64, error) { - pdb, ok := db.backend.(*pathdb.Database) - if !ok { - return 0, 0, errors.New("not supported") - } - return pdb.HistoryRange() + return db.backend.HistoryRange() } diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index 31e478117c..6920b91cb6 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -366,7 +366,7 @@ func (db *Database) Recover(root common.Hash) error { } // Short circuit if the target state is not recoverable. root = types.TrieRootHash(root) - if !db.Recoverable(root) { + if !db.recoverable(root) { return errStateUnrecoverable } // Apply the state histories upon the disk layer in order. @@ -397,8 +397,15 @@ func (db *Database) Recover(root common.Hash) error { return nil } -// Recoverable returns the indicator if the specified state is recoverable. -func (db *Database) Recoverable(root common.Hash) bool { +// Recoverable returns the indicator if the specified state is recoverable. It +// always returns a nil error. +func (db *Database) Recoverable(root common.Hash) (bool, error) { + return db.recoverable(root), nil +} + +// recoverable is the internal implementation of [Database.Recoverable], which +// has to return an error for conformity with the triedb.backend interface. +func (db *Database) recoverable(root common.Hash) bool { // Ensure the requested state is a known state. root = types.TrieRootHash(root) id := rawdb.ReadStateID(db.diskdb, root) diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index f667944784..34a6d92a33 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -469,7 +469,13 @@ func TestDatabaseRecoverable(t *testing.T) { {tester.roots[index+1], false}, } for i, c := range cases { - result := tester.db.Recoverable(c.root) + result, err := tester.db.Recoverable(c.root) + if err != nil { + // Recoverable() always returns nil so this should never happen. The + // signature only includes a returned error to conform with a + // triedb-internal interface. + t.Fatalf("case: %d, %T.Recoverable() got error %v", i, tester.db, err) + } if result != c.expect { t.Fatalf("case: %d, unexpected result, want %t, got %t", i, c.expect, result) } diff --git a/triedb/pathdb/unsupported.go b/triedb/pathdb/unsupported.go new file mode 100644 index 0000000000..6816369bc6 --- /dev/null +++ b/triedb/pathdb/unsupported.go @@ -0,0 +1,37 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it 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 go-ethereum library is distributed in the hope that it 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 . + +package pathdb + +import ( + "errors" + + "github.com/ethereum/go-ethereum/common" +) + +// These methods are implemented by hashdb but not supported by pathdb. They are +// included for interface parity to avoid triedb having to check concrete types. + +var errUnsupported = errors.New("method not supported by pathdb") + +// Cap isn't supported and always returns an error. +func (*Database) Cap(limit common.StorageSize) error { return errUnsupported } + +// Reference isn't supported and always returns an error. +func (*Database) Reference(root, parent common.Hash) error { return errUnsupported } + +// Dereference isn't supported and always returns an error. +func (*Database) Dereference(root common.Hash) error { return errUnsupported }