github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/core/state/statedb_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 //版权所有2016 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 "encoding/binary" 30 "fmt" 31 "math" 32 "math/big" 33 "math/rand" 34 "reflect" 35 "strings" 36 "testing" 37 "testing/quick" 38 39 check "gopkg.in/check.v1" 40 41 "github.com/ethereum/go-ethereum/common" 42 "github.com/ethereum/go-ethereum/core/types" 43 "github.com/ethereum/go-ethereum/ethdb" 44 ) 45 46 //更新状态trie之前不泄漏任何数据库写入的测试 47 //实际提交状态。 48 func TestUpdateLeaks(t *testing.T) { 49 //创建空状态数据库 50 db := ethdb.NewMemDatabase() 51 state, _ := New(common.Hash{}, NewDatabase(db)) 52 53 //用一些帐户更新它 54 for i := byte(0); i < 255; i++ { 55 addr := common.BytesToAddress([]byte{i}) 56 state.AddBalance(addr, big.NewInt(int64(11*i))) 57 state.SetNonce(addr, uint64(42*i)) 58 if i%2 == 0 { 59 state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i})) 60 } 61 if i%3 == 0 { 62 state.SetCode(addr, []byte{i, i, i, i, i}) 63 } 64 state.IntermediateRoot(false) 65 } 66 //确保没有数据泄漏到数据库中 67 for _, key := range db.Keys() { 68 value, _ := db.Get(key) 69 t.Errorf("State leaked into database: %x -> %x", key, value) 70 } 71 } 72 73 //测试对象的中间状态是否未存储到数据库中, 74 //只有一个在提交之前。 75 func TestIntermediateLeaks(t *testing.T) { 76 //创建两个状态数据库,一个转换为最终状态,另一个从一开始就是最终状态 77 transDb := ethdb.NewMemDatabase() 78 finalDb := ethdb.NewMemDatabase() 79 transState, _ := New(common.Hash{}, NewDatabase(transDb)) 80 finalState, _ := New(common.Hash{}, NewDatabase(finalDb)) 81 82 modify := func(state *StateDB, addr common.Address, i, tweak byte) { 83 state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak))) 84 state.SetNonce(addr, uint64(42*i+tweak)) 85 if i%2 == 0 { 86 state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{}) 87 state.SetState(addr, common.Hash{i, i, i, tweak}, common.Hash{i, i, i, i, tweak}) 88 } 89 if i%3 == 0 { 90 state.SetCode(addr, []byte{i, i, i, i, i, tweak}) 91 } 92 } 93 94 //修改瞬态。 95 for i := byte(0); i < 255; i++ { 96 modify(transState, common.Address{byte(i)}, i, 0) 97 } 98 //将修改写入trie。 99 transState.IntermediateRoot(false) 100 101 //用临时数据库中的新值覆盖所有数据。 102 for i := byte(0); i < 255; i++ { 103 modify(transState, common.Address{byte(i)}, i, 99) 104 modify(finalState, common.Address{byte(i)}, i, 99) 105 } 106 107 //提交并交叉检查数据库。 108 if _, err := transState.Commit(false); err != nil { 109 t.Fatalf("failed to commit transition state: %v", err) 110 } 111 if _, err := finalState.Commit(false); err != nil { 112 t.Fatalf("failed to commit final state: %v", err) 113 } 114 for _, key := range finalDb.Keys() { 115 if _, err := transDb.Get(key); err != nil { 116 val, _ := finalDb.Get(key) 117 t.Errorf("entry missing from the transition database: %x -> %x", key, val) 118 } 119 } 120 for _, key := range transDb.Keys() { 121 if _, err := finalDb.Get(key); err != nil { 122 val, _ := transDb.Get(key) 123 t.Errorf("extra entry in the transition database: %x -> %x", key, val) 124 } 125 } 126 } 127 128 //testcopy测试复制statedb对象确实会使 129 //相互独立的副本。此测试是对 130 //https://github.com/ethereum/go-ethereum/pull/15549。 131 func TestCopy(t *testing.T) { 132 //创建随机状态测试以“独立”复制和修改 133 orig, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase())) 134 135 for i := byte(0); i < 255; i++ { 136 obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 137 obj.AddBalance(big.NewInt(int64(i))) 138 orig.updateStateObject(obj) 139 } 140 orig.Finalise(false) 141 142 //复制状态,在内存中修改 143 copy := orig.Copy() 144 145 for i := byte(0); i < 255; i++ { 146 origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 147 copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 148 149 origObj.AddBalance(big.NewInt(2 * int64(i))) 150 copyObj.AddBalance(big.NewInt(3 * int64(i))) 151 152 orig.updateStateObject(origObj) 153 copy.updateStateObject(copyObj) 154 } 155 //同时完成两个方面的更改 156 done := make(chan struct{}) 157 go func() { 158 orig.Finalise(true) 159 close(done) 160 }() 161 copy.Finalise(true) 162 <-done 163 164 //验证两个状态是否已独立更新 165 for i := byte(0); i < 255; i++ { 166 origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 167 copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 168 169 if want := big.NewInt(3 * int64(i)); origObj.Balance().Cmp(want) != 0 { 170 t.Errorf("orig obj %d: balance mismatch: have %v, want %v", i, origObj.Balance(), want) 171 } 172 if want := big.NewInt(4 * int64(i)); copyObj.Balance().Cmp(want) != 0 { 173 t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, copyObj.Balance(), want) 174 } 175 } 176 } 177 178 func TestSnapshotRandom(t *testing.T) { 179 config := &quick.Config{MaxCount: 1000} 180 err := quick.Check((*snapshotTest).run, config) 181 if cerr, ok := err.(*quick.CheckError); ok { 182 test := cerr.In[0].(*snapshotTest) 183 t.Errorf("%v:\n%s", test.err, test) 184 } else if err != nil { 185 t.Error(err) 186 } 187 } 188 189 //Snapshottest检查恢复statedb快照是否正确撤消所有更改 190 //由快照捕获。将创建具有伪随机内容的此测试的实例 191 //通过生成。 192 // 193 //试验工作如下: 194 // 195 //将创建一个新状态并对其应用所有操作。拍摄了几个快照 196 //在行动之间。然后测试恢复每个快照。对于每个快照,操作 197 //在它之前是在一个新鲜的、空的状态下重播的。所有公众的行为 198 //还原状态的访问器方法必须与等效的返回值匹配 199 //方法。 200 type snapshotTest struct { 201 addrs []common.Address //所有帐户地址 202 actions []testAction //对国家的修改 203 snapshots []int //执行快照的操作索引 204 err error //通过此字段报告故障详细信息 205 } 206 207 type testAction struct { 208 name string 209 fn func(testAction, *StateDB) 210 args []int64 211 noAddr bool 212 } 213 214 //NewTestAction创建一个更改状态的随机操作。 215 func newTestAction(addr common.Address, r *rand.Rand) testAction { 216 actions := []testAction{ 217 { 218 name: "SetBalance", 219 fn: func(a testAction, s *StateDB) { 220 s.SetBalance(addr, big.NewInt(a.args[0])) 221 }, 222 args: make([]int64, 1), 223 }, 224 { 225 name: "AddBalance", 226 fn: func(a testAction, s *StateDB) { 227 s.AddBalance(addr, big.NewInt(a.args[0])) 228 }, 229 args: make([]int64, 1), 230 }, 231 { 232 name: "SetNonce", 233 fn: func(a testAction, s *StateDB) { 234 s.SetNonce(addr, uint64(a.args[0])) 235 }, 236 args: make([]int64, 1), 237 }, 238 { 239 name: "SetState", 240 fn: func(a testAction, s *StateDB) { 241 var key, val common.Hash 242 binary.BigEndian.PutUint16(key[:], uint16(a.args[0])) 243 binary.BigEndian.PutUint16(val[:], uint16(a.args[1])) 244 s.SetState(addr, key, val) 245 }, 246 args: make([]int64, 2), 247 }, 248 { 249 name: "SetCode", 250 fn: func(a testAction, s *StateDB) { 251 code := make([]byte, 16) 252 binary.BigEndian.PutUint64(code, uint64(a.args[0])) 253 binary.BigEndian.PutUint64(code[8:], uint64(a.args[1])) 254 s.SetCode(addr, code) 255 }, 256 args: make([]int64, 2), 257 }, 258 { 259 name: "CreateAccount", 260 fn: func(a testAction, s *StateDB) { 261 s.CreateAccount(addr) 262 }, 263 }, 264 { 265 name: "Suicide", 266 fn: func(a testAction, s *StateDB) { 267 s.Suicide(addr) 268 }, 269 }, 270 { 271 name: "AddRefund", 272 fn: func(a testAction, s *StateDB) { 273 s.AddRefund(uint64(a.args[0])) 274 }, 275 args: make([]int64, 1), 276 noAddr: true, 277 }, 278 { 279 name: "AddLog", 280 fn: func(a testAction, s *StateDB) { 281 data := make([]byte, 2) 282 binary.BigEndian.PutUint16(data, uint16(a.args[0])) 283 s.AddLog(&types.Log{Address: addr, Data: data}) 284 }, 285 args: make([]int64, 1), 286 }, 287 } 288 action := actions[r.Intn(len(actions))] 289 var nameargs []string 290 if !action.noAddr { 291 nameargs = append(nameargs, addr.Hex()) 292 } 293 for _, i := range action.args { 294 action.args[i] = rand.Int63n(100) 295 nameargs = append(nameargs, fmt.Sprint(action.args[i])) 296 } 297 action.name += strings.Join(nameargs, ", ") 298 return action 299 } 300 301 //generate返回给定大小的新快照测试。所有的随机性都是 302 //源自R 303 func (*snapshotTest) Generate(r *rand.Rand, size int) reflect.Value { 304 //生成随机动作。 305 addrs := make([]common.Address, 50) 306 for i := range addrs { 307 addrs[i][0] = byte(i) 308 } 309 actions := make([]testAction, size) 310 for i := range actions { 311 addr := addrs[r.Intn(len(addrs))] 312 actions[i] = newTestAction(addr, r) 313 } 314 //生成快照索引。 315 nsnapshots := int(math.Sqrt(float64(size))) 316 if size > 0 && nsnapshots == 0 { 317 nsnapshots = 1 318 } 319 snapshots := make([]int, nsnapshots) 320 snaplen := len(actions) / nsnapshots 321 for i := range snapshots { 322 //试着把快照放在一些动作之间。 323 snapshots[i] = (i * snaplen) + r.Intn(snaplen) 324 } 325 return reflect.ValueOf(&snapshotTest{addrs, actions, snapshots, nil}) 326 } 327 328 func (test *snapshotTest) String() string { 329 out := new(bytes.Buffer) 330 sindex := 0 331 for i, action := range test.actions { 332 if len(test.snapshots) > sindex && i == test.snapshots[sindex] { 333 fmt.Fprintf(out, "---- snapshot %d ----\n", sindex) 334 sindex++ 335 } 336 fmt.Fprintf(out, "%4d: %s\n", i, action.name) 337 } 338 return out.String() 339 } 340 341 func (test *snapshotTest) run() bool { 342 //运行所有操作并创建快照。 343 var ( 344 state, _ = New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase())) 345 snapshotRevs = make([]int, len(test.snapshots)) 346 sindex = 0 347 ) 348 for i, action := range test.actions { 349 if len(test.snapshots) > sindex && i == test.snapshots[sindex] { 350 snapshotRevs[sindex] = state.Snapshot() 351 sindex++ 352 } 353 action.fn(action, state) 354 } 355 //按相反顺序还原所有快照。每个还原都必须产生一个状态 356 //这相当于应用了快照上的所有操作后的新状态。 357 for sindex--; sindex >= 0; sindex-- { 358 checkstate, _ := New(common.Hash{}, state.Database()) 359 for _, action := range test.actions[:test.snapshots[sindex]] { 360 action.fn(action, checkstate) 361 } 362 state.RevertToSnapshot(snapshotRevs[sindex]) 363 if err := test.checkEqual(state, checkstate); err != nil { 364 test.err = fmt.Errorf("state mismatch after revert to snapshot %d\n%v", sindex, err) 365 return false 366 } 367 } 368 return true 369 } 370 371 //checkequal检查state和checkstate方法是否返回相同的值。 372 func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { 373 for _, addr := range test.addrs { 374 var err error 375 checkeq := func(op string, a, b interface{}) bool { 376 if err == nil && !reflect.DeepEqual(a, b) { 377 err = fmt.Errorf("got %s(%s) == %v, want %v", op, addr.Hex(), a, b) 378 return false 379 } 380 return true 381 } 382 //检查基本访问器方法。 383 checkeq("Exist", state.Exist(addr), checkstate.Exist(addr)) 384 checkeq("HasSuicided", state.HasSuicided(addr), checkstate.HasSuicided(addr)) 385 checkeq("GetBalance", state.GetBalance(addr), checkstate.GetBalance(addr)) 386 checkeq("GetNonce", state.GetNonce(addr), checkstate.GetNonce(addr)) 387 checkeq("GetCode", state.GetCode(addr), checkstate.GetCode(addr)) 388 checkeq("GetCodeHash", state.GetCodeHash(addr), checkstate.GetCodeHash(addr)) 389 checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr)) 390 //检查存储。 391 if obj := state.getStateObject(addr); obj != nil { 392 state.ForEachStorage(addr, func(key, val common.Hash) bool { 393 return checkeq("GetState("+key.Hex()+")", val, checkstate.GetState(addr, key)) 394 }) 395 checkstate.ForEachStorage(addr, func(key, checkval common.Hash) bool { 396 return checkeq("GetState("+key.Hex()+")", state.GetState(addr, key), checkval) 397 }) 398 } 399 if err != nil { 400 return err 401 } 402 } 403 404 if state.GetRefund() != checkstate.GetRefund() { 405 return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d", 406 state.GetRefund(), checkstate.GetRefund()) 407 } 408 if !reflect.DeepEqual(state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{})) { 409 return fmt.Errorf("got GetLogs(common.Hash{}) == %v, want GetLogs(common.Hash{}) == %v", 410 state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{})) 411 } 412 return nil 413 } 414 415 func (s *StateSuite) TestTouchDelete(c *check.C) { 416 s.state.GetOrNewStateObject(common.Address{}) 417 root, _ := s.state.Commit(false) 418 s.state.Reset(root) 419 420 snapshot := s.state.Snapshot() 421 s.state.AddBalance(common.Address{}, new(big.Int)) 422 423 if len(s.state.journal.dirties) != 1 { 424 c.Fatal("expected one dirty state object") 425 } 426 s.state.RevertToSnapshot(snapshot) 427 if len(s.state.journal.dirties) != 0 { 428 c.Fatal("expected no dirty state object") 429 } 430 } 431 432 //testcopyofcopy测试修改后的对象将被转移到副本和副本。 433 //请参见https://github.com/ethereum/go-ethereum/pull/15225_issuecomment-380191512 434 func TestCopyOfCopy(t *testing.T) { 435 sdb, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase())) 436 addr := common.HexToAddress("aaaa") 437 sdb.SetBalance(addr, big.NewInt(42)) 438 439 if got := sdb.Copy().GetBalance(addr).Uint64(); got != 42 { 440 t.Fatalf("1st copy fail, expected 42, got %v", got) 441 } 442 if got := sdb.Copy().Copy().GetBalance(addr).Uint64(); got != 42 { 443 t.Fatalf("2nd copy fail, expected 42, got %v", got) 444 } 445 }