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