github.hscsec.cn/juliankolbe/go-ethereum@v1.9.7/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  	"sync"
    29  	"testing"
    30  	"testing/quick"
    31  
    32  	"gopkg.in/check.v1"
    33  
    34  	"github.com/ethereum/go-ethereum/common"
    35  	"github.com/ethereum/go-ethereum/core/rawdb"
    36  	"github.com/ethereum/go-ethereum/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  	}
    58  
    59  	root := state.IntermediateRoot(false)
    60  	if err := state.Database().TrieDB().Commit(root, false); err != nil {
    61  		t.Errorf("can not commit trie %v to persistent database", root.Hex())
    62  	}
    63  
    64  	// Ensure that no data was leaked into the database
    65  	it := db.NewIterator()
    66  	for it.Next() {
    67  		t.Errorf("State leaked into database: %x -> %x", it.Key(), it.Value())
    68  	}
    69  	it.Release()
    70  }
    71  
    72  // Tests that no intermediate state of an object is stored into the database,
    73  // only the one right before the commit.
    74  func TestIntermediateLeaks(t *testing.T) {
    75  	// Create two state databases, one transitioning to the final state, the other final from the beginning
    76  	transDb := rawdb.NewMemoryDatabase()
    77  	finalDb := rawdb.NewMemoryDatabase()
    78  	transState, _ := New(common.Hash{}, NewDatabase(transDb))
    79  	finalState, _ := New(common.Hash{}, NewDatabase(finalDb))
    80  
    81  	modify := func(state *StateDB, addr common.Address, i, tweak byte) {
    82  		state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak)))
    83  		state.SetNonce(addr, uint64(42*i+tweak))
    84  		if i%2 == 0 {
    85  			state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{})
    86  			state.SetState(addr, common.Hash{i, i, i, tweak}, common.Hash{i, i, i, i, tweak})
    87  		}
    88  		if i%3 == 0 {
    89  			state.SetCode(addr, []byte{i, i, i, i, i, tweak})
    90  		}
    91  	}
    92  
    93  	// Modify the transient state.
    94  	for i := byte(0); i < 255; i++ {
    95  		modify(transState, common.Address{i}, i, 0)
    96  	}
    97  	// Write modifications to trie.
    98  	transState.IntermediateRoot(false)
    99  
   100  	// Overwrite all the data with new values in the transient database.
   101  	for i := byte(0); i < 255; i++ {
   102  		modify(transState, common.Address{i}, i, 99)
   103  		modify(finalState, common.Address{i}, i, 99)
   104  	}
   105  
   106  	// Commit and cross check the databases.
   107  	transRoot, err := transState.Commit(false)
   108  	if err != nil {
   109  		t.Fatalf("failed to commit transition state: %v", err)
   110  	}
   111  	if err = transState.Database().TrieDB().Commit(transRoot, false); err != nil {
   112  		t.Errorf("can not commit trie %v to persistent database", transRoot.Hex())
   113  	}
   114  
   115  	finalRoot, err := finalState.Commit(false)
   116  	if err != nil {
   117  		t.Fatalf("failed to commit final state: %v", err)
   118  	}
   119  	if err = finalState.Database().TrieDB().Commit(finalRoot, false); err != nil {
   120  		t.Errorf("can not commit trie %v to persistent database", finalRoot.Hex())
   121  	}
   122  
   123  	it := finalDb.NewIterator()
   124  	for it.Next() {
   125  		key, fvalue := it.Key(), it.Value()
   126  		tvalue, err := transDb.Get(key)
   127  		if err != nil {
   128  			t.Errorf("entry missing from the transition database: %x -> %x", key, fvalue)
   129  		}
   130  		if !bytes.Equal(fvalue, tvalue) {
   131  			t.Errorf("the value associate key %x is mismatch,: %x in transition database ,%x in final database", key, tvalue, fvalue)
   132  		}
   133  	}
   134  	it.Release()
   135  
   136  	it = transDb.NewIterator()
   137  	for it.Next() {
   138  		key, tvalue := it.Key(), it.Value()
   139  		fvalue, err := finalDb.Get(key)
   140  		if err != nil {
   141  			t.Errorf("extra entry in the transition database: %x -> %x", key, it.Value())
   142  		}
   143  		if !bytes.Equal(fvalue, tvalue) {
   144  			t.Errorf("the value associate key %x is mismatch,: %x in transition database ,%x in final database", key, tvalue, fvalue)
   145  		}
   146  	}
   147  }
   148  
   149  // TestCopy tests that copying a statedb object indeed makes the original and
   150  // the copy independent of each other. This test is a regression test against
   151  // https://github.com/ethereum/go-ethereum/pull/15549.
   152  func TestCopy(t *testing.T) {
   153  	// Create a random state test to copy and modify "independently"
   154  	orig, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
   155  
   156  	for i := byte(0); i < 255; i++ {
   157  		obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   158  		obj.AddBalance(big.NewInt(int64(i)))
   159  		orig.updateStateObject(obj)
   160  	}
   161  	orig.Finalise(false)
   162  
   163  	// Copy the state
   164  	copy := orig.Copy()
   165  
   166  	// Copy the copy state
   167  	ccopy := copy.Copy()
   168  
   169  	// modify all in memory
   170  	for i := byte(0); i < 255; i++ {
   171  		origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   172  		copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   173  		ccopyObj := ccopy.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   174  
   175  		origObj.AddBalance(big.NewInt(2 * int64(i)))
   176  		copyObj.AddBalance(big.NewInt(3 * int64(i)))
   177  		ccopyObj.AddBalance(big.NewInt(4 * int64(i)))
   178  
   179  		orig.updateStateObject(origObj)
   180  		copy.updateStateObject(copyObj)
   181  		ccopy.updateStateObject(copyObj)
   182  	}
   183  
   184  	// Finalise the changes on all concurrently
   185  	finalise := func(wg *sync.WaitGroup, db *StateDB) {
   186  		defer wg.Done()
   187  		db.Finalise(true)
   188  	}
   189  
   190  	var wg sync.WaitGroup
   191  	wg.Add(3)
   192  	go finalise(&wg, orig)
   193  	go finalise(&wg, copy)
   194  	go finalise(&wg, ccopy)
   195  	wg.Wait()
   196  
   197  	// Verify that the three states have been updated independently
   198  	for i := byte(0); i < 255; i++ {
   199  		origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   200  		copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   201  		ccopyObj := ccopy.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   202  
   203  		if want := big.NewInt(3 * int64(i)); origObj.Balance().Cmp(want) != 0 {
   204  			t.Errorf("orig obj %d: balance mismatch: have %v, want %v", i, origObj.Balance(), want)
   205  		}
   206  		if want := big.NewInt(4 * int64(i)); copyObj.Balance().Cmp(want) != 0 {
   207  			t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, copyObj.Balance(), want)
   208  		}
   209  		if want := big.NewInt(5 * int64(i)); ccopyObj.Balance().Cmp(want) != 0 {
   210  			t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, ccopyObj.Balance(), want)
   211  		}
   212  	}
   213  }
   214  
   215  func TestSnapshotRandom(t *testing.T) {
   216  	config := &quick.Config{MaxCount: 1000}
   217  	err := quick.Check((*snapshotTest).run, config)
   218  	if cerr, ok := err.(*quick.CheckError); ok {
   219  		test := cerr.In[0].(*snapshotTest)
   220  		t.Errorf("%v:\n%s", test.err, test)
   221  	} else if err != nil {
   222  		t.Error(err)
   223  	}
   224  }
   225  
   226  // A snapshotTest checks that reverting StateDB snapshots properly undoes all changes
   227  // captured by the snapshot. Instances of this test with pseudorandom content are created
   228  // by Generate.
   229  //
   230  // The test works as follows:
   231  //
   232  // A new state is created and all actions are applied to it. Several snapshots are taken
   233  // in between actions. The test then reverts each snapshot. For each snapshot the actions
   234  // leading up to it are replayed on a fresh, empty state. The behaviour of all public
   235  // accessor methods on the reverted state must match the return value of the equivalent
   236  // methods on the replayed state.
   237  type snapshotTest struct {
   238  	addrs     []common.Address // all account addresses
   239  	actions   []testAction     // modifications to the state
   240  	snapshots []int            // actions indexes at which snapshot is taken
   241  	err       error            // failure details are reported through this field
   242  }
   243  
   244  type testAction struct {
   245  	name   string
   246  	fn     func(testAction, *StateDB)
   247  	args   []int64
   248  	noAddr bool
   249  }
   250  
   251  // newTestAction creates a random action that changes state.
   252  func newTestAction(addr common.Address, r *rand.Rand) testAction {
   253  	actions := []testAction{
   254  		{
   255  			name: "SetBalance",
   256  			fn: func(a testAction, s *StateDB) {
   257  				s.SetBalance(addr, big.NewInt(a.args[0]))
   258  			},
   259  			args: make([]int64, 1),
   260  		},
   261  		{
   262  			name: "AddBalance",
   263  			fn: func(a testAction, s *StateDB) {
   264  				s.AddBalance(addr, big.NewInt(a.args[0]))
   265  			},
   266  			args: make([]int64, 1),
   267  		},
   268  		{
   269  			name: "SetNonce",
   270  			fn: func(a testAction, s *StateDB) {
   271  				s.SetNonce(addr, uint64(a.args[0]))
   272  			},
   273  			args: make([]int64, 1),
   274  		},
   275  		{
   276  			name: "SetState",
   277  			fn: func(a testAction, s *StateDB) {
   278  				var key, val common.Hash
   279  				binary.BigEndian.PutUint16(key[:], uint16(a.args[0]))
   280  				binary.BigEndian.PutUint16(val[:], uint16(a.args[1]))
   281  				s.SetState(addr, key, val)
   282  			},
   283  			args: make([]int64, 2),
   284  		},
   285  		{
   286  			name: "SetCode",
   287  			fn: func(a testAction, s *StateDB) {
   288  				code := make([]byte, 16)
   289  				binary.BigEndian.PutUint64(code, uint64(a.args[0]))
   290  				binary.BigEndian.PutUint64(code[8:], uint64(a.args[1]))
   291  				s.SetCode(addr, code)
   292  			},
   293  			args: make([]int64, 2),
   294  		},
   295  		{
   296  			name: "CreateAccount",
   297  			fn: func(a testAction, s *StateDB) {
   298  				s.CreateAccount(addr)
   299  			},
   300  		},
   301  		{
   302  			name: "Suicide",
   303  			fn: func(a testAction, s *StateDB) {
   304  				s.Suicide(addr)
   305  			},
   306  		},
   307  		{
   308  			name: "AddRefund",
   309  			fn: func(a testAction, s *StateDB) {
   310  				s.AddRefund(uint64(a.args[0]))
   311  			},
   312  			args:   make([]int64, 1),
   313  			noAddr: true,
   314  		},
   315  		{
   316  			name: "AddLog",
   317  			fn: func(a testAction, s *StateDB) {
   318  				data := make([]byte, 2)
   319  				binary.BigEndian.PutUint16(data, uint16(a.args[0]))
   320  				s.AddLog(&types.Log{Address: addr, Data: data})
   321  			},
   322  			args: make([]int64, 1),
   323  		},
   324  		{
   325  			name: "AddPreimage",
   326  			fn: func(a testAction, s *StateDB) {
   327  				preimage := []byte{1}
   328  				hash := common.BytesToHash(preimage)
   329  				s.AddPreimage(hash, preimage)
   330  			},
   331  			args: make([]int64, 1),
   332  		},
   333  	}
   334  	action := actions[r.Intn(len(actions))]
   335  	var nameargs []string
   336  	if !action.noAddr {
   337  		nameargs = append(nameargs, addr.Hex())
   338  	}
   339  	for i := range action.args {
   340  		action.args[i] = rand.Int63n(100)
   341  		nameargs = append(nameargs, fmt.Sprint(action.args[i]))
   342  	}
   343  	action.name += strings.Join(nameargs, ", ")
   344  	return action
   345  }
   346  
   347  // Generate returns a new snapshot test of the given size. All randomness is
   348  // derived from r.
   349  func (*snapshotTest) Generate(r *rand.Rand, size int) reflect.Value {
   350  	// Generate random actions.
   351  	addrs := make([]common.Address, 50)
   352  	for i := range addrs {
   353  		addrs[i][0] = byte(i)
   354  	}
   355  	actions := make([]testAction, size)
   356  	for i := range actions {
   357  		addr := addrs[r.Intn(len(addrs))]
   358  		actions[i] = newTestAction(addr, r)
   359  	}
   360  	// Generate snapshot indexes.
   361  	nsnapshots := int(math.Sqrt(float64(size)))
   362  	if size > 0 && nsnapshots == 0 {
   363  		nsnapshots = 1
   364  	}
   365  	snapshots := make([]int, nsnapshots)
   366  	snaplen := len(actions) / nsnapshots
   367  	for i := range snapshots {
   368  		// Try to place the snapshots some number of actions apart from each other.
   369  		snapshots[i] = (i * snaplen) + r.Intn(snaplen)
   370  	}
   371  	return reflect.ValueOf(&snapshotTest{addrs, actions, snapshots, nil})
   372  }
   373  
   374  func (test *snapshotTest) String() string {
   375  	out := new(bytes.Buffer)
   376  	sindex := 0
   377  	for i, action := range test.actions {
   378  		if len(test.snapshots) > sindex && i == test.snapshots[sindex] {
   379  			fmt.Fprintf(out, "---- snapshot %d ----\n", sindex)
   380  			sindex++
   381  		}
   382  		fmt.Fprintf(out, "%4d: %s\n", i, action.name)
   383  	}
   384  	return out.String()
   385  }
   386  
   387  func (test *snapshotTest) run() bool {
   388  	// Run all actions and create snapshots.
   389  	var (
   390  		state, _     = New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
   391  		snapshotRevs = make([]int, len(test.snapshots))
   392  		sindex       = 0
   393  	)
   394  	for i, action := range test.actions {
   395  		if len(test.snapshots) > sindex && i == test.snapshots[sindex] {
   396  			snapshotRevs[sindex] = state.Snapshot()
   397  			sindex++
   398  		}
   399  		action.fn(action, state)
   400  	}
   401  	// Revert all snapshots in reverse order. Each revert must yield a state
   402  	// that is equivalent to fresh state with all actions up the snapshot applied.
   403  	for sindex--; sindex >= 0; sindex-- {
   404  		checkstate, _ := New(common.Hash{}, state.Database())
   405  		for _, action := range test.actions[:test.snapshots[sindex]] {
   406  			action.fn(action, checkstate)
   407  		}
   408  		state.RevertToSnapshot(snapshotRevs[sindex])
   409  		if err := test.checkEqual(state, checkstate); err != nil {
   410  			test.err = fmt.Errorf("state mismatch after revert to snapshot %d\n%v", sindex, err)
   411  			return false
   412  		}
   413  	}
   414  	return true
   415  }
   416  
   417  // checkEqual checks that methods of state and checkstate return the same values.
   418  func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error {
   419  	for _, addr := range test.addrs {
   420  		var err error
   421  		checkeq := func(op string, a, b interface{}) bool {
   422  			if err == nil && !reflect.DeepEqual(a, b) {
   423  				err = fmt.Errorf("got %s(%s) == %v, want %v", op, addr.Hex(), a, b)
   424  				return false
   425  			}
   426  			return true
   427  		}
   428  		// Check basic accessor methods.
   429  		checkeq("Exist", state.Exist(addr), checkstate.Exist(addr))
   430  		checkeq("HasSuicided", state.HasSuicided(addr), checkstate.HasSuicided(addr))
   431  		checkeq("GetBalance", state.GetBalance(addr), checkstate.GetBalance(addr))
   432  		checkeq("GetNonce", state.GetNonce(addr), checkstate.GetNonce(addr))
   433  		checkeq("GetCode", state.GetCode(addr), checkstate.GetCode(addr))
   434  		checkeq("GetCodeHash", state.GetCodeHash(addr), checkstate.GetCodeHash(addr))
   435  		checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr))
   436  		// Check storage.
   437  		if obj := state.getStateObject(addr); obj != nil {
   438  			state.ForEachStorage(addr, func(key, value common.Hash) bool {
   439  				return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value)
   440  			})
   441  			checkstate.ForEachStorage(addr, func(key, value common.Hash) bool {
   442  				return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value)
   443  			})
   444  		}
   445  		if err != nil {
   446  			return err
   447  		}
   448  	}
   449  
   450  	if state.GetRefund() != checkstate.GetRefund() {
   451  		return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d",
   452  			state.GetRefund(), checkstate.GetRefund())
   453  	}
   454  	if !reflect.DeepEqual(state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{})) {
   455  		return fmt.Errorf("got GetLogs(common.Hash{}) == %v, want GetLogs(common.Hash{}) == %v",
   456  			state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{}))
   457  	}
   458  	return nil
   459  }
   460  
   461  func (s *StateSuite) TestTouchDelete(c *check.C) {
   462  	s.state.GetOrNewStateObject(common.Address{})
   463  	root, _ := s.state.Commit(false)
   464  	s.state.Reset(root)
   465  
   466  	snapshot := s.state.Snapshot()
   467  	s.state.AddBalance(common.Address{}, new(big.Int))
   468  
   469  	if len(s.state.journal.dirties) != 1 {
   470  		c.Fatal("expected one dirty state object")
   471  	}
   472  	s.state.RevertToSnapshot(snapshot)
   473  	if len(s.state.journal.dirties) != 0 {
   474  		c.Fatal("expected no dirty state object")
   475  	}
   476  }
   477  
   478  // TestCopyOfCopy tests that modified objects are carried over to the copy, and the copy of the copy.
   479  // See https://github.com/ethereum/go-ethereum/pull/15225#issuecomment-380191512
   480  func TestCopyOfCopy(t *testing.T) {
   481  	state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
   482  	addr := common.HexToAddress("aaaa")
   483  	state.SetBalance(addr, big.NewInt(42))
   484  
   485  	if got := state.Copy().GetBalance(addr).Uint64(); got != 42 {
   486  		t.Fatalf("1st copy fail, expected 42, got %v", got)
   487  	}
   488  	if got := state.Copy().Copy().GetBalance(addr).Uint64(); got != 42 {
   489  		t.Fatalf("2nd copy fail, expected 42, got %v", got)
   490  	}
   491  }
   492  
   493  // Tests a regression where committing a copy lost some internal meta information,
   494  // leading to corrupted subsequent copies.
   495  //
   496  // See https://github.com/ethereum/go-ethereum/issues/20106.
   497  func TestCopyCommitCopy(t *testing.T) {
   498  	state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
   499  
   500  	// Create an account and check if the retrieved balance is correct
   501  	addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe")
   502  	skey := common.HexToHash("aaa")
   503  	sval := common.HexToHash("bbb")
   504  
   505  	state.SetBalance(addr, big.NewInt(42)) // Change the account trie
   506  	state.SetCode(addr, []byte("hello"))   // Change an external metadata
   507  	state.SetState(addr, skey, sval)       // Change the storage trie
   508  
   509  	if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
   510  		t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42)
   511  	}
   512  	if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
   513  		t.Fatalf("initial code mismatch: have %x, want %x", code, []byte("hello"))
   514  	}
   515  	if val := state.GetState(addr, skey); val != sval {
   516  		t.Fatalf("initial non-committed storage slot mismatch: have %x, want %x", val, sval)
   517  	}
   518  	if val := state.GetCommittedState(addr, skey); val != (common.Hash{}) {
   519  		t.Fatalf("initial committed storage slot mismatch: have %x, want %x", val, common.Hash{})
   520  	}
   521  	// Copy the non-committed state database and check pre/post commit balance
   522  	copyOne := state.Copy()
   523  	if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
   524  		t.Fatalf("first copy pre-commit balance mismatch: have %v, want %v", balance, 42)
   525  	}
   526  	if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
   527  		t.Fatalf("first copy pre-commit code mismatch: have %x, want %x", code, []byte("hello"))
   528  	}
   529  	if val := copyOne.GetState(addr, skey); val != sval {
   530  		t.Fatalf("first copy pre-commit non-committed storage slot mismatch: have %x, want %x", val, sval)
   531  	}
   532  	if val := copyOne.GetCommittedState(addr, skey); val != (common.Hash{}) {
   533  		t.Fatalf("first copy pre-commit committed storage slot mismatch: have %x, want %x", val, common.Hash{})
   534  	}
   535  
   536  	copyOne.Commit(false)
   537  	if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
   538  		t.Fatalf("first copy post-commit balance mismatch: have %v, want %v", balance, 42)
   539  	}
   540  	if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
   541  		t.Fatalf("first copy post-commit code mismatch: have %x, want %x", code, []byte("hello"))
   542  	}
   543  	if val := copyOne.GetState(addr, skey); val != sval {
   544  		t.Fatalf("first copy post-commit non-committed storage slot mismatch: have %x, want %x", val, sval)
   545  	}
   546  	if val := copyOne.GetCommittedState(addr, skey); val != sval {
   547  		t.Fatalf("first copy post-commit committed storage slot mismatch: have %x, want %x", val, sval)
   548  	}
   549  	// Copy the copy and check the balance once more
   550  	copyTwo := copyOne.Copy()
   551  	if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
   552  		t.Fatalf("second copy balance mismatch: have %v, want %v", balance, 42)
   553  	}
   554  	if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
   555  		t.Fatalf("second copy code mismatch: have %x, want %x", code, []byte("hello"))
   556  	}
   557  	if val := copyTwo.GetState(addr, skey); val != sval {
   558  		t.Fatalf("second copy non-committed storage slot mismatch: have %x, want %x", val, sval)
   559  	}
   560  	if val := copyTwo.GetCommittedState(addr, skey); val != sval {
   561  		t.Fatalf("second copy post-commit committed storage slot mismatch: have %x, want %x", val, sval)
   562  	}
   563  }
   564  
   565  // Tests a regression where committing a copy lost some internal meta information,
   566  // leading to corrupted subsequent copies.
   567  //
   568  // See https://github.com/ethereum/go-ethereum/issues/20106.
   569  func TestCopyCopyCommitCopy(t *testing.T) {
   570  	state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
   571  
   572  	// Create an account and check if the retrieved balance is correct
   573  	addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe")
   574  	skey := common.HexToHash("aaa")
   575  	sval := common.HexToHash("bbb")
   576  
   577  	state.SetBalance(addr, big.NewInt(42)) // Change the account trie
   578  	state.SetCode(addr, []byte("hello"))   // Change an external metadata
   579  	state.SetState(addr, skey, sval)       // Change the storage trie
   580  
   581  	if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
   582  		t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42)
   583  	}
   584  	if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
   585  		t.Fatalf("initial code mismatch: have %x, want %x", code, []byte("hello"))
   586  	}
   587  	if val := state.GetState(addr, skey); val != sval {
   588  		t.Fatalf("initial non-committed storage slot mismatch: have %x, want %x", val, sval)
   589  	}
   590  	if val := state.GetCommittedState(addr, skey); val != (common.Hash{}) {
   591  		t.Fatalf("initial committed storage slot mismatch: have %x, want %x", val, common.Hash{})
   592  	}
   593  	// Copy the non-committed state database and check pre/post commit balance
   594  	copyOne := state.Copy()
   595  	if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
   596  		t.Fatalf("first copy balance mismatch: have %v, want %v", balance, 42)
   597  	}
   598  	if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
   599  		t.Fatalf("first copy code mismatch: have %x, want %x", code, []byte("hello"))
   600  	}
   601  	if val := copyOne.GetState(addr, skey); val != sval {
   602  		t.Fatalf("first copy non-committed storage slot mismatch: have %x, want %x", val, sval)
   603  	}
   604  	if val := copyOne.GetCommittedState(addr, skey); val != (common.Hash{}) {
   605  		t.Fatalf("first copy committed storage slot mismatch: have %x, want %x", val, common.Hash{})
   606  	}
   607  	// Copy the copy and check the balance once more
   608  	copyTwo := copyOne.Copy()
   609  	if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
   610  		t.Fatalf("second copy pre-commit balance mismatch: have %v, want %v", balance, 42)
   611  	}
   612  	if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
   613  		t.Fatalf("second copy pre-commit code mismatch: have %x, want %x", code, []byte("hello"))
   614  	}
   615  	if val := copyTwo.GetState(addr, skey); val != sval {
   616  		t.Fatalf("second copy pre-commit non-committed storage slot mismatch: have %x, want %x", val, sval)
   617  	}
   618  	if val := copyTwo.GetCommittedState(addr, skey); val != (common.Hash{}) {
   619  		t.Fatalf("second copy pre-commit committed storage slot mismatch: have %x, want %x", val, common.Hash{})
   620  	}
   621  	copyTwo.Commit(false)
   622  	if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
   623  		t.Fatalf("second copy post-commit balance mismatch: have %v, want %v", balance, 42)
   624  	}
   625  	if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
   626  		t.Fatalf("second copy post-commit code mismatch: have %x, want %x", code, []byte("hello"))
   627  	}
   628  	if val := copyTwo.GetState(addr, skey); val != sval {
   629  		t.Fatalf("second copy post-commit non-committed storage slot mismatch: have %x, want %x", val, sval)
   630  	}
   631  	if val := copyTwo.GetCommittedState(addr, skey); val != sval {
   632  		t.Fatalf("second copy post-commit committed storage slot mismatch: have %x, want %x", val, sval)
   633  	}
   634  	// Copy the copy-copy and check the balance once more
   635  	copyThree := copyTwo.Copy()
   636  	if balance := copyThree.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
   637  		t.Fatalf("third copy balance mismatch: have %v, want %v", balance, 42)
   638  	}
   639  	if code := copyThree.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
   640  		t.Fatalf("third copy code mismatch: have %x, want %x", code, []byte("hello"))
   641  	}
   642  	if val := copyThree.GetState(addr, skey); val != sval {
   643  		t.Fatalf("third copy non-committed storage slot mismatch: have %x, want %x", val, sval)
   644  	}
   645  	if val := copyThree.GetCommittedState(addr, skey); val != sval {
   646  		t.Fatalf("third copy committed storage slot mismatch: have %x, want %x", val, sval)
   647  	}
   648  }
   649  
   650  // TestDeleteCreateRevert tests a weird state transition corner case that we hit
   651  // while changing the internals of statedb. The workflow is that a contract is
   652  // self destructed, then in a followup transaction (but same block) it's created
   653  // again and the transaction reverted.
   654  //
   655  // The original statedb implementation flushed dirty objects to the tries after
   656  // each transaction, so this works ok. The rework accumulated writes in memory
   657  // first, but the journal wiped the entire state object on create-revert.
   658  func TestDeleteCreateRevert(t *testing.T) {
   659  	// Create an initial state with a single contract
   660  	state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
   661  
   662  	addr := toAddr([]byte("so"))
   663  	state.SetBalance(addr, big.NewInt(1))
   664  
   665  	root, _ := state.Commit(false)
   666  	state.Reset(root)
   667  
   668  	// Simulate self-destructing in one transaction, then create-reverting in another
   669  	state.Suicide(addr)
   670  	state.Finalise(true)
   671  
   672  	id := state.Snapshot()
   673  	state.SetBalance(addr, big.NewInt(2))
   674  	state.RevertToSnapshot(id)
   675  
   676  	// Commit the entire state and make sure we don't crash and have the correct state
   677  	root, _ = state.Commit(true)
   678  	state.Reset(root)
   679  
   680  	if state.getStateObject(addr) != nil {
   681  		t.Fatalf("self-destructed contract came alive")
   682  	}
   683  }