@@ -22,6 +22,7 @@ import (
2222 "errors"
2323
2424 "github.com/ethereum/go-ethereum/common"
25+ "github.com/ethereum/go-ethereum/ethdb"
2526 "github.com/ethereum/go-ethereum/rlp"
2627)
2728
@@ -102,6 +103,19 @@ type NodeIterator interface {
102103 // iterator is not positioned at a leaf. Callers must not retain references
103104 // to the value after calling Next.
104105 LeafProof () [][]byte
106+
107+ // AddResolver sets an intermediate database to use for looking up trie nodes
108+ // before reaching into the real persistent layer.
109+ //
110+ // This is not required for normal operation, rather is an optimization for
111+ // cases where trie nodes can be recovered from some external mechanism without
112+ // reading from disk. In those cases, this resolver allows short circuiting
113+ // accesses and returning them from memory.
114+ //
115+ // Before adding a similar mechanism to any other place in Geth, consider
116+ // making trie.Database an interface and wrapping at that level. It's a huge
117+ // refactor, but it could be worth it if another occurrence arises.
118+ AddResolver (ethdb.KeyValueStore )
105119}
106120
107121// nodeIteratorState represents the iteration state at one particular node of the
@@ -119,6 +133,8 @@ type nodeIterator struct {
119133 stack []* nodeIteratorState // Hierarchy of trie nodes persisting the iteration state
120134 path []byte // Path to the current node
121135 err error // Failure set in case of an internal error in the iterator
136+
137+ resolver ethdb.KeyValueStore // Optional intermediate resolver above the disk layer
122138}
123139
124140// errIteratorEnd is stored in nodeIterator.err when iteration is done.
@@ -143,6 +159,10 @@ func newNodeIterator(trie *Trie, start []byte) NodeIterator {
143159 return it
144160}
145161
162+ func (it * nodeIterator ) AddResolver (resolver ethdb.KeyValueStore ) {
163+ it .resolver = resolver
164+ }
165+
146166func (it * nodeIterator ) Hash () common.Hash {
147167 if len (it .stack ) == 0 {
148168 return common.Hash {}
@@ -262,7 +282,7 @@ func (it *nodeIterator) init() (*nodeIteratorState, error) {
262282 if root != emptyRoot {
263283 state .hash = root
264284 }
265- return state , state .resolve (it . trie , nil )
285+ return state , state .resolve (it , nil )
266286}
267287
268288// peek creates the next state of the iterator.
@@ -286,7 +306,7 @@ func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, er
286306 }
287307 state , path , ok := it .nextChild (parent , ancestor )
288308 if ok {
289- if err := state .resolve (it . trie , path ); err != nil {
309+ if err := state .resolve (it , path ); err != nil {
290310 return parent , & parent .index , path , err
291311 }
292312 return state , & parent .index , path , nil
@@ -319,7 +339,7 @@ func (it *nodeIterator) peekSeek(seekKey []byte) (*nodeIteratorState, *int, []by
319339 }
320340 state , path , ok := it .nextChildAt (parent , ancestor , seekKey )
321341 if ok {
322- if err := state .resolve (it . trie , path ); err != nil {
342+ if err := state .resolve (it , path ); err != nil {
323343 return parent , & parent .index , path , err
324344 }
325345 return state , & parent .index , path , nil
@@ -330,9 +350,21 @@ func (it *nodeIterator) peekSeek(seekKey []byte) (*nodeIteratorState, *int, []by
330350 return nil , nil , nil , errIteratorEnd
331351}
332352
333- func (st * nodeIteratorState ) resolve (tr * Trie , path []byte ) error {
353+ func (it * nodeIterator ) resolveHash (hash hashNode , path []byte ) (node , error ) {
354+ if it .resolver != nil {
355+ if blob , err := it .resolver .Get (hash ); err == nil && len (blob ) > 0 {
356+ if resolved , err := decodeNode (hash , blob ); err == nil {
357+ return resolved , nil
358+ }
359+ }
360+ }
361+ resolved , err := it .trie .resolveHash (hash , path )
362+ return resolved , err
363+ }
364+
365+ func (st * nodeIteratorState ) resolve (it * nodeIterator , path []byte ) error {
334366 if hash , ok := st .node .(hashNode ); ok {
335- resolved , err := tr .resolveHash (hash , path )
367+ resolved , err := it .resolveHash (hash , path )
336368 if err != nil {
337369 return err
338370 }
@@ -517,6 +549,10 @@ func (it *differenceIterator) Path() []byte {
517549 return it .b .Path ()
518550}
519551
552+ func (it * differenceIterator ) AddResolver (resolver ethdb.KeyValueStore ) {
553+ panic ("not implemented" )
554+ }
555+
520556func (it * differenceIterator ) Next (bool ) bool {
521557 // Invariants:
522558 // - We always advance at least one element in b.
@@ -624,6 +660,10 @@ func (it *unionIterator) Path() []byte {
624660 return (* it .items )[0 ].Path ()
625661}
626662
663+ func (it * unionIterator ) AddResolver (resolver ethdb.KeyValueStore ) {
664+ panic ("not implemented" )
665+ }
666+
627667// Next returns the next node in the union of tries being iterated over.
628668//
629669// It does this by maintaining a heap of iterators, sorted by the iteration
0 commit comments