github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/core/state/statedb_test.go (about)

     1  // This file is part of the go-sberex library. The go-sberex library is 
     2  // free software: you can redistribute it and/or modify it under the terms 
     3  // of the GNU Lesser General Public License as published by the Free 
     4  // Software Foundation, either version 3 of the License, or (at your option)
     5  // any later version.
     6  //
     7  // The go-sberex library is distributed in the hope that it will be useful, 
     8  // but WITHOUT ANY WARRANTY; without even the implied warranty of
     9  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 
    10  // General Public License <http://www.gnu.org/licenses/> for more details.
    11  
    12  package state
    13  
    14  import (
    15  	"bytes"
    16  	"encoding/binary"
    17  	"fmt"
    18  	"math"
    19  	"math/big"
    20  	"math/rand"
    21  	"reflect"
    22  	"strings"
    23  	"testing"
    24  	"testing/quick"
    25  
    26  	check "gopkg.in/check.v1"
    27  
    28  	"github.com/Sberex/go-sberex/common"
    29  	"github.com/Sberex/go-sberex/core/types"
    30  	"github.com/Sberex/go-sberex/ethdb"
    31  )
    32  
    33  // Tests that updating a state trie does not leak any database writes prior to
    34  // actually committing the state.
    35  func TestUpdateLeaks(t *testing.T) {
    36  	// Create an empty state database
    37  	db, _ := ethdb.NewMemDatabase()
    38  	state, _ := New(common.Hash{}, NewDatabase(db))
    39  
    40  	// Update it with some accounts
    41  	for i := byte(0); i < 255; i++ {
    42  		addr := common.BytesToAddress([]byte{i})
    43  		state.AddBalance(addr, big.NewInt(int64(11*i)))
    44  		state.SetNonce(addr, uint64(42*i))
    45  		if i%2 == 0 {
    46  			state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i}))
    47  		}
    48  		if i%3 == 0 {
    49  			state.SetCode(addr, []byte{i, i, i, i, i})
    50  		}
    51  		state.IntermediateRoot(false)
    52  	}
    53  	// Ensure that no data was leaked into the database
    54  	for _, key := range db.Keys() {
    55  		value, _ := db.Get(key)
    56  		t.Errorf("State leaked into database: %x -> %x", key, value)
    57  	}
    58  }
    59  
    60  // Tests that no intermediate state of an object is stored into the database,
    61  // only the one right before the commit.
    62  func TestIntermediateLeaks(t *testing.T) {
    63  	// Create two state databases, one transitioning to the final state, the other final from the beginning
    64  	transDb, _ := ethdb.NewMemDatabase()
    65  	finalDb, _ := ethdb.NewMemDatabase()
    66  	transState, _ := New(common.Hash{}, NewDatabase(transDb))
    67  	finalState, _ := New(common.Hash{}, NewDatabase(finalDb))
    68  
    69  	modify := func(state *StateDB, addr common.Address, i, tweak byte) {
    70  		state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak)))
    71  		state.SetNonce(addr, uint64(42*i+tweak))
    72  		if i%2 == 0 {
    73  			state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{})
    74  			state.SetState(addr, common.Hash{i, i, i, tweak}, common.Hash{i, i, i, i, tweak})
    75  		}
    76  		if i%3 == 0 {
    77  			state.SetCode(addr, []byte{i, i, i, i, i, tweak})
    78  		}
    79  	}
    80  
    81  	// Modify the transient state.
    82  	for i := byte(0); i < 255; i++ {
    83  		modify(transState, common.Address{byte(i)}, i, 0)
    84  	}
    85  	// Write modifications to trie.
    86  	transState.IntermediateRoot(false)
    87  
    88  	// Overwrite all the data with new values in the transient database.
    89  	for i := byte(0); i < 255; i++ {
    90  		modify(transState, common.Address{byte(i)}, i, 99)
    91  		modify(finalState, common.Address{byte(i)}, i, 99)
    92  	}
    93  
    94  	// Commit and cross check the databases.
    95  	if _, err := transState.Commit(false); err != nil {
    96  		t.Fatalf("failed to commit transition state: %v", err)
    97  	}
    98  	if _, err := finalState.Commit(false); err != nil {
    99  		t.Fatalf("failed to commit final state: %v", err)
   100  	}
   101  	for _, key := range finalDb.Keys() {
   102  		if _, err := transDb.Get(key); err != nil {
   103  			val, _ := finalDb.Get(key)
   104  			t.Errorf("entry missing from the transition database: %x -> %x", key, val)
   105  		}
   106  	}
   107  	for _, key := range transDb.Keys() {
   108  		if _, err := finalDb.Get(key); err != nil {
   109  			val, _ := transDb.Get(key)
   110  			t.Errorf("extra entry in the transition database: %x -> %x", key, val)
   111  		}
   112  	}
   113  }
   114  
   115  // TestCopy tests that copying a statedb object indeed makes the original and
   116  // the copy independent of each other. This test is a regression test against
   117  // https://github.com/Sberex/go-sberex/pull/15549.
   118  func TestCopy(t *testing.T) {
   119  	// Create a random state test to copy and modify "independently"
   120  	db, _ := ethdb.NewMemDatabase()
   121  	orig, _ := New(common.Hash{}, NewDatabase(db))
   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  	// Copy the state, modify both in-memory
   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  	// Finalise the changes on both concurrently
   144  	done := make(chan struct{})
   145  	go func() {
   146  		orig.Finalise(true)
   147  		close(done)
   148  	}()
   149  	copy.Finalise(true)
   150  	<-done
   151  
   152  	// Verify that the two states have been updated independently
   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  // A snapshotTest checks that reverting StateDB snapshots properly undoes all changes
   178  // captured by the snapshot. Instances of this test with pseudorandom content are created
   179  // by Generate.
   180  //
   181  // The test works as follows:
   182  //
   183  // A new state is created and all actions are applied to it. Several snapshots are taken
   184  // in between actions. The test then reverts each snapshot. For each snapshot the actions
   185  // leading up to it are replayed on a fresh, empty state. The behaviour of all public
   186  // accessor methods on the reverted state must match the return value of the equivalent
   187  // methods on the replayed state.
   188  type snapshotTest struct {
   189  	addrs     []common.Address // all account addresses
   190  	actions   []testAction     // modifications to the state
   191  	snapshots []int            // actions indexes at which snapshot is taken
   192  	err       error            // failure details are reported through this field
   193  }
   194  
   195  type testAction struct {
   196  	name   string
   197  	fn     func(testAction, *StateDB)
   198  	args   []int64
   199  	noAddr bool
   200  }
   201  
   202  // newTestAction creates a random action that changes state.
   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 returns a new snapshot test of the given size. All randomness is
   290  // derived from r.
   291  func (*snapshotTest) Generate(r *rand.Rand, size int) reflect.Value {
   292  	// Generate random actions.
   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  	// Generate snapshot indexes.
   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  		// Try to place the snapshots some number of actions apart from each other.
   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  	// Run all actions and create snapshots.
   331  	var (
   332  		db, _        = ethdb.NewMemDatabase()
   333  		state, _     = New(common.Hash{}, NewDatabase(db))
   334  		snapshotRevs = make([]int, len(test.snapshots))
   335  		sindex       = 0
   336  	)
   337  	for i, action := range test.actions {
   338  		if len(test.snapshots) > sindex && i == test.snapshots[sindex] {
   339  			snapshotRevs[sindex] = state.Snapshot()
   340  			sindex++
   341  		}
   342  		action.fn(action, state)
   343  	}
   344  	// Revert all snapshots in reverse order. Each revert must yield a state
   345  	// that is equivalent to fresh state with all actions up the snapshot applied.
   346  	for sindex--; sindex >= 0; sindex-- {
   347  		checkstate, _ := New(common.Hash{}, state.Database())
   348  		for _, action := range test.actions[:test.snapshots[sindex]] {
   349  			action.fn(action, checkstate)
   350  		}
   351  		state.RevertToSnapshot(snapshotRevs[sindex])
   352  		if err := test.checkEqual(state, checkstate); err != nil {
   353  			test.err = fmt.Errorf("state mismatch after revert to snapshot %d\n%v", sindex, err)
   354  			return false
   355  		}
   356  	}
   357  	return true
   358  }
   359  
   360  // checkEqual checks that methods of state and checkstate return the same values.
   361  func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error {
   362  	for _, addr := range test.addrs {
   363  		var err error
   364  		checkeq := func(op string, a, b interface{}) bool {
   365  			if err == nil && !reflect.DeepEqual(a, b) {
   366  				err = fmt.Errorf("got %s(%s) == %v, want %v", op, addr.Hex(), a, b)
   367  				return false
   368  			}
   369  			return true
   370  		}
   371  		// Check basic accessor methods.
   372  		checkeq("Exist", state.Exist(addr), checkstate.Exist(addr))
   373  		checkeq("HasSuicided", state.HasSuicided(addr), checkstate.HasSuicided(addr))
   374  		checkeq("GetBalance", state.GetBalance(addr), checkstate.GetBalance(addr))
   375  		checkeq("GetNonce", state.GetNonce(addr), checkstate.GetNonce(addr))
   376  		checkeq("GetCode", state.GetCode(addr), checkstate.GetCode(addr))
   377  		checkeq("GetCodeHash", state.GetCodeHash(addr), checkstate.GetCodeHash(addr))
   378  		checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr))
   379  		// Check storage.
   380  		if obj := state.getStateObject(addr); obj != nil {
   381  			state.ForEachStorage(addr, func(key, val common.Hash) bool {
   382  				return checkeq("GetState("+key.Hex()+")", val, checkstate.GetState(addr, key))
   383  			})
   384  			checkstate.ForEachStorage(addr, func(key, checkval common.Hash) bool {
   385  				return checkeq("GetState("+key.Hex()+")", state.GetState(addr, key), checkval)
   386  			})
   387  		}
   388  		if err != nil {
   389  			return err
   390  		}
   391  	}
   392  
   393  	if state.GetRefund() != checkstate.GetRefund() {
   394  		return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d",
   395  			state.GetRefund(), checkstate.GetRefund())
   396  	}
   397  	if !reflect.DeepEqual(state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{})) {
   398  		return fmt.Errorf("got GetLogs(common.Hash{}) == %v, want GetLogs(common.Hash{}) == %v",
   399  			state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{}))
   400  	}
   401  	return nil
   402  }
   403  
   404  func (s *StateSuite) TestTouchDelete(c *check.C) {
   405  	s.state.GetOrNewStateObject(common.Address{})
   406  	root, _ := s.state.Commit(false)
   407  	s.state.Reset(root)
   408  
   409  	snapshot := s.state.Snapshot()
   410  	s.state.AddBalance(common.Address{}, new(big.Int))
   411  	if len(s.state.stateObjectsDirty) != 1 {
   412  		c.Fatal("expected one dirty state object")
   413  	}
   414  	s.state.RevertToSnapshot(snapshot)
   415  	if len(s.state.stateObjectsDirty) != 0 {
   416  		c.Fatal("expected no dirty state object")
   417  	}
   418  }