github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/core/state/statedb_test.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:34</date>
    10  //</624342618091819008>
    11  
    12  
    13  package state
    14  
    15  import (
    16  	"bytes"
    17  	"encoding/binary"
    18  	"fmt"
    19  	"math"
    20  	"math/big"
    21  	"math/rand"
    22  	"reflect"
    23  	"strings"
    24  	"testing"
    25  	"testing/quick"
    26  
    27  	check "gopkg.in/check.v1"
    28  
    29  	"github.com/ethereum/go-ethereum/common"
    30  	"github.com/ethereum/go-ethereum/core/types"
    31  	"github.com/ethereum/go-ethereum/ethdb"
    32  )
    33  
    34  //更新状态trie之前不泄漏任何数据库写入的测试
    35  //实际提交状态。
    36  func TestUpdateLeaks(t *testing.T) {
    37  //创建空状态数据库
    38  	db := ethdb.NewMemDatabase()
    39  	state, _ := New(common.Hash{}, NewDatabase(db))
    40  
    41  //用一些帐户更新它
    42  	for i := byte(0); i < 255; i++ {
    43  		addr := common.BytesToAddress([]byte{i})
    44  		state.AddBalance(addr, big.NewInt(int64(11*i)))
    45  		state.SetNonce(addr, uint64(42*i))
    46  		if i%2 == 0 {
    47  			state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i}))
    48  		}
    49  		if i%3 == 0 {
    50  			state.SetCode(addr, []byte{i, i, i, i, i})
    51  		}
    52  		state.IntermediateRoot(false)
    53  	}
    54  //确保没有数据泄漏到数据库中
    55  	for _, key := range db.Keys() {
    56  		value, _ := db.Get(key)
    57  		t.Errorf("State leaked into database: %x -> %x", key, value)
    58  	}
    59  }
    60  
    61  //测试对象的中间状态是否未存储到数据库中,
    62  //只有一个在提交之前。
    63  func TestIntermediateLeaks(t *testing.T) {
    64  //创建两个状态数据库,一个转换为最终状态,另一个从一开始就是最终状态
    65  	transDb := ethdb.NewMemDatabase()
    66  	finalDb := ethdb.NewMemDatabase()
    67  	transState, _ := New(common.Hash{}, NewDatabase(transDb))
    68  	finalState, _ := New(common.Hash{}, NewDatabase(finalDb))
    69  
    70  	modify := func(state *StateDB, addr common.Address, i, tweak byte) {
    71  		state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak)))
    72  		state.SetNonce(addr, uint64(42*i+tweak))
    73  		if i%2 == 0 {
    74  			state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{})
    75  			state.SetState(addr, common.Hash{i, i, i, tweak}, common.Hash{i, i, i, i, tweak})
    76  		}
    77  		if i%3 == 0 {
    78  			state.SetCode(addr, []byte{i, i, i, i, i, tweak})
    79  		}
    80  	}
    81  
    82  //修改瞬态。
    83  	for i := byte(0); i < 255; i++ {
    84  		modify(transState, common.Address{byte(i)}, i, 0)
    85  	}
    86  //将修改写入trie。
    87  	transState.IntermediateRoot(false)
    88  
    89  //用临时数据库中的新值覆盖所有数据。
    90  	for i := byte(0); i < 255; i++ {
    91  		modify(transState, common.Address{byte(i)}, i, 99)
    92  		modify(finalState, common.Address{byte(i)}, i, 99)
    93  	}
    94  
    95  //提交并交叉检查数据库。
    96  	if _, err := transState.Commit(false); err != nil {
    97  		t.Fatalf("failed to commit transition state: %v", err)
    98  	}
    99  	if _, err := finalState.Commit(false); err != nil {
   100  		t.Fatalf("failed to commit final state: %v", err)
   101  	}
   102  	for _, key := range finalDb.Keys() {
   103  		if _, err := transDb.Get(key); err != nil {
   104  			val, _ := finalDb.Get(key)
   105  			t.Errorf("entry missing from the transition database: %x -> %x", key, val)
   106  		}
   107  	}
   108  	for _, key := range transDb.Keys() {
   109  		if _, err := finalDb.Get(key); err != nil {
   110  			val, _ := transDb.Get(key)
   111  			t.Errorf("extra entry in the transition database: %x -> %x", key, val)
   112  		}
   113  	}
   114  }
   115  
   116  //testcopy测试复制statedb对象确实会使
   117  //相互独立的副本。此测试是对
   118  //https://github.com/ethereum/go-ethereum/pull/15549。
   119  func TestCopy(t *testing.T) {
   120  //创建随机状态测试以“独立”复制和修改
   121  	orig, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
   122  
   123  	for i := byte(0); i < 255; i++ {
   124  		obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   125  		obj.AddBalance(big.NewInt(int64(i)))
   126  		orig.updateStateObject(obj)
   127  	}
   128  	orig.Finalise(false)
   129  
   130  //复制状态,在内存中修改
   131  	copy := orig.Copy()
   132  
   133  	for i := byte(0); i < 255; i++ {
   134  		origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   135  		copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   136  
   137  		origObj.AddBalance(big.NewInt(2 * int64(i)))
   138  		copyObj.AddBalance(big.NewInt(3 * int64(i)))
   139  
   140  		orig.updateStateObject(origObj)
   141  		copy.updateStateObject(copyObj)
   142  	}
   143  //同时完成两个方面的更改
   144  	done := make(chan struct{})
   145  	go func() {
   146  		orig.Finalise(true)
   147  		close(done)
   148  	}()
   149  	copy.Finalise(true)
   150  	<-done
   151  
   152  //验证两个状态是否已独立更新
   153  	for i := byte(0); i < 255; i++ {
   154  		origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   155  		copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   156  
   157  		if want := big.NewInt(3 * int64(i)); origObj.Balance().Cmp(want) != 0 {
   158  			t.Errorf("orig obj %d: balance mismatch: have %v, want %v", i, origObj.Balance(), want)
   159  		}
   160  		if want := big.NewInt(4 * int64(i)); copyObj.Balance().Cmp(want) != 0 {
   161  			t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, copyObj.Balance(), want)
   162  		}
   163  	}
   164  }
   165  
   166  func TestSnapshotRandom(t *testing.T) {
   167  	config := &quick.Config{MaxCount: 1000}
   168  	err := quick.Check((*snapshotTest).run, config)
   169  	if cerr, ok := err.(*quick.CheckError); ok {
   170  		test := cerr.In[0].(*snapshotTest)
   171  		t.Errorf("%v:\n%s", test.err, test)
   172  	} else if err != nil {
   173  		t.Error(err)
   174  	}
   175  }
   176  
   177  //Snapshottest检查恢复statedb快照是否正确撤消所有更改
   178  //由快照捕获。将创建具有伪随机内容的此测试的实例
   179  //通过生成。
   180  //
   181  //试验工作如下:
   182  //
   183  //将创建一个新状态并对其应用所有操作。拍摄了几个快照
   184  //在行动之间。然后测试恢复每个快照。对于每个快照,操作
   185  //在它之前是在一个新鲜的、空的状态下重播的。所有公众的行为
   186  //还原状态的访问器方法必须与等效的返回值匹配
   187  //方法。
   188  type snapshotTest struct {
   189  addrs     []common.Address //所有帐户地址
   190  actions   []testAction     //对国家的修改
   191  snapshots []int            //执行快照的操作索引
   192  err       error            //通过此字段报告故障详细信息
   193  }
   194  
   195  type testAction struct {
   196  	name   string
   197  	fn     func(testAction, *StateDB)
   198  	args   []int64
   199  	noAddr bool
   200  }
   201  
   202  //NewTestAction创建一个更改状态的随机操作。
   203  func newTestAction(addr common.Address, r *rand.Rand) testAction {
   204  	actions := []testAction{
   205  		{
   206  			name: "SetBalance",
   207  			fn: func(a testAction, s *StateDB) {
   208  				s.SetBalance(addr, big.NewInt(a.args[0]))
   209  			},
   210  			args: make([]int64, 1),
   211  		},
   212  		{
   213  			name: "AddBalance",
   214  			fn: func(a testAction, s *StateDB) {
   215  				s.AddBalance(addr, big.NewInt(a.args[0]))
   216  			},
   217  			args: make([]int64, 1),
   218  		},
   219  		{
   220  			name: "SetNonce",
   221  			fn: func(a testAction, s *StateDB) {
   222  				s.SetNonce(addr, uint64(a.args[0]))
   223  			},
   224  			args: make([]int64, 1),
   225  		},
   226  		{
   227  			name: "SetState",
   228  			fn: func(a testAction, s *StateDB) {
   229  				var key, val common.Hash
   230  				binary.BigEndian.PutUint16(key[:], uint16(a.args[0]))
   231  				binary.BigEndian.PutUint16(val[:], uint16(a.args[1]))
   232  				s.SetState(addr, key, val)
   233  			},
   234  			args: make([]int64, 2),
   235  		},
   236  		{
   237  			name: "SetCode",
   238  			fn: func(a testAction, s *StateDB) {
   239  				code := make([]byte, 16)
   240  				binary.BigEndian.PutUint64(code, uint64(a.args[0]))
   241  				binary.BigEndian.PutUint64(code[8:], uint64(a.args[1]))
   242  				s.SetCode(addr, code)
   243  			},
   244  			args: make([]int64, 2),
   245  		},
   246  		{
   247  			name: "CreateAccount",
   248  			fn: func(a testAction, s *StateDB) {
   249  				s.CreateAccount(addr)
   250  			},
   251  		},
   252  		{
   253  			name: "Suicide",
   254  			fn: func(a testAction, s *StateDB) {
   255  				s.Suicide(addr)
   256  			},
   257  		},
   258  		{
   259  			name: "AddRefund",
   260  			fn: func(a testAction, s *StateDB) {
   261  				s.AddRefund(uint64(a.args[0]))
   262  			},
   263  			args:   make([]int64, 1),
   264  			noAddr: true,
   265  		},
   266  		{
   267  			name: "AddLog",
   268  			fn: func(a testAction, s *StateDB) {
   269  				data := make([]byte, 2)
   270  				binary.BigEndian.PutUint16(data, uint16(a.args[0]))
   271  				s.AddLog(&types.Log{Address: addr, Data: data})
   272  			},
   273  			args: make([]int64, 1),
   274  		},
   275  	}
   276  	action := actions[r.Intn(len(actions))]
   277  	var nameargs []string
   278  	if !action.noAddr {
   279  		nameargs = append(nameargs, addr.Hex())
   280  	}
   281  	for _, i := range action.args {
   282  		action.args[i] = rand.Int63n(100)
   283  		nameargs = append(nameargs, fmt.Sprint(action.args[i]))
   284  	}
   285  	action.name += strings.Join(nameargs, ", ")
   286  	return action
   287  }
   288  
   289  //generate返回给定大小的新快照测试。所有的随机性都是
   290  //源自R
   291  func (*snapshotTest) Generate(r *rand.Rand, size int) reflect.Value {
   292  //生成随机动作。
   293  	addrs := make([]common.Address, 50)
   294  	for i := range addrs {
   295  		addrs[i][0] = byte(i)
   296  	}
   297  	actions := make([]testAction, size)
   298  	for i := range actions {
   299  		addr := addrs[r.Intn(len(addrs))]
   300  		actions[i] = newTestAction(addr, r)
   301  	}
   302  //生成快照索引。
   303  	nsnapshots := int(math.Sqrt(float64(size)))
   304  	if size > 0 && nsnapshots == 0 {
   305  		nsnapshots = 1
   306  	}
   307  	snapshots := make([]int, nsnapshots)
   308  	snaplen := len(actions) / nsnapshots
   309  	for i := range snapshots {
   310  //试着把快照放在一些动作之间。
   311  		snapshots[i] = (i * snaplen) + r.Intn(snaplen)
   312  	}
   313  	return reflect.ValueOf(&snapshotTest{addrs, actions, snapshots, nil})
   314  }
   315  
   316  func (test *snapshotTest) String() string {
   317  	out := new(bytes.Buffer)
   318  	sindex := 0
   319  	for i, action := range test.actions {
   320  		if len(test.snapshots) > sindex && i == test.snapshots[sindex] {
   321  			fmt.Fprintf(out, "---- snapshot %d ----\n", sindex)
   322  			sindex++
   323  		}
   324  		fmt.Fprintf(out, "%4d: %s\n", i, action.name)
   325  	}
   326  	return out.String()
   327  }
   328  
   329  func (test *snapshotTest) run() bool {
   330  //运行所有操作并创建快照。
   331  	var (
   332  		state, _     = New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
   333  		snapshotRevs = make([]int, len(test.snapshots))
   334  		sindex       = 0
   335  	)
   336  	for i, action := range test.actions {
   337  		if len(test.snapshots) > sindex && i == test.snapshots[sindex] {
   338  			snapshotRevs[sindex] = state.Snapshot()
   339  			sindex++
   340  		}
   341  		action.fn(action, state)
   342  	}
   343  //按相反顺序还原所有快照。每个还原都必须产生一个状态
   344  //这相当于应用了快照上的所有操作后的新状态。
   345  	for sindex--; sindex >= 0; sindex-- {
   346  		checkstate, _ := New(common.Hash{}, state.Database())
   347  		for _, action := range test.actions[:test.snapshots[sindex]] {
   348  			action.fn(action, checkstate)
   349  		}
   350  		state.RevertToSnapshot(snapshotRevs[sindex])
   351  		if err := test.checkEqual(state, checkstate); err != nil {
   352  			test.err = fmt.Errorf("state mismatch after revert to snapshot %d\n%v", sindex, err)
   353  			return false
   354  		}
   355  	}
   356  	return true
   357  }
   358  
   359  //checkequal检查state和checkstate方法是否返回相同的值。
   360  func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error {
   361  	for _, addr := range test.addrs {
   362  		var err error
   363  		checkeq := func(op string, a, b interface{}) bool {
   364  			if err == nil && !reflect.DeepEqual(a, b) {
   365  				err = fmt.Errorf("got %s(%s) == %v, want %v", op, addr.Hex(), a, b)
   366  				return false
   367  			}
   368  			return true
   369  		}
   370  //检查基本访问器方法。
   371  		checkeq("Exist", state.Exist(addr), checkstate.Exist(addr))
   372  		checkeq("HasSuicided", state.HasSuicided(addr), checkstate.HasSuicided(addr))
   373  		checkeq("GetBalance", state.GetBalance(addr), checkstate.GetBalance(addr))
   374  		checkeq("GetNonce", state.GetNonce(addr), checkstate.GetNonce(addr))
   375  		checkeq("GetCode", state.GetCode(addr), checkstate.GetCode(addr))
   376  		checkeq("GetCodeHash", state.GetCodeHash(addr), checkstate.GetCodeHash(addr))
   377  		checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr))
   378  //检查存储。
   379  		if obj := state.getStateObject(addr); obj != nil {
   380  			state.ForEachStorage(addr, func(key, val common.Hash) bool {
   381  				return checkeq("GetState("+key.Hex()+")", val, checkstate.GetState(addr, key))
   382  			})
   383  			checkstate.ForEachStorage(addr, func(key, checkval common.Hash) bool {
   384  				return checkeq("GetState("+key.Hex()+")", state.GetState(addr, key), checkval)
   385  			})
   386  		}
   387  		if err != nil {
   388  			return err
   389  		}
   390  	}
   391  
   392  	if state.GetRefund() != checkstate.GetRefund() {
   393  		return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d",
   394  			state.GetRefund(), checkstate.GetRefund())
   395  	}
   396  	if !reflect.DeepEqual(state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{})) {
   397  		return fmt.Errorf("got GetLogs(common.Hash{}) == %v, want GetLogs(common.Hash{}) == %v",
   398  			state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{}))
   399  	}
   400  	return nil
   401  }
   402  
   403  func (s *StateSuite) TestTouchDelete(c *check.C) {
   404  	s.state.GetOrNewStateObject(common.Address{})
   405  	root, _ := s.state.Commit(false)
   406  	s.state.Reset(root)
   407  
   408  	snapshot := s.state.Snapshot()
   409  	s.state.AddBalance(common.Address{}, new(big.Int))
   410  
   411  	if len(s.state.journal.dirties) != 1 {
   412  		c.Fatal("expected one dirty state object")
   413  	}
   414  	s.state.RevertToSnapshot(snapshot)
   415  	if len(s.state.journal.dirties) != 0 {
   416  		c.Fatal("expected no dirty state object")
   417  	}
   418  }
   419  
   420  //testcopyofcopy测试修改后的对象将被转移到副本和副本。
   421  //请参见https://github.com/ethereum/go-ethereum/pull/15225_issuecomment-380191512
   422  func TestCopyOfCopy(t *testing.T) {
   423  	sdb, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
   424  	addr := common.HexToAddress("aaaa")
   425  	sdb.SetBalance(addr, big.NewInt(42))
   426  
   427  	if got := sdb.Copy().GetBalance(addr).Uint64(); got != 42 {
   428  		t.Fatalf("1st copy fail, expected 42, got %v", got)
   429  	}
   430  	if got := sdb.Copy().Copy().GetBalance(addr).Uint64(); got != 42 {
   431  		t.Fatalf("2nd copy fail, expected 42, got %v", got)
   432  	}
   433  }
   434