github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/core/state/sync_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:35</date> 10 //</624450080560123904> 11 12 13 package state 14 15 import ( 16 "bytes" 17 "math/big" 18 "testing" 19 20 "github.com/ethereum/go-ethereum/common" 21 "github.com/ethereum/go-ethereum/crypto" 22 "github.com/ethereum/go-ethereum/ethdb" 23 "github.com/ethereum/go-ethereum/trie" 24 ) 25 26 //TestAccount是与状态测试使用的帐户关联的数据。 27 type testAccount struct { 28 address common.Address 29 balance *big.Int 30 nonce uint64 31 code []byte 32 } 33 34 //maketeststate创建一个样本测试状态来测试节点重构。 35 func makeTestState() (Database, common.Hash, []*testAccount) { 36 //创建空状态 37 db := NewDatabase(ethdb.NewMemDatabase()) 38 state, _ := New(common.Hash{}, db) 39 40 //用任意数据填充它 41 accounts := []*testAccount{} 42 for i := byte(0); i < 96; i++ { 43 obj := state.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 44 acc := &testAccount{address: common.BytesToAddress([]byte{i})} 45 46 obj.AddBalance(big.NewInt(int64(11 * i))) 47 acc.balance = big.NewInt(int64(11 * i)) 48 49 obj.SetNonce(uint64(42 * i)) 50 acc.nonce = uint64(42 * i) 51 52 if i%3 == 0 { 53 obj.SetCode(crypto.Keccak256Hash([]byte{i, i, i, i, i}), []byte{i, i, i, i, i}) 54 acc.code = []byte{i, i, i, i, i} 55 } 56 state.updateStateObject(obj) 57 accounts = append(accounts, acc) 58 } 59 root, _ := state.Commit(false) 60 61 //返回生成的状态 62 return db, root, accounts 63 } 64 65 //checkStateAccounts交叉引用一个重构的状态,该状态应为 66 //帐户数组。 67 func checkStateAccounts(t *testing.T, db ethdb.Database, root common.Hash, accounts []*testAccount) { 68 //检查根可用性和状态内容 69 state, err := New(root, NewDatabase(db)) 70 if err != nil { 71 t.Fatalf("failed to create state trie at %x: %v", root, err) 72 } 73 if err := checkStateConsistency(db, root); err != nil { 74 t.Fatalf("inconsistent state trie at %x: %v", root, err) 75 } 76 for i, acc := range accounts { 77 if balance := state.GetBalance(acc.address); balance.Cmp(acc.balance) != 0 { 78 t.Errorf("account %d: balance mismatch: have %v, want %v", i, balance, acc.balance) 79 } 80 if nonce := state.GetNonce(acc.address); nonce != acc.nonce { 81 t.Errorf("account %d: nonce mismatch: have %v, want %v", i, nonce, acc.nonce) 82 } 83 if code := state.GetCode(acc.address); !bytes.Equal(code, acc.code) { 84 t.Errorf("account %d: code mismatch: have %x, want %x", i, code, acc.code) 85 } 86 } 87 } 88 89 //checktrie一致性检查(sub-)trie中的所有节点是否确实存在。 90 func checkTrieConsistency(db ethdb.Database, root common.Hash) error { 91 if v, _ := db.Get(root[:]); v == nil { 92 return nil //认为不存在的状态是一致的。 93 } 94 trie, err := trie.New(root, trie.NewDatabase(db)) 95 if err != nil { 96 return err 97 } 98 it := trie.NodeIterator(nil) 99 for it.Next(true) { 100 } 101 return it.Error() 102 } 103 104 //checkstateconsistency检查状态根的所有数据是否存在。 105 func checkStateConsistency(db ethdb.Database, root common.Hash) error { 106 //创建并迭代子节点中的状态trie 107 if _, err := db.Get(root.Bytes()); err != nil { 108 return nil //认为不存在的状态是一致的。 109 } 110 state, err := New(root, NewDatabase(db)) 111 if err != nil { 112 return err 113 } 114 it := NewNodeIterator(state) 115 for it.Next() { 116 } 117 return it.Error 118 } 119 120 //测试是否未计划空状态进行同步。 121 func TestEmptyStateSync(t *testing.T) { 122 empty := common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") 123 if req := NewStateSync(empty, ethdb.NewMemDatabase()).Missing(1); len(req) != 0 { 124 t.Errorf("content requested for empty state: %v", req) 125 } 126 } 127 128 //测试给定根哈希,状态可以在单个线程上迭代同步, 129 //请求检索任务并一次性返回所有任务。 130 func TestIterativeStateSyncIndividual(t *testing.T) { testIterativeStateSync(t, 1) } 131 func TestIterativeStateSyncBatched(t *testing.T) { testIterativeStateSync(t, 100) } 132 133 func testIterativeStateSync(t *testing.T, batch int) { 134 //创建要复制的随机状态 135 srcDb, srcRoot, srcAccounts := makeTestState() 136 137 //Create a destination state and sync with the scheduler 138 dstDb := ethdb.NewMemDatabase() 139 sched := NewStateSync(srcRoot, dstDb) 140 141 queue := append([]common.Hash{}, sched.Missing(batch)...) 142 for len(queue) > 0 { 143 results := make([]trie.SyncResult, len(queue)) 144 for i, hash := range queue { 145 data, err := srcDb.TrieDB().Node(hash) 146 if err != nil { 147 t.Fatalf("failed to retrieve node data for %x", hash) 148 } 149 results[i] = trie.SyncResult{Hash: hash, Data: data} 150 } 151 if _, index, err := sched.Process(results); err != nil { 152 t.Fatalf("failed to process result #%d: %v", index, err) 153 } 154 if index, err := sched.Commit(dstDb); err != nil { 155 t.Fatalf("failed to commit data #%d: %v", index, err) 156 } 157 queue = append(queue[:0], sched.Missing(batch)...) 158 } 159 //交叉检查两个状态是否同步 160 checkStateAccounts(t, dstDb, srcRoot, srcAccounts) 161 } 162 163 //测试trie调度程序是否可以正确地重建状态,即使只有 164 //partial results are returned, and the others sent only later. 165 func TestIterativeDelayedStateSync(t *testing.T) { 166 //创建要复制的随机状态 167 srcDb, srcRoot, srcAccounts := makeTestState() 168 169 //创建目标状态并与调度程序同步 170 dstDb := ethdb.NewMemDatabase() 171 sched := NewStateSync(srcRoot, dstDb) 172 173 queue := append([]common.Hash{}, sched.Missing(0)...) 174 for len(queue) > 0 { 175 //只同步一半的计划节点 176 results := make([]trie.SyncResult, len(queue)/2+1) 177 for i, hash := range queue[:len(results)] { 178 data, err := srcDb.TrieDB().Node(hash) 179 if err != nil { 180 t.Fatalf("failed to retrieve node data for %x", hash) 181 } 182 results[i] = trie.SyncResult{Hash: hash, Data: data} 183 } 184 if _, index, err := sched.Process(results); err != nil { 185 t.Fatalf("failed to process result #%d: %v", index, err) 186 } 187 if index, err := sched.Commit(dstDb); err != nil { 188 t.Fatalf("failed to commit data #%d: %v", index, err) 189 } 190 queue = append(queue[len(results):], sched.Missing(0)...) 191 } 192 //交叉检查两个状态是否同步 193 checkStateAccounts(t, dstDb, srcRoot, srcAccounts) 194 } 195 196 //测试给定根哈希,trie可以在单个线程上迭代同步, 197 //请求检索任务并一次性返回所有任务,但是在 198 //随机顺序。 199 func TestIterativeRandomStateSyncIndividual(t *testing.T) { testIterativeRandomStateSync(t, 1) } 200 func TestIterativeRandomStateSyncBatched(t *testing.T) { testIterativeRandomStateSync(t, 100) } 201 202 func testIterativeRandomStateSync(t *testing.T, batch int) { 203 //创建要复制的随机状态 204 srcDb, srcRoot, srcAccounts := makeTestState() 205 206 //创建目标状态并与调度程序同步 207 dstDb := ethdb.NewMemDatabase() 208 sched := NewStateSync(srcRoot, dstDb) 209 210 queue := make(map[common.Hash]struct{}) 211 for _, hash := range sched.Missing(batch) { 212 queue[hash] = struct{}{} 213 } 214 for len(queue) > 0 { 215 //以随机顺序获取所有排队的节点 216 results := make([]trie.SyncResult, 0, len(queue)) 217 for hash := range queue { 218 data, err := srcDb.TrieDB().Node(hash) 219 if err != nil { 220 t.Fatalf("failed to retrieve node data for %x", hash) 221 } 222 results = append(results, trie.SyncResult{Hash: hash, Data: data}) 223 } 224 //将检索到的结果反馈并将新任务排队 225 if _, index, err := sched.Process(results); err != nil { 226 t.Fatalf("failed to process result #%d: %v", index, err) 227 } 228 if index, err := sched.Commit(dstDb); err != nil { 229 t.Fatalf("failed to commit data #%d: %v", index, err) 230 } 231 queue = make(map[common.Hash]struct{}) 232 for _, hash := range sched.Missing(batch) { 233 queue[hash] = struct{}{} 234 } 235 } 236 //交叉检查两个状态是否同步 237 checkStateAccounts(t, dstDb, srcRoot, srcAccounts) 238 } 239 240 //测试trie调度程序是否可以正确地重建状态,即使只有 241 //部分结果会被返回(甚至是随机返回的结果),其他结果只会在稍后发送。 242 func TestIterativeRandomDelayedStateSync(t *testing.T) { 243 //创建要复制的随机状态 244 srcDb, srcRoot, srcAccounts := makeTestState() 245 246 //创建目标状态并与调度程序同步 247 dstDb := ethdb.NewMemDatabase() 248 sched := NewStateSync(srcRoot, dstDb) 249 250 queue := make(map[common.Hash]struct{}) 251 for _, hash := range sched.Missing(0) { 252 queue[hash] = struct{}{} 253 } 254 for len(queue) > 0 { 255 //只同步一半的计划节点,甚至是随机顺序的节点 256 results := make([]trie.SyncResult, 0, len(queue)/2+1) 257 for hash := range queue { 258 delete(queue, hash) 259 260 data, err := srcDb.TrieDB().Node(hash) 261 if err != nil { 262 t.Fatalf("failed to retrieve node data for %x", hash) 263 } 264 results = append(results, trie.SyncResult{Hash: hash, Data: data}) 265 266 if len(results) >= cap(results) { 267 break 268 } 269 } 270 //将检索到的结果反馈并将新任务排队 271 if _, index, err := sched.Process(results); err != nil { 272 t.Fatalf("failed to process result #%d: %v", index, err) 273 } 274 if index, err := sched.Commit(dstDb); err != nil { 275 t.Fatalf("failed to commit data #%d: %v", index, err) 276 } 277 for _, hash := range sched.Missing(0) { 278 queue[hash] = struct{}{} 279 } 280 } 281 //交叉检查两个状态是否同步 282 checkStateAccounts(t, dstDb, srcRoot, srcAccounts) 283 } 284 285 //测试在同步过程中的任何时间点,只有完整的子尝试处于 286 //数据库。 287 func TestIncompleteStateSync(t *testing.T) { 288 //创建要复制的随机状态 289 srcDb, srcRoot, srcAccounts := makeTestState() 290 291 checkTrieConsistency(srcDb.TrieDB().DiskDB().(ethdb.Database), srcRoot) 292 293 //创建目标状态并与调度程序同步 294 dstDb := ethdb.NewMemDatabase() 295 sched := NewStateSync(srcRoot, dstDb) 296 297 added := []common.Hash{} 298 queue := append([]common.Hash{}, sched.Missing(1)...) 299 for len(queue) > 0 { 300 //获取一批状态节点 301 results := make([]trie.SyncResult, len(queue)) 302 for i, hash := range queue { 303 data, err := srcDb.TrieDB().Node(hash) 304 if err != nil { 305 t.Fatalf("failed to retrieve node data for %x", hash) 306 } 307 results[i] = trie.SyncResult{Hash: hash, Data: data} 308 } 309 //处理每个状态节点 310 if _, index, err := sched.Process(results); err != nil { 311 t.Fatalf("failed to process result #%d: %v", index, err) 312 } 313 if index, err := sched.Commit(dstDb); err != nil { 314 t.Fatalf("failed to commit data #%d: %v", index, err) 315 } 316 for _, result := range results { 317 added = append(added, result.Hash) 318 } 319 //检查到目前为止添加的所有已知子尝试是否完全完成或丢失。 320 checkSubtries: 321 for _, hash := range added { 322 for _, acc := range srcAccounts { 323 if hash == crypto.Keccak256Hash(acc.code) { 324 continue checkSubtries //跳过代码节点的三检。 325 } 326 } 327 //无法在此处使用CheckStateConsistency,因为子RIE键可能具有奇数 328 //长度和撞击力。 329 if err := checkTrieConsistency(dstDb, hash); err != nil { 330 t.Fatalf("state inconsistent: %v", err) 331 } 332 } 333 //获取要检索的下一批 334 queue = append(queue[:0], sched.Missing(1)...) 335 } 336 //健全性检查是否检测到从数据库中删除任何节点 337 for _, node := range added[1:] { 338 key := node.Bytes() 339 value, _ := dstDb.Get(key) 340 341 dstDb.Delete(key) 342 if err := checkStateConsistency(dstDb, added[0]); err == nil { 343 t.Fatalf("trie inconsistency not caught, missing: %x", key) 344 } 345 dstDb.Put(key, value) 346 } 347 } 348