mirror of https://github.com/ethereum/go-ethereum
parent
a38dafcc57
commit
6877660fe2
@ -0,0 +1,143 @@ |
||||
package ethtrie |
||||
|
||||
import ( |
||||
"bytes" |
||||
|
||||
"github.com/ethereum/eth-go/ethutil" |
||||
) |
||||
|
||||
type NodeType byte |
||||
|
||||
const ( |
||||
EmptyNode NodeType = iota |
||||
BranchNode |
||||
LeafNode |
||||
ExtNode |
||||
) |
||||
|
||||
func getType(node *ethutil.Value) NodeType { |
||||
if node.Len() == 0 { |
||||
return EmptyNode |
||||
} |
||||
|
||||
if node.Len() == 2 { |
||||
k := CompactDecode(node.Get(0).Str()) |
||||
if HasTerm(k) { |
||||
return LeafNode |
||||
} |
||||
|
||||
return ExtNode |
||||
} |
||||
|
||||
return BranchNode |
||||
} |
||||
|
||||
type Iterator struct { |
||||
Path [][]byte |
||||
trie *Trie |
||||
|
||||
Key []byte |
||||
Value *ethutil.Value |
||||
} |
||||
|
||||
func NewIterator(trie *Trie) *Iterator { |
||||
return &Iterator{trie: trie} |
||||
} |
||||
|
||||
func (self *Iterator) key(node *ethutil.Value, path [][]byte) []byte { |
||||
switch getType(node) { |
||||
case LeafNode: |
||||
k := RemTerm(CompactDecode(node.Get(0).Str())) |
||||
|
||||
self.Path = append(path, k) |
||||
self.Value = node.Get(1) |
||||
|
||||
return k |
||||
case BranchNode: |
||||
if node.Get(16).Len() > 0 { |
||||
return []byte{16} |
||||
} |
||||
|
||||
for i := byte(0); i < 16; i++ { |
||||
o := self.key(self.trie.getNode(node.Get(int(i)).Raw()), append(path, []byte{i})) |
||||
if o != nil { |
||||
return append([]byte{i}, o...) |
||||
} |
||||
} |
||||
case ExtNode: |
||||
currKey := node.Get(0).Bytes() |
||||
|
||||
return self.key(self.trie.getNode(node.Get(1).Raw()), append(path, currKey)) |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func (self *Iterator) next(node *ethutil.Value, key []byte, path [][]byte) []byte { |
||||
switch typ := getType(node); typ { |
||||
case EmptyNode: |
||||
return nil |
||||
case BranchNode: |
||||
if len(key) > 0 { |
||||
subNode := self.trie.getNode(node.Get(int(key[0])).Raw()) |
||||
|
||||
o := self.next(subNode, key[1:], append(path, key[:1])) |
||||
if o != nil { |
||||
return append([]byte{key[0]}, o...) |
||||
} |
||||
} |
||||
|
||||
var r byte = 0 |
||||
if len(key) > 0 { |
||||
r = key[0] + 1 |
||||
} |
||||
|
||||
for i := r; i < 16; i++ { |
||||
subNode := self.trie.getNode(node.Get(int(i)).Raw()) |
||||
o := self.key(subNode, append(path, []byte{i})) |
||||
if o != nil { |
||||
return append([]byte{i}, o...) |
||||
} |
||||
} |
||||
case LeafNode, ExtNode: |
||||
k := RemTerm(CompactDecode(node.Get(0).Str())) |
||||
if typ == LeafNode { |
||||
if bytes.Compare([]byte(k), []byte(key)) > 0 { |
||||
self.Value = node.Get(1) |
||||
self.Path = append(path, k) |
||||
|
||||
return k |
||||
} |
||||
} else { |
||||
subNode := self.trie.getNode(node.Get(1).Raw()) |
||||
subKey := key[len(k):] |
||||
var ret []byte |
||||
if BeginsWith(key, k) { |
||||
ret = self.next(subNode, subKey, append(path, k)) |
||||
} else if bytes.Compare(k, key[:len(k)]) > 0 { |
||||
ret = self.key(node, append(path, k)) |
||||
} else { |
||||
ret = nil |
||||
} |
||||
|
||||
if ret != nil { |
||||
return append(k, ret...) |
||||
} |
||||
} |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
// Get the next in keys
|
||||
func (self *Iterator) Next(key string) []byte { |
||||
self.trie.mut.Lock() |
||||
defer self.trie.mut.Unlock() |
||||
|
||||
k := RemTerm(CompactHexDecode(key)) |
||||
n := self.next(self.trie.getNode(self.trie.Root), k, nil) |
||||
|
||||
self.Key = []byte(DecodeCompact(n)) |
||||
|
||||
return self.Key |
||||
} |
Loading…
Reference in new issue