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