github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/trie/proof_test.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:45</date> 10 //</624450123203612672> 11 12 13 package trie 14 15 import ( 16 "bytes" 17 crand "crypto/rand" 18 mrand "math/rand" 19 "testing" 20 "time" 21 22 "github.com/ethereum/go-ethereum/common" 23 "github.com/ethereum/go-ethereum/crypto" 24 "github.com/ethereum/go-ethereum/ethdb" 25 ) 26 27 func init() { 28 mrand.Seed(time.Now().Unix()) 29 } 30 31 //makeprovers根据不同的实现创建merkle trie provers 32 //测试所有变化。 33 func makeProvers(trie *Trie) []func(key []byte) *ethdb.MemDatabase { 34 var provers []func(key []byte) *ethdb.MemDatabase 35 36 //创建直接基于trie的merkle prover 37 provers = append(provers, func(key []byte) *ethdb.MemDatabase { 38 proof := ethdb.NewMemDatabase() 39 trie.Prove(key, 0, proof) 40 return proof 41 }) 42 //创建基于叶迭代器的merkle prover 43 provers = append(provers, func(key []byte) *ethdb.MemDatabase { 44 proof := ethdb.NewMemDatabase() 45 if it := NewIterator(trie.NodeIterator(key)); it.Next() && bytes.Equal(key, it.Key) { 46 for _, p := range it.Prove() { 47 proof.Put(crypto.Keccak256(p), p) 48 } 49 } 50 return proof 51 }) 52 return provers 53 } 54 55 func TestProof(t *testing.T) { 56 trie, vals := randomTrie(500) 57 root := trie.Hash() 58 for i, prover := range makeProvers(trie) { 59 for _, kv := range vals { 60 proof := prover(kv.k) 61 if proof == nil { 62 t.Fatalf("prover %d: missing key %x while constructing proof", i, kv.k) 63 } 64 val, _, err := VerifyProof(root, kv.k, proof) 65 if err != nil { 66 t.Fatalf("prover %d: failed to verify proof for key %x: %v\nraw proof: %x", i, kv.k, err, proof) 67 } 68 if !bytes.Equal(val, kv.v) { 69 t.Fatalf("prover %d: verified value mismatch for key %x: have %x, want %x", i, kv.k, val, kv.v) 70 } 71 } 72 } 73 } 74 75 func TestOneElementProof(t *testing.T) { 76 trie := new(Trie) 77 updateString(trie, "k", "v") 78 for i, prover := range makeProvers(trie) { 79 proof := prover([]byte("k")) 80 if proof == nil { 81 t.Fatalf("prover %d: nil proof", i) 82 } 83 if proof.Len() != 1 { 84 t.Errorf("prover %d: proof should have one element", i) 85 } 86 val, _, err := VerifyProof(trie.Hash(), []byte("k"), proof) 87 if err != nil { 88 t.Fatalf("prover %d: failed to verify proof: %v\nraw proof: %x", i, err, proof) 89 } 90 if !bytes.Equal(val, []byte("v")) { 91 t.Fatalf("prover %d: verified value mismatch: have %x, want 'k'", i, val) 92 } 93 } 94 } 95 96 func TestBadProof(t *testing.T) { 97 trie, vals := randomTrie(800) 98 root := trie.Hash() 99 for i, prover := range makeProvers(trie) { 100 for _, kv := range vals { 101 proof := prover(kv.k) 102 if proof == nil { 103 t.Fatalf("prover %d: nil proof", i) 104 } 105 key := proof.Keys()[mrand.Intn(proof.Len())] 106 val, _ := proof.Get(key) 107 proof.Delete(key) 108 109 mutateByte(val) 110 proof.Put(crypto.Keccak256(val), val) 111 112 if _, _, err := VerifyProof(root, kv.k, proof); err == nil { 113 t.Fatalf("prover %d: expected proof to fail for key %x", i, kv.k) 114 } 115 } 116 } 117 } 118 119 //还可以证明缺少密钥的测试。测试显式使用 120 //条目检索并检查单个条目前后是否有丢失的键。 121 func TestMissingKeyProof(t *testing.T) { 122 trie := new(Trie) 123 updateString(trie, "k", "v") 124 125 for i, key := range []string{"a", "j", "l", "z"} { 126 proof := ethdb.NewMemDatabase() 127 trie.Prove([]byte(key), 0, proof) 128 129 if proof.Len() != 1 { 130 t.Errorf("test %d: proof should have one element", i) 131 } 132 val, _, err := VerifyProof(trie.Hash(), []byte(key), proof) 133 if err != nil { 134 t.Fatalf("test %d: failed to verify proof: %v\nraw proof: %x", i, err, proof) 135 } 136 if val != nil { 137 t.Fatalf("test %d: verified value mismatch: have %x, want nil", i, val) 138 } 139 } 140 } 141 142 //突变字节改变了B中的一个字节。 143 func mutateByte(b []byte) { 144 for r := mrand.Intn(len(b)); ; { 145 new := byte(mrand.Intn(255)) 146 if new != b[r] { 147 b[r] = new 148 break 149 } 150 } 151 } 152 153 func BenchmarkProve(b *testing.B) { 154 trie, vals := randomTrie(100) 155 var keys []string 156 for k := range vals { 157 keys = append(keys, k) 158 } 159 160 b.ResetTimer() 161 for i := 0; i < b.N; i++ { 162 kv := vals[keys[i%len(keys)]] 163 proofs := ethdb.NewMemDatabase() 164 if trie.Prove(kv.k, 0, proofs); len(proofs.Keys()) == 0 { 165 b.Fatalf("zero length proof for %x", kv.k) 166 } 167 } 168 } 169 170 func BenchmarkVerifyProof(b *testing.B) { 171 trie, vals := randomTrie(100) 172 root := trie.Hash() 173 var keys []string 174 var proofs []*ethdb.MemDatabase 175 for k := range vals { 176 keys = append(keys, k) 177 proof := ethdb.NewMemDatabase() 178 trie.Prove([]byte(k), 0, proof) 179 proofs = append(proofs, proof) 180 } 181 182 b.ResetTimer() 183 for i := 0; i < b.N; i++ { 184 im := i % len(keys) 185 if _, _, err := VerifyProof(root, []byte(keys[im]), proofs[im]); err != nil { 186 b.Fatalf("key %x: %v", keys[im], err) 187 } 188 } 189 } 190 191 func randomTrie(n int) (*Trie, map[string]*kv) { 192 trie := new(Trie) 193 vals := make(map[string]*kv) 194 for i := byte(0); i < 100; i++ { 195 value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} 196 value2 := &kv{common.LeftPadBytes([]byte{i + 10}, 32), []byte{i}, false} 197 trie.Update(value.k, value.v) 198 trie.Update(value2.k, value2.v) 199 vals[string(value.k)] = value 200 vals[string(value2.k)] = value2 201 } 202 for i := 0; i < n; i++ { 203 value := &kv{randBytes(32), randBytes(20), false} 204 trie.Update(value.k, value.v) 205 vals[string(value.k)] = value 206 } 207 return trie, vals 208 } 209 210 func randBytes(n int) []byte { 211 r := make([]byte, n) 212 crand.Read(r) 213 return r 214 } 215