| 
									
										
										
										
											2016-04-14 18:18:24 +02:00
										 |  |  | // Copyright 2015 The go-ethereum Authors | 
					
						
							|  |  |  | // This file is part of the go-ethereum library. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							|  |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-09 03:35:41 +02:00
										 |  |  | package trie | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							|  |  |  | 	crand "crypto/rand" | 
					
						
							|  |  |  | 	mrand "math/rand" | 
					
						
							| 
									
										
										
										
											2020-04-24 19:37:56 +08:00
										 |  |  | 	"sort" | 
					
						
							| 
									
										
										
										
											2015-09-09 03:35:41 +02:00
										 |  |  | 	"testing" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	"github.com/ethereum/go-ethereum/ethdb/memorydb" | 
					
						
							| 
									
										
										
										
											2015-09-09 03:35:41 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func init() { | 
					
						
							|  |  |  | 	mrand.Seed(time.Now().Unix()) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 12:49:27 +03:00
										 |  |  | // makeProvers creates Merkle trie provers based on different implementations to | 
					
						
							|  |  |  | // test all variations. | 
					
						
							| 
									
										
										
										
											2019-03-11 17:01:47 +02:00
										 |  |  | func makeProvers(trie *Trie) []func(key []byte) *memorydb.Database { | 
					
						
							|  |  |  | 	var provers []func(key []byte) *memorydb.Database | 
					
						
							| 
									
										
										
										
											2018-05-10 12:49:27 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Create a direct trie based Merkle prover | 
					
						
							| 
									
										
										
										
											2019-03-11 17:01:47 +02:00
										 |  |  | 	provers = append(provers, func(key []byte) *memorydb.Database { | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 		proof := memorydb.New() | 
					
						
							| 
									
										
										
										
											2018-05-10 12:49:27 +03:00
										 |  |  | 		trie.Prove(key, 0, proof) | 
					
						
							|  |  |  | 		return proof | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	// Create a leaf iterator based Merkle prover | 
					
						
							| 
									
										
										
										
											2019-03-11 17:01:47 +02:00
										 |  |  | 	provers = append(provers, func(key []byte) *memorydb.Database { | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 		proof := memorydb.New() | 
					
						
							| 
									
										
										
										
											2018-05-10 12:49:27 +03:00
										 |  |  | 		if it := NewIterator(trie.NodeIterator(key)); it.Next() && bytes.Equal(key, it.Key) { | 
					
						
							|  |  |  | 			for _, p := range it.Prove() { | 
					
						
							|  |  |  | 				proof.Put(crypto.Keccak256(p), p) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return proof | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	return provers | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-09 03:35:41 +02:00
										 |  |  | func TestProof(t *testing.T) { | 
					
						
							|  |  |  | 	trie, vals := randomTrie(500) | 
					
						
							|  |  |  | 	root := trie.Hash() | 
					
						
							| 
									
										
										
										
											2018-05-10 12:49:27 +03:00
										 |  |  | 	for i, prover := range makeProvers(trie) { | 
					
						
							|  |  |  | 		for _, kv := range vals { | 
					
						
							|  |  |  | 			proof := prover(kv.k) | 
					
						
							|  |  |  | 			if proof == nil { | 
					
						
							|  |  |  | 				t.Fatalf("prover %d: missing key %x while constructing proof", i, kv.k) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-04-24 19:37:56 +08:00
										 |  |  | 			val, err := VerifyProof(root, kv.k, proof) | 
					
						
							| 
									
										
										
										
											2018-05-10 12:49:27 +03:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Fatalf("prover %d: failed to verify proof for key %x: %v\nraw proof: %x", i, kv.k, err, proof) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if !bytes.Equal(val, kv.v) { | 
					
						
							|  |  |  | 				t.Fatalf("prover %d: verified value mismatch for key %x: have %x, want %x", i, kv.k, val, kv.v) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-09-09 03:35:41 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestOneElementProof(t *testing.T) { | 
					
						
							|  |  |  | 	trie := new(Trie) | 
					
						
							|  |  |  | 	updateString(trie, "k", "v") | 
					
						
							| 
									
										
										
										
											2018-05-10 12:49:27 +03:00
										 |  |  | 	for i, prover := range makeProvers(trie) { | 
					
						
							|  |  |  | 		proof := prover([]byte("k")) | 
					
						
							|  |  |  | 		if proof == nil { | 
					
						
							|  |  |  | 			t.Fatalf("prover %d: nil proof", i) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if proof.Len() != 1 { | 
					
						
							|  |  |  | 			t.Errorf("prover %d: proof should have one element", i) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-04-24 19:37:56 +08:00
										 |  |  | 		val, err := VerifyProof(trie.Hash(), []byte("k"), proof) | 
					
						
							| 
									
										
										
										
											2018-05-10 12:49:27 +03:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("prover %d: failed to verify proof: %v\nraw proof: %x", i, err, proof) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if !bytes.Equal(val, []byte("v")) { | 
					
						
							|  |  |  | 			t.Fatalf("prover %d: verified value mismatch: have %x, want 'k'", i, val) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-09-09 03:35:41 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-20 20:45:38 +08:00
										 |  |  | 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) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-24 19:37:56 +08:00
										 |  |  | 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] } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-20 20:45:38 +08:00
										 |  |  | // TestRangeProof tests normal range proof with both edge proofs | 
					
						
							|  |  |  | // as the existent proof. The test cases are generated randomly. | 
					
						
							| 
									
										
										
										
											2020-04-24 19:37:56 +08:00
										 |  |  | func TestRangeProof(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() | 
					
						
							|  |  |  | 		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[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) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-05-27 22:37:37 +08:00
										 |  |  | 		err, _ := VerifyRangeProof(trie.Hash(), keys[0], keys, vals, firstProof, lastProof) | 
					
						
							| 
									
										
										
										
											2020-05-20 20:45:38 +08:00
										 |  |  | 		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) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-05-27 22:37:37 +08:00
										 |  |  | 		err, _ := VerifyRangeProof(trie.Hash(), first, keys, vals, firstProof, lastProof) | 
					
						
							| 
									
										
										
										
											2020-04-24 19:37:56 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("Case %d(%d->%d) expect no error, got %v", i, start, end-1, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-20 20:45:38 +08:00
										 |  |  | // 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) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-27 22:37:37 +08:00
										 |  |  | 	err, _ := VerifyRangeProof(trie.Hash(), first, k, v, firstProof, lastProof) | 
					
						
							| 
									
										
										
										
											2020-05-20 20:45:38 +08:00
										 |  |  | 	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) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-27 22:37:37 +08:00
										 |  |  | 	err, _ = VerifyRangeProof(trie.Hash(), first, k, v, firstProof, lastProof) | 
					
						
							| 
									
										
										
										
											2020-05-20 20:45:38 +08:00
										 |  |  | 	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) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-27 22:37:37 +08:00
										 |  |  | 	err, _ := VerifyRangeProof(trie.Hash(), entries[start].k, [][]byte{entries[start].k}, [][]byte{entries[start].v}, firstProof, lastProof) | 
					
						
							| 
									
										
										
										
											2020-05-20 20:45:38 +08:00
										 |  |  | 	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) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-27 22:37:37 +08:00
										 |  |  | 	err, _ = VerifyRangeProof(trie.Hash(), first, [][]byte{entries[start].k}, [][]byte{entries[start].v}, firstProof, lastProof) | 
					
						
							| 
									
										
										
										
											2020-05-20 20:45:38 +08:00
										 |  |  | 	if 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) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-27 22:37:37 +08:00
										 |  |  | 	err, _ := VerifyRangeProof(trie.Hash(), k[0], k, v, nil, nil) | 
					
						
							| 
									
										
										
										
											2020-05-20 20:45:38 +08:00
										 |  |  | 	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) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-27 22:37:37 +08:00
										 |  |  | 	err, _ = VerifyRangeProof(trie.Hash(), k[0], k, v, firstProof, lastProof) | 
					
						
							| 
									
										
										
										
											2020-05-20 20:45:38 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Expected no error, got %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TestSingleSideRangeProof tests the range starts from zero. | 
					
						
							|  |  |  | func TestSingleSideRangeProof(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2020-05-26 18:11:29 +08:00
										 |  |  | 	for i := 0; i < 64; i++ { | 
					
						
							|  |  |  | 		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) | 
					
						
							| 
									
										
										
										
											2020-05-20 20:45:38 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-05-26 18:11:29 +08:00
										 |  |  | 		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) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-05-27 22:37:37 +08:00
										 |  |  | 			err, _ := VerifyRangeProof(trie.Hash(), common.Hash{}.Bytes(), k, v, firstProof, lastProof) | 
					
						
							| 
									
										
										
										
											2020-05-26 18:11:29 +08:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				t.Fatalf("Expected no error, got %v", err) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-05-20 20:45:38 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TestBadRangeProof tests a few cases which the proof is wrong. | 
					
						
							|  |  |  | // The prover is expected to detect the error. | 
					
						
							| 
									
										
										
										
											2020-04-24 19:37:56 +08:00
										 |  |  | func TestBadRangeProof(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() | 
					
						
							|  |  |  | 		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[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) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		testcase := mrand.Intn(6) | 
					
						
							|  |  |  | 		var index int | 
					
						
							|  |  |  | 		switch testcase { | 
					
						
							|  |  |  | 		case 0: | 
					
						
							|  |  |  | 			// Modified key | 
					
						
							|  |  |  | 			index = mrand.Intn(end - start) | 
					
						
							|  |  |  | 			keys[index] = randBytes(32) // In theory it can't be same | 
					
						
							|  |  |  | 		case 1: | 
					
						
							|  |  |  | 			// Modified val | 
					
						
							|  |  |  | 			index = mrand.Intn(end - start) | 
					
						
							|  |  |  | 			vals[index] = randBytes(20) // In theory it can't be same | 
					
						
							|  |  |  | 		case 2: | 
					
						
							|  |  |  | 			// Gapped entry slice | 
					
						
							| 
									
										
										
										
											2020-05-06 21:33:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// There are only two elements, skip it. Dropped any element | 
					
						
							|  |  |  | 			// will lead to single edge proof which is always correct. | 
					
						
							|  |  |  | 			if end-start <= 2 { | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// If the dropped element is the first or last one and it's a | 
					
						
							|  |  |  | 			// batch of small size elements. In this special case, it can | 
					
						
							|  |  |  | 			// happen that the proof for the edge element is exactly same | 
					
						
							|  |  |  | 			// with the first/last second element(since small values are | 
					
						
							|  |  |  | 			// embedded in the parent). Avoid this case. | 
					
						
							| 
									
										
										
										
											2020-04-24 19:37:56 +08:00
										 |  |  | 			index = mrand.Intn(end - start) | 
					
						
							| 
									
										
										
										
											2020-05-06 21:33:57 +08:00
										 |  |  | 			if (index == end-start-1 || index == 0) && end <= 100 { | 
					
						
							| 
									
										
										
										
											2020-04-24 19:37:56 +08:00
										 |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-05-06 21:33:57 +08:00
										 |  |  | 			keys = append(keys[:index], keys[index+1:]...) | 
					
						
							|  |  |  | 			vals = append(vals[:index], vals[index+1:]...) | 
					
						
							| 
									
										
										
										
											2020-04-24 19:37:56 +08:00
										 |  |  | 		case 3: | 
					
						
							|  |  |  | 			// Switched entry slice, same effect with gapped | 
					
						
							|  |  |  | 			index = mrand.Intn(end - start) | 
					
						
							|  |  |  | 			keys[index] = entries[len(entries)-1].k | 
					
						
							|  |  |  | 			vals[index] = entries[len(entries)-1].v | 
					
						
							|  |  |  | 		case 4: | 
					
						
							|  |  |  | 			// Set random key to nil | 
					
						
							|  |  |  | 			index = mrand.Intn(end - start) | 
					
						
							|  |  |  | 			keys[index] = nil | 
					
						
							|  |  |  | 		case 5: | 
					
						
							|  |  |  | 			// Set random value to nil | 
					
						
							|  |  |  | 			index = mrand.Intn(end - start) | 
					
						
							|  |  |  | 			vals[index] = nil | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-05-27 22:37:37 +08:00
										 |  |  | 		err, _ := VerifyRangeProof(trie.Hash(), keys[0], keys, vals, firstProof, lastProof) | 
					
						
							| 
									
										
										
										
											2020-04-24 19:37:56 +08:00
										 |  |  | 		if err == nil { | 
					
						
							|  |  |  | 			t.Fatalf("%d Case %d index %d range: (%d->%d) expect error, got nil", i, testcase, index, start, end-1) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TestGappedRangeProof focuses on the small trie with embedded nodes. | 
					
						
							|  |  |  | // If the gapped node is embedded in the trie, it should be detected too. | 
					
						
							|  |  |  | func TestGappedRangeProof(t *testing.T) { | 
					
						
							|  |  |  | 	trie := new(Trie) | 
					
						
							|  |  |  | 	var entries []*kv // Sorted entries | 
					
						
							|  |  |  | 	for i := byte(0); i < 10; i++ { | 
					
						
							|  |  |  | 		value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} | 
					
						
							|  |  |  | 		trie.Update(value.k, value.v) | 
					
						
							|  |  |  | 		entries = append(entries, value) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	first, last := 2, 8 | 
					
						
							|  |  |  | 	firstProof, lastProof := memorydb.New(), memorydb.New() | 
					
						
							|  |  |  | 	if err := trie.Prove(entries[first].k, 0, firstProof); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to prove the first node %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := trie.Prove(entries[last-1].k, 0, lastProof); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("Failed to prove the last node %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var keys [][]byte | 
					
						
							|  |  |  | 	var vals [][]byte | 
					
						
							|  |  |  | 	for i := first; i < last; i++ { | 
					
						
							|  |  |  | 		if i == (first+last)/2 { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		keys = append(keys, entries[i].k) | 
					
						
							|  |  |  | 		vals = append(vals, entries[i].v) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-27 22:37:37 +08:00
										 |  |  | 	err, _ := VerifyRangeProof(trie.Hash(), keys[0], keys, vals, firstProof, lastProof) | 
					
						
							| 
									
										
										
										
											2020-04-24 19:37:56 +08:00
										 |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		t.Fatal("expect error, got nil") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-27 22:37:37 +08:00
										 |  |  | func TestHasRightElement(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 = []struct { | 
					
						
							|  |  |  | 		start   int | 
					
						
							|  |  |  | 		end     int | 
					
						
							|  |  |  | 		hasMore bool | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{-1, 1, true}, // single element with non-existent left proof | 
					
						
							|  |  |  | 		{0, 1, true},  // single element with existent left proof | 
					
						
							|  |  |  | 		{0, 10, true}, | 
					
						
							|  |  |  | 		{50, 100, true}, | 
					
						
							|  |  |  | 		{50, len(entries), false},               // No more element expected | 
					
						
							|  |  |  | 		{len(entries) - 1, len(entries), false}, // Single last element | 
					
						
							|  |  |  | 		{0, len(entries), false},                // The whole set with existent left proof | 
					
						
							|  |  |  | 		{-1, len(entries), false},               // The whole set with non-existent left proof | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, c := range cases { | 
					
						
							|  |  |  | 		var ( | 
					
						
							|  |  |  | 			firstKey   []byte | 
					
						
							|  |  |  | 			start      = c.start | 
					
						
							|  |  |  | 			firstProof = memorydb.New() | 
					
						
							|  |  |  | 			lastProof  = memorydb.New() | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 		if c.start == -1 { | 
					
						
							|  |  |  | 			firstKey, start = common.Hash{}.Bytes(), 0 | 
					
						
							|  |  |  | 			if err := trie.Prove(firstKey, 0, firstProof); err != nil { | 
					
						
							|  |  |  | 				t.Fatalf("Failed to prove the first node %v", err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			firstKey = entries[c.start].k | 
					
						
							|  |  |  | 			if err := trie.Prove(entries[c.start].k, 0, firstProof); err != nil { | 
					
						
							|  |  |  | 				t.Fatalf("Failed to prove the first node %v", err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if err := trie.Prove(entries[c.end-1].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 := start; i < c.end; i++ { | 
					
						
							|  |  |  | 			k = append(k, entries[i].k) | 
					
						
							|  |  |  | 			v = append(v, entries[i].v) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		err, hasMore := VerifyRangeProof(trie.Hash(), firstKey, k, v, firstProof, lastProof) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("Expected no error, got %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if hasMore != c.hasMore { | 
					
						
							|  |  |  | 			t.Fatalf("Wrong hasMore indicator, want %t, got %t", c.hasMore, hasMore) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-20 20:45:38 +08:00
										 |  |  | // 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 | 
					
						
							| 
									
										
										
										
											2018-05-10 12:49:27 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-20 20:45:38 +08:00
										 |  |  | func increseKey(key []byte) []byte { | 
					
						
							|  |  |  | 	for i := len(key) - 1; i >= 0; i-- { | 
					
						
							|  |  |  | 		key[i]++ | 
					
						
							|  |  |  | 		if key[i] != 0x0 { | 
					
						
							|  |  |  | 			break | 
					
						
							| 
									
										
										
										
											2015-09-09 03:35:41 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-20 20:45:38 +08:00
										 |  |  | 	return key | 
					
						
							| 
									
										
										
										
											2015-09-09 03:35:41 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-20 20:45:38 +08:00
										 |  |  | func decreseKey(key []byte) []byte { | 
					
						
							|  |  |  | 	for i := len(key) - 1; i >= 0; i-- { | 
					
						
							|  |  |  | 		key[i]-- | 
					
						
							|  |  |  | 		if key[i] != 0xff { | 
					
						
							| 
									
										
										
										
											2015-09-09 03:35:41 +02:00
										 |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-20 20:45:38 +08:00
										 |  |  | 	return key | 
					
						
							| 
									
										
										
										
											2015-09-09 03:35:41 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func BenchmarkProve(b *testing.B) { | 
					
						
							|  |  |  | 	trie, vals := randomTrie(100) | 
					
						
							|  |  |  | 	var keys []string | 
					
						
							|  |  |  | 	for k := range vals { | 
					
						
							|  |  |  | 		keys = append(keys, k) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	b.ResetTimer() | 
					
						
							|  |  |  | 	for i := 0; i < b.N; i++ { | 
					
						
							|  |  |  | 		kv := vals[keys[i%len(keys)]] | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 		proofs := memorydb.New() | 
					
						
							|  |  |  | 		if trie.Prove(kv.k, 0, proofs); proofs.Len() == 0 { | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 			b.Fatalf("zero length proof for %x", kv.k) | 
					
						
							| 
									
										
										
										
											2015-09-09 03:35:41 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func BenchmarkVerifyProof(b *testing.B) { | 
					
						
							|  |  |  | 	trie, vals := randomTrie(100) | 
					
						
							|  |  |  | 	root := trie.Hash() | 
					
						
							|  |  |  | 	var keys []string | 
					
						
							| 
									
										
										
										
											2019-03-11 17:01:47 +02:00
										 |  |  | 	var proofs []*memorydb.Database | 
					
						
							| 
									
										
										
										
											2015-09-09 03:35:41 +02:00
										 |  |  | 	for k := range vals { | 
					
						
							|  |  |  | 		keys = append(keys, k) | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 		proof := memorydb.New() | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 		trie.Prove([]byte(k), 0, proof) | 
					
						
							|  |  |  | 		proofs = append(proofs, proof) | 
					
						
							| 
									
										
										
										
											2015-09-09 03:35:41 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	b.ResetTimer() | 
					
						
							|  |  |  | 	for i := 0; i < b.N; i++ { | 
					
						
							|  |  |  | 		im := i % len(keys) | 
					
						
							| 
									
										
										
										
											2020-04-24 19:37:56 +08:00
										 |  |  | 		if _, err := VerifyProof(root, []byte(keys[im]), proofs[im]); err != nil { | 
					
						
							| 
									
										
										
										
											2016-04-15 11:06:57 +02:00
										 |  |  | 			b.Fatalf("key %x: %v", keys[im], err) | 
					
						
							| 
									
										
										
										
											2015-09-09 03:35:41 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-24 19:37:56 +08:00
										 |  |  | func BenchmarkVerifyRangeProof10(b *testing.B)   { benchmarkVerifyRangeProof(b, 10) } | 
					
						
							|  |  |  | func BenchmarkVerifyRangeProof100(b *testing.B)  { benchmarkVerifyRangeProof(b, 100) } | 
					
						
							|  |  |  | func BenchmarkVerifyRangeProof1000(b *testing.B) { benchmarkVerifyRangeProof(b, 1000) } | 
					
						
							|  |  |  | func BenchmarkVerifyRangeProof5000(b *testing.B) { benchmarkVerifyRangeProof(b, 5000) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func benchmarkVerifyRangeProof(b *testing.B, size int) { | 
					
						
							|  |  |  | 	trie, vals := randomTrie(8192) | 
					
						
							|  |  |  | 	var entries entrySlice | 
					
						
							|  |  |  | 	for _, kv := range vals { | 
					
						
							|  |  |  | 		entries = append(entries, kv) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	sort.Sort(entries) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	start := 2 | 
					
						
							|  |  |  | 	end := start + size | 
					
						
							|  |  |  | 	firstProof, lastProof := memorydb.New(), memorydb.New() | 
					
						
							|  |  |  | 	if err := trie.Prove(entries[start].k, 0, firstProof); err != nil { | 
					
						
							|  |  |  | 		b.Fatalf("Failed to prove the first node %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := trie.Prove(entries[end-1].k, 0, lastProof); err != nil { | 
					
						
							|  |  |  | 		b.Fatalf("Failed to prove the last node %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var keys [][]byte | 
					
						
							|  |  |  | 	var values [][]byte | 
					
						
							|  |  |  | 	for i := start; i < end; i++ { | 
					
						
							|  |  |  | 		keys = append(keys, entries[i].k) | 
					
						
							|  |  |  | 		values = append(values, entries[i].v) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	b.ResetTimer() | 
					
						
							|  |  |  | 	for i := 0; i < b.N; i++ { | 
					
						
							| 
									
										
										
										
											2020-05-27 22:37:37 +08:00
										 |  |  | 		err, _ := VerifyRangeProof(trie.Hash(), keys[0], keys, values, firstProof, lastProof) | 
					
						
							| 
									
										
										
										
											2020-04-24 19:37:56 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			b.Fatalf("Case %d(%d->%d) expect no error, got %v", i, start, end-1, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-09 03:35:41 +02:00
										 |  |  | func randomTrie(n int) (*Trie, map[string]*kv) { | 
					
						
							|  |  |  | 	trie := new(Trie) | 
					
						
							|  |  |  | 	vals := make(map[string]*kv) | 
					
						
							|  |  |  | 	for i := byte(0); i < 100; i++ { | 
					
						
							|  |  |  | 		value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} | 
					
						
							|  |  |  | 		value2 := &kv{common.LeftPadBytes([]byte{i + 10}, 32), []byte{i}, false} | 
					
						
							|  |  |  | 		trie.Update(value.k, value.v) | 
					
						
							|  |  |  | 		trie.Update(value2.k, value2.v) | 
					
						
							|  |  |  | 		vals[string(value.k)] = value | 
					
						
							|  |  |  | 		vals[string(value2.k)] = value2 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for i := 0; i < n; i++ { | 
					
						
							|  |  |  | 		value := &kv{randBytes(32), randBytes(20), false} | 
					
						
							|  |  |  | 		trie.Update(value.k, value.v) | 
					
						
							|  |  |  | 		vals[string(value.k)] = value | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return trie, vals | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func randBytes(n int) []byte { | 
					
						
							|  |  |  | 	r := make([]byte, n) | 
					
						
							|  |  |  | 	crand.Read(r) | 
					
						
							|  |  |  | 	return r | 
					
						
							|  |  |  | } |