|
|
@ -1,7 +1,9 @@ |
|
|
|
package ethutil |
|
|
|
package ethtrie |
|
|
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
import ( |
|
|
|
"fmt" |
|
|
|
"fmt" |
|
|
|
|
|
|
|
"github.com/ethereum/eth-go/ethcrypto" |
|
|
|
|
|
|
|
"github.com/ethereum/eth-go/ethutil" |
|
|
|
"reflect" |
|
|
|
"reflect" |
|
|
|
"sync" |
|
|
|
"sync" |
|
|
|
) |
|
|
|
) |
|
|
@ -21,11 +23,11 @@ type StateObject interface { |
|
|
|
|
|
|
|
|
|
|
|
type Node struct { |
|
|
|
type Node struct { |
|
|
|
Key []byte |
|
|
|
Key []byte |
|
|
|
Value *Value |
|
|
|
Value *ethutil.Value |
|
|
|
Dirty bool |
|
|
|
Dirty bool |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func NewNode(key []byte, val *Value, dirty bool) *Node { |
|
|
|
func NewNode(key []byte, val *ethutil.Value, dirty bool) *Node { |
|
|
|
return &Node{Key: key, Value: val, Dirty: dirty} |
|
|
|
return &Node{Key: key, Value: val, Dirty: dirty} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -35,20 +37,20 @@ func (n *Node) Copy() *Node { |
|
|
|
|
|
|
|
|
|
|
|
type Cache struct { |
|
|
|
type Cache struct { |
|
|
|
nodes map[string]*Node |
|
|
|
nodes map[string]*Node |
|
|
|
db Database |
|
|
|
db ethutil.Database |
|
|
|
IsDirty bool |
|
|
|
IsDirty bool |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func NewCache(db Database) *Cache { |
|
|
|
func NewCache(db ethutil.Database) *Cache { |
|
|
|
return &Cache{db: db, nodes: make(map[string]*Node)} |
|
|
|
return &Cache{db: db, nodes: make(map[string]*Node)} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (cache *Cache) Put(v interface{}) interface{} { |
|
|
|
func (cache *Cache) Put(v interface{}) interface{} { |
|
|
|
value := NewValue(v) |
|
|
|
value := ethutil.NewValue(v) |
|
|
|
|
|
|
|
|
|
|
|
enc := value.Encode() |
|
|
|
enc := value.Encode() |
|
|
|
if len(enc) >= 32 { |
|
|
|
if len(enc) >= 32 { |
|
|
|
sha := Sha3Bin(enc) |
|
|
|
sha := ethcrypto.Sha3Bin(enc) |
|
|
|
|
|
|
|
|
|
|
|
cache.nodes[string(sha)] = NewNode(sha, value, true) |
|
|
|
cache.nodes[string(sha)] = NewNode(sha, value, true) |
|
|
|
cache.IsDirty = true |
|
|
|
cache.IsDirty = true |
|
|
@ -59,7 +61,7 @@ func (cache *Cache) Put(v interface{}) interface{} { |
|
|
|
return v |
|
|
|
return v |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (cache *Cache) Get(key []byte) *Value { |
|
|
|
func (cache *Cache) Get(key []byte) *ethutil.Value { |
|
|
|
// First check if the key is the cache
|
|
|
|
// First check if the key is the cache
|
|
|
|
if cache.nodes[string(key)] != nil { |
|
|
|
if cache.nodes[string(key)] != nil { |
|
|
|
return cache.nodes[string(key)].Value |
|
|
|
return cache.nodes[string(key)].Value |
|
|
@ -68,7 +70,7 @@ func (cache *Cache) Get(key []byte) *Value { |
|
|
|
// Get the key of the database instead and cache it
|
|
|
|
// Get the key of the database instead and cache it
|
|
|
|
data, _ := cache.db.Get(key) |
|
|
|
data, _ := cache.db.Get(key) |
|
|
|
// Create the cached value
|
|
|
|
// Create the cached value
|
|
|
|
value := NewValueFromBytes(data) |
|
|
|
value := ethutil.NewValueFromBytes(data) |
|
|
|
// Create caching node
|
|
|
|
// Create caching node
|
|
|
|
cache.nodes[string(key)] = NewNode(key, value, false) |
|
|
|
cache.nodes[string(key)] = NewNode(key, value, false) |
|
|
|
|
|
|
|
|
|
|
@ -128,7 +130,7 @@ type Trie struct { |
|
|
|
func copyRoot(root interface{}) interface{} { |
|
|
|
func copyRoot(root interface{}) interface{} { |
|
|
|
var prevRootCopy interface{} |
|
|
|
var prevRootCopy interface{} |
|
|
|
if b, ok := root.([]byte); ok { |
|
|
|
if b, ok := root.([]byte); ok { |
|
|
|
prevRootCopy = CopyBytes(b) |
|
|
|
prevRootCopy = ethutil.CopyBytes(b) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
prevRootCopy = root |
|
|
|
prevRootCopy = root |
|
|
|
} |
|
|
|
} |
|
|
@ -136,7 +138,7 @@ func copyRoot(root interface{}) interface{} { |
|
|
|
return prevRootCopy |
|
|
|
return prevRootCopy |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func NewTrie(db Database, Root interface{}) *Trie { |
|
|
|
func NewTrie(db ethutil.Database, Root interface{}) *Trie { |
|
|
|
// Make absolute sure the root is copied
|
|
|
|
// Make absolute sure the root is copied
|
|
|
|
r := copyRoot(Root) |
|
|
|
r := copyRoot(Root) |
|
|
|
p := copyRoot(Root) |
|
|
|
p := copyRoot(Root) |
|
|
@ -176,7 +178,7 @@ func (t *Trie) Get(key string) string { |
|
|
|
defer t.mut.RUnlock() |
|
|
|
defer t.mut.RUnlock() |
|
|
|
|
|
|
|
|
|
|
|
k := CompactHexDecode(key) |
|
|
|
k := CompactHexDecode(key) |
|
|
|
c := NewValue(t.GetState(t.Root, k)) |
|
|
|
c := ethutil.NewValue(t.GetState(t.Root, k)) |
|
|
|
|
|
|
|
|
|
|
|
return c.Str() |
|
|
|
return c.Str() |
|
|
|
} |
|
|
|
} |
|
|
@ -186,7 +188,7 @@ func (t *Trie) Delete(key string) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (t *Trie) GetState(node interface{}, key []int) interface{} { |
|
|
|
func (t *Trie) GetState(node interface{}, key []int) interface{} { |
|
|
|
n := NewValue(node) |
|
|
|
n := ethutil.NewValue(node) |
|
|
|
// Return the node if key is empty (= found)
|
|
|
|
// Return the node if key is empty (= found)
|
|
|
|
if len(key) == 0 || n.IsNil() || n.Len() == 0 { |
|
|
|
if len(key) == 0 || n.IsNil() || n.Len() == 0 { |
|
|
|
return node |
|
|
|
return node |
|
|
@ -216,8 +218,8 @@ func (t *Trie) GetState(node interface{}, key []int) interface{} { |
|
|
|
return "" |
|
|
|
return "" |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (t *Trie) GetNode(node interface{}) *Value { |
|
|
|
func (t *Trie) GetNode(node interface{}) *ethutil.Value { |
|
|
|
n := NewValue(node) |
|
|
|
n := ethutil.NewValue(node) |
|
|
|
|
|
|
|
|
|
|
|
if !n.Get(0).IsNil() { |
|
|
|
if !n.Get(0).IsNil() { |
|
|
|
return n |
|
|
|
return n |
|
|
@ -227,7 +229,7 @@ func (t *Trie) GetNode(node interface{}) *Value { |
|
|
|
if len(str) == 0 { |
|
|
|
if len(str) == 0 { |
|
|
|
return n |
|
|
|
return n |
|
|
|
} else if len(str) < 32 { |
|
|
|
} else if len(str) < 32 { |
|
|
|
return NewValueFromBytes([]byte(str)) |
|
|
|
return ethutil.NewValueFromBytes([]byte(str)) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return t.cache.Get(n.Bytes()) |
|
|
|
return t.cache.Get(n.Bytes()) |
|
|
@ -273,7 +275,7 @@ func (t *Trie) InsertState(node interface{}, key []int, value interface{}) inter |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// New node
|
|
|
|
// New node
|
|
|
|
n := NewValue(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.Type() == reflect.String && (n.Str() == "" || n.Get(0).IsNil())) || n.Len() == 0 { |
|
|
|
newNode := []interface{}{CompactEncode(key), value} |
|
|
|
newNode := []interface{}{CompactEncode(key), value} |
|
|
|
|
|
|
|
|
|
|
@ -345,7 +347,7 @@ func (t *Trie) DeleteState(node interface{}, key []int) interface{} { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// New node
|
|
|
|
// New node
|
|
|
|
n := NewValue(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.Type() == reflect.String && (n.Str() == "" || n.Get(0).IsNil())) || n.Len() == 0 { |
|
|
|
return "" |
|
|
|
return "" |
|
|
|
} |
|
|
|
} |
|
|
@ -422,7 +424,7 @@ func (t *Trie) DeleteState(node interface{}, key []int) interface{} { |
|
|
|
|
|
|
|
|
|
|
|
// Simple compare function which creates a rlp value out of the evaluated objects
|
|
|
|
// Simple compare function which creates a rlp value out of the evaluated objects
|
|
|
|
func (t *Trie) Cmp(trie *Trie) bool { |
|
|
|
func (t *Trie) Cmp(trie *Trie) bool { |
|
|
|
return NewValue(t.Root).Cmp(NewValue(trie.Root)) |
|
|
|
return ethutil.NewValue(t.Root).Cmp(ethutil.NewValue(trie.Root)) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Returns a copy of this trie
|
|
|
|
// Returns a copy of this trie
|
|
|
@ -452,7 +454,7 @@ func (t *Trie) NewIterator() *TrieIterator { |
|
|
|
|
|
|
|
|
|
|
|
// Some time in the near future this will need refactoring :-)
|
|
|
|
// Some time in the near future this will need refactoring :-)
|
|
|
|
// XXX Note to self, IsSlice == inline node. Str == sha3 to node
|
|
|
|
// XXX Note to self, IsSlice == inline node. Str == sha3 to node
|
|
|
|
func (it *TrieIterator) workNode(currentNode *Value) { |
|
|
|
func (it *TrieIterator) workNode(currentNode *ethutil.Value) { |
|
|
|
if currentNode.Len() == 2 { |
|
|
|
if currentNode.Len() == 2 { |
|
|
|
k := CompactDecode(currentNode.Get(0).Str()) |
|
|
|
k := CompactDecode(currentNode.Get(0).Str()) |
|
|
|
|
|
|
|
|
|
|
@ -495,7 +497,7 @@ func (it *TrieIterator) Collect() [][]byte { |
|
|
|
return nil |
|
|
|
return nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
it.getNode(NewValue(it.trie.Root).Bytes()) |
|
|
|
it.getNode(ethutil.NewValue(it.trie.Root).Bytes()) |
|
|
|
|
|
|
|
|
|
|
|
return it.shas |
|
|
|
return it.shas |
|
|
|
} |
|
|
|
} |
|
|
@ -516,17 +518,17 @@ func (it *TrieIterator) Value() string { |
|
|
|
return "" |
|
|
|
return "" |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
type EachCallback func(key string, node *Value) |
|
|
|
type EachCallback func(key string, node *ethutil.Value) |
|
|
|
|
|
|
|
|
|
|
|
func (it *TrieIterator) Each(cb EachCallback) { |
|
|
|
func (it *TrieIterator) Each(cb EachCallback) { |
|
|
|
it.fetchNode(nil, NewValue(it.trie.Root).Bytes(), cb) |
|
|
|
it.fetchNode(nil, ethutil.NewValue(it.trie.Root).Bytes(), cb) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (it *TrieIterator) fetchNode(key []int, node []byte, cb EachCallback) { |
|
|
|
func (it *TrieIterator) fetchNode(key []int, node []byte, cb EachCallback) { |
|
|
|
it.iterateNode(key, it.trie.cache.Get(node), cb) |
|
|
|
it.iterateNode(key, it.trie.cache.Get(node), cb) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (it *TrieIterator) iterateNode(key []int, currentNode *Value, cb EachCallback) { |
|
|
|
func (it *TrieIterator) iterateNode(key []int, currentNode *ethutil.Value, cb EachCallback) { |
|
|
|
if currentNode.Len() == 2 { |
|
|
|
if currentNode.Len() == 2 { |
|
|
|
k := CompactDecode(currentNode.Get(0).Str()) |
|
|
|
k := CompactDecode(currentNode.Get(0).Str()) |
|
|
|
|
|
|
|
|