| 
									
										
										
										
											2016-04-14 18:18:24 +02:00
										 |  |  | // Copyright 2016 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2016-01-20 12:09:24 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							|  |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package state | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 	"bytes" | 
					
						
							|  |  |  | 	"encoding/binary" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"math" | 
					
						
							| 
									
										
										
										
											2016-01-20 12:09:24 +02:00
										 |  |  | 	"math/big" | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 	"math/rand" | 
					
						
							|  |  |  | 	"reflect" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2016-01-20 12:09:24 +02:00
										 |  |  | 	"testing" | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 	"testing/quick" | 
					
						
							| 
									
										
										
										
											2016-01-20 12:09:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-27 15:57:06 +02:00
										 |  |  | 	check "gopkg.in/check.v1" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-20 12:09:24 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/rawdb" | 
					
						
							| 
									
										
										
										
											2017-01-05 14:03:50 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/types" | 
					
						
							| 
									
										
										
										
											2016-01-20 12:09:24 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Tests that updating a state trie does not leak any database writes prior to | 
					
						
							|  |  |  | // actually committing the state. | 
					
						
							|  |  |  | func TestUpdateLeaks(t *testing.T) { | 
					
						
							|  |  |  | 	// Create an empty state database | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	db := rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2017-06-27 15:57:06 +02:00
										 |  |  | 	state, _ := New(common.Hash{}, NewDatabase(db)) | 
					
						
							| 
									
										
										
										
											2016-01-20 12:09:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Update it with some accounts | 
					
						
							|  |  |  | 	for i := byte(0); i < 255; i++ { | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 		addr := common.BytesToAddress([]byte{i}) | 
					
						
							|  |  |  | 		state.AddBalance(addr, big.NewInt(int64(11*i))) | 
					
						
							|  |  |  | 		state.SetNonce(addr, uint64(42*i)) | 
					
						
							| 
									
										
										
										
											2016-01-20 12:09:24 +02:00
										 |  |  | 		if i%2 == 0 { | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 			state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i})) | 
					
						
							| 
									
										
										
										
											2016-01-20 12:09:24 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if i%3 == 0 { | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 			state.SetCode(addr, []byte{i, i, i, i, i}) | 
					
						
							| 
									
										
										
										
											2016-01-20 12:09:24 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 		state.IntermediateRoot(false) | 
					
						
							| 
									
										
										
										
											2016-01-20 12:09:24 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// Ensure that no data was leaked into the database | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	it := db.NewIterator() | 
					
						
							|  |  |  | 	for it.Next() { | 
					
						
							|  |  |  | 		t.Errorf("State leaked into database: %x -> %x", it.Key(), it.Value()) | 
					
						
							| 
									
										
										
										
											2016-01-20 12:09:24 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	it.Release() | 
					
						
							| 
									
										
										
										
											2016-01-20 12:09:24 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-01-20 16:06:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Tests that no intermediate state of an object is stored into the database, | 
					
						
							|  |  |  | // only the one right before the commit. | 
					
						
							|  |  |  | func TestIntermediateLeaks(t *testing.T) { | 
					
						
							|  |  |  | 	// Create two state databases, one transitioning to the final state, the other final from the beginning | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	transDb := rawdb.NewMemoryDatabase() | 
					
						
							|  |  |  | 	finalDb := rawdb.NewMemoryDatabase() | 
					
						
							| 
									
										
										
										
											2017-06-27 15:57:06 +02:00
										 |  |  | 	transState, _ := New(common.Hash{}, NewDatabase(transDb)) | 
					
						
							|  |  |  | 	finalState, _ := New(common.Hash{}, NewDatabase(finalDb)) | 
					
						
							| 
									
										
										
										
											2016-01-20 16:06:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 	modify := func(state *StateDB, addr common.Address, i, tweak byte) { | 
					
						
							|  |  |  | 		state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak))) | 
					
						
							|  |  |  | 		state.SetNonce(addr, uint64(42*i+tweak)) | 
					
						
							| 
									
										
										
										
											2016-01-20 16:06:28 +02:00
										 |  |  | 		if i%2 == 0 { | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 			state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{}) | 
					
						
							|  |  |  | 			state.SetState(addr, common.Hash{i, i, i, tweak}, common.Hash{i, i, i, i, tweak}) | 
					
						
							| 
									
										
										
										
											2016-01-20 16:06:28 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if i%3 == 0 { | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 			state.SetCode(addr, []byte{i, i, i, i, i, tweak}) | 
					
						
							| 
									
										
										
										
											2016-01-20 16:06:28 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-20 16:06:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 	// Modify the transient state. | 
					
						
							|  |  |  | 	for i := byte(0); i < 255; i++ { | 
					
						
							|  |  |  | 		modify(transState, common.Address{byte(i)}, i, 0) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Write modifications to trie. | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 	transState.IntermediateRoot(false) | 
					
						
							| 
									
										
										
										
											2016-01-20 16:06:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 	// Overwrite all the data with new values in the transient database. | 
					
						
							|  |  |  | 	for i := byte(0); i < 255; i++ { | 
					
						
							|  |  |  | 		modify(transState, common.Address{byte(i)}, i, 99) | 
					
						
							|  |  |  | 		modify(finalState, common.Address{byte(i)}, i, 99) | 
					
						
							| 
									
										
										
										
											2016-01-20 16:06:28 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Commit and cross check the databases. | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 	if _, err := transState.Commit(false); err != nil { | 
					
						
							| 
									
										
										
										
											2016-01-20 16:06:28 +02:00
										 |  |  | 		t.Fatalf("failed to commit transition state: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 	if _, err := finalState.Commit(false); err != nil { | 
					
						
							| 
									
										
										
										
											2016-01-20 16:06:28 +02:00
										 |  |  | 		t.Fatalf("failed to commit final state: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	it := finalDb.NewIterator() | 
					
						
							|  |  |  | 	for it.Next() { | 
					
						
							|  |  |  | 		key := it.Key() | 
					
						
							| 
									
										
										
										
											2016-01-20 16:06:28 +02:00
										 |  |  | 		if _, err := transDb.Get(key); err != nil { | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 			t.Errorf("entry missing from the transition database: %x -> %x", key, it.Value()) | 
					
						
							| 
									
										
										
										
											2016-01-20 16:06:28 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	it.Release() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	it = transDb.NewIterator() | 
					
						
							|  |  |  | 	for it.Next() { | 
					
						
							|  |  |  | 		key := it.Key() | 
					
						
							| 
									
										
										
										
											2016-01-20 16:06:28 +02:00
										 |  |  | 		if _, err := finalDb.Get(key); err != nil { | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 			t.Errorf("extra entry in the transition database: %x -> %x", key, it.Value()) | 
					
						
							| 
									
										
										
										
											2016-01-20 16:06:28 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-24 11:02:25 +02:00
										 |  |  | // TestCopy tests that copying a statedb object indeed makes the original and | 
					
						
							|  |  |  | // the copy independent of each other. This test is a regression test against | 
					
						
							|  |  |  | // https://github.com/ethereum/go-ethereum/pull/15549. | 
					
						
							|  |  |  | func TestCopy(t *testing.T) { | 
					
						
							|  |  |  | 	// Create a random state test to copy and modify "independently" | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	orig, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) | 
					
						
							| 
									
										
										
										
											2017-11-24 11:02:25 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for i := byte(0); i < 255; i++ { | 
					
						
							|  |  |  | 		obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) | 
					
						
							|  |  |  | 		obj.AddBalance(big.NewInt(int64(i))) | 
					
						
							|  |  |  | 		orig.updateStateObject(obj) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	orig.Finalise(false) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Copy the state, modify both in-memory | 
					
						
							|  |  |  | 	copy := orig.Copy() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i := byte(0); i < 255; i++ { | 
					
						
							|  |  |  | 		origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) | 
					
						
							|  |  |  | 		copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		origObj.AddBalance(big.NewInt(2 * int64(i))) | 
					
						
							|  |  |  | 		copyObj.AddBalance(big.NewInt(3 * int64(i))) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		orig.updateStateObject(origObj) | 
					
						
							|  |  |  | 		copy.updateStateObject(copyObj) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Finalise the changes on both concurrently | 
					
						
							|  |  |  | 	done := make(chan struct{}) | 
					
						
							|  |  |  | 	go func() { | 
					
						
							|  |  |  | 		orig.Finalise(true) | 
					
						
							|  |  |  | 		close(done) | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 	copy.Finalise(true) | 
					
						
							|  |  |  | 	<-done | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Verify that the two states have been updated independently | 
					
						
							|  |  |  | 	for i := byte(0); i < 255; i++ { | 
					
						
							|  |  |  | 		origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) | 
					
						
							|  |  |  | 		copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if want := big.NewInt(3 * int64(i)); origObj.Balance().Cmp(want) != 0 { | 
					
						
							|  |  |  | 			t.Errorf("orig obj %d: balance mismatch: have %v, want %v", i, origObj.Balance(), want) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if want := big.NewInt(4 * int64(i)); copyObj.Balance().Cmp(want) != 0 { | 
					
						
							|  |  |  | 			t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, copyObj.Balance(), want) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | func TestSnapshotRandom(t *testing.T) { | 
					
						
							|  |  |  | 	config := &quick.Config{MaxCount: 1000} | 
					
						
							|  |  |  | 	err := quick.Check((*snapshotTest).run, config) | 
					
						
							|  |  |  | 	if cerr, ok := err.(*quick.CheckError); ok { | 
					
						
							|  |  |  | 		test := cerr.In[0].(*snapshotTest) | 
					
						
							|  |  |  | 		t.Errorf("%v:\n%s", test.err, test) | 
					
						
							|  |  |  | 	} else if err != nil { | 
					
						
							|  |  |  | 		t.Error(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // A snapshotTest checks that reverting StateDB snapshots properly undoes all changes | 
					
						
							|  |  |  | // captured by the snapshot. Instances of this test with pseudorandom content are created | 
					
						
							|  |  |  | // by Generate. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The test works as follows: | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // A new state is created and all actions are applied to it. Several snapshots are taken | 
					
						
							|  |  |  | // in between actions. The test then reverts each snapshot. For each snapshot the actions | 
					
						
							|  |  |  | // leading up to it are replayed on a fresh, empty state. The behaviour of all public | 
					
						
							|  |  |  | // accessor methods on the reverted state must match the return value of the equivalent | 
					
						
							|  |  |  | // methods on the replayed state. | 
					
						
							|  |  |  | type snapshotTest struct { | 
					
						
							|  |  |  | 	addrs     []common.Address // all account addresses | 
					
						
							|  |  |  | 	actions   []testAction     // modifications to the state | 
					
						
							|  |  |  | 	snapshots []int            // actions indexes at which snapshot is taken | 
					
						
							|  |  |  | 	err       error            // failure details are reported through this field | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type testAction struct { | 
					
						
							|  |  |  | 	name   string | 
					
						
							|  |  |  | 	fn     func(testAction, *StateDB) | 
					
						
							|  |  |  | 	args   []int64 | 
					
						
							|  |  |  | 	noAddr bool | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // newTestAction creates a random action that changes state. | 
					
						
							|  |  |  | func newTestAction(addr common.Address, r *rand.Rand) testAction { | 
					
						
							|  |  |  | 	actions := []testAction{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "SetBalance", | 
					
						
							|  |  |  | 			fn: func(a testAction, s *StateDB) { | 
					
						
							|  |  |  | 				s.SetBalance(addr, big.NewInt(a.args[0])) | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			args: make([]int64, 1), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "AddBalance", | 
					
						
							|  |  |  | 			fn: func(a testAction, s *StateDB) { | 
					
						
							|  |  |  | 				s.AddBalance(addr, big.NewInt(a.args[0])) | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			args: make([]int64, 1), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "SetNonce", | 
					
						
							|  |  |  | 			fn: func(a testAction, s *StateDB) { | 
					
						
							|  |  |  | 				s.SetNonce(addr, uint64(a.args[0])) | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			args: make([]int64, 1), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "SetState", | 
					
						
							|  |  |  | 			fn: func(a testAction, s *StateDB) { | 
					
						
							|  |  |  | 				var key, val common.Hash | 
					
						
							|  |  |  | 				binary.BigEndian.PutUint16(key[:], uint16(a.args[0])) | 
					
						
							|  |  |  | 				binary.BigEndian.PutUint16(val[:], uint16(a.args[1])) | 
					
						
							|  |  |  | 				s.SetState(addr, key, val) | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			args: make([]int64, 2), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "SetCode", | 
					
						
							|  |  |  | 			fn: func(a testAction, s *StateDB) { | 
					
						
							|  |  |  | 				code := make([]byte, 16) | 
					
						
							|  |  |  | 				binary.BigEndian.PutUint64(code, uint64(a.args[0])) | 
					
						
							|  |  |  | 				binary.BigEndian.PutUint64(code[8:], uint64(a.args[1])) | 
					
						
							|  |  |  | 				s.SetCode(addr, code) | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			args: make([]int64, 2), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "CreateAccount", | 
					
						
							|  |  |  | 			fn: func(a testAction, s *StateDB) { | 
					
						
							|  |  |  | 				s.CreateAccount(addr) | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2016-10-05 22:22:31 +02:00
										 |  |  | 			name: "Suicide", | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 			fn: func(a testAction, s *StateDB) { | 
					
						
							| 
									
										
										
										
											2016-10-05 22:22:31 +02:00
										 |  |  | 				s.Suicide(addr) | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "AddRefund", | 
					
						
							|  |  |  | 			fn: func(a testAction, s *StateDB) { | 
					
						
							| 
									
										
										
										
											2017-11-13 13:47:27 +02:00
										 |  |  | 				s.AddRefund(uint64(a.args[0])) | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			args:   make([]int64, 1), | 
					
						
							|  |  |  | 			noAddr: true, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "AddLog", | 
					
						
							|  |  |  | 			fn: func(a testAction, s *StateDB) { | 
					
						
							|  |  |  | 				data := make([]byte, 2) | 
					
						
							|  |  |  | 				binary.BigEndian.PutUint16(data, uint16(a.args[0])) | 
					
						
							| 
									
										
										
										
											2017-01-05 14:03:50 +01:00
										 |  |  | 				s.AddLog(&types.Log{Address: addr, Data: data}) | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			args: make([]int64, 1), | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2019-02-07 18:44:45 +09:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			name: "AddPreimage", | 
					
						
							|  |  |  | 			fn: func(a testAction, s *StateDB) { | 
					
						
							|  |  |  | 				preimage := []byte{1} | 
					
						
							|  |  |  | 				hash := common.BytesToHash(preimage) | 
					
						
							|  |  |  | 				s.AddPreimage(hash, preimage) | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			args: make([]int64, 1), | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	action := actions[r.Intn(len(actions))] | 
					
						
							|  |  |  | 	var nameargs []string | 
					
						
							|  |  |  | 	if !action.noAddr { | 
					
						
							|  |  |  | 		nameargs = append(nameargs, addr.Hex()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, i := range action.args { | 
					
						
							|  |  |  | 		action.args[i] = rand.Int63n(100) | 
					
						
							|  |  |  | 		nameargs = append(nameargs, fmt.Sprint(action.args[i])) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	action.name += strings.Join(nameargs, ", ") | 
					
						
							|  |  |  | 	return action | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Generate returns a new snapshot test of the given size. All randomness is | 
					
						
							|  |  |  | // derived from r. | 
					
						
							|  |  |  | func (*snapshotTest) Generate(r *rand.Rand, size int) reflect.Value { | 
					
						
							|  |  |  | 	// Generate random actions. | 
					
						
							|  |  |  | 	addrs := make([]common.Address, 50) | 
					
						
							|  |  |  | 	for i := range addrs { | 
					
						
							|  |  |  | 		addrs[i][0] = byte(i) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	actions := make([]testAction, size) | 
					
						
							|  |  |  | 	for i := range actions { | 
					
						
							|  |  |  | 		addr := addrs[r.Intn(len(addrs))] | 
					
						
							|  |  |  | 		actions[i] = newTestAction(addr, r) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Generate snapshot indexes. | 
					
						
							|  |  |  | 	nsnapshots := int(math.Sqrt(float64(size))) | 
					
						
							|  |  |  | 	if size > 0 && nsnapshots == 0 { | 
					
						
							|  |  |  | 		nsnapshots = 1 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	snapshots := make([]int, nsnapshots) | 
					
						
							|  |  |  | 	snaplen := len(actions) / nsnapshots | 
					
						
							|  |  |  | 	for i := range snapshots { | 
					
						
							|  |  |  | 		// Try to place the snapshots some number of actions apart from each other. | 
					
						
							|  |  |  | 		snapshots[i] = (i * snaplen) + r.Intn(snaplen) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return reflect.ValueOf(&snapshotTest{addrs, actions, snapshots, nil}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (test *snapshotTest) String() string { | 
					
						
							|  |  |  | 	out := new(bytes.Buffer) | 
					
						
							|  |  |  | 	sindex := 0 | 
					
						
							|  |  |  | 	for i, action := range test.actions { | 
					
						
							|  |  |  | 		if len(test.snapshots) > sindex && i == test.snapshots[sindex] { | 
					
						
							|  |  |  | 			fmt.Fprintf(out, "---- snapshot %d ----\n", sindex) | 
					
						
							|  |  |  | 			sindex++ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		fmt.Fprintf(out, "%4d: %s\n", i, action.name) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return out.String() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (test *snapshotTest) run() bool { | 
					
						
							|  |  |  | 	// Run all actions and create snapshots. | 
					
						
							|  |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 		state, _     = New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 		snapshotRevs = make([]int, len(test.snapshots)) | 
					
						
							|  |  |  | 		sindex       = 0 | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	for i, action := range test.actions { | 
					
						
							|  |  |  | 		if len(test.snapshots) > sindex && i == test.snapshots[sindex] { | 
					
						
							|  |  |  | 			snapshotRevs[sindex] = state.Snapshot() | 
					
						
							|  |  |  | 			sindex++ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		action.fn(action, state) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Revert all snapshots in reverse order. Each revert must yield a state | 
					
						
							|  |  |  | 	// that is equivalent to fresh state with all actions up the snapshot applied. | 
					
						
							|  |  |  | 	for sindex--; sindex >= 0; sindex-- { | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 		checkstate, _ := New(common.Hash{}, state.Database()) | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 		for _, action := range test.actions[:test.snapshots[sindex]] { | 
					
						
							|  |  |  | 			action.fn(action, checkstate) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		state.RevertToSnapshot(snapshotRevs[sindex]) | 
					
						
							|  |  |  | 		if err := test.checkEqual(state, checkstate); err != nil { | 
					
						
							|  |  |  | 			test.err = fmt.Errorf("state mismatch after revert to snapshot %d\n%v", sindex, err) | 
					
						
							|  |  |  | 			return false | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // checkEqual checks that methods of state and checkstate return the same values. | 
					
						
							|  |  |  | func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { | 
					
						
							|  |  |  | 	for _, addr := range test.addrs { | 
					
						
							|  |  |  | 		var err error | 
					
						
							|  |  |  | 		checkeq := func(op string, a, b interface{}) bool { | 
					
						
							|  |  |  | 			if err == nil && !reflect.DeepEqual(a, b) { | 
					
						
							|  |  |  | 				err = fmt.Errorf("got %s(%s) == %v, want %v", op, addr.Hex(), a, b) | 
					
						
							|  |  |  | 				return false | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Check basic accessor methods. | 
					
						
							|  |  |  | 		checkeq("Exist", state.Exist(addr), checkstate.Exist(addr)) | 
					
						
							| 
									
										
										
										
											2016-10-05 22:22:31 +02:00
										 |  |  | 		checkeq("HasSuicided", state.HasSuicided(addr), checkstate.HasSuicided(addr)) | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 		checkeq("GetBalance", state.GetBalance(addr), checkstate.GetBalance(addr)) | 
					
						
							|  |  |  | 		checkeq("GetNonce", state.GetNonce(addr), checkstate.GetNonce(addr)) | 
					
						
							|  |  |  | 		checkeq("GetCode", state.GetCode(addr), checkstate.GetCode(addr)) | 
					
						
							|  |  |  | 		checkeq("GetCodeHash", state.GetCodeHash(addr), checkstate.GetCodeHash(addr)) | 
					
						
							|  |  |  | 		checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr)) | 
					
						
							|  |  |  | 		// Check storage. | 
					
						
							| 
									
										
										
										
											2017-02-22 23:29:59 +01:00
										 |  |  | 		if obj := state.getStateObject(addr); obj != nil { | 
					
						
							| 
									
										
										
										
											2018-09-18 16:24:35 +03:00
										 |  |  | 			state.ForEachStorage(addr, func(key, value common.Hash) bool { | 
					
						
							|  |  |  | 				return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2018-09-18 16:24:35 +03:00
										 |  |  | 			checkstate.ForEachStorage(addr, func(key, value common.Hash) bool { | 
					
						
							|  |  |  | 				return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-13 13:47:27 +02:00
										 |  |  | 	if state.GetRefund() != checkstate.GetRefund() { | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 		return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d", | 
					
						
							|  |  |  | 			state.GetRefund(), checkstate.GetRefund()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if !reflect.DeepEqual(state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{})) { | 
					
						
							|  |  |  | 		return fmt.Errorf("got GetLogs(common.Hash{}) == %v, want GetLogs(common.Hash{}) == %v", | 
					
						
							|  |  |  | 			state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{})) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-11-24 16:24:04 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-27 15:57:06 +02:00
										 |  |  | func (s *StateSuite) TestTouchDelete(c *check.C) { | 
					
						
							|  |  |  | 	s.state.GetOrNewStateObject(common.Address{}) | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 	root, _ := s.state.Commit(false) | 
					
						
							| 
									
										
										
										
											2017-06-27 15:57:06 +02:00
										 |  |  | 	s.state.Reset(root) | 
					
						
							| 
									
										
										
										
											2016-11-24 16:24:04 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-27 15:57:06 +02:00
										 |  |  | 	snapshot := s.state.Snapshot() | 
					
						
							|  |  |  | 	s.state.AddBalance(common.Address{}, new(big.Int)) | 
					
						
							| 
									
										
										
										
											2017-10-01 21:07:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-27 15:13:30 +03:00
										 |  |  | 	if len(s.state.journal.dirties) != 1 { | 
					
						
							| 
									
										
										
										
											2017-06-27 15:57:06 +02:00
										 |  |  | 		c.Fatal("expected one dirty state object") | 
					
						
							| 
									
										
										
										
											2016-11-24 16:24:04 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-06-27 15:57:06 +02:00
										 |  |  | 	s.state.RevertToSnapshot(snapshot) | 
					
						
							| 
									
										
										
										
											2018-03-27 15:13:30 +03:00
										 |  |  | 	if len(s.state.journal.dirties) != 0 { | 
					
						
							| 
									
										
										
										
											2017-06-27 15:57:06 +02:00
										 |  |  | 		c.Fatal("expected no dirty state object") | 
					
						
							| 
									
										
										
										
											2016-11-24 16:24:04 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-04-10 20:59:07 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // TestCopyOfCopy tests that modified objects are carried over to the copy, and the copy of the copy. | 
					
						
							|  |  |  | // See https://github.com/ethereum/go-ethereum/pull/15225#issuecomment-380191512 | 
					
						
							|  |  |  | func TestCopyOfCopy(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2018-09-24 15:57:49 +03:00
										 |  |  | 	sdb, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) | 
					
						
							| 
									
										
										
										
											2018-04-10 20:59:07 +02:00
										 |  |  | 	addr := common.HexToAddress("aaaa") | 
					
						
							|  |  |  | 	sdb.SetBalance(addr, big.NewInt(42)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if got := sdb.Copy().GetBalance(addr).Uint64(); got != 42 { | 
					
						
							|  |  |  | 		t.Fatalf("1st copy fail, expected 42, got %v", got) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if got := sdb.Copy().Copy().GetBalance(addr).Uint64(); got != 42 { | 
					
						
							|  |  |  | 		t.Fatalf("2nd copy fail, expected 42, got %v", got) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |