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