@ -24,14 +24,13 @@ import (
"github.com/ethereum/go-ethereum/common"
)
var iteratorEnd = errors . New ( "end of iteration" )
// Iterator is a key-value trie iterator that traverses a Trie.
type Iterator struct {
nodeIt NodeIterator
Key [ ] byte // Current data key on which the iterator is positioned on
Value [ ] byte // Current data value on which the iterator is positioned on
Err error
}
// NewIterator creates a new key-value iterator from a node iterator
@ -45,35 +44,42 @@ func NewIterator(it NodeIterator) *Iterator {
func ( it * Iterator ) Next ( ) bool {
for it . nodeIt . Next ( true ) {
if it . nodeIt . Leaf ( ) {
it . Key = hexToKeybytes ( it . nodeIt . Path ( ) )
it . Key = it . nodeIt . LeafKey ( )
it . Value = it . nodeIt . LeafBlob ( )
return true
}
}
it . Key = nil
it . Value = nil
it . Err = it . nodeIt . Error ( )
return false
}
// NodeIterator is an iterator to traverse the trie pre-order.
type NodeIterator interface {
// Hash returns the hash of the current node
Hash ( ) common . Hash
// Parent returns the hash of the parent of the current node
Parent ( ) common . Hash
// Leaf returns true iff the current node is a leaf node.
Leaf ( ) bool
// LeafBlob returns the contents of the node, if it is a leaf.
// Callers must not retain references to the return value after calling Next()
LeafBlob ( ) [ ] byte
// Path returns the hex-encoded path to the current node.
// Callers must not retain references to the return value after calling Next()
Path ( ) [ ] byte
// Next moves the iterator to the next node. If the parameter is false, any child
// nodes will be skipped.
Next ( bool ) bool
// Error returns the error status of the iterator.
Error ( ) error
// Hash returns the hash of the current node.
Hash ( ) common . Hash
// Parent returns the hash of the parent of the current node. The hash may be the one
// grandparent if the immediate parent is an internal node with no hash.
Parent ( ) common . Hash
// Path returns the hex-encoded path to the current node.
// Callers must not retain references to the return value after calling Next.
// For leaf nodes, the last element of the path is the 'terminator symbol' 0x10.
Path ( ) [ ] byte
// Leaf returns true iff the current node is a leaf node.
// LeafBlob, LeafKey return the contents and key of the leaf node. These
// method panic if the iterator is not positioned at a leaf.
// Callers must not retain references to their return value after calling Next
Leaf ( ) bool
LeafBlob ( ) [ ] byte
LeafKey ( ) [ ] byte
}
// nodeIteratorState represents the iteration state at one particular node of the
@ -89,8 +95,21 @@ type nodeIteratorState struct {
type nodeIterator struct {
trie * Trie // Trie being iterated
stack [ ] * nodeIteratorState // Hierarchy of trie nodes persisting the iteration state
err error // Failure set in case of an internal error in the iterator
path [ ] byte // Path to the current node
err error // Failure set in case of an internal error in the iterator
}
// iteratorEnd is stored in nodeIterator.err when iteration is done.
var iteratorEnd = errors . New ( "end of iteration" )
// seekError is stored in nodeIterator.err if the initial seek has failed.
type seekError struct {
key [ ] byte
err error
}
func ( e seekError ) Error ( ) string {
return "seek error: " + e . err . Error ( )
}
func newNodeIterator ( trie * Trie , start [ ] byte ) NodeIterator {
@ -98,60 +117,57 @@ func newNodeIterator(trie *Trie, start []byte) NodeIterator {
return new ( nodeIterator )
}
it := & nodeIterator { trie : trie }
it . seek ( start )
it . err = it . seek ( start )
return it
}
// Hash returns the hash of the current node
func ( it * nodeIterator ) Hash ( ) common . Hash {
if len ( it . stack ) == 0 {
return common . Hash { }
}
return it . stack [ len ( it . stack ) - 1 ] . hash
}
// Parent returns the hash of the parent node
func ( it * nodeIterator ) Parent ( ) common . Hash {
if len ( it . stack ) == 0 {
return common . Hash { }
}
return it . stack [ len ( it . stack ) - 1 ] . parent
}
// Leaf returns true if the current node is a leaf
func ( it * nodeIterator ) Leaf ( ) bool {
if len ( it . stack ) == 0 {
return false
}
_ , ok := it . stack [ len ( it . stack ) - 1 ] . node . ( valueNode )
return ok
return hasTerm ( it . path )
}
// LeafBlob returns the data for the current node, if it is a leaf
func ( it * nodeIterator ) LeafBlob ( ) [ ] byte {
if len ( it . stack ) == 0 {
return nil
if len ( it . stack ) > 0 {
if node , ok := it . stack [ len ( it . stack ) - 1 ] . node . ( valueNode ) ; ok {
return [ ] byte ( node )
}
}
panic ( "not at leaf" )
}
if node , ok := it . stack [ len ( it . stack ) - 1 ] . node . ( valueNode ) ; ok {
return [ ] byte ( node )
func ( it * nodeIterator ) LeafKey ( ) [ ] byte {
if len ( it . stack ) > 0 {
if _ , ok := it . stack [ len ( it . stack ) - 1 ] . node . ( valueNode ) ; ok {
return hexToKeybytes ( it . path )
}
}
return nil
panic ( "not at leaf" )
}
// Path returns the hex-encoded path to the current node
func ( it * nodeIterator ) Path ( ) [ ] byte {
return it . path
}
// Error returns the error set in case of an internal error in the iterator
func ( it * nodeIterator ) Error ( ) error {
if it . err == iteratorEnd {
return nil
}
if seek , ok := it . err . ( seekError ) ; ok {
return seek . err
}
return it . err
}
@ -160,29 +176,37 @@ func (it *nodeIterator) Error() error {
// sets the Error field to the encountered failure. If `descend` is false,
// skips iterating over any subnodes of the current node.
func ( it * nodeIterator ) Next ( descend bool ) bool {
if it . err != nil {
if it . err == iteratorEnd {
return false
}
// Otherwise step forward with the iterator and report any errors
if seek , ok := it . err . ( seekError ) ; ok {
if it . err = it . seek ( seek . key ) ; it . err != nil {
return false
}
}
// Otherwise step forward with the iterator and report any errors.
state , parentIndex , path , err := it . peek ( descend )
if err != nil {
it . err = err
it . err = err
if it . err != nil {
return false
}
it . push ( state , parentIndex , path )
return true
}
func ( it * nodeIterator ) seek ( prefix [ ] byte ) {
func ( it * nodeIterator ) seek ( prefix [ ] byte ) error {
// The path we're looking for is the hex encoded key without terminator.
key := keybytesToHex ( prefix )
key = key [ : len ( key ) - 1 ]
// Move forward until we're just before the closest match to key.
for {
state , parentIndex , path , err := it . peek ( bytes . HasPrefix ( key , it . path ) )
if err != nil || bytes . Compare ( path , key ) >= 0 {
it . err = err
return
if err == iteratorEnd {
return iteratorEnd
} else if err != nil {
return seekError { prefix , err }
} else if bytes . Compare ( path , key ) >= 0 {
return nil
}
it . push ( state , parentIndex , path )
}
@ -197,7 +221,8 @@ func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, er
if root != emptyRoot {
state . hash = root
}
return state , nil , nil , nil
err := state . resolve ( it . trie , nil )
return state , nil , nil , err
}
if ! descend {
// If we're skipping children, pop the current node first
@ -205,72 +230,73 @@ func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, er
}
// Continue iteration to the next child
for {
if len ( it . stack ) == 0 {
return nil , nil , nil , iteratorEnd
}
for len ( it . stack ) > 0 {
parent := it . stack [ len ( it . stack ) - 1 ]
ancestor := parent . hash
if ( ancestor == common . Hash { } ) {
ancestor = parent . parent
}
if node , ok := parent . node . ( * fullNode ) ; ok {
// Full node, move to the first non-nil child.
for i := parent . index + 1 ; i < len ( node . Children ) ; i ++ {
child := node . Children [ i ]
if child != nil {
hash , _ := child . cache ( )
state := & nodeIteratorState {
hash : common . BytesToHash ( hash ) ,
node : child ,
parent : ancestor ,
index : - 1 ,
pathlen : len ( it . path ) ,
}
path := append ( it . path , byte ( i ) )
parent . index = i - 1
return state , & parent . index , path , nil
}
state , path , ok := it . nextChild ( parent , ancestor )
if ok {
if err := state . resolve ( it . trie , path ) ; err != nil {
return parent , & parent . index , path , err
}
} else if node , ok := parent . node . ( * shortNode ) ; ok {
// Short node, return the pointer singleton child
if parent . index < 0 {
hash , _ := node . Val . cache ( )
return state , & parent . index , path , nil
}
// No more child nodes, move back up.
it . pop ( )
}
return nil , nil , nil , iteratorEnd
}
func ( st * nodeIteratorState ) resolve ( tr * Trie , path [ ] byte ) error {
if hash , ok := st . node . ( hashNode ) ; ok {
resolved , err := tr . resolveHash ( hash , path )
if err != nil {
return err
}
st . node = resolved
st . hash = common . BytesToHash ( hash )
}
return nil
}
func ( it * nodeIterator ) nextChild ( parent * nodeIteratorState , ancestor common . Hash ) ( * nodeIteratorState , [ ] byte , bool ) {
switch node := parent . node . ( type ) {
case * fullNode :
// Full node, move to the first non-nil child.
for i := parent . index + 1 ; i < len ( node . Children ) ; i ++ {
child := node . Children [ i ]
if child != nil {
hash , _ := child . cache ( )
state := & nodeIteratorState {
hash : common . BytesToHash ( hash ) ,
node : node . Val ,
node : child ,
parent : ancestor ,
index : - 1 ,
pathlen : len ( it . path ) ,
}
var path [ ] byte
if hasTerm ( node . Key ) {
path = append ( it . path , node . Key [ : len ( node . Key ) - 1 ] ... )
} else {
path = append ( it . path , node . Key ... )
}
return state , & parent . index , path , nil
path := append ( it . path , byte ( i ) )
parent . index = i - 1
return state , path , true
}
} else if hash , ok := parent . node . ( hashNode ) ; ok {
// Hash node, resolve the hash child from the database
if parent . index < 0 {
node , err := it . trie . resolveHash ( hash , nil , nil )
if err != nil {
return it . stack [ len ( it . stack ) - 1 ] , & parent . index , it . path , err
}
state := & nodeIteratorState {
hash : common . BytesToHash ( hash ) ,
node : node ,
parent : ancestor ,
index : - 1 ,
pathlen : len ( it . path ) ,
}
return state , & parent . index , it . path , nil
}
case * shortNode :
// Short node, return the pointer singleton child
if parent . index < 0 {
hash , _ := node . Val . cache ( )
state := & nodeIteratorState {
hash : common . BytesToHash ( hash ) ,
node : node . Val ,
parent : ancestor ,
index : - 1 ,
pathlen : len ( it . path ) ,
}
path := append ( it . path , node . Key ... )
return state , path , true
}
// No more child nodes, move back up.
it . pop ( )
}
return parent , it . path , false
}
func ( it * nodeIterator ) push ( state * nodeIteratorState , parentIndex * int , path [ ] byte ) {
@ -288,23 +314,21 @@ func (it *nodeIterator) pop() {
}
func compareNodes ( a , b NodeIterator ) int {
cmp := bytes . Compare ( a . Path ( ) , b . Path ( ) )
if cmp != 0 {
if cmp := bytes . Compare ( a . Path ( ) , b . Path ( ) ) ; cmp != 0 {
return cmp
}
if a . Leaf ( ) && ! b . Leaf ( ) {
return - 1
} else if b . Leaf ( ) && ! a . Leaf ( ) {
return 1
}
cmp = bytes . Compare ( a . Hash ( ) . Bytes ( ) , b . Hash ( ) . Bytes ( ) )
if cmp != 0 {
if cmp := bytes . Compare ( a . Hash ( ) . Bytes ( ) , b . Hash ( ) . Bytes ( ) ) ; cmp != 0 {
return cmp
}
return bytes . Compare ( a . LeafBlob ( ) , b . LeafBlob ( ) )
if a . Leaf ( ) && b . Leaf ( ) {
return bytes . Compare ( a . LeafBlob ( ) , b . LeafBlob ( ) )
}
return 0
}
type differenceIterator struct {
@ -341,6 +365,10 @@ func (it *differenceIterator) LeafBlob() []byte {
return it . b . LeafBlob ( )
}
func ( it * differenceIterator ) LeafKey ( ) [ ] byte {
return it . b . LeafKey ( )
}
func ( it * differenceIterator ) Path ( ) [ ] byte {
return it . b . Path ( )
}
@ -410,7 +438,6 @@ func (h *nodeIteratorHeap) Pop() interface{} {
type unionIterator struct {
items * nodeIteratorHeap // Nodes returned are the union of the ones in these iterators
count int // Number of nodes scanned across all tries
err error // The error, if one has been encountered
}
// NewUnionIterator constructs a NodeIterator that iterates over elements in the union
@ -421,9 +448,7 @@ func NewUnionIterator(iters []NodeIterator) (NodeIterator, *int) {
copy ( h , iters )
heap . Init ( & h )
ui := & unionIterator {
items : & h ,
}
ui := & unionIterator { items : & h }
return ui , & ui . count
}
@ -443,6 +468,10 @@ func (it *unionIterator) LeafBlob() []byte {
return ( * it . items ) [ 0 ] . LeafBlob ( )
}
func ( it * unionIterator ) LeafKey ( ) [ ] byte {
return ( * it . items ) [ 0 ] . LeafKey ( )
}
func ( it * unionIterator ) Path ( ) [ ] byte {
return ( * it . items ) [ 0 ] . Path ( )
}