github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/core/state/sync_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 19:16:35</date>
    10  //</624450080560123904>
    11  
    12  
    13  package state
    14  
    15  import (
    16  	"bytes"
    17  	"math/big"
    18  	"testing"
    19  
    20  	"github.com/ethereum/go-ethereum/common"
    21  	"github.com/ethereum/go-ethereum/crypto"
    22  	"github.com/ethereum/go-ethereum/ethdb"
    23  	"github.com/ethereum/go-ethereum/trie"
    24  )
    25  
    26  //TestAccount是与状态测试使用的帐户关联的数据。
    27  type testAccount struct {
    28  	address common.Address
    29  	balance *big.Int
    30  	nonce   uint64
    31  	code    []byte
    32  }
    33  
    34  //maketeststate创建一个样本测试状态来测试节点重构。
    35  func makeTestState() (Database, common.Hash, []*testAccount) {
    36  //创建空状态
    37  	db := NewDatabase(ethdb.NewMemDatabase())
    38  	state, _ := New(common.Hash{}, db)
    39  
    40  //用任意数据填充它
    41  	accounts := []*testAccount{}
    42  	for i := byte(0); i < 96; i++ {
    43  		obj := state.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
    44  		acc := &testAccount{address: common.BytesToAddress([]byte{i})}
    45  
    46  		obj.AddBalance(big.NewInt(int64(11 * i)))
    47  		acc.balance = big.NewInt(int64(11 * i))
    48  
    49  		obj.SetNonce(uint64(42 * i))
    50  		acc.nonce = uint64(42 * i)
    51  
    52  		if i%3 == 0 {
    53  			obj.SetCode(crypto.Keccak256Hash([]byte{i, i, i, i, i}), []byte{i, i, i, i, i})
    54  			acc.code = []byte{i, i, i, i, i}
    55  		}
    56  		state.updateStateObject(obj)
    57  		accounts = append(accounts, acc)
    58  	}
    59  	root, _ := state.Commit(false)
    60  
    61  //返回生成的状态
    62  	return db, root, accounts
    63  }
    64  
    65  //checkStateAccounts交叉引用一个重构的状态,该状态应为
    66  //帐户数组。
    67  func checkStateAccounts(t *testing.T, db ethdb.Database, root common.Hash, accounts []*testAccount) {
    68  //检查根可用性和状态内容
    69  	state, err := New(root, NewDatabase(db))
    70  	if err != nil {
    71  		t.Fatalf("failed to create state trie at %x: %v", root, err)
    72  	}
    73  	if err := checkStateConsistency(db, root); err != nil {
    74  		t.Fatalf("inconsistent state trie at %x: %v", root, err)
    75  	}
    76  	for i, acc := range accounts {
    77  		if balance := state.GetBalance(acc.address); balance.Cmp(acc.balance) != 0 {
    78  			t.Errorf("account %d: balance mismatch: have %v, want %v", i, balance, acc.balance)
    79  		}
    80  		if nonce := state.GetNonce(acc.address); nonce != acc.nonce {
    81  			t.Errorf("account %d: nonce mismatch: have %v, want %v", i, nonce, acc.nonce)
    82  		}
    83  		if code := state.GetCode(acc.address); !bytes.Equal(code, acc.code) {
    84  			t.Errorf("account %d: code mismatch: have %x, want %x", i, code, acc.code)
    85  		}
    86  	}
    87  }
    88  
    89  //checktrie一致性检查(sub-)trie中的所有节点是否确实存在。
    90  func checkTrieConsistency(db ethdb.Database, root common.Hash) error {
    91  	if v, _ := db.Get(root[:]); v == nil {
    92  return nil //认为不存在的状态是一致的。
    93  	}
    94  	trie, err := trie.New(root, trie.NewDatabase(db))
    95  	if err != nil {
    96  		return err
    97  	}
    98  	it := trie.NodeIterator(nil)
    99  	for it.Next(true) {
   100  	}
   101  	return it.Error()
   102  }
   103  
   104  //checkstateconsistency检查状态根的所有数据是否存在。
   105  func checkStateConsistency(db ethdb.Database, root common.Hash) error {
   106  //创建并迭代子节点中的状态trie
   107  	if _, err := db.Get(root.Bytes()); err != nil {
   108  return nil //认为不存在的状态是一致的。
   109  	}
   110  	state, err := New(root, NewDatabase(db))
   111  	if err != nil {
   112  		return err
   113  	}
   114  	it := NewNodeIterator(state)
   115  	for it.Next() {
   116  	}
   117  	return it.Error
   118  }
   119  
   120  //测试是否未计划空状态进行同步。
   121  func TestEmptyStateSync(t *testing.T) {
   122  	empty := common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
   123  	if req := NewStateSync(empty, ethdb.NewMemDatabase()).Missing(1); len(req) != 0 {
   124  		t.Errorf("content requested for empty state: %v", req)
   125  	}
   126  }
   127  
   128  //测试给定根哈希,状态可以在单个线程上迭代同步,
   129  //请求检索任务并一次性返回所有任务。
   130  func TestIterativeStateSyncIndividual(t *testing.T) { testIterativeStateSync(t, 1) }
   131  func TestIterativeStateSyncBatched(t *testing.T)    { testIterativeStateSync(t, 100) }
   132  
   133  func testIterativeStateSync(t *testing.T, batch int) {
   134  //创建要复制的随机状态
   135  	srcDb, srcRoot, srcAccounts := makeTestState()
   136  
   137  //Create a destination state and sync with the scheduler
   138  	dstDb := ethdb.NewMemDatabase()
   139  	sched := NewStateSync(srcRoot, dstDb)
   140  
   141  	queue := append([]common.Hash{}, sched.Missing(batch)...)
   142  	for len(queue) > 0 {
   143  		results := make([]trie.SyncResult, len(queue))
   144  		for i, hash := range queue {
   145  			data, err := srcDb.TrieDB().Node(hash)
   146  			if err != nil {
   147  				t.Fatalf("failed to retrieve node data for %x", hash)
   148  			}
   149  			results[i] = trie.SyncResult{Hash: hash, Data: data}
   150  		}
   151  		if _, index, err := sched.Process(results); err != nil {
   152  			t.Fatalf("failed to process result #%d: %v", index, err)
   153  		}
   154  		if index, err := sched.Commit(dstDb); err != nil {
   155  			t.Fatalf("failed to commit data #%d: %v", index, err)
   156  		}
   157  		queue = append(queue[:0], sched.Missing(batch)...)
   158  	}
   159  //交叉检查两个状态是否同步
   160  	checkStateAccounts(t, dstDb, srcRoot, srcAccounts)
   161  }
   162  
   163  //测试trie调度程序是否可以正确地重建状态,即使只有
   164  //partial results are returned, and the others sent only later.
   165  func TestIterativeDelayedStateSync(t *testing.T) {
   166  //创建要复制的随机状态
   167  	srcDb, srcRoot, srcAccounts := makeTestState()
   168  
   169  //创建目标状态并与调度程序同步
   170  	dstDb := ethdb.NewMemDatabase()
   171  	sched := NewStateSync(srcRoot, dstDb)
   172  
   173  	queue := append([]common.Hash{}, sched.Missing(0)...)
   174  	for len(queue) > 0 {
   175  //只同步一半的计划节点
   176  		results := make([]trie.SyncResult, len(queue)/2+1)
   177  		for i, hash := range queue[:len(results)] {
   178  			data, err := srcDb.TrieDB().Node(hash)
   179  			if err != nil {
   180  				t.Fatalf("failed to retrieve node data for %x", hash)
   181  			}
   182  			results[i] = trie.SyncResult{Hash: hash, Data: data}
   183  		}
   184  		if _, index, err := sched.Process(results); err != nil {
   185  			t.Fatalf("failed to process result #%d: %v", index, err)
   186  		}
   187  		if index, err := sched.Commit(dstDb); err != nil {
   188  			t.Fatalf("failed to commit data #%d: %v", index, err)
   189  		}
   190  		queue = append(queue[len(results):], sched.Missing(0)...)
   191  	}
   192  //交叉检查两个状态是否同步
   193  	checkStateAccounts(t, dstDb, srcRoot, srcAccounts)
   194  }
   195  
   196  //测试给定根哈希,trie可以在单个线程上迭代同步,
   197  //请求检索任务并一次性返回所有任务,但是在
   198  //随机顺序。
   199  func TestIterativeRandomStateSyncIndividual(t *testing.T) { testIterativeRandomStateSync(t, 1) }
   200  func TestIterativeRandomStateSyncBatched(t *testing.T)    { testIterativeRandomStateSync(t, 100) }
   201  
   202  func testIterativeRandomStateSync(t *testing.T, batch int) {
   203  //创建要复制的随机状态
   204  	srcDb, srcRoot, srcAccounts := makeTestState()
   205  
   206  //创建目标状态并与调度程序同步
   207  	dstDb := ethdb.NewMemDatabase()
   208  	sched := NewStateSync(srcRoot, dstDb)
   209  
   210  	queue := make(map[common.Hash]struct{})
   211  	for _, hash := range sched.Missing(batch) {
   212  		queue[hash] = struct{}{}
   213  	}
   214  	for len(queue) > 0 {
   215  //以随机顺序获取所有排队的节点
   216  		results := make([]trie.SyncResult, 0, len(queue))
   217  		for hash := range queue {
   218  			data, err := srcDb.TrieDB().Node(hash)
   219  			if err != nil {
   220  				t.Fatalf("failed to retrieve node data for %x", hash)
   221  			}
   222  			results = append(results, trie.SyncResult{Hash: hash, Data: data})
   223  		}
   224  //将检索到的结果反馈并将新任务排队
   225  		if _, index, err := sched.Process(results); err != nil {
   226  			t.Fatalf("failed to process result #%d: %v", index, err)
   227  		}
   228  		if index, err := sched.Commit(dstDb); err != nil {
   229  			t.Fatalf("failed to commit data #%d: %v", index, err)
   230  		}
   231  		queue = make(map[common.Hash]struct{})
   232  		for _, hash := range sched.Missing(batch) {
   233  			queue[hash] = struct{}{}
   234  		}
   235  	}
   236  //交叉检查两个状态是否同步
   237  	checkStateAccounts(t, dstDb, srcRoot, srcAccounts)
   238  }
   239  
   240  //测试trie调度程序是否可以正确地重建状态,即使只有
   241  //部分结果会被返回(甚至是随机返回的结果),其他结果只会在稍后发送。
   242  func TestIterativeRandomDelayedStateSync(t *testing.T) {
   243  //创建要复制的随机状态
   244  	srcDb, srcRoot, srcAccounts := makeTestState()
   245  
   246  //创建目标状态并与调度程序同步
   247  	dstDb := ethdb.NewMemDatabase()
   248  	sched := NewStateSync(srcRoot, dstDb)
   249  
   250  	queue := make(map[common.Hash]struct{})
   251  	for _, hash := range sched.Missing(0) {
   252  		queue[hash] = struct{}{}
   253  	}
   254  	for len(queue) > 0 {
   255  //只同步一半的计划节点,甚至是随机顺序的节点
   256  		results := make([]trie.SyncResult, 0, len(queue)/2+1)
   257  		for hash := range queue {
   258  			delete(queue, hash)
   259  
   260  			data, err := srcDb.TrieDB().Node(hash)
   261  			if err != nil {
   262  				t.Fatalf("failed to retrieve node data for %x", hash)
   263  			}
   264  			results = append(results, trie.SyncResult{Hash: hash, Data: data})
   265  
   266  			if len(results) >= cap(results) {
   267  				break
   268  			}
   269  		}
   270  //将检索到的结果反馈并将新任务排队
   271  		if _, index, err := sched.Process(results); err != nil {
   272  			t.Fatalf("failed to process result #%d: %v", index, err)
   273  		}
   274  		if index, err := sched.Commit(dstDb); err != nil {
   275  			t.Fatalf("failed to commit data #%d: %v", index, err)
   276  		}
   277  		for _, hash := range sched.Missing(0) {
   278  			queue[hash] = struct{}{}
   279  		}
   280  	}
   281  //交叉检查两个状态是否同步
   282  	checkStateAccounts(t, dstDb, srcRoot, srcAccounts)
   283  }
   284  
   285  //测试在同步过程中的任何时间点,只有完整的子尝试处于
   286  //数据库。
   287  func TestIncompleteStateSync(t *testing.T) {
   288  //创建要复制的随机状态
   289  	srcDb, srcRoot, srcAccounts := makeTestState()
   290  
   291  	checkTrieConsistency(srcDb.TrieDB().DiskDB().(ethdb.Database), srcRoot)
   292  
   293  //创建目标状态并与调度程序同步
   294  	dstDb := ethdb.NewMemDatabase()
   295  	sched := NewStateSync(srcRoot, dstDb)
   296  
   297  	added := []common.Hash{}
   298  	queue := append([]common.Hash{}, sched.Missing(1)...)
   299  	for len(queue) > 0 {
   300  //获取一批状态节点
   301  		results := make([]trie.SyncResult, len(queue))
   302  		for i, hash := range queue {
   303  			data, err := srcDb.TrieDB().Node(hash)
   304  			if err != nil {
   305  				t.Fatalf("failed to retrieve node data for %x", hash)
   306  			}
   307  			results[i] = trie.SyncResult{Hash: hash, Data: data}
   308  		}
   309  //处理每个状态节点
   310  		if _, index, err := sched.Process(results); err != nil {
   311  			t.Fatalf("failed to process result #%d: %v", index, err)
   312  		}
   313  		if index, err := sched.Commit(dstDb); err != nil {
   314  			t.Fatalf("failed to commit data #%d: %v", index, err)
   315  		}
   316  		for _, result := range results {
   317  			added = append(added, result.Hash)
   318  		}
   319  //检查到目前为止添加的所有已知子尝试是否完全完成或丢失。
   320  	checkSubtries:
   321  		for _, hash := range added {
   322  			for _, acc := range srcAccounts {
   323  				if hash == crypto.Keccak256Hash(acc.code) {
   324  continue checkSubtries //跳过代码节点的三检。
   325  				}
   326  			}
   327  //无法在此处使用CheckStateConsistency,因为子RIE键可能具有奇数
   328  //长度和撞击力。
   329  			if err := checkTrieConsistency(dstDb, hash); err != nil {
   330  				t.Fatalf("state inconsistent: %v", err)
   331  			}
   332  		}
   333  //获取要检索的下一批
   334  		queue = append(queue[:0], sched.Missing(1)...)
   335  	}
   336  //健全性检查是否检测到从数据库中删除任何节点
   337  	for _, node := range added[1:] {
   338  		key := node.Bytes()
   339  		value, _ := dstDb.Get(key)
   340  
   341  		dstDb.Delete(key)
   342  		if err := checkStateConsistency(dstDb, added[0]); err == nil {
   343  			t.Fatalf("trie inconsistency not caught, missing: %x", key)
   344  		}
   345  		dstDb.Put(key, value)
   346  	}
   347  }
   348