mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
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:
parent
0b210b11e3
commit
3a2fceedb9
4 changed files with 20 additions and 36 deletions
|
|
@ -23,24 +23,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// MissingNodeError is returned by the trie functions (TryGet, TryUpdate, TryDelete)
|
// 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
|
// in the case where a trie node is not present in the local database. It contains
|
||||||
// information necessary for retrieving the missing node through an ODR service.
|
// information necessary for retrieving the missing node.
|
||||||
//
|
|
||||||
// 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)
|
|
||||||
type MissingNodeError struct {
|
type MissingNodeError struct {
|
||||||
RootHash, NodeHash common.Hash
|
NodeHash common.Hash // hash of the missing node
|
||||||
PrefixLen, SuffixLen int
|
Path []byte // hex-encoded path to the missing node
|
||||||
}
|
}
|
||||||
|
|
||||||
func (err *MissingNodeError) Error() string {
|
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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -221,7 +221,7 @@ func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, er
|
||||||
if root != emptyRoot {
|
if root != emptyRoot {
|
||||||
state.hash = root
|
state.hash = root
|
||||||
}
|
}
|
||||||
err := state.resolve(it.trie)
|
err := state.resolve(it.trie, nil)
|
||||||
return state, nil, nil, err
|
return state, nil, nil, err
|
||||||
}
|
}
|
||||||
if !descend {
|
if !descend {
|
||||||
|
|
@ -238,8 +238,8 @@ func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, er
|
||||||
}
|
}
|
||||||
state, path, ok := it.nextChild(parent, ancestor)
|
state, path, ok := it.nextChild(parent, ancestor)
|
||||||
if ok {
|
if ok {
|
||||||
if err := state.resolve(it.trie); err != nil {
|
if err := state.resolve(it.trie, path); err != nil {
|
||||||
return parent, &parent.index, it.path, err
|
return parent, &parent.index, path, err
|
||||||
}
|
}
|
||||||
return state, &parent.index, path, nil
|
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
|
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 {
|
if hash, ok := st.node.(hashNode); ok {
|
||||||
resolved, err := tr.resolveHash(hash, nil, nil)
|
resolved, err := tr.resolveHash(hash, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ func (t *Trie) Prove(key []byte) []rlp.RawValue {
|
||||||
nodes = append(nodes, n)
|
nodes = append(nodes, n)
|
||||||
case hashNode:
|
case hashNode:
|
||||||
var err error
|
var err error
|
||||||
tn, err = t.resolveHash(n, nil, nil)
|
tn, err = t.resolveHash(n, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
|
log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
23
trie/trie.go
23
trie/trie.go
|
|
@ -116,7 +116,7 @@ func New(root common.Hash, db Database) (*Trie, error) {
|
||||||
if db == nil {
|
if db == nil {
|
||||||
panic("trie.New: cannot use existing root without a database")
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
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
|
return value, n, didResolve, err
|
||||||
case hashNode:
|
case hashNode:
|
||||||
child, err := t.resolveHash(n, key[:pos], key[pos:])
|
child, err := t.resolveHash(n, key[:pos])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, n, true, err
|
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
|
// 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 node and insert into it. This leaves all child nodes on
|
||||||
// the path to the value in the trie.
|
// the path to the value in the trie.
|
||||||
rn, err := t.resolveHash(n, prefix, key)
|
rn, err := t.resolveHash(n, prefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil, err
|
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
|
// shortNode{..., shortNode{...}}. Since the entry
|
||||||
// might not be loaded yet, resolve it just for this
|
// might not be loaded yet, resolve it just for this
|
||||||
// check.
|
// check.
|
||||||
cnode, err := t.resolve(n.Children[pos], prefix, []byte{byte(pos)})
|
cnode, err := t.resolve(n.Children[pos], prefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil, err
|
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
|
// 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 node and delete from it. This leaves all child nodes on
|
||||||
// the path to the value in the trie.
|
// the path to the value in the trie.
|
||||||
rn, err := t.resolveHash(n, prefix, key)
|
rn, err := t.resolveHash(n, prefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil, err
|
return false, nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -436,24 +436,19 @@ func concat(s1 []byte, s2 ...byte) []byte {
|
||||||
return r
|
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 {
|
if n, ok := n.(hashNode); ok {
|
||||||
return t.resolveHash(n, prefix, suffix)
|
return t.resolveHash(n, prefix)
|
||||||
}
|
}
|
||||||
return n, nil
|
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)
|
cacheMissCounter.Inc(1)
|
||||||
|
|
||||||
enc, err := t.db.Get(n)
|
enc, err := t.db.Get(n)
|
||||||
if err != nil || enc == nil {
|
if err != nil || enc == nil {
|
||||||
return nil, &MissingNodeError{
|
return nil, &MissingNodeError{NodeHash: common.BytesToHash(n), Path: prefix}
|
||||||
RootHash: t.originalRoot,
|
|
||||||
NodeHash: common.BytesToHash(n),
|
|
||||||
PrefixLen: len(prefix),
|
|
||||||
SuffixLen: len(suffix),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
dec := mustDecodeNode(n, enc, t.cachegen)
|
dec := mustDecodeNode(n, enc, t.cachegen)
|
||||||
return dec, nil
|
return dec, nil
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue