mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
trie: separate verification with/without proofs
This commit is contained in:
parent
3dc45a3e1d
commit
1fb6eb15dd
3 changed files with 41 additions and 28 deletions
|
|
@ -228,16 +228,8 @@ func (dl *diskLayer) proveRange(ctx *generatorContext, trieId *trie.ID, prefix [
|
|||
// The snap state is exhausted, pass the entire key/val set for verification
|
||||
root := trieId.Root
|
||||
if origin == nil && !diskMore {
|
||||
stackTr := trie.NewStackTrie(nil)
|
||||
for i, key := range keys {
|
||||
stackTr.Update(key, vals[i])
|
||||
}
|
||||
if gotRoot := stackTr.Hash(); gotRoot != root {
|
||||
return &proofResult{
|
||||
keys: keys,
|
||||
vals: vals,
|
||||
proofErr: fmt.Errorf("wrong root: have %#x want %#x", gotRoot, root),
|
||||
}, nil
|
||||
if err := trie.VerifyStandaloneRange(root, keys, vals); err != nil {
|
||||
return &proofResult{keys: keys, vals: vals, proofErr: err}, nil
|
||||
}
|
||||
return &proofResult{keys: keys, vals: vals}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2645,12 +2645,10 @@ func (s *Syncer) OnStorage(peer SyncPeer, id uint64, hashes [][]common.Hash, slo
|
|||
nodes = append(nodes, node)
|
||||
}
|
||||
}
|
||||
var err error
|
||||
if len(nodes) == 0 {
|
||||
// No proof has been attached, the response must cover the entire key
|
||||
// space and hash to the origin root.
|
||||
_, err = trie.VerifyRangeProof(req.roots[i], nil, nil, keys, slots[i], nil)
|
||||
if err != nil {
|
||||
if err := trie.VerifyStandaloneRange(req.roots[i], keys, slots[i]); err != nil {
|
||||
s.scheduleRevertStorageRequest(req) // reschedule request
|
||||
logger.Warn("Storage slots failed proof", "err", err)
|
||||
return err
|
||||
|
|
@ -2658,9 +2656,11 @@ func (s *Syncer) OnStorage(peer SyncPeer, id uint64, hashes [][]common.Hash, slo
|
|||
} else {
|
||||
// A proof was attached, the response is only partial, check that the
|
||||
// returned data is indeed part of the storage trie
|
||||
proofdb := nodes.NodeSet()
|
||||
|
||||
var end []byte
|
||||
var (
|
||||
proofdb = nodes.NodeSet()
|
||||
err error
|
||||
end []byte
|
||||
)
|
||||
if len(keys) > 0 {
|
||||
end = keys[len(keys)-1]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -482,6 +482,11 @@ func hasRightElement(node node, key []byte) bool {
|
|||
// proofs are 'bloated' with neighbour leaves or random data, aside from the 'useful'
|
||||
// data, then the proof will still be accepted.
|
||||
func VerifyRangeProof(rootHash common.Hash, firstKey []byte, lastKey []byte, keys [][]byte, values [][]byte, proof ethdb.KeyValueReader) (bool, error) {
|
||||
if proof == nil {
|
||||
// Special case, there is no edge proof at all. The given range is expected
|
||||
// to be the whole leaf-set in the trie.
|
||||
return false, VerifyStandaloneRange(rootHash, keys, values)
|
||||
}
|
||||
if len(keys) != len(values) {
|
||||
return false, fmt.Errorf("inconsistent proof data, keys: %d, values: %d", len(keys), len(values))
|
||||
}
|
||||
|
|
@ -496,18 +501,6 @@ func VerifyRangeProof(rootHash common.Hash, firstKey []byte, lastKey []byte, key
|
|||
return false, errors.New("range contains deletion")
|
||||
}
|
||||
}
|
||||
// Special case, there is no edge proof at all. The given range is expected
|
||||
// to be the whole leaf-set in the trie.
|
||||
if proof == nil {
|
||||
tr := NewStackTrie(nil)
|
||||
for index, key := range keys {
|
||||
tr.Update(key, values[index])
|
||||
}
|
||||
if have, want := tr.Hash(), rootHash; have != want {
|
||||
return false, fmt.Errorf("invalid proof, want hash %x, got %x", want, have)
|
||||
}
|
||||
return false, nil // No more elements
|
||||
}
|
||||
// Special case, there is a provided edge proof but zero key/value
|
||||
// pairs, ensure there are no more accounts / slots in the trie.
|
||||
if len(keys) == 0 {
|
||||
|
|
@ -579,6 +572,34 @@ func VerifyRangeProof(rootHash common.Hash, firstKey []byte, lastKey []byte, key
|
|||
return hasRightElement(tr.root, keys[len(keys)-1]), nil
|
||||
}
|
||||
|
||||
// VerifyStandaloneRange checks whether a trie built with the given leaf nodes
|
||||
// matches with the specific root.
|
||||
// The range must be monotonically increasing and contain no deletions.
|
||||
func VerifyStandaloneRange(rootHash common.Hash, keys [][]byte, values [][]byte) error {
|
||||
if len(keys) != len(values) {
|
||||
return fmt.Errorf("inconsistent proof data, keys: %d, values: %d", len(keys), len(values))
|
||||
}
|
||||
// Ensure the received batch is monotonic increasing and contains no deletions
|
||||
for i := 0; i < len(keys)-1; i++ {
|
||||
if bytes.Compare(keys[i], keys[i+1]) >= 0 {
|
||||
return errors.New("range is not monotonically increasing")
|
||||
}
|
||||
}
|
||||
for _, value := range values {
|
||||
if len(value) == 0 {
|
||||
return errors.New("range contains deletion")
|
||||
}
|
||||
}
|
||||
tr := NewStackTrie(nil)
|
||||
for index, key := range keys {
|
||||
tr.Update(key, values[index])
|
||||
}
|
||||
if have, want := tr.Hash(), rootHash; have != want {
|
||||
return fmt.Errorf("invalid proof, want hash %x, got %x", want, have)
|
||||
}
|
||||
return nil // No more elements
|
||||
}
|
||||
|
||||
// get returns the child of the given node. Return nil if the
|
||||
// node with specified key doesn't exist at all.
|
||||
//
|
||||
|
|
|
|||
Loading…
Reference in a new issue