github.com/intfoundation/intchain@v0.0.0-20220727031208-4316ad31ca73/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  
    24  	"math"
    25  	"math/big"
    26  	"math/rand"
    27  	"reflect"
    28  	"strings"
    29  	"testing"
    30  	"testing/quick"
    31  
    32  	"gopkg.in/check.v1"
    33  
    34  	"github.com/intfoundation/intchain/common"
    35  	"github.com/intfoundation/intchain/core/rawdb"
    36  	"github.com/intfoundation/intchain/core/types"
    37  )
    38  
    39  // Tests that updating a state trie does not leak any database writes prior to
    40  // actually committing the state.
    41  func TestUpdateLeaks(t *testing.T) {
    42  	// Create an empty state database
    43  	db := rawdb.NewMemoryDatabase()
    44  	state, _ := New(common.Hash{}, NewDatabase(db))
    45  
    46  	// Update it with some accounts
    47  	for i := byte(0); i < 255; i++ {
    48  		addr := common.BytesToAddress([]byte{i})
    49  		state.AddBalance(addr, big.NewInt(int64(11*i)))
    50  		state.SetNonce(addr, uint64(42*i))
    51  		if i%2 == 0 {
    52  			state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i}))
    53  		}
    54  		if i%3 == 0 {
    55  			state.SetCode(addr, []byte{i, i, i, i, i})
    56  		}
    57  		state.IntermediateRoot(false)
    58  	}
    59  	// Ensure that no data was leaked into the database
    60  	it := db.NewIterator()
    61  	for it.Next() {
    62  		t.Errorf("State leaked into database: %x -> %x", it.Key(), it.Value())
    63  	}
    64  	it.Release()
    65  }
    66  
    67  // Tests that no intermediate state of an object is stored into the database,
    68  // only the one right before the commit.
    69  func TestIntermediateLeaks(t *testing.T) {
    70  	// Create two state databases, one transitioning to the final state, the other final from the beginning
    71  	transDb := rawdb.NewMemoryDatabase()
    72  	finalDb := rawdb.NewMemoryDatabase()
    73  	transState, _ := New(common.Hash{}, NewDatabase(transDb))
    74  	finalState, _ := New(common.Hash{}, NewDatabase(finalDb))
    75  
    76  	modify := func(state *StateDB, addr common.Address, i, tweak byte) {
    77  		state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak)))
    78  		state.SetNonce(addr, uint64(42*i+tweak))
    79  		if i%2 == 0 {
    80  			state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{})
    81  			state.SetState(addr, common.Hash{i, i, i, tweak}, common.Hash{i, i, i, i, tweak})
    82  		}
    83  		if i%3 == 0 {
    84  			state.SetCode(addr, []byte{i, i, i, i, i, tweak})
    85  		}
    86  	}
    87  
    88  	// Modify the transient state.
    89  	for i := byte(0); i < 255; i++ {
    90  		modify(transState, common.Address{byte(i)}, i, 0)
    91  	}
    92  	// Write modifications to trie.
    93  	transState.IntermediateRoot(false)
    94  
    95  	// Overwrite all the data with new values in the transient database.
    96  	for i := byte(0); i < 255; i++ {
    97  		modify(transState, common.Address{byte(i)}, i, 99)
    98  		modify(finalState, common.Address{byte(i)}, i, 99)
    99  	}
   100  
   101  	// Commit and cross check the databases.
   102  	if _, err := transState.Commit(false); err != nil {
   103  		t.Fatalf("failed to commit transition state: %v", err)
   104  	}
   105  	if _, err := finalState.Commit(false); err != nil {
   106  		t.Fatalf("failed to commit final state: %v", err)
   107  	}
   108  	it := finalDb.NewIterator()
   109  	for it.Next() {
   110  		key := it.Key()
   111  		if _, err := transDb.Get(key); err != nil {
   112  			t.Errorf("entry missing from the transition database: %x -> %x", key, it.Value())
   113  		}
   114  	}
   115  	it.Release()
   116  
   117  	it = transDb.NewIterator()
   118  	for it.Next() {
   119  		key := it.Key()
   120  		if _, err := finalDb.Get(key); err != nil {
   121  			t.Errorf("extra entry in the transition database: %x -> %x", key, it.Value())
   122  		}
   123  	}
   124  }
   125  
   126  // TestCopy tests that copying a statedb object indeed makes the original and
   127  // the copy independent of each other. This test is a regression test against
   128  // https://github.com/intfoundation/intchain/pull/15549.
   129  func TestCopy(t *testing.T) {
   130  	// Create a random state test to copy and modify "independently"
   131  	orig, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
   132  
   133  	for i := byte(0); i < 255; i++ {
   134  		obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   135  		obj.AddBalance(big.NewInt(int64(i)))
   136  		orig.updateStateObject(obj)
   137  	}
   138  	orig.Finalise(false)
   139  
   140  	// Copy the state, modify both in-memory
   141  	copy := orig.Copy()
   142  
   143  	for i := byte(0); i < 255; i++ {
   144  		origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   145  		copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   146  
   147  		origObj.AddBalance(big.NewInt(2 * int64(i)))
   148  		copyObj.AddBalance(big.NewInt(3 * int64(i)))
   149  
   150  		orig.updateStateObject(origObj)
   151  		copy.updateStateObject(copyObj)
   152  	}
   153  	// Finalise the changes on both concurrently
   154  	done := make(chan struct{})
   155  	go func() {
   156  		orig.Finalise(true)
   157  		close(done)
   158  	}()
   159  	copy.Finalise(true)
   160  	<-done
   161  
   162  	// Verify that the two states have been updated independently
   163  	for i := byte(0); i < 255; i++ {
   164  		origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   165  		copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   166  
   167  		if want := big.NewInt(3 * int64(i)); origObj.Balance().Cmp(want) != 0 {
   168  			t.Errorf("orig obj %d: balance mismatch: have %v, want %v", i, origObj.Balance(), want)
   169  		}
   170  		if want := big.NewInt(4 * int64(i)); copyObj.Balance().Cmp(want) != 0 {
   171  			t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, copyObj.Balance(), want)
   172  		}
   173  	}
   174  }
   175  
   176  func TestSnapshotRandom(t *testing.T) {
   177  	config := &quick.Config{MaxCount: 1000}
   178  	err := quick.Check((*snapshotTest).run, config)
   179  	if cerr, ok := err.(*quick.CheckError); ok {
   180  		test := cerr.In[0].(*snapshotTest)
   181  		t.Errorf("%v:\n%s", test.err, test)
   182  	} else if err != nil {
   183  		t.Error(err)
   184  	}
   185  }
   186  
   187  // A snapshotTest checks that reverting StateDB snapshots properly undoes all changes
   188  // captured by the snapshot. Instances of this test with pseudorandom content are created
   189  // by Generate.
   190  //
   191  // The test works as follows:
   192  //
   193  // A new state is created and all actions are applied to it. Several snapshots are taken
   194  // in between actions. The test then reverts each snapshot. For each snapshot the actions
   195  // leading up to it are replayed on a fresh, empty state. The behaviour of all public
   196  // accessor methods on the reverted state must match the return value of the equivalent
   197  // methods on the replayed state.
   198  type snapshotTest struct {
   199  	addrs     []common.Address // all account addresses
   200  	actions   []testAction     // modifications to the state
   201  	snapshots []int            // actions indexes at which snapshot is taken
   202  	err       error            // failure details are reported through this field
   203  }
   204  
   205  type testAction struct {
   206  	name   string
   207  	fn     func(testAction, *StateDB)
   208  	args   []int64
   209  	noAddr bool
   210  }
   211  
   212  // newTestAction creates a random action that changes state.
   213  func newTestAction(addr common.Address, r *rand.Rand) testAction {
   214  	actions := []testAction{
   215  		{
   216  			name: "SetBalance",
   217  			fn: func(a testAction, s *StateDB) {
   218  				s.SetBalance(addr, big.NewInt(a.args[0]))
   219  			},
   220  			args: make([]int64, 1),
   221  		},
   222  		{
   223  			name: "AddBalance",
   224  			fn: func(a testAction, s *StateDB) {
   225  				s.AddBalance(addr, big.NewInt(a.args[0]))
   226  			},
   227  			args: make([]int64, 1),
   228  		},
   229  		{
   230  			name: "SetNonce",
   231  			fn: func(a testAction, s *StateDB) {
   232  				s.SetNonce(addr, uint64(a.args[0]))
   233  			},
   234  			args: make([]int64, 1),
   235  		},
   236  		{
   237  			name: "SetState",
   238  			fn: func(a testAction, s *StateDB) {
   239  				var key, val common.Hash
   240  				binary.BigEndian.PutUint16(key[:], uint16(a.args[0]))
   241  				binary.BigEndian.PutUint16(val[:], uint16(a.args[1]))
   242  				s.SetState(addr, key, val)
   243  			},
   244  			args: make([]int64, 2),
   245  		},
   246  		{
   247  			name: "SetCode",
   248  			fn: func(a testAction, s *StateDB) {
   249  				code := make([]byte, 16)
   250  				binary.BigEndian.PutUint64(code, uint64(a.args[0]))
   251  				binary.BigEndian.PutUint64(code[8:], uint64(a.args[1]))
   252  				s.SetCode(addr, code)
   253  			},
   254  			args: make([]int64, 2),
   255  		},
   256  		{
   257  			name: "CreateAccount",
   258  			fn: func(a testAction, s *StateDB) {
   259  				s.CreateAccount(addr)
   260  			},
   261  		},
   262  		{
   263  			name: "Suicide",
   264  			fn: func(a testAction, s *StateDB) {
   265  				s.Suicide(addr)
   266  			},
   267  		},
   268  		{
   269  			name: "AddRefund",
   270  			fn: func(a testAction, s *StateDB) {
   271  				s.AddRefund(uint64(a.args[0]))
   272  			},
   273  			args:   make([]int64, 1),
   274  			noAddr: true,
   275  		},
   276  		{
   277  			name: "AddLog",
   278  			fn: func(a testAction, s *StateDB) {
   279  				data := make([]byte, 2)
   280  				binary.BigEndian.PutUint16(data, uint16(a.args[0]))
   281  				s.AddLog(&types.Log{Address: addr, Data: data})
   282  			},
   283  			args: make([]int64, 1),
   284  		},
   285  	}
   286  	action := actions[r.Intn(len(actions))]
   287  	var nameargs []string
   288  	if !action.noAddr {
   289  		//nameargs = append(nameargs, addr.Hex())
   290  		nameargs = append(nameargs, addr.String())
   291  	}
   292  	for _, i := range action.args {
   293  		action.args[i] = rand.Int63n(100)
   294  		nameargs = append(nameargs, fmt.Sprint(action.args[i]))
   295  	}
   296  	action.name += strings.Join(nameargs, ", ")
   297  	return action
   298  }
   299  
   300  // Generate returns a new snapshot test of the given size. All randomness is
   301  // derived from r.
   302  func (*snapshotTest) Generate(r *rand.Rand, size int) reflect.Value {
   303  	// Generate random actions.
   304  	addrs := make([]common.Address, 50)
   305  	for i := range addrs {
   306  		addrs[i][0] = byte(i)
   307  	}
   308  	actions := make([]testAction, size)
   309  	for i := range actions {
   310  		addr := addrs[r.Intn(len(addrs))]
   311  		actions[i] = newTestAction(addr, r)
   312  	}
   313  	// Generate snapshot indexes.
   314  	nsnapshots := int(math.Sqrt(float64(size)))
   315  	if size > 0 && nsnapshots == 0 {
   316  		nsnapshots = 1
   317  	}
   318  	snapshots := make([]int, nsnapshots)
   319  	snaplen := len(actions) / nsnapshots
   320  	for i := range snapshots {
   321  		// Try to place the snapshots some number of actions apart from each other.
   322  		snapshots[i] = (i * snaplen) + r.Intn(snaplen)
   323  	}
   324  	return reflect.ValueOf(&snapshotTest{addrs, actions, snapshots, nil})
   325  }
   326  
   327  func (test *snapshotTest) String() string {
   328  	out := new(bytes.Buffer)
   329  	sindex := 0
   330  	for i, action := range test.actions {
   331  		if len(test.snapshots) > sindex && i == test.snapshots[sindex] {
   332  			fmt.Fprintf(out, "---- snapshot %d ----\n", sindex)
   333  			sindex++
   334  		}
   335  		fmt.Fprintf(out, "%4d: %s\n", i, action.name)
   336  	}
   337  	return out.String()
   338  }
   339  
   340  func (test *snapshotTest) run() bool {
   341  	// Run all actions and create snapshots.
   342  	var (
   343  		state, _     = New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
   344  		snapshotRevs = make([]int, len(test.snapshots))
   345  		sindex       = 0
   346  	)
   347  	for i, action := range test.actions {
   348  		if len(test.snapshots) > sindex && i == test.snapshots[sindex] {
   349  			snapshotRevs[sindex] = state.Snapshot()
   350  			sindex++
   351  		}
   352  		action.fn(action, state)
   353  	}
   354  	// Revert all snapshots in reverse order. Each revert must yield a state
   355  	// that is equivalent to fresh state with all actions up the snapshot applied.
   356  	for sindex--; sindex >= 0; sindex-- {
   357  		checkstate, _ := New(common.Hash{}, state.Database())
   358  		for _, action := range test.actions[:test.snapshots[sindex]] {
   359  			action.fn(action, checkstate)
   360  		}
   361  		state.RevertToSnapshot(snapshotRevs[sindex])
   362  		if err := test.checkEqual(state, checkstate); err != nil {
   363  			test.err = fmt.Errorf("state mismatch after revert to snapshot %d\n%v", sindex, err)
   364  			return false
   365  		}
   366  	}
   367  	return true
   368  }
   369  
   370  // checkEqual checks that methods of state and checkstate return the same values.
   371  func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error {
   372  	for _, addr := range test.addrs {
   373  		var err error
   374  		checkeq := func(op string, a, b interface{}) bool {
   375  			if err == nil && !reflect.DeepEqual(a, b) {
   376  				//err = fmt.Errorf("got %s(%s) == %v, want %v", op, addr.Hex(), a, b)
   377  				err = fmt.Errorf("got %s(%s) == %v, want %v", op, addr.String(), a, b)
   378  				return false
   379  			}
   380  			return true
   381  		}
   382  		// Check basic accessor methods.
   383  		checkeq("Exist", state.Exist(addr), checkstate.Exist(addr))
   384  		checkeq("HasSuicided", state.HasSuicided(addr), checkstate.HasSuicided(addr))
   385  		checkeq("GetBalance", state.GetBalance(addr), checkstate.GetBalance(addr))
   386  		checkeq("GetNonce", state.GetNonce(addr), checkstate.GetNonce(addr))
   387  		checkeq("GetCode", state.GetCode(addr), checkstate.GetCode(addr))
   388  		checkeq("GetCodeHash", state.GetCodeHash(addr), checkstate.GetCodeHash(addr))
   389  		checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr))
   390  		// Check storage.
   391  		if obj := state.getStateObject(addr); obj != nil {
   392  			state.ForEachStorage(addr, func(key, val common.Hash) bool {
   393  				return checkeq("GetState("+key.Hex()+")", val, checkstate.GetState(addr, key))
   394  			})
   395  			checkstate.ForEachStorage(addr, func(key, checkval common.Hash) bool {
   396  				return checkeq("GetState("+key.Hex()+")", state.GetState(addr, key), checkval)
   397  			})
   398  		}
   399  		if err != nil {
   400  			return err
   401  		}
   402  	}
   403  
   404  	if state.GetRefund() != checkstate.GetRefund() {
   405  		return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d",
   406  			state.GetRefund(), checkstate.GetRefund())
   407  	}
   408  	if !reflect.DeepEqual(state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{})) {
   409  		return fmt.Errorf("got GetLogs(common.Hash{}) == %v, want GetLogs(common.Hash{}) == %v",
   410  			state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{}))
   411  	}
   412  	return nil
   413  }
   414  
   415  func (s *StateSuite) TestTouchDelete(c *check.C) {
   416  	s.state.GetOrNewStateObject(common.Address{})
   417  	root, _ := s.state.Commit(false)
   418  	s.state.Reset(root)
   419  
   420  	snapshot := s.state.Snapshot()
   421  	s.state.AddBalance(common.Address{}, new(big.Int))
   422  	if len(s.state.stateObjectsDirty) != 1 {
   423  		c.Fatal("expected one dirty state object")
   424  	}
   425  	s.state.RevertToSnapshot(snapshot)
   426  	if len(s.state.stateObjectsDirty) != 0 {
   427  		c.Fatal("expected no dirty state object")
   428  	}
   429  }
   430  
   431  // TestCopyOfCopy tests that modified objects are carried over to the copy, and the copy of the copy.
   432  // See https://github.com/intfoundation/intchain/pull/15225#issuecomment-380191512
   433  func TestCopyOfCopy(t *testing.T) {
   434  	sdb, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
   435  	addr := common.HexToAddress("aaaa")
   436  	sdb.SetBalance(addr, big.NewInt(42))
   437  
   438  	if got := sdb.Copy().GetBalance(addr).Uint64(); got != 42 {
   439  		t.Fatalf("1st copy fail, expected 42, got %v", got)
   440  	}
   441  	if got := sdb.Copy().Copy().GetBalance(addr).Uint64(); got != 42 {
   442  		t.Fatalf("2nd copy fail, expected 42, got %v", got)
   443  	}
   444  }