forked from cerc-io/plugeth
trie: reject deletions when verifying range proofs
This commit is contained in:
parent
d15e423562
commit
743769f48e
@ -472,12 +472,17 @@ func VerifyRangeProof(rootHash common.Hash, firstKey []byte, lastKey []byte, key
|
||||
if len(keys) != len(values) {
|
||||
return false, fmt.Errorf("inconsistent proof data, keys: %d, values: %d", len(keys), len(values))
|
||||
}
|
||||
// Ensure the received batch is monotonic increasing.
|
||||
// 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 false, errors.New("range is not monotonically increasing")
|
||||
}
|
||||
}
|
||||
for _, value := range values {
|
||||
if len(value) == 0 {
|
||||
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 {
|
||||
|
@ -813,6 +813,85 @@ func TestBloatedProof(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestEmptyValueRangeProof tests normal range proof with both edge proofs
|
||||
// as the existent proof, but with an extra empty value included, which is a
|
||||
// noop technically, but practically should be rejected.
|
||||
func TestEmptyValueRangeProof(t *testing.T) {
|
||||
trie, values := randomTrie(512)
|
||||
var entries entrySlice
|
||||
for _, kv := range values {
|
||||
entries = append(entries, kv)
|
||||
}
|
||||
sort.Sort(entries)
|
||||
|
||||
// Create a new entry with a slightly modified key
|
||||
mid := len(entries) / 2
|
||||
key := common.CopyBytes(entries[mid-1].k)
|
||||
for n := len(key) - 1; n >= 0; n-- {
|
||||
if key[n] < 0xff {
|
||||
key[n]++
|
||||
break
|
||||
}
|
||||
}
|
||||
noop := &kv{key, []byte{}, false}
|
||||
entries = append(append(append([]*kv{}, entries[:mid]...), noop), entries[mid:]...)
|
||||
|
||||
start, end := 1, len(entries)-1
|
||||
|
||||
proof := memorydb.New()
|
||||
if err := trie.Prove(entries[start].k, 0, proof); err != nil {
|
||||
t.Fatalf("Failed to prove the first node %v", err)
|
||||
}
|
||||
if err := trie.Prove(entries[end-1].k, 0, proof); err != nil {
|
||||
t.Fatalf("Failed to prove the last node %v", err)
|
||||
}
|
||||
var keys [][]byte
|
||||
var vals [][]byte
|
||||
for i := start; i < end; i++ {
|
||||
keys = append(keys, entries[i].k)
|
||||
vals = append(vals, entries[i].v)
|
||||
}
|
||||
_, err := VerifyRangeProof(trie.Hash(), keys[0], keys[len(keys)-1], keys, vals, proof)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected failure on noop entry")
|
||||
}
|
||||
}
|
||||
|
||||
// TestAllElementsEmptyValueRangeProof tests the range proof with all elements,
|
||||
// but with an extra empty value included, which is a noop technically, but
|
||||
// practically should be rejected.
|
||||
func TestAllElementsEmptyValueRangeProof(t *testing.T) {
|
||||
trie, values := randomTrie(512)
|
||||
var entries entrySlice
|
||||
for _, kv := range values {
|
||||
entries = append(entries, kv)
|
||||
}
|
||||
sort.Sort(entries)
|
||||
|
||||
// Create a new entry with a slightly modified key
|
||||
mid := len(entries) / 2
|
||||
key := common.CopyBytes(entries[mid-1].k)
|
||||
for n := len(key) - 1; n >= 0; n-- {
|
||||
if key[n] < 0xff {
|
||||
key[n]++
|
||||
break
|
||||
}
|
||||
}
|
||||
noop := &kv{key, []byte{}, false}
|
||||
entries = append(append(append([]*kv{}, entries[:mid]...), noop), entries[mid:]...)
|
||||
|
||||
var keys [][]byte
|
||||
var vals [][]byte
|
||||
for i := 0; i < len(entries); i++ {
|
||||
keys = append(keys, entries[i].k)
|
||||
vals = append(vals, entries[i].v)
|
||||
}
|
||||
_, err := VerifyRangeProof(trie.Hash(), nil, nil, keys, vals, nil)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected failure on noop entry")
|
||||
}
|
||||
}
|
||||
|
||||
// mutateByte changes one byte in b.
|
||||
func mutateByte(b []byte) {
|
||||
for r := mrand.Intn(len(b)); ; {
|
||||
|
Loading…
Reference in New Issue
Block a user