Skip to content

Commit ef93b63

Browse files
rjl493456442enriquefynn
authored andcommitted
trie: support empty range proof (ethereum#21199)
1 parent 8388e6a commit ef93b63

File tree

2 files changed

+50
-4
lines changed

2 files changed

+50
-4
lines changed

trie/proof.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -393,23 +393,24 @@ func hasRightElement(node node, key []byte) bool {
393393
// (unless firstProof is an existent proof).
394394
//
395395
// Expect the normal case, this function can also be used to verify the following
396-
// range proofs(note this function doesn't accept zero element proof):
396+
// range proofs:
397397
//
398398
// - All elements proof. In this case the left and right proof can be nil, but the
399399
// range should be all the leaves in the trie.
400400
//
401401
// - One element proof. In this case no matter the left edge proof is a non-existent
402402
// proof or not, we can always verify the correctness of the proof.
403403
//
404+
// - Zero element proof(left edge proof should be a non-existent proof). In this
405+
// case if there are still some other leaves available on the right side, then
406+
// an error will be returned.
407+
//
404408
// Except returning the error to indicate the proof is valid or not, the function will
405409
// also return a flag to indicate whether there exists more accounts/slots in the trie.
406410
func VerifyRangeProof(rootHash common.Hash, firstKey []byte, keys [][]byte, values [][]byte, firstProof ethdb.KeyValueReader, lastProof ethdb.KeyValueReader) (error, bool) {
407411
if len(keys) != len(values) {
408412
return fmt.Errorf("inconsistent proof data, keys: %d, values: %d", len(keys), len(values)), false
409413
}
410-
if len(keys) == 0 {
411-
return errors.New("empty proof"), false
412-
}
413414
// Ensure the received batch is monotonic increasing.
414415
for i := 0; i < len(keys)-1; i++ {
415416
if bytes.Compare(keys[i], keys[i+1]) >= 0 {
@@ -431,6 +432,18 @@ func VerifyRangeProof(rootHash common.Hash, firstKey []byte, keys [][]byte, valu
431432
}
432433
return nil, false // no more element.
433434
}
435+
// Special case, there is a provided left edge proof and zero key/value
436+
// pairs, ensure there are no more accounts / slots in the trie.
437+
if len(keys) == 0 {
438+
root, val, err := proofToPath(rootHash, nil, firstKey, firstProof, true)
439+
if err != nil {
440+
return err, false
441+
}
442+
if val != nil || hasRightElement(root, firstKey) {
443+
return errors.New("more entries available"), false
444+
}
445+
return nil, false
446+
}
434447
// Special case, there is only one element and left edge
435448
// proof is an existent one.
436449
if len(keys) == 1 && bytes.Equal(keys[0], firstKey) {

trie/proof_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,39 @@ func TestHasRightElement(t *testing.T) {
571571
}
572572
}
573573

574+
// TestEmptyRangeProof tests the range proof with "no" element.
575+
// The first edge proof must be a non-existent proof.
576+
func TestEmptyRangeProof(t *testing.T) {
577+
trie, vals := randomTrie(4096)
578+
var entries entrySlice
579+
for _, kv := range vals {
580+
entries = append(entries, kv)
581+
}
582+
sort.Sort(entries)
583+
584+
var cases = []struct {
585+
pos int
586+
err bool
587+
}{
588+
{len(entries) - 1, false},
589+
{500, true},
590+
}
591+
for _, c := range cases {
592+
firstProof := memorydb.New()
593+
first := increseKey(common.CopyBytes(entries[c.pos].k))
594+
if err := trie.Prove(first, 0, firstProof); err != nil {
595+
t.Fatalf("Failed to prove the first node %v", err)
596+
}
597+
err, _ := VerifyRangeProof(trie.Hash(), first, nil, nil, firstProof, nil)
598+
if c.err && err == nil {
599+
t.Fatalf("Expected error, got nil")
600+
}
601+
if !c.err && err != nil {
602+
t.Fatalf("Expected no error, got %v", err)
603+
}
604+
}
605+
}
606+
574607
// mutateByte changes one byte in b.
575608
func mutateByte(b []byte) {
576609
for r := mrand.Intn(len(b)); ; {

0 commit comments

Comments
 (0)