Skip to content

Commit f0ee121

Browse files
gzliudankaralabe
andauthored
trie: reject deletions when verifying range proofs ethereum#23960 (#1076)
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
1 parent 3da4549 commit f0ee121

File tree

2 files changed

+85
-1
lines changed

2 files changed

+85
-1
lines changed

trie/proof.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,12 +471,17 @@ func VerifyRangeProof(rootHash common.Hash, firstKey []byte, lastKey []byte, key
471471
if len(keys) != len(values) {
472472
return false, fmt.Errorf("inconsistent proof data, keys: %d, values: %d", len(keys), len(values))
473473
}
474-
// Ensure the received batch is monotonic increasing.
474+
// Ensure the received batch is monotonic increasing and contains no deletions
475475
for i := 0; i < len(keys)-1; i++ {
476476
if bytes.Compare(keys[i], keys[i+1]) >= 0 {
477477
return false, errors.New("range is not monotonically increasing")
478478
}
479479
}
480+
for _, value := range values {
481+
if len(value) == 0 {
482+
return false, errors.New("range contains deletion")
483+
}
484+
}
480485
// Special case, there is no edge proof at all. The given range is expected
481486
// to be the whole leaf-set in the trie.
482487
if proof == nil {

trie/proof_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,85 @@ func TestBloatedProof(t *testing.T) {
808808
}
809809
}
810810

811+
// TestEmptyValueRangeProof tests normal range proof with both edge proofs
812+
// as the existent proof, but with an extra empty value included, which is a
813+
// noop technically, but practically should be rejected.
814+
func TestEmptyValueRangeProof(t *testing.T) {
815+
trie, values := randomTrie(512)
816+
var entries entrySlice
817+
for _, kv := range values {
818+
entries = append(entries, kv)
819+
}
820+
sort.Sort(entries)
821+
822+
// Create a new entry with a slightly modified key
823+
mid := len(entries) / 2
824+
key := common.CopyBytes(entries[mid-1].k)
825+
for n := len(key) - 1; n >= 0; n-- {
826+
if key[n] < 0xff {
827+
key[n]++
828+
break
829+
}
830+
}
831+
noop := &kv{key, []byte{}, false}
832+
entries = append(append(append([]*kv{}, entries[:mid]...), noop), entries[mid:]...)
833+
834+
start, end := 1, len(entries)-1
835+
836+
proof := memorydb.New()
837+
if err := trie.Prove(entries[start].k, 0, proof); err != nil {
838+
t.Fatalf("Failed to prove the first node %v", err)
839+
}
840+
if err := trie.Prove(entries[end-1].k, 0, proof); err != nil {
841+
t.Fatalf("Failed to prove the last node %v", err)
842+
}
843+
var keys [][]byte
844+
var vals [][]byte
845+
for i := start; i < end; i++ {
846+
keys = append(keys, entries[i].k)
847+
vals = append(vals, entries[i].v)
848+
}
849+
_, err := VerifyRangeProof(trie.Hash(), keys[0], keys[len(keys)-1], keys, vals, proof)
850+
if err == nil {
851+
t.Fatalf("Expected failure on noop entry")
852+
}
853+
}
854+
855+
// TestAllElementsEmptyValueRangeProof tests the range proof with all elements,
856+
// but with an extra empty value included, which is a noop technically, but
857+
// practically should be rejected.
858+
func TestAllElementsEmptyValueRangeProof(t *testing.T) {
859+
trie, values := randomTrie(512)
860+
var entries entrySlice
861+
for _, kv := range values {
862+
entries = append(entries, kv)
863+
}
864+
sort.Sort(entries)
865+
866+
// Create a new entry with a slightly modified key
867+
mid := len(entries) / 2
868+
key := common.CopyBytes(entries[mid-1].k)
869+
for n := len(key) - 1; n >= 0; n-- {
870+
if key[n] < 0xff {
871+
key[n]++
872+
break
873+
}
874+
}
875+
noop := &kv{key, []byte{}, false}
876+
entries = append(append(append([]*kv{}, entries[:mid]...), noop), entries[mid:]...)
877+
878+
var keys [][]byte
879+
var vals [][]byte
880+
for i := 0; i < len(entries); i++ {
881+
keys = append(keys, entries[i].k)
882+
vals = append(vals, entries[i].v)
883+
}
884+
_, err := VerifyRangeProof(trie.Hash(), nil, nil, keys, vals, nil)
885+
if err == nil {
886+
t.Fatalf("Expected failure on noop entry")
887+
}
888+
}
889+
811890
// mutateByte changes one byte in b.
812891
func mutateByte(b []byte) {
813892
for r := mrand.Intn(len(b)); ; {

0 commit comments

Comments
 (0)