|
|
|
@ -1,8 +1,8 @@ |
|
|
|
|
package trie |
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
import ( |
|
|
|
|
"bytes" |
|
|
|
|
"container/list" |
|
|
|
|
"fmt" |
|
|
|
|
"sync" |
|
|
|
|
|
|
|
|
@ -10,618 +10,325 @@ import ( |
|
|
|
|
"github.com/ethereum/go-ethereum/ethutil" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
func ParanoiaCheck(t1 *Trie) (bool, *Trie) { |
|
|
|
|
t2 := New(ethutil.Config.Db, "") |
|
|
|
|
func ParanoiaCheck(t1 *Trie, backend Backend) (bool, *Trie) { |
|
|
|
|
t2 := New(nil, backend) |
|
|
|
|
|
|
|
|
|
t1.NewIterator().Each(func(key string, v *ethutil.Value) { |
|
|
|
|
t2.Update(key, v.Str()) |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
return bytes.Compare(t2.GetRoot(), t1.GetRoot()) == 0, t2 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (s *Cache) Len() int { |
|
|
|
|
return len(s.nodes) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
// A StateObject is an object that has a state root
|
|
|
|
|
// This is goig to be the object for the second level caching (the caching of object which have a state such as contracts)
|
|
|
|
|
type StateObject interface { |
|
|
|
|
State() *Trie |
|
|
|
|
Sync() |
|
|
|
|
Undo() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type Node struct { |
|
|
|
|
Key []byte |
|
|
|
|
Value *ethutil.Value |
|
|
|
|
Dirty bool |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func NewNode(key []byte, val *ethutil.Value, dirty bool) *Node { |
|
|
|
|
return &Node{Key: key, Value: val, Dirty: dirty} |
|
|
|
|
} |
|
|
|
|
it := t1.Iterator() |
|
|
|
|
for it.Next() { |
|
|
|
|
t2.Update(it.Key, it.Value) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (n *Node) Copy() *Node { |
|
|
|
|
return NewNode(n.Key, n.Value, n.Dirty) |
|
|
|
|
return bytes.Equal(t2.Hash(), t1.Hash()), t2 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type Cache struct { |
|
|
|
|
nodes map[string]*Node |
|
|
|
|
db ethutil.Database |
|
|
|
|
IsDirty bool |
|
|
|
|
} |
|
|
|
|
type Trie struct { |
|
|
|
|
mu sync.Mutex |
|
|
|
|
root Node |
|
|
|
|
roothash []byte |
|
|
|
|
cache *Cache |
|
|
|
|
|
|
|
|
|
func NewCache(db ethutil.Database) *Cache { |
|
|
|
|
return &Cache{db: db, nodes: make(map[string]*Node)} |
|
|
|
|
revisions *list.List |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (cache *Cache) PutValue(v interface{}, force bool) interface{} { |
|
|
|
|
value := ethutil.NewValue(v) |
|
|
|
|
func New(root []byte, backend Backend) *Trie { |
|
|
|
|
trie := &Trie{} |
|
|
|
|
trie.revisions = list.New() |
|
|
|
|
trie.roothash = root |
|
|
|
|
trie.cache = NewCache(backend) |
|
|
|
|
|
|
|
|
|
enc := value.Encode() |
|
|
|
|
if len(enc) >= 32 || force { |
|
|
|
|
sha := crypto.Sha3(enc) |
|
|
|
|
|
|
|
|
|
cache.nodes[string(sha)] = NewNode(sha, value, true) |
|
|
|
|
cache.IsDirty = true |
|
|
|
|
|
|
|
|
|
return sha |
|
|
|
|
if root != nil { |
|
|
|
|
value := ethutil.NewValueFromBytes(trie.cache.Get(root)) |
|
|
|
|
trie.root = trie.mknode(value) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return v |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (cache *Cache) Put(v interface{}) interface{} { |
|
|
|
|
return cache.PutValue(v, false) |
|
|
|
|
return trie |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (cache *Cache) Get(key []byte) *ethutil.Value { |
|
|
|
|
// First check if the key is the cache
|
|
|
|
|
if cache.nodes[string(key)] != nil { |
|
|
|
|
return cache.nodes[string(key)].Value |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Get the key of the database instead and cache it
|
|
|
|
|
data, _ := cache.db.Get(key) |
|
|
|
|
// Create the cached value
|
|
|
|
|
value := ethutil.NewValueFromBytes(data) |
|
|
|
|
|
|
|
|
|
defer func() { |
|
|
|
|
if r := recover(); r != nil { |
|
|
|
|
fmt.Println("RECOVER GET", cache, cache.nodes) |
|
|
|
|
panic("bye") |
|
|
|
|
} |
|
|
|
|
}() |
|
|
|
|
// Create caching node
|
|
|
|
|
cache.nodes[string(key)] = NewNode(key, value, true) |
|
|
|
|
|
|
|
|
|
return value |
|
|
|
|
func (self *Trie) Iterator() *Iterator { |
|
|
|
|
return NewIterator(self) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (cache *Cache) Delete(key []byte) { |
|
|
|
|
delete(cache.nodes, string(key)) |
|
|
|
|
|
|
|
|
|
cache.db.Delete(key) |
|
|
|
|
func (self *Trie) Copy() *Trie { |
|
|
|
|
return New(self.roothash, self.cache.backend) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (cache *Cache) Commit() { |
|
|
|
|
// Don't try to commit if it isn't dirty
|
|
|
|
|
if !cache.IsDirty { |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for key, node := range cache.nodes { |
|
|
|
|
if node.Dirty { |
|
|
|
|
cache.db.Put([]byte(key), node.Value.Encode()) |
|
|
|
|
node.Dirty = false |
|
|
|
|
} |
|
|
|
|
// Legacy support
|
|
|
|
|
func (self *Trie) Root() []byte { return self.Hash() } |
|
|
|
|
func (self *Trie) Hash() []byte { |
|
|
|
|
var hash []byte |
|
|
|
|
if self.root != nil { |
|
|
|
|
t := self.root.Hash() |
|
|
|
|
if byts, ok := t.([]byte); ok && len(byts) > 0 { |
|
|
|
|
hash = byts |
|
|
|
|
} else { |
|
|
|
|
hash = crypto.Sha3(ethutil.Encode(self.root.RlpData())) |
|
|
|
|
} |
|
|
|
|
cache.IsDirty = false |
|
|
|
|
|
|
|
|
|
// If the nodes grows beyond the 200 entries we simple empty it
|
|
|
|
|
// FIXME come up with something better
|
|
|
|
|
if len(cache.nodes) > 200 { |
|
|
|
|
cache.nodes = make(map[string]*Node) |
|
|
|
|
} else { |
|
|
|
|
hash = crypto.Sha3(ethutil.Encode("")) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (cache *Cache) Undo() { |
|
|
|
|
for key, node := range cache.nodes { |
|
|
|
|
if node.Dirty { |
|
|
|
|
delete(cache.nodes, key) |
|
|
|
|
} |
|
|
|
|
if !bytes.Equal(hash, self.roothash) { |
|
|
|
|
self.revisions.PushBack(self.roothash) |
|
|
|
|
self.roothash = hash |
|
|
|
|
} |
|
|
|
|
cache.IsDirty = false |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// A (modified) Radix Trie implementation. The Trie implements
|
|
|
|
|
// a caching mechanism and will used cached values if they are
|
|
|
|
|
// present. If a node is not present in the cache it will try to
|
|
|
|
|
// fetch it from the database and store the cached value.
|
|
|
|
|
// Please note that the data isn't persisted unless `Sync` is
|
|
|
|
|
// explicitly called.
|
|
|
|
|
type Trie struct { |
|
|
|
|
mut sync.RWMutex |
|
|
|
|
prevRoot interface{} |
|
|
|
|
Root interface{} |
|
|
|
|
//db Database
|
|
|
|
|
cache *Cache |
|
|
|
|
return hash |
|
|
|
|
} |
|
|
|
|
func (self *Trie) Commit() { |
|
|
|
|
self.mu.Lock() |
|
|
|
|
defer self.mu.Unlock() |
|
|
|
|
|
|
|
|
|
func copyRoot(root interface{}) interface{} { |
|
|
|
|
var prevRootCopy interface{} |
|
|
|
|
if b, ok := root.([]byte); ok { |
|
|
|
|
prevRootCopy = ethutil.CopyBytes(b) |
|
|
|
|
} else { |
|
|
|
|
prevRootCopy = root |
|
|
|
|
} |
|
|
|
|
// Hash first
|
|
|
|
|
self.Hash() |
|
|
|
|
|
|
|
|
|
return prevRootCopy |
|
|
|
|
self.cache.Flush() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func New(db ethutil.Database, Root interface{}) *Trie { |
|
|
|
|
// Make absolute sure the root is copied
|
|
|
|
|
r := copyRoot(Root) |
|
|
|
|
p := copyRoot(Root) |
|
|
|
|
|
|
|
|
|
trie := &Trie{cache: NewCache(db), Root: r, prevRoot: p} |
|
|
|
|
trie.setRoot(Root) |
|
|
|
|
// Reset should only be called if the trie has been hashed
|
|
|
|
|
func (self *Trie) Reset() { |
|
|
|
|
self.mu.Lock() |
|
|
|
|
defer self.mu.Unlock() |
|
|
|
|
|
|
|
|
|
return trie |
|
|
|
|
} |
|
|
|
|
self.cache.Reset() |
|
|
|
|
|
|
|
|
|
func (self *Trie) setRoot(root interface{}) { |
|
|
|
|
switch t := root.(type) { |
|
|
|
|
case string: |
|
|
|
|
//if t == "" {
|
|
|
|
|
// root = crypto.Sha3(ethutil.Encode(""))
|
|
|
|
|
//}
|
|
|
|
|
self.Root = []byte(t) |
|
|
|
|
case []byte: |
|
|
|
|
self.Root = root |
|
|
|
|
default: |
|
|
|
|
self.Root = self.cache.PutValue(root, true) |
|
|
|
|
if self.revisions.Len() > 0 { |
|
|
|
|
revision := self.revisions.Remove(self.revisions.Back()).([]byte) |
|
|
|
|
self.roothash = revision |
|
|
|
|
} |
|
|
|
|
value := ethutil.NewValueFromBytes(self.cache.Get(self.roothash)) |
|
|
|
|
self.root = self.mknode(value) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (t *Trie) Update(key, value string) { |
|
|
|
|
t.mut.Lock() |
|
|
|
|
defer t.mut.Unlock() |
|
|
|
|
func (self *Trie) UpdateString(key, value string) Node { return self.Update([]byte(key), []byte(value)) } |
|
|
|
|
func (self *Trie) Update(key, value []byte) Node { |
|
|
|
|
self.mu.Lock() |
|
|
|
|
defer self.mu.Unlock() |
|
|
|
|
|
|
|
|
|
k := CompactHexDecode(key) |
|
|
|
|
k := CompactHexDecode(string(key)) |
|
|
|
|
|
|
|
|
|
var root interface{} |
|
|
|
|
if value != "" { |
|
|
|
|
root = t.UpdateState(t.Root, k, value) |
|
|
|
|
if len(value) != 0 { |
|
|
|
|
self.root = self.insert(self.root, k, &ValueNode{self, value}) |
|
|
|
|
} else { |
|
|
|
|
root = t.deleteState(t.Root, k) |
|
|
|
|
self.root = self.delete(self.root, k) |
|
|
|
|
} |
|
|
|
|
t.setRoot(root) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (t *Trie) Get(key string) string { |
|
|
|
|
t.mut.Lock() |
|
|
|
|
defer t.mut.Unlock() |
|
|
|
|
|
|
|
|
|
k := CompactHexDecode(key) |
|
|
|
|
c := ethutil.NewValue(t.getState(t.Root, k)) |
|
|
|
|
|
|
|
|
|
return c.Str() |
|
|
|
|
return self.root |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (t *Trie) Delete(key string) { |
|
|
|
|
t.mut.Lock() |
|
|
|
|
defer t.mut.Unlock() |
|
|
|
|
|
|
|
|
|
k := CompactHexDecode(key) |
|
|
|
|
|
|
|
|
|
root := t.deleteState(t.Root, k) |
|
|
|
|
t.setRoot(root) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (self *Trie) GetRoot() []byte { |
|
|
|
|
switch t := self.Root.(type) { |
|
|
|
|
case string: |
|
|
|
|
if t == "" { |
|
|
|
|
return crypto.Sha3(ethutil.Encode("")) |
|
|
|
|
} |
|
|
|
|
return []byte(t) |
|
|
|
|
case []byte: |
|
|
|
|
if len(t) == 0 { |
|
|
|
|
return crypto.Sha3(ethutil.Encode("")) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return t |
|
|
|
|
default: |
|
|
|
|
panic(fmt.Sprintf("invalid root type %T (%v)", self.Root, self.Root)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
func (self *Trie) GetString(key string) []byte { return self.Get([]byte(key)) } |
|
|
|
|
func (self *Trie) Get(key []byte) []byte { |
|
|
|
|
self.mu.Lock() |
|
|
|
|
defer self.mu.Unlock() |
|
|
|
|
|
|
|
|
|
// Simple compare function which creates a rlp value out of the evaluated objects
|
|
|
|
|
func (t *Trie) Cmp(trie *Trie) bool { |
|
|
|
|
return ethutil.NewValue(t.Root).Cmp(ethutil.NewValue(trie.Root)) |
|
|
|
|
} |
|
|
|
|
k := CompactHexDecode(string(key)) |
|
|
|
|
|
|
|
|
|
// Returns a copy of this trie
|
|
|
|
|
func (t *Trie) Copy() *Trie { |
|
|
|
|
trie := New(t.cache.db, t.Root) |
|
|
|
|
for key, node := range t.cache.nodes { |
|
|
|
|
trie.cache.nodes[key] = node.Copy() |
|
|
|
|
n := self.get(self.root, k) |
|
|
|
|
if n != nil { |
|
|
|
|
return n.(*ValueNode).Val() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return trie |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Save the cached value to the database.
|
|
|
|
|
func (t *Trie) Sync() { |
|
|
|
|
t.cache.Commit() |
|
|
|
|
t.prevRoot = copyRoot(t.Root) |
|
|
|
|
} |
|
|
|
|
func (self *Trie) DeleteString(key string) Node { return self.Delete([]byte(key)) } |
|
|
|
|
func (self *Trie) Delete(key []byte) Node { |
|
|
|
|
self.mu.Lock() |
|
|
|
|
defer self.mu.Unlock() |
|
|
|
|
|
|
|
|
|
func (t *Trie) Undo() { |
|
|
|
|
t.cache.Undo() |
|
|
|
|
t.Root = t.prevRoot |
|
|
|
|
} |
|
|
|
|
k := CompactHexDecode(string(key)) |
|
|
|
|
self.root = self.delete(self.root, k) |
|
|
|
|
|
|
|
|
|
func (t *Trie) Cache() *Cache { |
|
|
|
|
return t.cache |
|
|
|
|
return self.root |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (t *Trie) getState(node interface{}, key []byte) interface{} { |
|
|
|
|
n := ethutil.NewValue(node) |
|
|
|
|
// Return the node if key is empty (= found)
|
|
|
|
|
if len(key) == 0 || n.IsNil() || n.Len() == 0 { |
|
|
|
|
return node |
|
|
|
|
func (self *Trie) insert(node Node, key []byte, value Node) Node { |
|
|
|
|
if len(key) == 0 { |
|
|
|
|
return value |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
currentNode := t.getNode(node) |
|
|
|
|
length := currentNode.Len() |
|
|
|
|
|
|
|
|
|
if length == 0 { |
|
|
|
|
return "" |
|
|
|
|
} else if length == 2 { |
|
|
|
|
// Decode the key
|
|
|
|
|
k := CompactDecode(currentNode.Get(0).Str()) |
|
|
|
|
v := currentNode.Get(1).Raw() |
|
|
|
|
|
|
|
|
|
if len(key) >= len(k) && bytes.Equal(k, key[:len(k)]) { //CompareIntSlice(k, key[:len(k)]) {
|
|
|
|
|
return t.getState(v, key[len(k):]) |
|
|
|
|
} else { |
|
|
|
|
return "" |
|
|
|
|
if node == nil { |
|
|
|
|
return NewShortNode(self, key, value) |
|
|
|
|
} |
|
|
|
|
} else if length == 17 { |
|
|
|
|
return t.getState(currentNode.Get(int(key[0])).Raw(), key[1:]) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// It shouldn't come this far
|
|
|
|
|
panic("unexpected return") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (t *Trie) getNode(node interface{}) *ethutil.Value { |
|
|
|
|
n := ethutil.NewValue(node) |
|
|
|
|
|
|
|
|
|
if !n.Get(0).IsNil() { |
|
|
|
|
return n |
|
|
|
|
switch node := node.(type) { |
|
|
|
|
case *ShortNode: |
|
|
|
|
k := node.Key() |
|
|
|
|
cnode := node.Value() |
|
|
|
|
if bytes.Equal(k, key) { |
|
|
|
|
return NewShortNode(self, key, value) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
str := n.Str() |
|
|
|
|
if len(str) == 0 { |
|
|
|
|
var n Node |
|
|
|
|
matchlength := MatchingNibbleLength(key, k) |
|
|
|
|
if matchlength == len(k) { |
|
|
|
|
n = self.insert(cnode, key[matchlength:], value) |
|
|
|
|
} else { |
|
|
|
|
pnode := self.insert(nil, k[matchlength+1:], cnode) |
|
|
|
|
nnode := self.insert(nil, key[matchlength+1:], value) |
|
|
|
|
fulln := NewFullNode(self) |
|
|
|
|
fulln.set(k[matchlength], pnode) |
|
|
|
|
fulln.set(key[matchlength], nnode) |
|
|
|
|
n = fulln |
|
|
|
|
} |
|
|
|
|
if matchlength == 0 { |
|
|
|
|
return n |
|
|
|
|
} else if len(str) < 32 { |
|
|
|
|
return ethutil.NewValueFromBytes([]byte(str)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
data := t.cache.Get(n.Bytes()) |
|
|
|
|
return NewShortNode(self, key[:matchlength], n) |
|
|
|
|
|
|
|
|
|
return data |
|
|
|
|
} |
|
|
|
|
case *FullNode: |
|
|
|
|
cpy := node.Copy().(*FullNode) |
|
|
|
|
cpy.set(key[0], self.insert(node.branch(key[0]), key[1:], value)) |
|
|
|
|
|
|
|
|
|
func (t *Trie) UpdateState(node interface{}, key []byte, value string) interface{} { |
|
|
|
|
return t.InsertState(node, key, value) |
|
|
|
|
} |
|
|
|
|
return cpy |
|
|
|
|
|
|
|
|
|
func (t *Trie) Put(node interface{}) interface{} { |
|
|
|
|
return t.cache.Put(node) |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func EmptyStringSlice(l int) []interface{} { |
|
|
|
|
slice := make([]interface{}, l) |
|
|
|
|
for i := 0; i < l; i++ { |
|
|
|
|
slice[i] = "" |
|
|
|
|
default: |
|
|
|
|
panic(fmt.Sprintf("%T: invalid node: %v", node, node)) |
|
|
|
|
} |
|
|
|
|
return slice |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (t *Trie) InsertState(node interface{}, key []byte, value interface{}) interface{} { |
|
|
|
|
func (self *Trie) get(node Node, key []byte) Node { |
|
|
|
|
if len(key) == 0 { |
|
|
|
|
return value |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// New node
|
|
|
|
|
n := ethutil.NewValue(node) |
|
|
|
|
if node == nil || n.Len() == 0 { |
|
|
|
|
newNode := []interface{}{CompactEncode(key), value} |
|
|
|
|
|
|
|
|
|
return t.Put(newNode) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
currentNode := t.getNode(node) |
|
|
|
|
// Check for "special" 2 slice type node
|
|
|
|
|
if currentNode.Len() == 2 { |
|
|
|
|
// Decode the key
|
|
|
|
|
|
|
|
|
|
k := CompactDecode(currentNode.Get(0).Str()) |
|
|
|
|
v := currentNode.Get(1).Raw() |
|
|
|
|
|
|
|
|
|
// Matching key pair (ie. there's already an object with this key)
|
|
|
|
|
if bytes.Equal(k, key) { //CompareIntSlice(k, key) {
|
|
|
|
|
newNode := []interface{}{CompactEncode(key), value} |
|
|
|
|
return t.Put(newNode) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var newHash interface{} |
|
|
|
|
matchingLength := MatchingNibbleLength(key, k) |
|
|
|
|
if matchingLength == len(k) { |
|
|
|
|
// Insert the hash, creating a new node
|
|
|
|
|
newHash = t.InsertState(v, key[matchingLength:], value) |
|
|
|
|
} else { |
|
|
|
|
// Expand the 2 length slice to a 17 length slice
|
|
|
|
|
oldNode := t.InsertState("", k[matchingLength+1:], v) |
|
|
|
|
newNode := t.InsertState("", key[matchingLength+1:], value) |
|
|
|
|
// Create an expanded slice
|
|
|
|
|
scaledSlice := EmptyStringSlice(17) |
|
|
|
|
// Set the copied and new node
|
|
|
|
|
scaledSlice[k[matchingLength]] = oldNode |
|
|
|
|
scaledSlice[key[matchingLength]] = newNode |
|
|
|
|
|
|
|
|
|
newHash = t.Put(scaledSlice) |
|
|
|
|
return node |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if matchingLength == 0 { |
|
|
|
|
// End of the chain, return
|
|
|
|
|
return newHash |
|
|
|
|
} else { |
|
|
|
|
newNode := []interface{}{CompactEncode(key[:matchingLength]), newHash} |
|
|
|
|
return t.Put(newNode) |
|
|
|
|
if node == nil { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
|
|
|
|
|
// Copy the current node over to the new node and replace the first nibble in the key
|
|
|
|
|
newNode := EmptyStringSlice(17) |
|
|
|
|
switch node := node.(type) { |
|
|
|
|
case *ShortNode: |
|
|
|
|
k := node.Key() |
|
|
|
|
cnode := node.Value() |
|
|
|
|
|
|
|
|
|
for i := 0; i < 17; i++ { |
|
|
|
|
cpy := currentNode.Get(i).Raw() |
|
|
|
|
if cpy != nil { |
|
|
|
|
newNode[i] = cpy |
|
|
|
|
} |
|
|
|
|
if len(key) >= len(k) && bytes.Equal(k, key[:len(k)]) { |
|
|
|
|
return self.get(cnode, key[len(k):]) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
newNode[key[0]] = t.InsertState(currentNode.Get(int(key[0])).Raw(), key[1:], value) |
|
|
|
|
|
|
|
|
|
return t.Put(newNode) |
|
|
|
|
return nil |
|
|
|
|
case *FullNode: |
|
|
|
|
return self.get(node.branch(key[0]), key[1:]) |
|
|
|
|
default: |
|
|
|
|
panic(fmt.Sprintf("%T: invalid node: %v", node, node)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
panic("unexpected end") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (t *Trie) deleteState(node interface{}, key []byte) interface{} { |
|
|
|
|
if len(key) == 0 { |
|
|
|
|
return "" |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// New node
|
|
|
|
|
n := ethutil.NewValue(node) |
|
|
|
|
//if node == nil || (n.Type() == reflect.String && (n.Str() == "" || n.Get(0).IsNil())) || n.Len() == 0 {
|
|
|
|
|
if node == nil || n.Len() == 0 { |
|
|
|
|
//return nil
|
|
|
|
|
//fmt.Printf("<empty ret> %x %d\n", n, len(n.Bytes()))
|
|
|
|
|
|
|
|
|
|
return "" |
|
|
|
|
func (self *Trie) delete(node Node, key []byte) Node { |
|
|
|
|
if len(key) == 0 && node == nil { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
currentNode := t.getNode(node) |
|
|
|
|
// Check for "special" 2 slice type node
|
|
|
|
|
if currentNode.Len() == 2 { |
|
|
|
|
// Decode the key
|
|
|
|
|
k := CompactDecode(currentNode.Get(0).Str()) |
|
|
|
|
v := currentNode.Get(1).Raw() |
|
|
|
|
|
|
|
|
|
// Matching key pair (ie. there's already an object with this key)
|
|
|
|
|
if bytes.Equal(k, key) { //CompareIntSlice(k, key) {
|
|
|
|
|
//fmt.Printf("<delete ret> %x\n", v)
|
|
|
|
|
|
|
|
|
|
return "" |
|
|
|
|
} else if bytes.Equal(key[:len(k)], k) { //CompareIntSlice(key[:len(k)], k) {
|
|
|
|
|
hash := t.deleteState(v, key[len(k):]) |
|
|
|
|
child := t.getNode(hash) |
|
|
|
|
switch node := node.(type) { |
|
|
|
|
case *ShortNode: |
|
|
|
|
k := node.Key() |
|
|
|
|
cnode := node.Value() |
|
|
|
|
if bytes.Equal(key, k) { |
|
|
|
|
return nil |
|
|
|
|
} else if bytes.Equal(key[:len(k)], k) { |
|
|
|
|
child := self.delete(cnode, key[len(k):]) |
|
|
|
|
|
|
|
|
|
var newNode []interface{} |
|
|
|
|
if child.Len() == 2 { |
|
|
|
|
newKey := append(k, CompactDecode(child.Get(0).Str())...) |
|
|
|
|
newNode = []interface{}{CompactEncode(newKey), child.Get(1).Raw()} |
|
|
|
|
} else { |
|
|
|
|
newNode = []interface{}{currentNode.Get(0).Str(), hash} |
|
|
|
|
var n Node |
|
|
|
|
switch child := child.(type) { |
|
|
|
|
case *ShortNode: |
|
|
|
|
nkey := append(k, child.Key()...) |
|
|
|
|
n = NewShortNode(self, nkey, child.Value()) |
|
|
|
|
case *FullNode: |
|
|
|
|
sn := NewShortNode(self, node.Key(), child) |
|
|
|
|
sn.key = node.key |
|
|
|
|
n = sn |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//fmt.Printf("%x\n", newNode)
|
|
|
|
|
|
|
|
|
|
return t.Put(newNode) |
|
|
|
|
return n |
|
|
|
|
} else { |
|
|
|
|
return node |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// Copy the current node over to the new node and replace the first nibble in the key
|
|
|
|
|
n := EmptyStringSlice(17) |
|
|
|
|
var newNode []interface{} |
|
|
|
|
|
|
|
|
|
for i := 0; i < 17; i++ { |
|
|
|
|
cpy := currentNode.Get(i).Raw() |
|
|
|
|
if cpy != nil { |
|
|
|
|
n[i] = cpy |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
case *FullNode: |
|
|
|
|
n := node.Copy().(*FullNode) |
|
|
|
|
n.set(key[0], self.delete(n.branch(key[0]), key[1:])) |
|
|
|
|
|
|
|
|
|
n[key[0]] = t.deleteState(n[key[0]], key[1:]) |
|
|
|
|
amount := -1 |
|
|
|
|
pos := -1 |
|
|
|
|
for i := 0; i < 17; i++ { |
|
|
|
|
if n[i] != "" { |
|
|
|
|
if amount == -1 { |
|
|
|
|
amount = i |
|
|
|
|
if n.branch(byte(i)) != nil { |
|
|
|
|
if pos == -1 { |
|
|
|
|
pos = i |
|
|
|
|
} else { |
|
|
|
|
amount = -2 |
|
|
|
|
} |
|
|
|
|
pos = -2 |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if amount == 16 { |
|
|
|
|
newNode = []interface{}{CompactEncode([]byte{16}), n[amount]} |
|
|
|
|
} else if amount >= 0 { |
|
|
|
|
child := t.getNode(n[amount]) |
|
|
|
|
if child.Len() == 17 { |
|
|
|
|
newNode = []interface{}{CompactEncode([]byte{byte(amount)}), n[amount]} |
|
|
|
|
} else if child.Len() == 2 { |
|
|
|
|
key := append([]byte{byte(amount)}, CompactDecode(child.Get(0).Str())...) |
|
|
|
|
newNode = []interface{}{CompactEncode(key), child.Get(1).Str()} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var nnode Node |
|
|
|
|
if pos == 16 { |
|
|
|
|
nnode = NewShortNode(self, []byte{16}, n.branch(byte(pos))) |
|
|
|
|
} else if pos >= 0 { |
|
|
|
|
cnode := n.branch(byte(pos)) |
|
|
|
|
switch cnode := cnode.(type) { |
|
|
|
|
case *ShortNode: |
|
|
|
|
// Stitch keys
|
|
|
|
|
k := append([]byte{byte(pos)}, cnode.Key()...) |
|
|
|
|
nnode = NewShortNode(self, k, cnode.Value()) |
|
|
|
|
case *FullNode: |
|
|
|
|
nnode = NewShortNode(self, []byte{byte(pos)}, n.branch(byte(pos))) |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
newNode = n |
|
|
|
|
nnode = n |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//fmt.Printf("%x\n", newNode)
|
|
|
|
|
return t.Put(newNode) |
|
|
|
|
return nnode |
|
|
|
|
case nil: |
|
|
|
|
return nil |
|
|
|
|
default: |
|
|
|
|
panic(fmt.Sprintf("%T: invalid node: %v (%v)", node, node, key)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
panic("unexpected return") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type TrieIterator struct { |
|
|
|
|
trie *Trie |
|
|
|
|
key string |
|
|
|
|
value string |
|
|
|
|
|
|
|
|
|
shas [][]byte |
|
|
|
|
values []string |
|
|
|
|
|
|
|
|
|
lastNode []byte |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (t *Trie) NewIterator() *TrieIterator { |
|
|
|
|
return &TrieIterator{trie: t} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (self *Trie) Iterator() *Iterator { |
|
|
|
|
return NewIterator(self) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Some time in the near future this will need refactoring :-)
|
|
|
|
|
// XXX Note to self, IsSlice == inline node. Str == sha3 to node
|
|
|
|
|
func (it *TrieIterator) workNode(currentNode *ethutil.Value) { |
|
|
|
|
if currentNode.Len() == 2 { |
|
|
|
|
k := CompactDecode(currentNode.Get(0).Str()) |
|
|
|
|
|
|
|
|
|
if currentNode.Get(1).Str() == "" { |
|
|
|
|
it.workNode(currentNode.Get(1)) |
|
|
|
|
} else { |
|
|
|
|
if k[len(k)-1] == 16 { |
|
|
|
|
it.values = append(it.values, currentNode.Get(1).Str()) |
|
|
|
|
} else { |
|
|
|
|
it.shas = append(it.shas, currentNode.Get(1).Bytes()) |
|
|
|
|
it.getNode(currentNode.Get(1).Bytes()) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
for i := 0; i < currentNode.Len(); i++ { |
|
|
|
|
if i == 16 && currentNode.Get(i).Len() != 0 { |
|
|
|
|
it.values = append(it.values, currentNode.Get(i).Str()) |
|
|
|
|
} else { |
|
|
|
|
if currentNode.Get(i).Str() == "" { |
|
|
|
|
it.workNode(currentNode.Get(i)) |
|
|
|
|
} else { |
|
|
|
|
val := currentNode.Get(i).Str() |
|
|
|
|
if val != "" { |
|
|
|
|
it.shas = append(it.shas, currentNode.Get(1).Bytes()) |
|
|
|
|
it.getNode([]byte(val)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// casting functions and cache storing
|
|
|
|
|
func (self *Trie) mknode(value *ethutil.Value) Node { |
|
|
|
|
l := value.Len() |
|
|
|
|
switch l { |
|
|
|
|
case 0: |
|
|
|
|
return nil |
|
|
|
|
case 2: |
|
|
|
|
// A value node may consists of 2 bytes.
|
|
|
|
|
if value.Get(0).Len() != 0 { |
|
|
|
|
return NewShortNode(self, CompactDecode(string(value.Get(0).Bytes())), self.mknode(value.Get(1))) |
|
|
|
|
} |
|
|
|
|
case 17: |
|
|
|
|
fnode := NewFullNode(self) |
|
|
|
|
for i := 0; i < l; i++ { |
|
|
|
|
fnode.set(byte(i), self.mknode(value.Get(i))) |
|
|
|
|
} |
|
|
|
|
return fnode |
|
|
|
|
case 32: |
|
|
|
|
return &HashNode{value.Bytes()} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (it *TrieIterator) getNode(node []byte) { |
|
|
|
|
currentNode := it.trie.cache.Get(node) |
|
|
|
|
it.workNode(currentNode) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (it *TrieIterator) Collect() [][]byte { |
|
|
|
|
if it.trie.Root == "" { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
it.getNode(ethutil.NewValue(it.trie.Root).Bytes()) |
|
|
|
|
|
|
|
|
|
return it.shas |
|
|
|
|
return &ValueNode{self, value.Bytes()} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (it *TrieIterator) Purge() int { |
|
|
|
|
shas := it.Collect() |
|
|
|
|
for _, sha := range shas { |
|
|
|
|
it.trie.cache.Delete(sha) |
|
|
|
|
func (self *Trie) trans(node Node) Node { |
|
|
|
|
switch node := node.(type) { |
|
|
|
|
case *HashNode: |
|
|
|
|
value := ethutil.NewValueFromBytes(self.cache.Get(node.key)) |
|
|
|
|
return self.mknode(value) |
|
|
|
|
default: |
|
|
|
|
return node |
|
|
|
|
} |
|
|
|
|
return len(it.values) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (it *TrieIterator) Key() string { |
|
|
|
|
return "" |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (it *TrieIterator) Value() string { |
|
|
|
|
return "" |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type EachCallback func(key string, node *ethutil.Value) |
|
|
|
|
func (self *Trie) store(node Node) interface{} { |
|
|
|
|
data := ethutil.Encode(node) |
|
|
|
|
if len(data) >= 32 { |
|
|
|
|
key := crypto.Sha3(data) |
|
|
|
|
self.cache.Put(key, data) |
|
|
|
|
|
|
|
|
|
func (it *TrieIterator) Each(cb EachCallback) { |
|
|
|
|
it.fetchNode(nil, ethutil.NewValue(it.trie.Root).Bytes(), cb) |
|
|
|
|
} |
|
|
|
|
return key |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (it *TrieIterator) fetchNode(key []byte, node []byte, cb EachCallback) { |
|
|
|
|
it.iterateNode(key, it.trie.cache.Get(node), cb) |
|
|
|
|
return node.RlpData() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (it *TrieIterator) iterateNode(key []byte, currentNode *ethutil.Value, cb EachCallback) { |
|
|
|
|
if currentNode.Len() == 2 { |
|
|
|
|
k := CompactDecode(currentNode.Get(0).Str()) |
|
|
|
|
|
|
|
|
|
pk := append(key, k...) |
|
|
|
|
if currentNode.Get(1).Len() != 0 && currentNode.Get(1).Str() == "" { |
|
|
|
|
it.iterateNode(pk, currentNode.Get(1), cb) |
|
|
|
|
} else { |
|
|
|
|
if k[len(k)-1] == 16 { |
|
|
|
|
cb(DecodeCompact(pk), currentNode.Get(1)) |
|
|
|
|
} else { |
|
|
|
|
it.fetchNode(pk, currentNode.Get(1).Bytes(), cb) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
for i := 0; i < currentNode.Len(); i++ { |
|
|
|
|
pk := append(key, byte(i)) |
|
|
|
|
if i == 16 && currentNode.Get(i).Len() != 0 { |
|
|
|
|
cb(DecodeCompact(pk), currentNode.Get(i)) |
|
|
|
|
} else { |
|
|
|
|
if currentNode.Get(i).Len() != 0 && currentNode.Get(i).Str() == "" { |
|
|
|
|
it.iterateNode(pk, currentNode.Get(i), cb) |
|
|
|
|
} else { |
|
|
|
|
val := currentNode.Get(i).Str() |
|
|
|
|
if val != "" { |
|
|
|
|
it.fetchNode(pk, []byte(val), cb) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
func (self *Trie) PrintRoot() { |
|
|
|
|
fmt.Println(self.root) |
|
|
|
|
} |
|
|
|
|
*/ |
|
|
|
|