Skip to content

Commit 655f975

Browse files
authored
trie: simplify range proofs ethereum#22762 (XinFinOrg#1067)
1 parent ae58eb9 commit 655f975

File tree

3 files changed

+56
-145
lines changed

3 files changed

+56
-145
lines changed

trie/notary.go

Lines changed: 0 additions & 57 deletions
This file was deleted.

trie/proof.go

Lines changed: 29 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -463,125 +463,101 @@ func hasRightElement(node node, key []byte) bool {
463463
//
464464
// Except returning the error to indicate the proof is valid or not, the function will
465465
// also return a flag to indicate whether there exists more accounts/slots in the trie.
466-
func VerifyRangeProof(rootHash common.Hash, firstKey []byte, lastKey []byte, keys [][]byte, values [][]byte, proof ethdb.KeyValueReader) (ethdb.KeyValueStore, bool, error) {
466+
//
467+
// Note: This method does not verify that the proof is of minimal form. If the input
468+
// proofs are 'bloated' with neighbour leaves or random data, aside from the 'useful'
469+
// data, then the proof will still be accepted.
470+
func VerifyRangeProof(rootHash common.Hash, firstKey []byte, lastKey []byte, keys [][]byte, values [][]byte, proof ethdb.KeyValueReader) (bool, error) {
467471
if len(keys) != len(values) {
468-
return nil, false, fmt.Errorf("inconsistent proof data, keys: %d, values: %d", len(keys), len(values))
472+
return false, fmt.Errorf("inconsistent proof data, keys: %d, values: %d", len(keys), len(values))
469473
}
470474
// Ensure the received batch is monotonic increasing.
471475
for i := 0; i < len(keys)-1; i++ {
472476
if bytes.Compare(keys[i], keys[i+1]) >= 0 {
473-
return nil, false, errors.New("range is not monotonically increasing")
477+
return false, errors.New("range is not monotonically increasing")
474478
}
475479
}
476-
// Create a key-value notary to track which items from the given proof the
477-
// range prover actually needed to verify the data
478-
notary := newKeyValueNotary(proof)
479-
480480
// Special case, there is no edge proof at all. The given range is expected
481481
// to be the whole leaf-set in the trie.
482482
if proof == nil {
483-
var (
484-
diskdb = memorydb.New()
485-
tr = NewStackTrie(diskdb)
486-
)
483+
tr := NewStackTrie(nil)
487484
for index, key := range keys {
488485
tr.TryUpdate(key, values[index])
489486
}
490487
if have, want := tr.Hash(), rootHash; have != want {
491-
return nil, false, fmt.Errorf("invalid proof, want hash %x, got %x", want, have)
492-
}
493-
// Proof seems valid, serialize remaining nodes into the database
494-
if _, err := tr.Commit(); err != nil {
495-
return nil, false, err
488+
return false, fmt.Errorf("invalid proof, want hash %x, got %x", want, have)
496489
}
497-
return diskdb, false, nil // No more elements
490+
return false, nil // No more elements
498491
}
499492
// Special case, there is a provided edge proof but zero key/value
500493
// pairs, ensure there are no more accounts / slots in the trie.
501494
if len(keys) == 0 {
502-
root, val, err := proofToPath(rootHash, nil, firstKey, notary, true)
495+
root, val, err := proofToPath(rootHash, nil, firstKey, proof, true)
503496
if err != nil {
504-
return nil, false, err
497+
return false, err
505498
}
506499
if val != nil || hasRightElement(root, firstKey) {
507-
return nil, false, errors.New("more entries available")
500+
return false, errors.New("more entries available")
508501
}
509-
// Since the entire proof is a single path, we can construct a trie and a
510-
// node database directly out of the inputs, no need to generate them
511-
diskdb := notary.Accessed()
512-
return diskdb, hasRightElement(root, firstKey), nil
502+
return hasRightElement(root, firstKey), nil
513503
}
514504
// Special case, there is only one element and two edge keys are same.
515505
// In this case, we can't construct two edge paths. So handle it here.
516506
if len(keys) == 1 && bytes.Equal(firstKey, lastKey) {
517-
root, val, err := proofToPath(rootHash, nil, firstKey, notary, false)
507+
root, val, err := proofToPath(rootHash, nil, firstKey, proof, false)
518508
if err != nil {
519-
return nil, false, err
509+
return false, err
520510
}
521511
if !bytes.Equal(firstKey, keys[0]) {
522-
return nil, false, errors.New("correct proof but invalid key")
512+
return false, errors.New("correct proof but invalid key")
523513
}
524514
if !bytes.Equal(val, values[0]) {
525-
return nil, false, errors.New("correct proof but invalid data")
515+
return false, errors.New("correct proof but invalid data")
526516
}
527-
// Since the entire proof is a single path, we can construct a trie and a
528-
// node database directly out of the inputs, no need to generate them
529-
diskdb := notary.Accessed()
530-
return diskdb, hasRightElement(root, firstKey), nil
517+
return hasRightElement(root, firstKey), nil
531518
}
532519
// Ok, in all other cases, we require two edge paths available.
533520
// First check the validity of edge keys.
534521
if bytes.Compare(firstKey, lastKey) >= 0 {
535-
return nil, false, errors.New("invalid edge keys")
522+
return false, errors.New("invalid edge keys")
536523
}
537524
// todo(rjl493456442) different length edge keys should be supported
538525
if len(firstKey) != len(lastKey) {
539-
return nil, false, errors.New("inconsistent edge keys")
526+
return false, errors.New("inconsistent edge keys")
540527
}
541528
// Convert the edge proofs to edge trie paths. Then we can
542529
// have the same tree architecture with the original one.
543530
// For the first edge proof, non-existent proof is allowed.
544-
root, _, err := proofToPath(rootHash, nil, firstKey, notary, true)
531+
root, _, err := proofToPath(rootHash, nil, firstKey, proof, true)
545532
if err != nil {
546-
return nil, false, err
533+
return false, err
547534
}
548535
// Pass the root node here, the second path will be merged
549536
// with the first one. For the last edge proof, non-existent
550537
// proof is also allowed.
551-
root, _, err = proofToPath(rootHash, root, lastKey, notary, true)
538+
root, _, err = proofToPath(rootHash, root, lastKey, proof, true)
552539
if err != nil {
553-
return nil, false, err
540+
return false, err
554541
}
555542
// Remove all internal references. All the removed parts should
556543
// be re-filled(or re-constructed) by the given leaves range.
557544
empty, err := unsetInternal(root, firstKey, lastKey)
558545
if err != nil {
559-
return nil, false, err
546+
return false, err
560547
}
561548
// Rebuild the trie with the leaf stream, the shape of trie
562549
// should be same with the original one.
563-
var (
564-
diskdb = memorydb.New()
565-
triedb = NewDatabase(diskdb)
566-
)
567-
tr := &Trie{root: root, Db: triedb}
550+
tr := &Trie{root: root, Db: NewDatabase(memorydb.New())}
568551
if empty {
569552
tr.root = nil
570553
}
571554
for index, key := range keys {
572555
tr.TryUpdate(key, values[index])
573556
}
574557
if tr.Hash() != rootHash {
575-
return nil, false, fmt.Errorf("invalid proof, want hash %x, got %x", rootHash, tr.Hash())
576-
}
577-
// Proof seems valid, serialize all the nodes into the database
578-
if _, _, err := tr.Commit(nil); err != nil {
579-
return nil, false, err
580-
}
581-
if err := triedb.Commit(rootHash, false); err != nil {
582-
return nil, false, err
558+
return false, fmt.Errorf("invalid proof, want hash %x, got %x", rootHash, tr.Hash())
583559
}
584-
return diskdb, hasRightElement(root, keys[len(keys)-1]), nil
560+
return hasRightElement(root, keys[len(keys)-1]), nil
585561
}
586562

587563
// get returns the child of the given Node. Return nil if the

0 commit comments

Comments
 (0)