|
|
|
@ -98,12 +98,65 @@ func TestOneElementProof(t *testing.T) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func TestBadProof(t *testing.T) { |
|
|
|
|
trie, vals := randomTrie(800) |
|
|
|
|
root := trie.Hash() |
|
|
|
|
for i, prover := range makeProvers(trie) { |
|
|
|
|
for _, kv := range vals { |
|
|
|
|
proof := prover(kv.k) |
|
|
|
|
if proof == nil { |
|
|
|
|
t.Fatalf("prover %d: nil proof", i) |
|
|
|
|
} |
|
|
|
|
it := proof.NewIterator(nil, nil) |
|
|
|
|
for i, d := 0, mrand.Intn(proof.Len()); i <= d; i++ { |
|
|
|
|
it.Next() |
|
|
|
|
} |
|
|
|
|
key := it.Key() |
|
|
|
|
val, _ := proof.Get(key) |
|
|
|
|
proof.Delete(key) |
|
|
|
|
it.Release() |
|
|
|
|
|
|
|
|
|
mutateByte(val) |
|
|
|
|
proof.Put(crypto.Keccak256(val), val) |
|
|
|
|
|
|
|
|
|
if _, err := VerifyProof(root, kv.k, proof); err == nil { |
|
|
|
|
t.Fatalf("prover %d: expected proof to fail for key %x", i, kv.k) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests that missing keys can also be proven. The test explicitly uses a single
|
|
|
|
|
// entry trie and checks for missing keys both before and after the single entry.
|
|
|
|
|
func TestMissingKeyProof(t *testing.T) { |
|
|
|
|
trie := new(Trie) |
|
|
|
|
updateString(trie, "k", "v") |
|
|
|
|
|
|
|
|
|
for i, key := range []string{"a", "j", "l", "z"} { |
|
|
|
|
proof := memorydb.New() |
|
|
|
|
trie.Prove([]byte(key), 0, proof) |
|
|
|
|
|
|
|
|
|
if proof.Len() != 1 { |
|
|
|
|
t.Errorf("test %d: proof should have one element", i) |
|
|
|
|
} |
|
|
|
|
val, err := VerifyProof(trie.Hash(), []byte(key), proof) |
|
|
|
|
if err != nil { |
|
|
|
|
t.Fatalf("test %d: failed to verify proof: %v\nraw proof: %x", i, err, proof) |
|
|
|
|
} |
|
|
|
|
if val != nil { |
|
|
|
|
t.Fatalf("test %d: verified value mismatch: have %x, want nil", i, val) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type entrySlice []*kv |
|
|
|
|
|
|
|
|
|
func (p entrySlice) Len() int { return len(p) } |
|
|
|
|
func (p entrySlice) Less(i, j int) bool { return bytes.Compare(p[i].k, p[j].k) < 0 } |
|
|
|
|
func (p entrySlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } |
|
|
|
|
|
|
|
|
|
// TestRangeProof tests normal range proof with both edge proofs
|
|
|
|
|
// as the existent proof. The test cases are generated randomly.
|
|
|
|
|
func TestRangeProof(t *testing.T) { |
|
|
|
|
trie, vals := randomTrie(4096) |
|
|
|
|
var entries entrySlice |
|
|
|
@ -130,13 +183,253 @@ func TestRangeProof(t *testing.T) { |
|
|
|
|
keys = append(keys, entries[i].k) |
|
|
|
|
vals = append(vals, entries[i].v) |
|
|
|
|
} |
|
|
|
|
err := VerifyRangeProof(trie.Hash(), keys, vals, firstProof, lastProof) |
|
|
|
|
err := VerifyRangeProof(trie.Hash(), keys[0], keys, vals, firstProof, lastProof) |
|
|
|
|
if err != nil { |
|
|
|
|
t.Fatalf("Case %d(%d->%d) expect no error, got %v", i, start, end-1, err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TestRangeProof tests normal range proof with the first edge proof
|
|
|
|
|
// as the non-existent proof. The test cases are generated randomly.
|
|
|
|
|
func TestRangeProofWithNonExistentProof(t *testing.T) { |
|
|
|
|
trie, vals := randomTrie(4096) |
|
|
|
|
var entries entrySlice |
|
|
|
|
for _, kv := range vals { |
|
|
|
|
entries = append(entries, kv) |
|
|
|
|
} |
|
|
|
|
sort.Sort(entries) |
|
|
|
|
for i := 0; i < 500; i++ { |
|
|
|
|
start := mrand.Intn(len(entries)) |
|
|
|
|
end := mrand.Intn(len(entries)-start) + start |
|
|
|
|
if start == end { |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
firstProof, lastProof := memorydb.New(), memorydb.New() |
|
|
|
|
|
|
|
|
|
first := decreseKey(common.CopyBytes(entries[start].k)) |
|
|
|
|
if start != 0 && bytes.Equal(first, entries[start-1].k) { |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
if err := trie.Prove(first, 0, firstProof); err != nil { |
|
|
|
|
t.Fatalf("Failed to prove the first node %v", err) |
|
|
|
|
} |
|
|
|
|
if err := trie.Prove(entries[end-1].k, 0, lastProof); 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(), first, keys, vals, firstProof, lastProof) |
|
|
|
|
if err != nil { |
|
|
|
|
t.Fatalf("Case %d(%d->%d) expect no error, got %v", i, start, end-1, err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TestRangeProofWithInvalidNonExistentProof tests such scenarios:
|
|
|
|
|
// - The last edge proof is an non-existent proof
|
|
|
|
|
// - There exists a gap between the first element and the left edge proof
|
|
|
|
|
func TestRangeProofWithInvalidNonExistentProof(t *testing.T) { |
|
|
|
|
trie, vals := randomTrie(4096) |
|
|
|
|
var entries entrySlice |
|
|
|
|
for _, kv := range vals { |
|
|
|
|
entries = append(entries, kv) |
|
|
|
|
} |
|
|
|
|
sort.Sort(entries) |
|
|
|
|
|
|
|
|
|
// Case 1
|
|
|
|
|
start, end := 100, 200 |
|
|
|
|
first, last := decreseKey(common.CopyBytes(entries[start].k)), increseKey(common.CopyBytes(entries[end].k)) |
|
|
|
|
firstProof, lastProof := memorydb.New(), memorydb.New() |
|
|
|
|
if err := trie.Prove(first, 0, firstProof); err != nil { |
|
|
|
|
t.Fatalf("Failed to prove the first node %v", err) |
|
|
|
|
} |
|
|
|
|
if err := trie.Prove(last, 0, lastProof); err != nil { |
|
|
|
|
t.Fatalf("Failed to prove the last node %v", err) |
|
|
|
|
} |
|
|
|
|
var k [][]byte |
|
|
|
|
var v [][]byte |
|
|
|
|
for i := start; i < end; i++ { |
|
|
|
|
k = append(k, entries[i].k) |
|
|
|
|
v = append(v, entries[i].v) |
|
|
|
|
} |
|
|
|
|
err := VerifyRangeProof(trie.Hash(), first, k, v, firstProof, lastProof) |
|
|
|
|
if err == nil { |
|
|
|
|
t.Fatalf("Expected to detect the error, got nil") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Case 2
|
|
|
|
|
start, end = 100, 200 |
|
|
|
|
first = decreseKey(common.CopyBytes(entries[start].k)) |
|
|
|
|
|
|
|
|
|
firstProof, lastProof = memorydb.New(), memorydb.New() |
|
|
|
|
if err := trie.Prove(first, 0, firstProof); err != nil { |
|
|
|
|
t.Fatalf("Failed to prove the first node %v", err) |
|
|
|
|
} |
|
|
|
|
if err := trie.Prove(entries[end-1].k, 0, lastProof); err != nil { |
|
|
|
|
t.Fatalf("Failed to prove the last node %v", err) |
|
|
|
|
} |
|
|
|
|
start = 105 // Gap created
|
|
|
|
|
k = make([][]byte, 0) |
|
|
|
|
v = make([][]byte, 0) |
|
|
|
|
for i := start; i < end; i++ { |
|
|
|
|
k = append(k, entries[i].k) |
|
|
|
|
v = append(v, entries[i].v) |
|
|
|
|
} |
|
|
|
|
err = VerifyRangeProof(trie.Hash(), first, k, v, firstProof, lastProof) |
|
|
|
|
if err == nil { |
|
|
|
|
t.Fatalf("Expected to detect the error, got nil") |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TestOneElementRangeProof tests the proof with only one
|
|
|
|
|
// element. The first edge proof can be existent one or
|
|
|
|
|
// non-existent one.
|
|
|
|
|
func TestOneElementRangeProof(t *testing.T) { |
|
|
|
|
trie, vals := randomTrie(4096) |
|
|
|
|
var entries entrySlice |
|
|
|
|
for _, kv := range vals { |
|
|
|
|
entries = append(entries, kv) |
|
|
|
|
} |
|
|
|
|
sort.Sort(entries) |
|
|
|
|
|
|
|
|
|
// One element with existent edge proof
|
|
|
|
|
start := 1000 |
|
|
|
|
firstProof, lastProof := memorydb.New(), memorydb.New() |
|
|
|
|
if err := trie.Prove(entries[start].k, 0, firstProof); err != nil { |
|
|
|
|
t.Fatalf("Failed to prove the first node %v", err) |
|
|
|
|
} |
|
|
|
|
if err := trie.Prove(entries[start].k, 0, lastProof); err != nil { |
|
|
|
|
t.Fatalf("Failed to prove the last node %v", err) |
|
|
|
|
} |
|
|
|
|
err := VerifyRangeProof(trie.Hash(), entries[start].k, [][]byte{entries[start].k}, [][]byte{entries[start].v}, firstProof, lastProof) |
|
|
|
|
if err != nil { |
|
|
|
|
t.Fatalf("Expected no error, got %v", err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// One element with non-existent edge proof
|
|
|
|
|
start = 1000 |
|
|
|
|
first := decreseKey(common.CopyBytes(entries[start].k)) |
|
|
|
|
firstProof, lastProof = memorydb.New(), memorydb.New() |
|
|
|
|
if err := trie.Prove(first, 0, firstProof); err != nil { |
|
|
|
|
t.Fatalf("Failed to prove the first node %v", err) |
|
|
|
|
} |
|
|
|
|
if err := trie.Prove(entries[start].k, 0, lastProof); err != nil { |
|
|
|
|
t.Fatalf("Failed to prove the last node %v", err) |
|
|
|
|
} |
|
|
|
|
err = VerifyRangeProof(trie.Hash(), first, [][]byte{entries[start].k}, [][]byte{entries[start].v}, firstProof, lastProof) |
|
|
|
|
if err != nil { |
|
|
|
|
t.Fatalf("Expected no error, got %v", err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TestEmptyRangeProof tests the range proof with "no" element.
|
|
|
|
|
// The first edge proof must be a non-existent proof.
|
|
|
|
|
func TestEmptyRangeProof(t *testing.T) { |
|
|
|
|
trie, vals := randomTrie(4096) |
|
|
|
|
var entries entrySlice |
|
|
|
|
for _, kv := range vals { |
|
|
|
|
entries = append(entries, kv) |
|
|
|
|
} |
|
|
|
|
sort.Sort(entries) |
|
|
|
|
|
|
|
|
|
var cases = []struct { |
|
|
|
|
pos int |
|
|
|
|
err bool |
|
|
|
|
}{ |
|
|
|
|
{len(entries) - 1, false}, |
|
|
|
|
{500, true}, |
|
|
|
|
} |
|
|
|
|
for _, c := range cases { |
|
|
|
|
firstProof := memorydb.New() |
|
|
|
|
first := increseKey(common.CopyBytes(entries[c.pos].k)) |
|
|
|
|
if err := trie.Prove(first, 0, firstProof); err != nil { |
|
|
|
|
t.Fatalf("Failed to prove the first node %v", err) |
|
|
|
|
} |
|
|
|
|
err := VerifyRangeProof(trie.Hash(), first, nil, nil, firstProof, nil) |
|
|
|
|
if c.err && err == nil { |
|
|
|
|
t.Fatalf("Expected error, got nil") |
|
|
|
|
} |
|
|
|
|
if !c.err && err != nil { |
|
|
|
|
t.Fatalf("Expected no error, got %v", err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TestAllElementsProof tests the range proof with all elements.
|
|
|
|
|
// The edge proofs can be nil.
|
|
|
|
|
func TestAllElementsProof(t *testing.T) { |
|
|
|
|
trie, vals := randomTrie(4096) |
|
|
|
|
var entries entrySlice |
|
|
|
|
for _, kv := range vals { |
|
|
|
|
entries = append(entries, kv) |
|
|
|
|
} |
|
|
|
|
sort.Sort(entries) |
|
|
|
|
|
|
|
|
|
var k [][]byte |
|
|
|
|
var v [][]byte |
|
|
|
|
for i := 0; i < len(entries); i++ { |
|
|
|
|
k = append(k, entries[i].k) |
|
|
|
|
v = append(v, entries[i].v) |
|
|
|
|
} |
|
|
|
|
err := VerifyRangeProof(trie.Hash(), k[0], k, v, nil, nil) |
|
|
|
|
if err != nil { |
|
|
|
|
t.Fatalf("Expected no error, got %v", err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Even with edge proofs, it should still work.
|
|
|
|
|
firstProof, lastProof := memorydb.New(), memorydb.New() |
|
|
|
|
if err := trie.Prove(entries[0].k, 0, firstProof); err != nil { |
|
|
|
|
t.Fatalf("Failed to prove the first node %v", err) |
|
|
|
|
} |
|
|
|
|
if err := trie.Prove(entries[len(entries)-1].k, 0, lastProof); err != nil { |
|
|
|
|
t.Fatalf("Failed to prove the last node %v", err) |
|
|
|
|
} |
|
|
|
|
err = VerifyRangeProof(trie.Hash(), k[0], k, v, firstProof, lastProof) |
|
|
|
|
if err != nil { |
|
|
|
|
t.Fatalf("Expected no error, got %v", err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TestSingleSideRangeProof tests the range starts from zero.
|
|
|
|
|
func TestSingleSideRangeProof(t *testing.T) { |
|
|
|
|
trie := new(Trie) |
|
|
|
|
var entries entrySlice |
|
|
|
|
for i := 0; i < 4096; i++ { |
|
|
|
|
value := &kv{randBytes(32), randBytes(20), false} |
|
|
|
|
trie.Update(value.k, value.v) |
|
|
|
|
entries = append(entries, value) |
|
|
|
|
} |
|
|
|
|
sort.Sort(entries) |
|
|
|
|
|
|
|
|
|
var cases = []int{0, 1, 50, 100, 1000, 2000, len(entries) - 1} |
|
|
|
|
for _, pos := range cases { |
|
|
|
|
firstProof, lastProof := memorydb.New(), memorydb.New() |
|
|
|
|
if err := trie.Prove(common.Hash{}.Bytes(), 0, firstProof); err != nil { |
|
|
|
|
t.Fatalf("Failed to prove the first node %v", err) |
|
|
|
|
} |
|
|
|
|
if err := trie.Prove(entries[pos].k, 0, lastProof); err != nil { |
|
|
|
|
t.Fatalf("Failed to prove the first node %v", err) |
|
|
|
|
} |
|
|
|
|
k := make([][]byte, 0) |
|
|
|
|
v := make([][]byte, 0) |
|
|
|
|
for i := 0; i <= pos; i++ { |
|
|
|
|
k = append(k, entries[i].k) |
|
|
|
|
v = append(v, entries[i].v) |
|
|
|
|
} |
|
|
|
|
err := VerifyRangeProof(trie.Hash(), common.Hash{}.Bytes(), k, v, firstProof, lastProof) |
|
|
|
|
if err != nil { |
|
|
|
|
t.Fatalf("Expected no error, got %v", err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TestBadRangeProof tests a few cases which the proof is wrong.
|
|
|
|
|
// The prover is expected to detect the error.
|
|
|
|
|
func TestBadRangeProof(t *testing.T) { |
|
|
|
|
trie, vals := randomTrie(4096) |
|
|
|
|
var entries entrySlice |
|
|
|
@ -208,7 +501,7 @@ func TestBadRangeProof(t *testing.T) { |
|
|
|
|
index = mrand.Intn(end - start) |
|
|
|
|
vals[index] = nil |
|
|
|
|
} |
|
|
|
|
err := VerifyRangeProof(trie.Hash(), keys, vals, firstProof, lastProof) |
|
|
|
|
err := VerifyRangeProof(trie.Hash(), keys[0], keys, vals, firstProof, lastProof) |
|
|
|
|
if err == nil { |
|
|
|
|
t.Fatalf("%d Case %d index %d range: (%d->%d) expect error, got nil", i, testcase, index, start, end-1) |
|
|
|
|
} |
|
|
|
@ -242,72 +535,41 @@ func TestGappedRangeProof(t *testing.T) { |
|
|
|
|
keys = append(keys, entries[i].k) |
|
|
|
|
vals = append(vals, entries[i].v) |
|
|
|
|
} |
|
|
|
|
err := VerifyRangeProof(trie.Hash(), keys, vals, firstProof, lastProof) |
|
|
|
|
err := VerifyRangeProof(trie.Hash(), keys[0], keys, vals, firstProof, lastProof) |
|
|
|
|
if err == nil { |
|
|
|
|
t.Fatal("expect error, got nil") |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func TestBadProof(t *testing.T) { |
|
|
|
|
trie, vals := randomTrie(800) |
|
|
|
|
root := trie.Hash() |
|
|
|
|
for i, prover := range makeProvers(trie) { |
|
|
|
|
for _, kv := range vals { |
|
|
|
|
proof := prover(kv.k) |
|
|
|
|
if proof == nil { |
|
|
|
|
t.Fatalf("prover %d: nil proof", i) |
|
|
|
|
} |
|
|
|
|
it := proof.NewIterator(nil, nil) |
|
|
|
|
for i, d := 0, mrand.Intn(proof.Len()); i <= d; i++ { |
|
|
|
|
it.Next() |
|
|
|
|
} |
|
|
|
|
key := it.Key() |
|
|
|
|
val, _ := proof.Get(key) |
|
|
|
|
proof.Delete(key) |
|
|
|
|
it.Release() |
|
|
|
|
|
|
|
|
|
mutateByte(val) |
|
|
|
|
proof.Put(crypto.Keccak256(val), val) |
|
|
|
|
|
|
|
|
|
if _, err := VerifyProof(root, kv.k, proof); err == nil { |
|
|
|
|
t.Fatalf("prover %d: expected proof to fail for key %x", i, kv.k) |
|
|
|
|
} |
|
|
|
|
// mutateByte changes one byte in b.
|
|
|
|
|
func mutateByte(b []byte) { |
|
|
|
|
for r := mrand.Intn(len(b)); ; { |
|
|
|
|
new := byte(mrand.Intn(255)) |
|
|
|
|
if new != b[r] { |
|
|
|
|
b[r] = new |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests that missing keys can also be proven. The test explicitly uses a single
|
|
|
|
|
// entry trie and checks for missing keys both before and after the single entry.
|
|
|
|
|
func TestMissingKeyProof(t *testing.T) { |
|
|
|
|
trie := new(Trie) |
|
|
|
|
updateString(trie, "k", "v") |
|
|
|
|
|
|
|
|
|
for i, key := range []string{"a", "j", "l", "z"} { |
|
|
|
|
proof := memorydb.New() |
|
|
|
|
trie.Prove([]byte(key), 0, proof) |
|
|
|
|
|
|
|
|
|
if proof.Len() != 1 { |
|
|
|
|
t.Errorf("test %d: proof should have one element", i) |
|
|
|
|
} |
|
|
|
|
val, err := VerifyProof(trie.Hash(), []byte(key), proof) |
|
|
|
|
if err != nil { |
|
|
|
|
t.Fatalf("test %d: failed to verify proof: %v\nraw proof: %x", i, err, proof) |
|
|
|
|
} |
|
|
|
|
if val != nil { |
|
|
|
|
t.Fatalf("test %d: verified value mismatch: have %x, want nil", i, val) |
|
|
|
|
func increseKey(key []byte) []byte { |
|
|
|
|
for i := len(key) - 1; i >= 0; i-- { |
|
|
|
|
key[i]++ |
|
|
|
|
if key[i] != 0x0 { |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return key |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// mutateByte changes one byte in b.
|
|
|
|
|
func mutateByte(b []byte) { |
|
|
|
|
for r := mrand.Intn(len(b)); ; { |
|
|
|
|
new := byte(mrand.Intn(255)) |
|
|
|
|
if new != b[r] { |
|
|
|
|
b[r] = new |
|
|
|
|
func decreseKey(key []byte) []byte { |
|
|
|
|
for i := len(key) - 1; i >= 0; i-- { |
|
|
|
|
key[i]-- |
|
|
|
|
if key[i] != 0xff { |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return key |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func BenchmarkProve(b *testing.B) { |
|
|
|
@ -379,7 +641,7 @@ func benchmarkVerifyRangeProof(b *testing.B, size int) { |
|
|
|
|
|
|
|
|
|
b.ResetTimer() |
|
|
|
|
for i := 0; i < b.N; i++ { |
|
|
|
|
err := VerifyRangeProof(trie.Hash(), keys, values, firstProof, lastProof) |
|
|
|
|
err := VerifyRangeProof(trie.Hash(), keys[0], keys, values, firstProof, lastProof) |
|
|
|
|
if err != nil { |
|
|
|
|
b.Fatalf("Case %d(%d->%d) expect no error, got %v", i, start, end-1, err) |
|
|
|
|
} |
|
|
|
|