core, eth, trie: prepare trie sync for path based operation
This commit is contained in:
84
trie/trie.go
84
trie/trie.go
@ -25,6 +25,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -102,8 +103,7 @@ func (t *Trie) Get(key []byte) []byte {
|
||||
// The value bytes must not be modified by the caller.
|
||||
// If a node was not found in the database, a MissingNodeError is returned.
|
||||
func (t *Trie) TryGet(key []byte) ([]byte, error) {
|
||||
key = keybytesToHex(key)
|
||||
value, newroot, didResolve, err := t.tryGet(t.root, key, 0)
|
||||
value, newroot, didResolve, err := t.tryGet(t.root, keybytesToHex(key), 0)
|
||||
if err == nil && didResolve {
|
||||
t.root = newroot
|
||||
}
|
||||
@ -146,6 +146,86 @@ func (t *Trie) tryGet(origNode node, key []byte, pos int) (value []byte, newnode
|
||||
}
|
||||
}
|
||||
|
||||
// TryGetNode attempts to retrieve a trie node by compact-encoded path. It is not
|
||||
// possible to use keybyte-encoding as the path might contain odd nibbles.
|
||||
func (t *Trie) TryGetNode(path []byte) ([]byte, int, error) {
|
||||
item, newroot, resolved, err := t.tryGetNode(t.root, compactToHex(path), 0)
|
||||
if err != nil {
|
||||
return nil, resolved, err
|
||||
}
|
||||
if resolved > 0 {
|
||||
t.root = newroot
|
||||
}
|
||||
if item == nil {
|
||||
return nil, resolved, nil
|
||||
}
|
||||
enc, err := rlp.EncodeToBytes(item)
|
||||
if err != nil {
|
||||
log.Error("Encoding existing trie node failed", "err", err)
|
||||
return nil, resolved, err
|
||||
}
|
||||
return enc, resolved, err
|
||||
}
|
||||
|
||||
func (t *Trie) tryGetNode(origNode node, path []byte, pos int) (item node, newnode node, resolved int, err error) {
|
||||
// If we reached the requested path, return the current node
|
||||
if pos >= len(path) {
|
||||
// Don't return collapsed hash nodes though
|
||||
if _, ok := origNode.(hashNode); !ok {
|
||||
// Short nodes have expanded keys, compact them before returning
|
||||
item := origNode
|
||||
if sn, ok := item.(*shortNode); ok {
|
||||
item = &shortNode{
|
||||
Key: hexToCompact(sn.Key),
|
||||
Val: sn.Val,
|
||||
}
|
||||
}
|
||||
return item, origNode, 0, nil
|
||||
}
|
||||
}
|
||||
// Path still needs to be traversed, descend into children
|
||||
switch n := (origNode).(type) {
|
||||
case nil:
|
||||
// Non-existent path requested, abort
|
||||
return nil, nil, 0, nil
|
||||
|
||||
case valueNode:
|
||||
// Path prematurely ended, abort
|
||||
return nil, nil, 0, nil
|
||||
|
||||
case *shortNode:
|
||||
if len(path)-pos < len(n.Key) || !bytes.Equal(n.Key, path[pos:pos+len(n.Key)]) {
|
||||
// Path branches off from short node
|
||||
return nil, n, 0, nil
|
||||
}
|
||||
item, newnode, resolved, err = t.tryGetNode(n.Val, path, pos+len(n.Key))
|
||||
if err == nil && resolved > 0 {
|
||||
n = n.copy()
|
||||
n.Val = newnode
|
||||
}
|
||||
return item, n, resolved, err
|
||||
|
||||
case *fullNode:
|
||||
item, newnode, resolved, err = t.tryGetNode(n.Children[path[pos]], path, pos+1)
|
||||
if err == nil && resolved > 0 {
|
||||
n = n.copy()
|
||||
n.Children[path[pos]] = newnode
|
||||
}
|
||||
return item, n, resolved, err
|
||||
|
||||
case hashNode:
|
||||
child, err := t.resolveHash(n, path[:pos])
|
||||
if err != nil {
|
||||
return nil, n, 1, err
|
||||
}
|
||||
item, newnode, resolved, err := t.tryGetNode(child, path, pos)
|
||||
return item, newnode, resolved + 1, err
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("%T: invalid node: %v", origNode, origNode))
|
||||
}
|
||||
}
|
||||
|
||||
// Update associates key with value in the trie. Subsequent calls to
|
||||
// Get will return value. If value has length zero, any existing value
|
||||
// is deleted from the trie and calls to Get will return nil.
|
||||
|
Reference in New Issue
Block a user