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  }