github.com/jincm/wesharechain@v0.0.0-20210122032815-1537409ce26a/chain/core/state/statedb_test.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package state 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "fmt" 23 "math" 24 "math/big" 25 "math/rand" 26 "reflect" 27 "strings" 28 "testing" 29 "testing/quick" 30 31 check "gopkg.in/check.v1" 32 33 "github.com/ethereum/go-ethereum/common" 34 "github.com/ethereum/go-ethereum/core/types" 35 "github.com/ethereum/go-ethereum/ethdb" 36 ) 37 38 // Tests that updating a state trie does not leak any database writes prior to 39 // actually committing the state. 40 func TestUpdateLeaks(t *testing.T) { 41 // Create an empty state database 42 db := ethdb.NewMemDatabase() 43 state, _ := New(common.Hash{}, NewDatabase(db)) 44 45 // Update it with some accounts 46 for i := byte(0); i < 255; i++ { 47 addr := common.BytesToAddress([]byte{i}) 48 state.AddBalance(addr, big.NewInt(int64(11*i))) 49 state.SetNonce(addr, uint64(42*i)) 50 if i%2 == 0 { 51 state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i})) 52 } 53 if i%3 == 0 { 54 state.SetCode(addr, []byte{i, i, i, i, i}) 55 } 56 state.IntermediateRoot(false) 57 } 58 // Ensure that no data was leaked into the database 59 for _, key := range db.Keys() { 60 value, _ := db.Get(key) 61 t.Errorf("State leaked into database: %x -> %x", key, value) 62 } 63 } 64 65 // Tests that no intermediate state of an object is stored into the database, 66 // only the one right before the commit. 67 func TestIntermediateLeaks(t *testing.T) { 68 // Create two state databases, one transitioning to the final state, the other final from the beginning 69 transDb := ethdb.NewMemDatabase() 70 finalDb := ethdb.NewMemDatabase() 71 transState, _ := New(common.Hash{}, NewDatabase(transDb)) 72 finalState, _ := New(common.Hash{}, NewDatabase(finalDb)) 73 74 modify := func(state *StateDB, addr common.Address, i, tweak byte) { 75 state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak))) 76 state.SetNonce(addr, uint64(42*i+tweak)) 77 if i%2 == 0 { 78 state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{}) 79 state.SetState(addr, common.Hash{i, i, i, tweak}, common.Hash{i, i, i, i, tweak}) 80 } 81 if i%3 == 0 { 82 state.SetCode(addr, []byte{i, i, i, i, i, tweak}) 83 } 84 } 85 86 // Modify the transient state. 87 for i := byte(0); i < 255; i++ { 88 modify(transState, common.Address{byte(i)}, i, 0) 89 } 90 // Write modifications to trie. 91 transState.IntermediateRoot(false) 92 93 // Overwrite all the data with new values in the transient database. 94 for i := byte(0); i < 255; i++ { 95 modify(transState, common.Address{byte(i)}, i, 99) 96 modify(finalState, common.Address{byte(i)}, i, 99) 97 } 98 99 // Commit and cross check the databases. 100 if _, err := transState.Commit(false); err != nil { 101 t.Fatalf("failed to commit transition state: %v", err) 102 } 103 if _, err := finalState.Commit(false); err != nil { 104 t.Fatalf("failed to commit final state: %v", err) 105 } 106 for _, key := range finalDb.Keys() { 107 if _, err := transDb.Get(key); err != nil { 108 val, _ := finalDb.Get(key) 109 t.Errorf("entry missing from the transition database: %x -> %x", key, val) 110 } 111 } 112 for _, key := range transDb.Keys() { 113 if _, err := finalDb.Get(key); err != nil { 114 val, _ := transDb.Get(key) 115 t.Errorf("extra entry in the transition database: %x -> %x", key, val) 116 } 117 } 118 } 119 120 // TestCopy tests that copying a statedb object indeed makes the original and 121 // the copy independent of each other. This test is a regression test against 122 // https://github.com/ethereum/go-ethereum/pull/15549. 123 func TestCopy(t *testing.T) { 124 // Create a random state test to copy and modify "independently" 125 orig, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase())) 126 127 for i := byte(0); i < 255; i++ { 128 obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 129 obj.AddBalance(big.NewInt(int64(i))) 130 orig.updateStateObject(obj) 131 } 132 orig.Finalise(false) 133 134 // Copy the state, modify both in-memory 135 copy := orig.Copy() 136 137 for i := byte(0); i < 255; i++ { 138 origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 139 copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 140 141 origObj.AddBalance(big.NewInt(2 * int64(i))) 142 copyObj.AddBalance(big.NewInt(3 * int64(i))) 143 144 orig.updateStateObject(origObj) 145 copy.updateStateObject(copyObj) 146 } 147 // Finalise the changes on both concurrently 148 done := make(chan struct{}) 149 go func() { 150 orig.Finalise(true) 151 close(done) 152 }() 153 copy.Finalise(true) 154 <-done 155 156 // Verify that the two states have been updated independently 157 for i := byte(0); i < 255; i++ { 158 origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 159 copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 160 161 if want := big.NewInt(3 * int64(i)); origObj.Balance().Cmp(want) != 0 { 162 t.Errorf("orig obj %d: balance mismatch: have %v, want %v", i, origObj.Balance(), want) 163 } 164 if want := big.NewInt(4 * int64(i)); copyObj.Balance().Cmp(want) != 0 { 165 t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, copyObj.Balance(), want) 166 } 167 } 168 } 169 170 func TestSnapshotRandom(t *testing.T) { 171 config := &quick.Config{MaxCount: 1000} 172 err := quick.Check((*snapshotTest).run, config) 173 if cerr, ok := err.(*quick.CheckError); ok { 174 test := cerr.In[0].(*snapshotTest) 175 t.Errorf("%v:\n%s", test.err, test) 176 } else if err != nil { 177 t.Error(err) 178 } 179 } 180 181 // A snapshotTest checks that reverting StateDB snapshots properly undoes all changes 182 // captured by the snapshot. Instances of this test with pseudorandom content are created 183 // by Generate. 184 // 185 // The test works as follows: 186 // 187 // A new state is created and all actions are applied to it. Several snapshots are taken 188 // in between actions. The test then reverts each snapshot. For each snapshot the actions 189 // leading up to it are replayed on a fresh, empty state. The behaviour of all public 190 // accessor methods on the reverted state must match the return value of the equivalent 191 // methods on the replayed state. 192 type snapshotTest struct { 193 addrs []common.Address // all account addresses 194 actions []testAction // modifications to the state 195 snapshots []int // actions indexes at which snapshot is taken 196 err error // failure details are reported through this field 197 } 198 199 type testAction struct { 200 name string 201 fn func(testAction, *StateDB) 202 args []int64 203 noAddr bool 204 } 205 206 // newTestAction creates a random action that changes state. 207 func newTestAction(addr common.Address, r *rand.Rand) testAction { 208 actions := []testAction{ 209 { 210 name: "SetBalance", 211 fn: func(a testAction, s *StateDB) { 212 s.SetBalance(addr, big.NewInt(a.args[0])) 213 }, 214 args: make([]int64, 1), 215 }, 216 { 217 name: "AddBalance", 218 fn: func(a testAction, s *StateDB) { 219 s.AddBalance(addr, big.NewInt(a.args[0])) 220 }, 221 args: make([]int64, 1), 222 }, 223 { 224 name: "SetNonce", 225 fn: func(a testAction, s *StateDB) { 226 s.SetNonce(addr, uint64(a.args[0])) 227 }, 228 args: make([]int64, 1), 229 }, 230 { 231 name: "SetState", 232 fn: func(a testAction, s *StateDB) { 233 var key, val common.Hash 234 binary.BigEndian.PutUint16(key[:], uint16(a.args[0])) 235 binary.BigEndian.PutUint16(val[:], uint16(a.args[1])) 236 s.SetState(addr, key, val) 237 }, 238 args: make([]int64, 2), 239 }, 240 { 241 name: "SetCode", 242 fn: func(a testAction, s *StateDB) { 243 code := make([]byte, 16) 244 binary.BigEndian.PutUint64(code, uint64(a.args[0])) 245 binary.BigEndian.PutUint64(code[8:], uint64(a.args[1])) 246 s.SetCode(addr, code) 247 }, 248 args: make([]int64, 2), 249 }, 250 { 251 name: "CreateAccount", 252 fn: func(a testAction, s *StateDB) { 253 s.CreateAccount(addr) 254 }, 255 }, 256 { 257 name: "Suicide", 258 fn: func(a testAction, s *StateDB) { 259 s.Suicide(addr) 260 }, 261 }, 262 { 263 name: "AddRefund", 264 fn: func(a testAction, s *StateDB) { 265 s.AddRefund(uint64(a.args[0])) 266 }, 267 args: make([]int64, 1), 268 noAddr: true, 269 }, 270 { 271 name: "AddLog", 272 fn: func(a testAction, s *StateDB) { 273 data := make([]byte, 2) 274 binary.BigEndian.PutUint16(data, uint16(a.args[0])) 275 s.AddLog(&types.Log{Address: addr, Data: data}) 276 }, 277 args: make([]int64, 1), 278 }, 279 { 280 name: "AddPreimage", 281 fn: func(a testAction, s *StateDB) { 282 preimage := []byte{1} 283 hash := common.BytesToHash(preimage) 284 s.AddPreimage(hash, preimage) 285 }, 286 args: make([]int64, 1), 287 }, 288 } 289 action := actions[r.Intn(len(actions))] 290 var nameargs []string 291 if !action.noAddr { 292 nameargs = append(nameargs, addr.Hex()) 293 } 294 for _, i := range action.args { 295 action.args[i] = rand.Int63n(100) 296 nameargs = append(nameargs, fmt.Sprint(action.args[i])) 297 } 298 action.name += strings.Join(nameargs, ", ") 299 return action 300 } 301 302 // Generate returns a new snapshot test of the given size. All randomness is 303 // derived from r. 304 func (*snapshotTest) Generate(r *rand.Rand, size int) reflect.Value { 305 // Generate random actions. 306 addrs := make([]common.Address, 50) 307 for i := range addrs { 308 addrs[i][0] = byte(i) 309 } 310 actions := make([]testAction, size) 311 for i := range actions { 312 addr := addrs[r.Intn(len(addrs))] 313 actions[i] = newTestAction(addr, r) 314 } 315 // Generate snapshot indexes. 316 nsnapshots := int(math.Sqrt(float64(size))) 317 if size > 0 && nsnapshots == 0 { 318 nsnapshots = 1 319 } 320 snapshots := make([]int, nsnapshots) 321 snaplen := len(actions) / nsnapshots 322 for i := range snapshots { 323 // Try to place the snapshots some number of actions apart from each other. 324 snapshots[i] = (i * snaplen) + r.Intn(snaplen) 325 } 326 return reflect.ValueOf(&snapshotTest{addrs, actions, snapshots, nil}) 327 } 328 329 func (test *snapshotTest) String() string { 330 out := new(bytes.Buffer) 331 sindex := 0 332 for i, action := range test.actions { 333 if len(test.snapshots) > sindex && i == test.snapshots[sindex] { 334 fmt.Fprintf(out, "---- snapshot %d ----\n", sindex) 335 sindex++ 336 } 337 fmt.Fprintf(out, "%4d: %s\n", i, action.name) 338 } 339 return out.String() 340 } 341 342 func (test *snapshotTest) run() bool { 343 // Run all actions and create snapshots. 344 var ( 345 state, _ = New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase())) 346 snapshotRevs = make([]int, len(test.snapshots)) 347 sindex = 0 348 ) 349 for i, action := range test.actions { 350 if len(test.snapshots) > sindex && i == test.snapshots[sindex] { 351 snapshotRevs[sindex] = state.Snapshot() 352 sindex++ 353 } 354 action.fn(action, state) 355 } 356 // Revert all snapshots in reverse order. Each revert must yield a state 357 // that is equivalent to fresh state with all actions up the snapshot applied. 358 for sindex--; sindex >= 0; sindex-- { 359 checkstate, _ := New(common.Hash{}, state.Database()) 360 for _, action := range test.actions[:test.snapshots[sindex]] { 361 action.fn(action, checkstate) 362 } 363 state.RevertToSnapshot(snapshotRevs[sindex]) 364 if err := test.checkEqual(state, checkstate); err != nil { 365 test.err = fmt.Errorf("state mismatch after revert to snapshot %d\n%v", sindex, err) 366 return false 367 } 368 } 369 return true 370 } 371 372 // checkEqual checks that methods of state and checkstate return the same values. 373 func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { 374 for _, addr := range test.addrs { 375 var err error 376 checkeq := func(op string, a, b interface{}) bool { 377 if err == nil && !reflect.DeepEqual(a, b) { 378 err = fmt.Errorf("got %s(%s) == %v, want %v", op, addr.Hex(), a, b) 379 return false 380 } 381 return true 382 } 383 // Check basic accessor methods. 384 checkeq("Exist", state.Exist(addr), checkstate.Exist(addr)) 385 checkeq("HasSuicided", state.HasSuicided(addr), checkstate.HasSuicided(addr)) 386 checkeq("GetBalance", state.GetBalance(addr), checkstate.GetBalance(addr)) 387 checkeq("GetNonce", state.GetNonce(addr), checkstate.GetNonce(addr)) 388 checkeq("GetCode", state.GetCode(addr), checkstate.GetCode(addr)) 389 checkeq("GetCodeHash", state.GetCodeHash(addr), checkstate.GetCodeHash(addr)) 390 checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr)) 391 // Check storage. 392 if obj := state.getStateObject(addr); obj != nil { 393 state.ForEachStorage(addr, func(key, value common.Hash) bool { 394 return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) 395 }) 396 checkstate.ForEachStorage(addr, func(key, value common.Hash) bool { 397 return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) 398 }) 399 } 400 if err != nil { 401 return err 402 } 403 } 404 405 if state.GetRefund() != checkstate.GetRefund() { 406 return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d", 407 state.GetRefund(), checkstate.GetRefund()) 408 } 409 if !reflect.DeepEqual(state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{})) { 410 return fmt.Errorf("got GetLogs(common.Hash{}) == %v, want GetLogs(common.Hash{}) == %v", 411 state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{})) 412 } 413 return nil 414 } 415 416 func (s *StateSuite) TestTouchDelete(c *check.C) { 417 s.state.GetOrNewStateObject(common.Address{}) 418 root, _ := s.state.Commit(false) 419 s.state.Reset(root) 420 421 snapshot := s.state.Snapshot() 422 s.state.AddBalance(common.Address{}, new(big.Int)) 423 424 if len(s.state.journal.dirties) != 1 { 425 c.Fatal("expected one dirty state object") 426 } 427 s.state.RevertToSnapshot(snapshot) 428 if len(s.state.journal.dirties) != 0 { 429 c.Fatal("expected no dirty state object") 430 } 431 } 432 433 // TestCopyOfCopy tests that modified objects are carried over to the copy, and the copy of the copy. 434 // See https://github.com/ethereum/go-ethereum/pull/15225#issuecomment-380191512 435 func TestCopyOfCopy(t *testing.T) { 436 sdb, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase())) 437 addr := common.HexToAddress("aaaa") 438 sdb.SetBalance(addr, big.NewInt(42)) 439 440 if got := sdb.Copy().GetBalance(addr).Uint64(); got != 42 { 441 t.Fatalf("1st copy fail, expected 42, got %v", got) 442 } 443 if got := sdb.Copy().Copy().GetBalance(addr).Uint64(); got != 42 { 444 t.Fatalf("2nd copy fail, expected 42, got %v", got) 445 } 446 }