github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/trie/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:45</date>
    10  //</624450123509796864>
    11  
    12  
    13  package trie
    14  
    15  import (
    16  	"bytes"
    17  	"testing"
    18  
    19  	"github.com/ethereum/go-ethereum/common"
    20  	"github.com/ethereum/go-ethereum/ethdb"
    21  )
    22  
    23  //maketesttrie创建一个样本test trie来测试节点重建。
    24  func makeTestTrie() (*Database, *Trie, map[string][]byte) {
    25  //创建空的trie
    26  	triedb := NewDatabase(ethdb.NewMemDatabase())
    27  	trie, _ := New(common.Hash{}, triedb)
    28  
    29  //用任意数据填充它
    30  	content := make(map[string][]byte)
    31  	for i := byte(0); i < 255; i++ {
    32  //在多个键下映射相同的数据
    33  		key, val := common.LeftPadBytes([]byte{1, i}, 32), []byte{i}
    34  		content[string(key)] = val
    35  		trie.Update(key, val)
    36  
    37  		key, val = common.LeftPadBytes([]byte{2, i}, 32), []byte{i}
    38  		content[string(key)] = val
    39  		trie.Update(key, val)
    40  
    41  //添加一些其他数据来填充trie
    42  		for j := byte(3); j < 13; j++ {
    43  			key, val = common.LeftPadBytes([]byte{j, i}, 32), []byte{j, i}
    44  			content[string(key)] = val
    45  			trie.Update(key, val)
    46  		}
    47  	}
    48  	trie.Commit(nil)
    49  
    50  //返回生成的trie
    51  	return triedb, trie, content
    52  }
    53  
    54  //checktrieContents使用预期数据交叉引用重构的trie
    55  //内容图。
    56  func checkTrieContents(t *testing.T, db *Database, root []byte, content map[string][]byte) {
    57  //检查根可用性和trie内容
    58  	trie, err := New(common.BytesToHash(root), db)
    59  	if err != nil {
    60  		t.Fatalf("failed to create trie at %x: %v", root, err)
    61  	}
    62  	if err := checkTrieConsistency(db, common.BytesToHash(root)); err != nil {
    63  		t.Fatalf("inconsistent trie at %x: %v", root, err)
    64  	}
    65  	for key, val := range content {
    66  		if have := trie.Get([]byte(key)); !bytes.Equal(have, val) {
    67  			t.Errorf("entry %x: content mismatch: have %x, want %x", key, have, val)
    68  		}
    69  	}
    70  }
    71  
    72  //checktrieconsibility检查trie中的所有节点是否确实存在。
    73  func checkTrieConsistency(db *Database, root common.Hash) error {
    74  //创建并迭代子节点中的trie
    75  	trie, err := New(root, db)
    76  	if err != nil {
    77  return nil //认为不存在的状态是一致的
    78  	}
    79  	it := trie.NodeIterator(nil)
    80  	for it.Next(true) {
    81  	}
    82  	return it.Error()
    83  }
    84  
    85  //测试空的trie没有计划同步。
    86  func TestEmptySync(t *testing.T) {
    87  	dbA := NewDatabase(ethdb.NewMemDatabase())
    88  	dbB := NewDatabase(ethdb.NewMemDatabase())
    89  	emptyA, _ := New(common.Hash{}, dbA)
    90  	emptyB, _ := New(emptyRoot, dbB)
    91  
    92  	for i, trie := range []*Trie{emptyA, emptyB} {
    93  		if req := NewSync(trie.Hash(), ethdb.NewMemDatabase(), nil).Missing(1); len(req) != 0 {
    94  			t.Errorf("test %d: content requested for empty trie: %v", i, req)
    95  		}
    96  	}
    97  }
    98  
    99  //测试给定根哈希,trie可以在单个线程上迭代同步,
   100  //请求检索任务并一次性返回所有任务。
   101  func TestIterativeSyncIndividual(t *testing.T) { testIterativeSync(t, 1) }
   102  func TestIterativeSyncBatched(t *testing.T)    { testIterativeSync(t, 100) }
   103  
   104  func testIterativeSync(t *testing.T, batch int) {
   105  //创建要复制的随机trie
   106  	srcDb, srcTrie, srcData := makeTestTrie()
   107  
   108  //创建目标trie并与调度程序同步
   109  	diskdb := ethdb.NewMemDatabase()
   110  	triedb := NewDatabase(diskdb)
   111  	sched := NewSync(srcTrie.Hash(), diskdb, nil)
   112  
   113  	queue := append([]common.Hash{}, sched.Missing(batch)...)
   114  	for len(queue) > 0 {
   115  		results := make([]SyncResult, len(queue))
   116  		for i, hash := range queue {
   117  			data, err := srcDb.Node(hash)
   118  			if err != nil {
   119  				t.Fatalf("failed to retrieve node data for %x: %v", hash, err)
   120  			}
   121  			results[i] = SyncResult{hash, data}
   122  		}
   123  		if _, index, err := sched.Process(results); err != nil {
   124  			t.Fatalf("failed to process result #%d: %v", index, err)
   125  		}
   126  		if index, err := sched.Commit(diskdb); err != nil {
   127  			t.Fatalf("failed to commit data #%d: %v", index, err)
   128  		}
   129  		queue = append(queue[:0], sched.Missing(batch)...)
   130  	}
   131  //交叉检查两次尝试是否同步
   132  	checkTrieContents(t, triedb, srcTrie.Root(), srcData)
   133  }
   134  
   135  //测试trie调度程序是否可以正确地重建状态,即使只有
   136  //返回部分结果,其他结果只在稍后发送。
   137  func TestIterativeDelayedSync(t *testing.T) {
   138  //创建要复制的随机trie
   139  	srcDb, srcTrie, srcData := makeTestTrie()
   140  
   141  //创建目标trie并与调度程序同步
   142  	diskdb := ethdb.NewMemDatabase()
   143  	triedb := NewDatabase(diskdb)
   144  	sched := NewSync(srcTrie.Hash(), diskdb, nil)
   145  
   146  	queue := append([]common.Hash{}, sched.Missing(10000)...)
   147  	for len(queue) > 0 {
   148  //只同步一半的计划节点
   149  		results := make([]SyncResult, len(queue)/2+1)
   150  		for i, hash := range queue[:len(results)] {
   151  			data, err := srcDb.Node(hash)
   152  			if err != nil {
   153  				t.Fatalf("failed to retrieve node data for %x: %v", hash, err)
   154  			}
   155  			results[i] = SyncResult{hash, data}
   156  		}
   157  		if _, index, err := sched.Process(results); err != nil {
   158  			t.Fatalf("failed to process result #%d: %v", index, err)
   159  		}
   160  		if index, err := sched.Commit(diskdb); err != nil {
   161  			t.Fatalf("failed to commit data #%d: %v", index, err)
   162  		}
   163  		queue = append(queue[len(results):], sched.Missing(10000)...)
   164  	}
   165  //交叉检查两次尝试是否同步
   166  	checkTrieContents(t, triedb, srcTrie.Root(), srcData)
   167  }
   168  
   169  //测试给定根哈希,trie可以在单个线程上迭代同步,
   170  //请求检索任务并一次性返回所有任务,但是在
   171  //随机顺序。
   172  func TestIterativeRandomSyncIndividual(t *testing.T) { testIterativeRandomSync(t, 1) }
   173  func TestIterativeRandomSyncBatched(t *testing.T)    { testIterativeRandomSync(t, 100) }
   174  
   175  func testIterativeRandomSync(t *testing.T, batch int) {
   176  //创建要复制的随机trie
   177  	srcDb, srcTrie, srcData := makeTestTrie()
   178  
   179  //创建目标trie并与调度程序同步
   180  	diskdb := ethdb.NewMemDatabase()
   181  	triedb := NewDatabase(diskdb)
   182  	sched := NewSync(srcTrie.Hash(), diskdb, nil)
   183  
   184  	queue := make(map[common.Hash]struct{})
   185  	for _, hash := range sched.Missing(batch) {
   186  		queue[hash] = struct{}{}
   187  	}
   188  	for len(queue) > 0 {
   189  //以随机顺序获取所有排队的节点
   190  		results := make([]SyncResult, 0, len(queue))
   191  		for hash := range queue {
   192  			data, err := srcDb.Node(hash)
   193  			if err != nil {
   194  				t.Fatalf("failed to retrieve node data for %x: %v", hash, err)
   195  			}
   196  			results = append(results, SyncResult{hash, data})
   197  		}
   198  //将检索到的结果反馈并将新任务排队
   199  		if _, index, err := sched.Process(results); err != nil {
   200  			t.Fatalf("failed to process result #%d: %v", index, err)
   201  		}
   202  		if index, err := sched.Commit(diskdb); err != nil {
   203  			t.Fatalf("failed to commit data #%d: %v", index, err)
   204  		}
   205  		queue = make(map[common.Hash]struct{})
   206  		for _, hash := range sched.Missing(batch) {
   207  			queue[hash] = struct{}{}
   208  		}
   209  	}
   210  //交叉检查两次尝试是否同步
   211  	checkTrieContents(t, triedb, srcTrie.Root(), srcData)
   212  }
   213  
   214  //测试trie调度程序是否可以正确地重建状态,即使只有
   215  //部分结果会被返回(甚至是随机返回的结果),其他结果只会在稍后发送。
   216  func TestIterativeRandomDelayedSync(t *testing.T) {
   217  //创建要复制的随机trie
   218  	srcDb, srcTrie, srcData := makeTestTrie()
   219  
   220  //创建目标trie并与调度程序同步
   221  	diskdb := ethdb.NewMemDatabase()
   222  	triedb := NewDatabase(diskdb)
   223  	sched := NewSync(srcTrie.Hash(), diskdb, nil)
   224  
   225  	queue := make(map[common.Hash]struct{})
   226  	for _, hash := range sched.Missing(10000) {
   227  		queue[hash] = struct{}{}
   228  	}
   229  	for len(queue) > 0 {
   230  //只同步一半的计划节点,甚至是随机顺序的节点
   231  		results := make([]SyncResult, 0, len(queue)/2+1)
   232  		for hash := range queue {
   233  			data, err := srcDb.Node(hash)
   234  			if err != nil {
   235  				t.Fatalf("failed to retrieve node data for %x: %v", hash, err)
   236  			}
   237  			results = append(results, SyncResult{hash, data})
   238  
   239  			if len(results) >= cap(results) {
   240  				break
   241  			}
   242  		}
   243  //将检索到的结果反馈并将新任务排队
   244  		if _, index, err := sched.Process(results); err != nil {
   245  			t.Fatalf("failed to process result #%d: %v", index, err)
   246  		}
   247  		if index, err := sched.Commit(diskdb); err != nil {
   248  			t.Fatalf("failed to commit data #%d: %v", index, err)
   249  		}
   250  		for _, result := range results {
   251  			delete(queue, result.Hash)
   252  		}
   253  		for _, hash := range sched.Missing(10000) {
   254  			queue[hash] = struct{}{}
   255  		}
   256  	}
   257  //交叉检查两次尝试是否同步
   258  	checkTrieContents(t, triedb, srcTrie.Root(), srcData)
   259  }
   260  
   261  //测试trie-sync不会多次请求节点,即使它们
   262  //有这样的证明人。
   263  func TestDuplicateAvoidanceSync(t *testing.T) {
   264  //创建要复制的随机trie
   265  	srcDb, srcTrie, srcData := makeTestTrie()
   266  
   267  //创建目标trie并与调度程序同步
   268  	diskdb := ethdb.NewMemDatabase()
   269  	triedb := NewDatabase(diskdb)
   270  	sched := NewSync(srcTrie.Hash(), diskdb, nil)
   271  
   272  	queue := append([]common.Hash{}, sched.Missing(0)...)
   273  	requested := make(map[common.Hash]struct{})
   274  
   275  	for len(queue) > 0 {
   276  		results := make([]SyncResult, len(queue))
   277  		for i, hash := range queue {
   278  			data, err := srcDb.Node(hash)
   279  			if err != nil {
   280  				t.Fatalf("failed to retrieve node data for %x: %v", hash, err)
   281  			}
   282  			if _, ok := requested[hash]; ok {
   283  				t.Errorf("hash %x already requested once", hash)
   284  			}
   285  			requested[hash] = struct{}{}
   286  
   287  			results[i] = SyncResult{hash, data}
   288  		}
   289  		if _, index, err := sched.Process(results); err != nil {
   290  			t.Fatalf("failed to process result #%d: %v", index, err)
   291  		}
   292  		if index, err := sched.Commit(diskdb); err != nil {
   293  			t.Fatalf("failed to commit data #%d: %v", index, err)
   294  		}
   295  		queue = append(queue[:0], sched.Missing(0)...)
   296  	}
   297  //交叉检查两次尝试是否同步
   298  	checkTrieContents(t, triedb, srcTrie.Root(), srcData)
   299  }
   300  
   301  //测试在同步过程中的任何时间点,只有完整的子尝试处于
   302  //数据库。
   303  func TestIncompleteSync(t *testing.T) {
   304  //创建要复制的随机trie
   305  	srcDb, srcTrie, _ := makeTestTrie()
   306  
   307  //创建目标trie并与调度程序同步
   308  	diskdb := ethdb.NewMemDatabase()
   309  	triedb := NewDatabase(diskdb)
   310  	sched := NewSync(srcTrie.Hash(), diskdb, nil)
   311  
   312  	added := []common.Hash{}
   313  	queue := append([]common.Hash{}, sched.Missing(1)...)
   314  	for len(queue) > 0 {
   315  //获取一批trie节点
   316  		results := make([]SyncResult, len(queue))
   317  		for i, hash := range queue {
   318  			data, err := srcDb.Node(hash)
   319  			if err != nil {
   320  				t.Fatalf("failed to retrieve node data for %x: %v", hash, err)
   321  			}
   322  			results[i] = SyncResult{hash, data}
   323  		}
   324  //处理每个trie节点
   325  		if _, index, err := sched.Process(results); err != nil {
   326  			t.Fatalf("failed to process result #%d: %v", index, err)
   327  		}
   328  		if index, err := sched.Commit(diskdb); err != nil {
   329  			t.Fatalf("failed to commit data #%d: %v", index, err)
   330  		}
   331  		for _, result := range results {
   332  			added = append(added, result.Hash)
   333  		}
   334  //检查同步trie中的所有已知子尝试是否完成
   335  		for _, root := range added {
   336  			if err := checkTrieConsistency(triedb, root); err != nil {
   337  				t.Fatalf("trie inconsistent: %v", err)
   338  			}
   339  		}
   340  //获取要检索的下一批
   341  		queue = append(queue[:0], sched.Missing(1)...)
   342  	}
   343  //健全性检查是否检测到从数据库中删除任何节点
   344  	for _, node := range added[1:] {
   345  		key := node.Bytes()
   346  		value, _ := diskdb.Get(key)
   347  
   348  		diskdb.Delete(key)
   349  		if err := checkTrieConsistency(triedb, added[0]); err == nil {
   350  			t.Fatalf("trie inconsistency not caught, missing: %x", key)
   351  		}
   352  		diskdb.Put(key, value)
   353  	}
   354  }
   355