trie: add Path to MissingNodeError

The light client trie iterator needs to know the path of the node that's
missing so it can retrieve a proof for it. NodeIterator.Path is not
sufficient because it is updated when the node is resolved and actually
visited by the iterator.

Also remove unused fields. They were added a long time ago before we
knew which fields would be needed for the light client.
This commit is contained in:
Felix Lange 2017-06-15 17:17:58 +02:00
parent 0b210b11e3
commit 3a2fceedb9
4 changed files with 20 additions and 36 deletions

View file

@ -23,24 +23,13 @@ import (
)
// MissingNodeError is returned by the trie functions (TryGet, TryUpdate, TryDelete)
// in the case where a trie node is not present in the local database. Contains
// information necessary for retrieving the missing node through an ODR service.
//
// NodeHash is the hash of the missing node
//
// RootHash is the original root of the trie that contains the node
//
// PrefixLen is the nibble length of the key prefix that leads from the root to
// the missing node
//
// SuffixLen is the nibble length of the remaining part of the key that hints on
// which further nodes should also be retrieved (can be zero when there are no
// such hints in the error message)
// in the case where a trie node is not present in the local database. It contains
// information necessary for retrieving the missing node.
type MissingNodeError struct {
RootHash, NodeHash common.Hash
PrefixLen, SuffixLen int
NodeHash common.Hash // hash of the missing node
Path []byte // hex-encoded path to the missing node
}
func (err *MissingNodeError) Error() string {
return fmt.Sprintf("Missing trie node %064x", err.NodeHash)
return fmt.Sprintf("missing trie node %x (path %x)", err.NodeHash, err.Path)
}

View file

@ -221,7 +221,7 @@ func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, er
if root != emptyRoot {
state.hash = root
}
err := state.resolve(it.trie)
err := state.resolve(it.trie, nil)
return state, nil, nil, err
}
if !descend {
@ -238,8 +238,8 @@ func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, er
}
state, path, ok := it.nextChild(parent, ancestor)
if ok {
if err := state.resolve(it.trie); err != nil {
return parent, &parent.index, it.path, err
if err := state.resolve(it.trie, path); err != nil {
return parent, &parent.index, path, err
}
return state, &parent.index, path, nil
}
@ -249,9 +249,9 @@ func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, er
return nil, nil, nil, iteratorEnd
}
func (st *nodeIteratorState) resolve(tr *Trie) error {
func (st *nodeIteratorState) resolve(tr *Trie, path []byte) error {
if hash, ok := st.node.(hashNode); ok {
resolved, err := tr.resolveHash(hash, nil, nil)
resolved, err := tr.resolveHash(hash, path)
if err != nil {
return err
}

View file

@ -58,7 +58,7 @@ func (t *Trie) Prove(key []byte) []rlp.RawValue {
nodes = append(nodes, n)
case hashNode:
var err error
tn, err = t.resolveHash(n, nil, nil)
tn, err = t.resolveHash(n, nil)
if err != nil {
log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
return nil

View file

@ -116,7 +116,7 @@ func New(root common.Hash, db Database) (*Trie, error) {
if db == nil {
panic("trie.New: cannot use existing root without a database")
}
rootnode, err := trie.resolveHash(root[:], nil, nil)
rootnode, err := trie.resolveHash(root[:], nil)
if err != nil {
return nil, err
}
@ -180,7 +180,7 @@ func (t *Trie) tryGet(origNode node, key []byte, pos int) (value []byte, newnode
}
return value, n, didResolve, err
case hashNode:
child, err := t.resolveHash(n, key[:pos], key[pos:])
child, err := t.resolveHash(n, key[:pos])
if err != nil {
return nil, n, true, err
}
@ -283,7 +283,7 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error
// We've hit a part of the trie that isn't loaded yet. Load
// the node and insert into it. This leaves all child nodes on
// the path to the value in the trie.
rn, err := t.resolveHash(n, prefix, key)
rn, err := t.resolveHash(n, prefix)
if err != nil {
return false, nil, err
}
@ -388,7 +388,7 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) {
// shortNode{..., shortNode{...}}. Since the entry
// might not be loaded yet, resolve it just for this
// check.
cnode, err := t.resolve(n.Children[pos], prefix, []byte{byte(pos)})
cnode, err := t.resolve(n.Children[pos], prefix)
if err != nil {
return false, nil, err
}
@ -414,7 +414,7 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) {
// We've hit a part of the trie that isn't loaded yet. Load
// the node and delete from it. This leaves all child nodes on
// the path to the value in the trie.
rn, err := t.resolveHash(n, prefix, key)
rn, err := t.resolveHash(n, prefix)
if err != nil {
return false, nil, err
}
@ -436,24 +436,19 @@ func concat(s1 []byte, s2 ...byte) []byte {
return r
}
func (t *Trie) resolve(n node, prefix, suffix []byte) (node, error) {
func (t *Trie) resolve(n node, prefix []byte) (node, error) {
if n, ok := n.(hashNode); ok {
return t.resolveHash(n, prefix, suffix)
return t.resolveHash(n, prefix)
}
return n, nil
}
func (t *Trie) resolveHash(n hashNode, prefix, suffix []byte) (node, error) {
func (t *Trie) resolveHash(n hashNode, prefix []byte) (node, error) {
cacheMissCounter.Inc(1)
enc, err := t.db.Get(n)
if err != nil || enc == nil {
return nil, &MissingNodeError{
RootHash: t.originalRoot,
NodeHash: common.BytesToHash(n),
PrefixLen: len(prefix),
SuffixLen: len(suffix),
}
return nil, &MissingNodeError{NodeHash: common.BytesToHash(n), Path: prefix}
}
dec := mustDecodeNode(n, enc, t.cachegen)
return dec, nil