Skip to content

Commit

Permalink
trie: refactor triereader, return err when state reader won't be crea…
Browse files Browse the repository at this point in the history
…ted in hash and path
  • Loading branch information
huyngopt1994 authored and Francesco4203 committed Oct 15, 2024
1 parent d817aee commit 32b52ac
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 23 deletions.
8 changes: 3 additions & 5 deletions trie/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,16 +131,14 @@ func NewDatabase(diskdb ethdb.Database, config *Config) *Database {

// Reader returns a reader for accessing all trie nodes with provided state root.
// Nil is returned in case the state is not available.
func (db *Database) Reader(blockRoot common.Hash) Reader {
func (db *Database) Reader(blockRoot common.Hash) (Reader, error) {
switch b := db.backend.(type) {
case *hashdb.Database:
return b.Reader(blockRoot)
case *pathdb.Database:
reader, _ := b.Reader(blockRoot)
return reader
return b.Reader(blockRoot)
}
return nil

return nil, errors.New("unsupported")
}

// Update performs a state transition by committing dirty nodes contained in the
Expand Down
7 changes: 6 additions & 1 deletion trie/iterator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,12 @@ func testNodeIteratorCoverage(t *testing.T, scheme string) {
}
// Cross check the hashes and the database itself
for _, element := range elements {
if blob, err := nodeDb.Reader(trie.Hash()).Node(common.Hash{}, element.path, element.hash); err != nil {
reader, err := nodeDb.Reader(trie.Hash())
if err != nil {
t.Errorf("failed to retrieve reader %v", err)
}

if blob, err := reader.Node(common.Hash{}, element.path, element.hash); err != nil {
t.Errorf("failed to retrieve reported node %x: %v", element.hash, err)
} else if !bytes.Equal(blob, element.blob) {
t.Errorf("node blob is different, want %v got %v", element.blob, blob)
Expand Down
50 changes: 42 additions & 8 deletions trie/sync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,11 @@ func testIterativeSync(t *testing.T, count int, bypath bool, scheme string) {
if !bypath {
for i, element := range elements {
owner, inner := ResolvePath([]byte(element.path))
data, err := srcDb.Reader(srcTrie.Hash()).Node(owner, inner, element.hash)
reader, err := srcDb.Reader(srcTrie.Hash())
if err != nil {
t.Fatalf("failed to create reader for trie %x: %v", srcTrie.Hash(), err)
}
data, err := reader.Node(owner, inner, element.hash)
if err != nil {
t.Fatalf("failed to retrieve node data for hash %x: %v", element.hash, err)
}
Expand Down Expand Up @@ -238,7 +242,11 @@ func testIterativeDelayedSync(t *testing.T, scheme string) {
results := make([]NodeSyncResult, len(elements)/2+1)
for i, element := range elements[:len(results)] {
owner, inner := ResolvePath([]byte(element.path))
data, err := srcDb.Reader(srcTrie.Hash()).Node(owner, inner, element.hash)
reader, err := srcDb.Reader(srcTrie.Hash())
if err != nil {
t.Fatalf("failed to create reader for trie %x: %v", srcTrie.Hash(), err)
}
data, err := reader.Node(owner, inner, element.hash)
if err != nil {
t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err)
}
Expand Down Expand Up @@ -303,7 +311,11 @@ func testIterativeRandomSync(t *testing.T, count int, scheme string) {
results := make([]NodeSyncResult, 0, len(queue))
for path, element := range queue {
owner, inner := ResolvePath([]byte(element.path))
data, err := srcDb.Reader(srcTrie.Hash()).Node(owner, inner, element.hash)
reader, err := srcDb.Reader(srcTrie.Hash())
if err != nil {
t.Fatalf("failed to create reader for trie %x: %v", srcTrie.Hash(), err)
}
data, err := reader.Node(owner, inner, element.hash)
if err != nil {
t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err)
}
Expand Down Expand Up @@ -366,7 +378,11 @@ func testIterativeRandomDelayedSync(t *testing.T, scheme string) {
results := make([]NodeSyncResult, 0, len(queue)/2+1)
for path, element := range queue {
owner, inner := ResolvePath([]byte(element.path))
data, err := srcDb.Reader(srcTrie.Hash()).Node(owner, inner, element.hash)
reader, err := srcDb.Reader(srcTrie.Hash())
if err != nil {
t.Fatalf("failed to create reader for trie %x: %v", srcTrie.Hash(), err)
}
data, err := reader.Node(owner, inner, element.hash)
if err != nil {
t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err)
}
Expand Down Expand Up @@ -435,7 +451,12 @@ func testDuplicateAvoidanceSync(t *testing.T, scheme string) {
results := make([]NodeSyncResult, len(elements))
for i, element := range elements {
owner, inner := ResolvePath([]byte(element.path))
data, err := srcDb.Reader(srcTrie.Hash()).Node(owner, inner, element.hash)
reader, err := srcDb.Reader(srcTrie.Hash())
if err != nil {
t.Fatalf("failed to create reader for trie %x: %v", srcTrie.Hash(), err)
}

data, err := reader.Node(owner, inner, element.hash)
if err != nil {
t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err)
}
Expand Down Expand Up @@ -509,7 +530,11 @@ func testIncompleteSync(t *testing.T, scheme string) {
results := make([]NodeSyncResult, len(elements))
for i, element := range elements {
owner, inner := ResolvePath([]byte(element.path))
data, err := srcDb.Reader(srcTrie.Hash()).Node(owner, inner, element.hash)
reader, err := srcDb.Reader(srcTrie.Hash())
if err != nil {
t.Fatalf("failed to create reader for trie %x: %v", srcTrie.Hash(), err)
}
data, err := reader.Node(owner, inner, element.hash)
if err != nil {
t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err)
}
Expand Down Expand Up @@ -593,7 +618,12 @@ func testSyncOrdering(t *testing.T, scheme string) {
results := make([]NodeSyncResult, len(elements))
for i, element := range elements {
owner, inner := ResolvePath([]byte(element.path))
data, err := srcDb.Reader(srcTrie.Hash()).Node(owner, inner, element.hash)
reader, err := srcDb.Reader(srcTrie.Hash())
if err != nil {
t.Fatalf("failed to create reader for trie %x: %v", srcTrie.Hash(), err)
}

data, err := reader.Node(owner, inner, element.hash)
if err != nil {
t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err)
}
Expand Down Expand Up @@ -656,7 +686,11 @@ func syncWith(t *testing.T, root common.Hash, db ethdb.Database, srcDb *Database
results := make([]NodeSyncResult, len(elements))
for i, element := range elements {
owner, inner := ResolvePath([]byte(element.path))
data, err := srcDb.Reader(root).Node(owner, inner, element.hash)
reader, err := srcDb.Reader(root)
if err != nil {
t.Fatalf("failed to create reader for trie %x: %v", root, err)
}
data, err := reader.Node(owner, inner, element.hash)
if err != nil {
t.Fatalf("failed to retrieve node data for hash %x: %v", element.hash, err)
}
Expand Down
19 changes: 13 additions & 6 deletions trie/trie_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
package trie

import (
"fmt"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/trie/triestate"
)

Expand All @@ -38,7 +38,7 @@ type Reader interface {
type NodeReader interface {
// Reader returns a reader for accessing all trie nodes with provided
// state root. Nil is returned in case the state is not available.
Reader(root common.Hash) Reader
Reader(root common.Hash) (Reader, error)
}

// trieReader is a wrapper of the underlying node reader. It's not safe
Expand All @@ -51,9 +51,16 @@ type trieReader struct {

// newTrieReader initializes the trie reader with the given node reader.
func newTrieReader(stateRoot, owner common.Hash, db NodeReader) (*trieReader, error) {
reader := db.Reader(stateRoot)
if reader == nil {
return nil, fmt.Errorf("state not found #%x", stateRoot)
if stateRoot == (common.Hash{}) || stateRoot == types.EmptyRootHash {
if stateRoot == (common.Hash{}) {
log.Error("zero state root")
}
return &trieReader{owner: owner}, nil
}

reader, err := db.Reader(stateRoot)
if err != nil {
return nil, &MissingNodeError{Owner: owner, NodeHash: stateRoot, err: err}
}
return &trieReader{owner: owner, reader: reader}, nil
}
Expand Down
9 changes: 7 additions & 2 deletions trie/triedb/hashdb/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package hashdb

import (
"errors"
"fmt"
"reflect"
"sync"
"time"
Expand Down Expand Up @@ -641,8 +642,12 @@ func (db *Database) Scheme() string {
}

// Reader retrieves a node reader belonging to the given state root.
func (db *Database) Reader(root common.Hash) *reader {
return &reader{db: db}
func (db *Database) Reader(root common.Hash) (*reader, error) {
if _, err := db.Node(root); err != nil {
return nil, fmt.Errorf("state %#x is not available, %v", root, err)
}

return &reader{db: db}, nil
}

// reader is a state reader of Database which implements the Reader interface.
Expand Down
2 changes: 1 addition & 1 deletion trie/triedb/pathdb/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ func (db *Database) Reader(root common.Hash) (layer, error) {
// Update adds a new layer into the tree, if that can be linked to an existing
// old parent. It is disallowed to insert a disk layer (the origin of all). Apart
// from that this function will flatten the extra diff layers at bottom into disk
// to only keep 128 diff layers in memory by default.
// to only keep 128 diff layerReaders in memory by default.
//
// The passed in maps(nodes, states) will be retained to avoid copying everything.
// Therefore, these maps must not be changed afterwards.
Expand Down

0 comments on commit 32b52ac

Please sign in to comment.