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