@@ -22,6 +22,7 @@ import (
22
22
"errors"
23
23
24
24
"github.com/ethereum/go-ethereum/common"
25
+ "github.com/ethereum/go-ethereum/ethdb"
25
26
"github.com/ethereum/go-ethereum/rlp"
26
27
)
27
28
@@ -102,6 +103,19 @@ type NodeIterator interface {
102
103
// iterator is not positioned at a leaf. Callers must not retain references
103
104
// to the value after calling Next.
104
105
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 )
105
119
}
106
120
107
121
// nodeIteratorState represents the iteration state at one particular node of the
@@ -119,6 +133,8 @@ type nodeIterator struct {
119
133
stack []* nodeIteratorState // Hierarchy of trie nodes persisting the iteration state
120
134
path []byte // Path to the current node
121
135
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
122
138
}
123
139
124
140
// errIteratorEnd is stored in nodeIterator.err when iteration is done.
@@ -143,6 +159,10 @@ func newNodeIterator(trie *Trie, start []byte) NodeIterator {
143
159
return it
144
160
}
145
161
162
+ func (it * nodeIterator ) AddResolver (resolver ethdb.KeyValueStore ) {
163
+ it .resolver = resolver
164
+ }
165
+
146
166
func (it * nodeIterator ) Hash () common.Hash {
147
167
if len (it .stack ) == 0 {
148
168
return common.Hash {}
@@ -262,7 +282,7 @@ func (it *nodeIterator) init() (*nodeIteratorState, error) {
262
282
if root != emptyRoot {
263
283
state .hash = root
264
284
}
265
- return state , state .resolve (it . trie , nil )
285
+ return state , state .resolve (it , nil )
266
286
}
267
287
268
288
// peek creates the next state of the iterator.
@@ -286,7 +306,7 @@ func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, er
286
306
}
287
307
state , path , ok := it .nextChild (parent , ancestor )
288
308
if ok {
289
- if err := state .resolve (it . trie , path ); err != nil {
309
+ if err := state .resolve (it , path ); err != nil {
290
310
return parent , & parent .index , path , err
291
311
}
292
312
return state , & parent .index , path , nil
@@ -319,7 +339,7 @@ func (it *nodeIterator) peekSeek(seekKey []byte) (*nodeIteratorState, *int, []by
319
339
}
320
340
state , path , ok := it .nextChildAt (parent , ancestor , seekKey )
321
341
if ok {
322
- if err := state .resolve (it . trie , path ); err != nil {
342
+ if err := state .resolve (it , path ); err != nil {
323
343
return parent , & parent .index , path , err
324
344
}
325
345
return state , & parent .index , path , nil
@@ -330,9 +350,21 @@ func (it *nodeIterator) peekSeek(seekKey []byte) (*nodeIteratorState, *int, []by
330
350
return nil , nil , nil , errIteratorEnd
331
351
}
332
352
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 {
334
366
if hash , ok := st .node .(hashNode ); ok {
335
- resolved , err := tr .resolveHash (hash , path )
367
+ resolved , err := it .resolveHash (hash , path )
336
368
if err != nil {
337
369
return err
338
370
}
@@ -517,6 +549,10 @@ func (it *differenceIterator) Path() []byte {
517
549
return it .b .Path ()
518
550
}
519
551
552
+ func (it * differenceIterator ) AddResolver (resolver ethdb.KeyValueStore ) {
553
+ panic ("not implemented" )
554
+ }
555
+
520
556
func (it * differenceIterator ) Next (bool ) bool {
521
557
// Invariants:
522
558
// - We always advance at least one element in b.
@@ -624,6 +660,10 @@ func (it *unionIterator) Path() []byte {
624
660
return (* it .items )[0 ].Path ()
625
661
}
626
662
663
+ func (it * unionIterator ) AddResolver (resolver ethdb.KeyValueStore ) {
664
+ panic ("not implemented" )
665
+ }
666
+
627
667
// Next returns the next node in the union of tries being iterated over.
628
668
//
629
669
// It does this by maintaining a heap of iterators, sorted by the iteration
0 commit comments