| 
									
										
										
										
											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" | 
					
						
							|  |  |  | 	"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) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			val, _, err := VerifyProof(root, kv.k, proof) | 
					
						
							|  |  |  | 			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) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		val, _, err := VerifyProof(trie.Hash(), []byte("k"), proof) | 
					
						
							|  |  |  | 		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
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 12:49:27 +03:00
										 |  |  | func TestBadProof(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2015-09-09 03:35:41 +02:00
										 |  |  | 	trie, vals := randomTrie(800) | 
					
						
							|  |  |  | 	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: nil proof", i) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 			it := proof.NewIterator() | 
					
						
							|  |  |  | 			for i, d := 0, mrand.Intn(proof.Len()); i <= d; i++ { | 
					
						
							|  |  |  | 				it.Next() | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			key := it.Key() | 
					
						
							| 
									
										
										
										
											2018-05-10 12:49:27 +03:00
										 |  |  | 			val, _ := proof.Get(key) | 
					
						
							|  |  |  | 			proof.Delete(key) | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 			it.Release() | 
					
						
							| 
									
										
										
										
											2018-05-10 12:49:27 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			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"} { | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 		proof := memorydb.New() | 
					
						
							| 
									
										
										
										
											2018-05-10 12:49:27 +03:00
										 |  |  | 		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) | 
					
						
							| 
									
										
										
										
											2015-09-09 03:35:41 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-05-10 12:49:27 +03:00
										 |  |  | 		if val != nil { | 
					
						
							|  |  |  | 			t.Fatalf("test %d: verified value mismatch: have %x, want nil", i, val) | 
					
						
							| 
									
										
										
										
											2015-09-09 03:35:41 +02: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 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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) | 
					
						
							| 
									
										
										
										
											2018-05-21 13:41:31 -07: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
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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 | 
					
						
							|  |  |  | } |