@ -19,10 +19,13 @@ package trie
import (
import (
"bytes"
"bytes"
"container/heap"
"container/heap"
"errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common"
)
)
var iteratorEnd = errors . New ( "end of iteration" )
// Iterator is a key-value trie iterator that traverses a Trie.
// Iterator is a key-value trie iterator that traverses a Trie.
type Iterator struct {
type Iterator struct {
nodeIt NodeIterator
nodeIt NodeIterator
@ -79,25 +82,24 @@ type nodeIteratorState struct {
hash common . Hash // Hash of the node being iterated (nil if not standalone)
hash common . Hash // Hash of the node being iterated (nil if not standalone)
node node // Trie node being iterated
node node // Trie node being iterated
parent common . Hash // Hash of the first full ancestor node (nil if current is the root)
parent common . Hash // Hash of the first full ancestor node (nil if current is the root)
child int // Child to be processed next
index int // Child to be processed next
pathlen int // Length of the path to this node
pathlen int // Length of the path to this node
}
}
type nodeIterator struct {
type nodeIterator struct {
trie * Trie // Trie being iterated
trie * Trie // Trie being iterated
stack [ ] * nodeIteratorState // Hierarchy of trie nodes persisting the iteration state
stack [ ] * nodeIteratorState // Hierarchy of trie nodes persisting the iteration state
err error // Failure set in case of an internal error in the iterator
err error // Failure set in case of an internal error in the iterator
path [ ] byte // Path to the current node
path [ ] byte // Path to the current node
}
}
// newNodeIterator creates an post-order trie iterator.
func newNodeIterator ( trie * Trie , start [ ] byte ) NodeIterator {
func newNodeIterator ( trie * Trie ) NodeIterator {
if trie . Hash ( ) == emptyState {
if trie . Hash ( ) == emptyState {
return new ( nodeIterator )
return new ( nodeIterator )
}
}
return & nodeIterator { trie : trie }
it := & nodeIterator { trie : trie }
it . seek ( start )
return it
}
}
// Hash returns the hash of the current node
// Hash returns the hash of the current node
@ -147,6 +149,9 @@ func (it *nodeIterator) Path() []byte {
// Error returns the error set in case of an internal error in the iterator
// Error returns the error set in case of an internal error in the iterator
func ( it * nodeIterator ) Error ( ) error {
func ( it * nodeIterator ) Error ( ) error {
if it . err == iteratorEnd {
return nil
}
return it . err
return it . err
}
}
@ -155,47 +160,54 @@ func (it *nodeIterator) Error() error {
// sets the Error field to the encountered failure. If `descend` is false,
// sets the Error field to the encountered failure. If `descend` is false,
// skips iterating over any subnodes of the current node.
// skips iterating over any subnodes of the current node.
func ( it * nodeIterator ) Next ( descend bool ) bool {
func ( it * nodeIterator ) Next ( descend bool ) bool {
// If the iterator failed previously, don't do anything
if it . err != nil {
if it . err != nil {
return false
return false
}
}
// Otherwise step forward with the iterator and report any errors
// Otherwise step forward with the iterator and report any errors
if err := it . step ( descend ) ; err != nil {
state , parentIndex , path , err := it . peek ( descend )
if err != nil {
it . err = err
it . err = err
return false
return false
}
}
return it . trie != nil
it . push ( state , parentIndex , path )
return true
}
}
// step moves the iterator to the next node of the trie.
func ( it * nodeIterator ) seek ( prefix [ ] byte ) {
func ( it * nodeIterator ) step ( descend bool ) error {
// The path we're looking for is the hex encoded key without terminator.
if it . trie == nil {
key := keybytesToHex ( prefix )
// Abort if we reached the end of the iteration
key = key [ : len ( key ) - 1 ]
return nil
// 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
}
it . push ( state , parentIndex , path )
}
}
}
// peek creates the next state of the iterator.
func ( it * nodeIterator ) peek ( descend bool ) ( * nodeIteratorState , * int , [ ] byte , error ) {
if len ( it . stack ) == 0 {
if len ( it . stack ) == 0 {
// Initialize the iterator if we've just started.
// Initialize the iterator if we've just started.
root := it . trie . Hash ( )
root := it . trie . Hash ( )
state := & nodeIteratorState { node : it . trie . root , child : - 1 }
state := & nodeIteratorState { node : it . trie . root , index : - 1 }
if root != emptyRoot {
if root != emptyRoot {
state . hash = root
state . hash = root
}
}
it . stack = append ( it . stack , state )
return state , nil , nil , nil
return nil
}
}
if ! descend {
if ! descend {
// If we're skipping children, pop the current node first
// If we're skipping children, pop the current node first
it . path = it . path [ : it . stack [ len ( it . stack ) - 1 ] . pathlen ]
it . pop ( )
it . stack = it . stack [ : len ( it . stack ) - 1 ]
}
}
// Continue iteration to the next child
// Continue iteration to the next child
outer :
for {
for {
if len ( it . stack ) == 0 {
if len ( it . stack ) == 0 {
it . trie = nil
return nil , nil , nil , iteratorEnd
return nil
}
}
parent := it . stack [ len ( it . stack ) - 1 ]
parent := it . stack [ len ( it . stack ) - 1 ]
ancestor := parent . hash
ancestor := parent . hash
@ -203,64 +215,77 @@ outer:
ancestor = parent . parent
ancestor = parent . parent
}
}
if node , ok := parent . node . ( * fullNode ) ; ok {
if node , ok := parent . node . ( * fullNode ) ; ok {
// Full node, iterate over children
// Full node, move to the first non-nil child.
for parent . child ++ ; parent . child < len ( node . Children ) ; parent . ch ild ++ {
for i := parent . index + 1 ; i < len ( node . Children ) ; i ++ {
child := node . Children [ parent . ch ild ]
child := node . Children [ i ]
if child != nil {
if child != nil {
hash , _ := child . cache ( )
hash , _ := child . cache ( )
it . stack = append ( it . stack , & nodeIteratorState {
state := & nodeIteratorState {
hash : common . BytesToHash ( hash ) ,
hash : common . BytesToHash ( hash ) ,
node : child ,
node : child ,
parent : ancestor ,
parent : ancestor ,
child : - 1 ,
index : - 1 ,
pathlen : len ( it . path ) ,
pathlen : len ( it . path ) ,
} )
}
it . path = append ( it . path , byte ( parent . child ) )
path := append ( it . path , byte ( i ) )
break outer
parent . index = i - 1
return state , & parent . index , path , nil
}
}
}
}
} else if node , ok := parent . node . ( * shortNode ) ; ok {
} else if node , ok := parent . node . ( * shortNode ) ; ok {
// Short node, return the pointer singleton child
// Short node, return the pointer singleton child
if parent . child < 0 {
if parent . index < 0 {
parent . child ++
hash , _ := node . Val . cache ( )
hash , _ := node . Val . cache ( )
it . stack = append ( it . stack , & nodeIteratorState {
state := & nodeIteratorState {
hash : common . BytesToHash ( hash ) ,
hash : common . BytesToHash ( hash ) ,
node : node . Val ,
node : node . Val ,
parent : ancestor ,
parent : ancestor ,
child : - 1 ,
index : - 1 ,
pathlen : len ( it . path ) ,
pathlen : len ( it . path ) ,
} )
}
var path [ ] byte
if hasTerm ( node . Key ) {
if hasTerm ( node . Key ) {
it . path = append ( it . path , node . Key [ : len ( node . Key ) - 1 ] ... )
path = append ( it . path , node . Key [ : len ( node . Key ) - 1 ] ... )
} else {
} else {
it . path = append ( it . path , node . Key ... )
path = append ( it . path , node . Key ... )
}
}
break
return state , & parent . index , path , nil
}
}
} else if hash , ok := parent . node . ( hashNode ) ; ok {
} else if hash , ok := parent . node . ( hashNode ) ; ok {
// Hash node, resolve the hash child from the database
// Hash node, resolve the hash child from the database
if parent . child < 0 {
if parent . index < 0 {
parent . child ++
node , err := it . trie . resolveHash ( hash , nil , nil )
node , err := it . trie . resolveHash ( hash , nil , nil )
if err != nil {
if err != nil {
return err
return it . stack [ len ( it . stack ) - 1 ] , & parent . index , it . path , err
}
}
it . stack = append ( it . stack , & nodeIteratorState {
state := & nodeIteratorState {
hash : common . BytesToHash ( hash ) ,
hash : common . BytesToHash ( hash ) ,
node : node ,
node : node ,
parent : ancestor ,
parent : ancestor ,
child : - 1 ,
index : - 1 ,
pathlen : len ( it . path ) ,
pathlen : len ( it . path ) ,
} )
}
break
return state , & parent . index , it . path , nil
}
}
// No more child nodes, move back up.
it . pop ( )
}
}
}
}
func ( it * nodeIterator ) push ( state * nodeIteratorState , parentIndex * int , path [ ] byte ) {
it . path = path
it . stack = append ( it . stack , state )
if parentIndex != nil {
* parentIndex += 1
}
}
func ( it * nodeIterator ) pop ( ) {
parent := it . stack [ len ( it . stack ) - 1 ]
it . path = it . path [ : parent . pathlen ]
it . path = it . path [ : parent . pathlen ]
it . stack = it . stack [ : len ( it . stack ) - 1 ]
it . stack = it . stack [ : len ( it . stack ) - 1 ]
}
}
return nil
}
func compareNodes ( a , b NodeIterator ) int {
func compareNodes ( a , b NodeIterator ) int {
cmp := bytes . Compare ( a . Path ( ) , b . Path ( ) )
cmp := bytes . Compare ( a . Path ( ) , b . Path ( ) )