@ -22,6 +22,7 @@ import (
"errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/rlp"
)
@ -102,6 +103,19 @@ type NodeIterator interface {
// iterator is not positioned at a leaf. Callers must not retain references
// to the value after calling Next.
LeafProof ( ) [ ] [ ] byte
// AddResolver sets an intermediate database to use for looking up trie nodes
// before reaching into the real persistent layer.
//
// This is not required for normal operation, rather is an optimization for
// cases where trie nodes can be recovered from some external mechanism without
// reading from disk. In those cases, this resolver allows short circuiting
// accesses and returning them from memory.
//
// Before adding a similar mechanism to any other place in Geth, consider
// making trie.Database an interface and wrapping at that level. It's a huge
// refactor, but it could be worth it if another occurrence arises.
AddResolver ( ethdb . KeyValueStore )
}
// nodeIteratorState represents the iteration state at one particular node of the
@ -119,6 +133,8 @@ type nodeIterator struct {
stack [ ] * nodeIteratorState // Hierarchy of trie nodes persisting the iteration state
path [ ] byte // Path to the current node
err error // Failure set in case of an internal error in the iterator
resolver ethdb . KeyValueStore // Optional intermediate resolver above the disk layer
}
// errIteratorEnd is stored in nodeIterator.err when iteration is done.
@ -143,6 +159,10 @@ func newNodeIterator(trie *Trie, start []byte) NodeIterator {
return it
}
func ( it * nodeIterator ) AddResolver ( resolver ethdb . KeyValueStore ) {
it . resolver = resolver
}
func ( it * nodeIterator ) Hash ( ) common . Hash {
if len ( it . stack ) == 0 {
return common . Hash { }
@ -262,7 +282,7 @@ func (it *nodeIterator) init() (*nodeIteratorState, error) {
if root != emptyRoot {
state . hash = root
}
return state , state . resolve ( it . trie , nil )
return state , state . resolve ( it , nil )
}
// peek creates the next state of the iterator.
@ -286,7 +306,7 @@ func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, er
}
state , path , ok := it . nextChild ( parent , ancestor )
if ok {
if err := state . resolve ( it . trie , path ) ; err != nil {
if err := state . resolve ( it , path ) ; err != nil {
return parent , & parent . index , path , err
}
return state , & parent . index , path , nil
@ -319,7 +339,7 @@ func (it *nodeIterator) peekSeek(seekKey []byte) (*nodeIteratorState, *int, []by
}
state , path , ok := it . nextChildAt ( parent , ancestor , seekKey )
if ok {
if err := state . resolve ( it . trie , path ) ; err != nil {
if err := state . resolve ( it , path ) ; err != nil {
return parent , & parent . index , path , err
}
return state , & parent . index , path , nil
@ -330,9 +350,21 @@ func (it *nodeIterator) peekSeek(seekKey []byte) (*nodeIteratorState, *int, []by
return nil , nil , nil , errIteratorEnd
}
func ( st * nodeIteratorState ) resolve ( tr * Trie , path [ ] byte ) error {
func ( it * nodeIterator ) resolveHash ( hash hashNode , path [ ] byte ) ( node , error ) {
if it . resolver != nil {
if blob , err := it . resolver . Get ( hash ) ; err == nil && len ( blob ) > 0 {
if resolved , err := decodeNode ( hash , blob ) ; err == nil {
return resolved , nil
}
}
}
resolved , err := it . trie . resolveHash ( hash , path )
return resolved , err
}
func ( st * nodeIteratorState ) resolve ( it * nodeIterator , path [ ] byte ) error {
if hash , ok := st . node . ( hashNode ) ; ok {
resolved , err := tr . resolveHash ( hash , path )
resolved , err := i t. resolveHash ( hash , path )
if err != nil {
return err
}
@ -517,6 +549,10 @@ func (it *differenceIterator) Path() []byte {
return it . b . Path ( )
}
func ( it * differenceIterator ) AddResolver ( resolver ethdb . KeyValueStore ) {
panic ( "not implemented" )
}
func ( it * differenceIterator ) Next ( bool ) bool {
// Invariants:
// - We always advance at least one element in b.
@ -624,6 +660,10 @@ func (it *unionIterator) Path() []byte {
return ( * it . items ) [ 0 ] . Path ( )
}
func ( it * unionIterator ) AddResolver ( resolver ethdb . KeyValueStore ) {
panic ( "not implemented" )
}
// Next returns the next node in the union of tries being iterated over.
//
// It does this by maintaining a heap of iterators, sorted by the iteration