github.com/luckypickle/go-ethereum-vet@v1.14.2/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/luckypickle/go-ethereum-vet/common"
    34  	"github.com/luckypickle/go-ethereum-vet/core/types"
    35  	"github.com/luckypickle/go-ethereum-vet/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  		state.IntermediateRoot(false)
    57  	}
    58  	// Ensure that no data was leaked into the database
    59  	for _, key := range db.Keys() {
    60  		value, _ := db.Get(key)
    61  		t.Errorf("State leaked into database: %x -> %x", key, value)
    62  	}
    63  }
    64  
    65  // Tests that no intermediate state of an object is stored into the database,
    66  // only the one right before the commit.
    67  func TestIntermediateLeaks(t *testing.T) {
    68  	// Create two state databases, one transitioning to the final state, the other final from the beginning
    69  	transDb := ethdb.NewMemDatabase()
    70  	finalDb := ethdb.NewMemDatabase()
    71  	transState, _ := New(common.Hash{}, NewDatabase(transDb))
    72  	finalState, _ := New(common.Hash{}, NewDatabase(finalDb))
    73  
    74  	modify := func(state *StateDB, addr common.Address, i, tweak byte) {
    75  		state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak)))
    76  		state.SetNonce(addr, uint64(42*i+tweak))
    77  		if i%2 == 0 {
    78  			state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{})
    79  			state.SetState(addr, common.Hash{i, i, i, tweak}, common.Hash{i, i, i, i, tweak})
    80  		}
    81  		if i%3 == 0 {
    82  			state.SetCode(addr, []byte{i, i, i, i, i, tweak})
    83  		}
    84  	}
    85  
    86  	// Modify the transient state.
    87  	for i := byte(0); i < 255; i++ {
    88  		modify(transState, common.Address{byte(i)}, i, 0)
    89  	}
    90  	// Write modifications to trie.
    91  	transState.IntermediateRoot(false)
    92  
    93  	// Overwrite all the data with new values in the transient database.
    94  	for i := byte(0); i < 255; i++ {
    95  		modify(transState, common.Address{byte(i)}, i, 99)
    96  		modify(finalState, common.Address{byte(i)}, i, 99)
    97  	}
    98  
    99  	// Commit and cross check the databases.
   100  	if _, err := transState.Commit(false); err != nil {
   101  		t.Fatalf("failed to commit transition state: %v", err)
   102  	}
   103  	if _, err := finalState.Commit(false); err != nil {
   104  		t.Fatalf("failed to commit final state: %v", err)
   105  	}
   106  	for _, key := range finalDb.Keys() {
   107  		if _, err := transDb.Get(key); err != nil {
   108  			val, _ := finalDb.Get(key)
   109  			t.Errorf("entry missing from the transition database: %x -> %x", key, val)
   110  		}
   111  	}
   112  	for _, key := range transDb.Keys() {
   113  		if _, err := finalDb.Get(key); err != nil {
   114  			val, _ := transDb.Get(key)
   115  			t.Errorf("extra entry in the transition database: %x -> %x", key, val)
   116  		}
   117  	}
   118  }
   119  
   120  // TestCopy tests that copying a statedb object indeed makes the original and
   121  // the copy independent of each other. This test is a regression test against
   122  // https://github.com/luckypickle/go-ethereum-vet/pull/15549.
   123  func TestCopy(t *testing.T) {
   124  	// Create a random state test to copy and modify "independently"
   125  	orig, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
   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(uint64(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(&types.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  		state, _     = New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
   337  		snapshotRevs = make([]int, len(test.snapshots))
   338  		sindex       = 0
   339  	)
   340  	for i, action := range test.actions {
   341  		if len(test.snapshots) > sindex && i == test.snapshots[sindex] {
   342  			snapshotRevs[sindex] = state.Snapshot()
   343  			sindex++
   344  		}
   345  		action.fn(action, state)
   346  	}
   347  	// Revert all snapshots in reverse order. Each revert must yield a state
   348  	// that is equivalent to fresh state with all actions up the snapshot applied.
   349  	for sindex--; sindex >= 0; sindex-- {
   350  		checkstate, _ := New(common.Hash{}, state.Database())
   351  		for _, action := range test.actions[:test.snapshots[sindex]] {
   352  			action.fn(action, checkstate)
   353  		}
   354  		state.RevertToSnapshot(snapshotRevs[sindex])
   355  		if err := test.checkEqual(state, checkstate); err != nil {
   356  			test.err = fmt.Errorf("state mismatch after revert to snapshot %d\n%v", sindex, err)
   357  			return false
   358  		}
   359  	}
   360  	return true
   361  }
   362  
   363  // checkEqual checks that methods of state and checkstate return the same values.
   364  func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error {
   365  	for _, addr := range test.addrs {
   366  		var err error
   367  		checkeq := func(op string, a, b interface{}) bool {
   368  			if err == nil && !reflect.DeepEqual(a, b) {
   369  				err = fmt.Errorf("got %s(%s) == %v, want %v", op, addr.Hex(), a, b)
   370  				return false
   371  			}
   372  			return true
   373  		}
   374  		// Check basic accessor methods.
   375  		checkeq("Exist", state.Exist(addr), checkstate.Exist(addr))
   376  		checkeq("HasSuicided", state.HasSuicided(addr), checkstate.HasSuicided(addr))
   377  		checkeq("GetBalance", state.GetBalance(addr), checkstate.GetBalance(addr))
   378  		checkeq("GetNonce", state.GetNonce(addr), checkstate.GetNonce(addr))
   379  		checkeq("GetCode", state.GetCode(addr), checkstate.GetCode(addr))
   380  		checkeq("GetCodeHash", state.GetCodeHash(addr), checkstate.GetCodeHash(addr))
   381  		checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr))
   382  		// Check storage.
   383  		if obj := state.getStateObject(addr); obj != nil {
   384  			state.ForEachStorage(addr, func(key, val common.Hash) bool {
   385  				return checkeq("GetState("+key.Hex()+")", val, checkstate.GetState(addr, key))
   386  			})
   387  			checkstate.ForEachStorage(addr, func(key, checkval common.Hash) bool {
   388  				return checkeq("GetState("+key.Hex()+")", state.GetState(addr, key), checkval)
   389  			})
   390  		}
   391  		if err != nil {
   392  			return err
   393  		}
   394  	}
   395  
   396  	if state.GetRefund() != checkstate.GetRefund() {
   397  		return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d",
   398  			state.GetRefund(), checkstate.GetRefund())
   399  	}
   400  	if !reflect.DeepEqual(state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{})) {
   401  		return fmt.Errorf("got GetLogs(common.Hash{}) == %v, want GetLogs(common.Hash{}) == %v",
   402  			state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{}))
   403  	}
   404  	return nil
   405  }
   406  
   407  func (s *StateSuite) TestTouchDelete(c *check.C) {
   408  	s.state.GetOrNewStateObject(common.Address{})
   409  	root, _ := s.state.Commit(false)
   410  	s.state.Reset(root)
   411  
   412  	snapshot := s.state.Snapshot()
   413  	s.state.AddBalance(common.Address{}, new(big.Int))
   414  
   415  	if len(s.state.journal.dirties) != 1 {
   416  		c.Fatal("expected one dirty state object")
   417  	}
   418  	s.state.RevertToSnapshot(snapshot)
   419  	if len(s.state.journal.dirties) != 0 {
   420  		c.Fatal("expected no dirty state object")
   421  	}
   422  }
   423  
   424  // TestCopyOfCopy tests that modified objects are carried over to the copy, and the copy of the copy.
   425  // See https://github.com/luckypickle/go-ethereum-vet/pull/15225#issuecomment-380191512
   426  func TestCopyOfCopy(t *testing.T) {
   427  	sdb, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
   428  	addr := common.HexToAddress("aaaa")
   429  	sdb.SetBalance(addr, big.NewInt(42))
   430  
   431  	if got := sdb.Copy().GetBalance(addr).Uint64(); got != 42 {
   432  		t.Fatalf("1st copy fail, expected 42, got %v", got)
   433  	}
   434  	if got := sdb.Copy().Copy().GetBalance(addr).Uint64(); got != 42 {
   435  		t.Fatalf("2nd copy fail, expected 42, got %v", got)
   436  	}
   437  }