github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/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 "github.com/ethereumproject/go-ethereum/common" 32 "github.com/ethereumproject/go-ethereum/core/vm" 33 "github.com/ethereumproject/go-ethereum/ethdb" 34 "gopkg.in/check.v1" 35 ) 36 37 // Tests that updating a state trie does not leak any database writes prior to 38 // actually committing the state. 39 func TestUpdateLeaks(t *testing.T) { 40 // Create an empty state database 41 db, _ := ethdb.NewMemDatabase() 42 state, _ := New(common.Hash{}, NewDatabase(db)) 43 44 // Update it with some accounts 45 for i := byte(0); i < 255; i++ { 46 addr := common.BytesToAddress([]byte{i}) 47 state.AddBalance(addr, big.NewInt(int64(11*i))) 48 state.SetNonce(addr, uint64(42*i)) 49 if i%2 == 0 { 50 state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i})) 51 } 52 if i%3 == 0 { 53 state.SetCode(addr, []byte{i, i, i, i, i}) 54 } 55 state.IntermediateRoot(false) 56 } 57 // Ensure that no data was leaked into the database 58 for _, key := range db.Keys() { 59 value, _ := db.Get(key) 60 t.Errorf("State leaked into database: %x -> %x", key, value) 61 } 62 } 63 64 // Tests that no intermediate state of an object is stored into the database, 65 // only the one right before the commit. 66 func TestIntermediateLeaks(t *testing.T) { 67 // Create two state databases, one transitioning to the final state, the other final from the beginning 68 transDb, _ := ethdb.NewMemDatabase() 69 finalDb, _ := ethdb.NewMemDatabase() 70 transState, _ := New(common.Hash{}, NewDatabase(transDb)) 71 finalState, _ := New(common.Hash{}, NewDatabase(finalDb)) 72 73 modify := func(state *StateDB, addr common.Address, i, tweak byte) { 74 state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak))) 75 state.SetNonce(addr, uint64(42*i+tweak)) 76 if i%2 == 0 { 77 state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{}) 78 state.SetState(addr, common.Hash{i, i, i, tweak}, common.Hash{i, i, i, i, tweak}) 79 } 80 if i%3 == 0 { 81 state.SetCode(addr, []byte{i, i, i, i, i, tweak}) 82 } 83 } 84 85 // Modify the transient state. 86 for i := byte(0); i < 255; i++ { 87 modify(transState, common.Address{byte(i)}, i, 0) 88 } 89 // Write modifications to trie. 90 transState.IntermediateRoot(false) 91 92 // Overwrite all the data with new values in the transient database. 93 for i := byte(0); i < 255; i++ { 94 modify(transState, common.Address{byte(i)}, i, 99) 95 modify(finalState, common.Address{byte(i)}, i, 99) 96 } 97 98 // Commit and cross check the databases. 99 if _, err := transState.CommitTo(transDb, false); err != nil { 100 t.Fatalf("failed to commit transition state: %v", err) 101 } 102 if _, err := finalState.CommitTo(finalDb, false); err != nil { 103 t.Fatalf("failed to commit final state: %v", err) 104 } 105 for _, key := range finalDb.Keys() { 106 if _, err := transDb.Get(key); err != nil { 107 val, _ := finalDb.Get(key) 108 t.Errorf("entry missing from the transition database: %x -> %x", key, val) 109 } 110 } 111 for _, key := range transDb.Keys() { 112 if _, err := finalDb.Get(key); err != nil { 113 val, _ := transDb.Get(key) 114 t.Errorf("extra entry in the transition database: %x -> %x", key, val) 115 } 116 } 117 } 118 119 // TestCopy tests that copying a statedb object indeed makes the original and 120 // the copy independent of each other. This test is a regression test against 121 // https://github.com/ethereum/go-ethereum/pull/15549. 122 func TestCopy(t *testing.T) { 123 // Create a random state test to copy and modify "independently" 124 mem, _ := ethdb.NewMemDatabase() 125 orig, _ := New(common.Hash{}, NewDatabase(mem)) 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(big.NewInt(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(vm.Log{Address: addr, Data: data}) 276 }, 277 args: make([]int64, 1), 278 }, 279 } 280 action := actions[r.Intn(len(actions))] 281 var nameargs []string 282 if !action.noAddr { 283 nameargs = append(nameargs, addr.Hex()) 284 } 285 for _, i := range action.args { 286 action.args[i] = rand.Int63n(100) 287 nameargs = append(nameargs, fmt.Sprint(action.args[i])) 288 } 289 action.name += strings.Join(nameargs, ", ") 290 return action 291 } 292 293 // Generate returns a new snapshot test of the given size. All randomness is 294 // derived from r. 295 func (*snapshotTest) Generate(r *rand.Rand, size int) reflect.Value { 296 // Generate random actions. 297 addrs := make([]common.Address, 50) 298 for i := range addrs { 299 addrs[i][0] = byte(i) 300 } 301 actions := make([]testAction, size) 302 for i := range actions { 303 addr := addrs[r.Intn(len(addrs))] 304 actions[i] = newTestAction(addr, r) 305 } 306 // Generate snapshot indexes. 307 nsnapshots := int(math.Sqrt(float64(size))) 308 if size > 0 && nsnapshots == 0 { 309 nsnapshots = 1 310 } 311 snapshots := make([]int, nsnapshots) 312 snaplen := len(actions) / nsnapshots 313 for i := range snapshots { 314 // Try to place the snapshots some number of actions apart from each other. 315 snapshots[i] = (i * snaplen) + r.Intn(snaplen) 316 } 317 return reflect.ValueOf(&snapshotTest{addrs, actions, snapshots, nil}) 318 } 319 320 func (test *snapshotTest) String() string { 321 out := new(bytes.Buffer) 322 sindex := 0 323 for i, action := range test.actions { 324 if len(test.snapshots) > sindex && i == test.snapshots[sindex] { 325 fmt.Fprintf(out, "---- snapshot %d ----\n", sindex) 326 sindex++ 327 } 328 fmt.Fprintf(out, "%4d: %s\n", i, action.name) 329 } 330 return out.String() 331 } 332 333 func (test *snapshotTest) run() bool { 334 // Run all actions and create snapshots. 335 var ( 336 db, _ = ethdb.NewMemDatabase() 337 state, _ = New(common.Hash{}, NewDatabase(db)) 338 snapshotRevs = make([]int, len(test.snapshots)) 339 sindex = 0 340 ) 341 for i, action := range test.actions { 342 if len(test.snapshots) > sindex && i == test.snapshots[sindex] { 343 snapshotRevs[sindex] = state.Snapshot() 344 sindex++ 345 } 346 action.fn(action, state) 347 } 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{}, NewDatabase(db)) 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, val common.Hash) bool { 387 return checkeq("GetState("+key.Hex()+")", val, checkstate.GetState(addr, key)) 388 }) 389 checkstate.ForEachStorage(addr, func(key, checkval common.Hash) bool { 390 return checkeq("GetState("+key.Hex()+")", state.GetState(addr, key), checkval) 391 }) 392 } 393 if err != nil { 394 return err 395 } 396 } 397 398 if state.GetRefund().Cmp(checkstate.GetRefund()) != 0 { 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.CommitTo(s.db, false) 412 s.state.Reset(root) 413 414 snapshot := s.state.Snapshot() 415 s.state.AddBalance(common.Address{}, new(big.Int)) 416 if len(s.state.stateObjectsDirty) != 1 { 417 c.Fatal("expected one dirty state object") 418 } 419 420 s.state.RevertToSnapshot(snapshot) 421 if len(s.state.stateObjectsDirty) != 0 { 422 c.Fatal("expected no dirty state object") 423 } 424 }