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