github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/trie/sync.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  //</624450123451076608>
    11  
    12  
    13  package trie
    14  
    15  import (
    16  	"errors"
    17  	"fmt"
    18  
    19  	"github.com/ethereum/go-ethereum/common"
    20  	"github.com/ethereum/go-ethereum/common/prque"
    21  	"github.com/ethereum/go-ethereum/ethdb"
    22  )
    23  
    24  //当请求trie-sync处理
    25  //它没有请求的节点。
    26  var ErrNotRequested = errors.New("not requested")
    27  
    28  //当请求trie-sync处理
    29  //它以前已经处理过的节点。
    30  var ErrAlreadyProcessed = errors.New("already processed")
    31  
    32  //请求表示预定的或已在飞行中的状态检索请求。
    33  type request struct {
    34  hash common.Hash //要检索的节点数据内容的哈希
    35  data []byte      //节点的数据内容,缓存到所有子树完成
    36  raw  bool        //这是原始条目(代码)还是trie节点
    37  
    38  parents []*request //引用此条目的父状态节点(完成时通知所有节点)
    39  depth   int        //Trie中的深度级别节点的位置可优先考虑DFS
    40  deps    int        //允许提交此节点之前的依赖项数
    41  
    42  callback LeafCallback //调用此分支上的叶节点
    43  }
    44  
    45  //SyncResult是一个简单的列表,用于返回丢失的节点及其请求
    46  //散列。
    47  type SyncResult struct {
    48  Hash common.Hash //原始未知trie节点的哈希
    49  Data []byte      //检索节点的数据内容
    50  }
    51  
    52  //SyncMembatch是成功下载但尚未下载的内存缓冲区。
    53  //保留的数据项。
    54  type syncMemBatch struct {
    55  batch map[common.Hash][]byte //内存中最近完成的项的membatch
    56  order []common.Hash          //完成订单以防止无序数据丢失
    57  }
    58  
    59  //newsyncmembatch为尚未持久化的trie节点分配新的内存缓冲区。
    60  func newSyncMemBatch() *syncMemBatch {
    61  	return &syncMemBatch{
    62  		batch: make(map[common.Hash][]byte),
    63  		order: make([]common.Hash, 0, 256),
    64  	}
    65  }
    66  
    67  //同步是主要的状态三同步调度程序,它提供了
    68  //要检索的trie哈希未知,接受与所述哈希关联的节点数据
    69  //一步一步地重建Trie,直到全部完成。
    70  type Sync struct {
    71  database DatabaseReader           //用于检查现有条目的持久数据库
    72  membatch *syncMemBatch            //内存缓冲区以避免频繁的数据库写入
    73  requests map[common.Hash]*request //与密钥哈希相关的挂起请求
    74  queue    *prque.Prque             //具有挂起请求的优先级队列
    75  }
    76  
    77  //newsync创建一个新的trie数据下载调度程序。
    78  func NewSync(root common.Hash, database DatabaseReader, callback LeafCallback) *Sync {
    79  	ts := &Sync{
    80  		database: database,
    81  		membatch: newSyncMemBatch(),
    82  		requests: make(map[common.Hash]*request),
    83  		queue:    prque.New(nil),
    84  	}
    85  	ts.AddSubTrie(root, 0, common.Hash{}, callback)
    86  	return ts
    87  }
    88  
    89  //addsubrie将一个新的trie注册到同步代码,根位于指定的父级。
    90  func (s *Sync) AddSubTrie(root common.Hash, depth int, parent common.Hash, callback LeafCallback) {
    91  //如果Trie为空或已知,则短路
    92  	if root == emptyRoot {
    93  		return
    94  	}
    95  	if _, ok := s.membatch.batch[root]; ok {
    96  		return
    97  	}
    98  	key := root.Bytes()
    99  	blob, _ := s.database.Get(key)
   100  	if local, err := decodeNode(key, blob, 0); local != nil && err == nil {
   101  		return
   102  	}
   103  //组装新的Sub-Trie同步请求
   104  	req := &request{
   105  		hash:     root,
   106  		depth:    depth,
   107  		callback: callback,
   108  	}
   109  //如果此子目录有指定的父目录,请将它们链接在一起
   110  	if parent != (common.Hash{}) {
   111  		ancestor := s.requests[parent]
   112  		if ancestor == nil {
   113  			panic(fmt.Sprintf("sub-trie ancestor not found: %x", parent))
   114  		}
   115  		ancestor.deps++
   116  		req.parents = append(req.parents, ancestor)
   117  	}
   118  	s.schedule(req)
   119  }
   120  
   121  //addrawentry计划直接检索不应
   122  //解释为trie节点,但被接受并存储到数据库中
   123  //事实也是如此。此方法的目标是支持各种状态元数据检索(例如
   124  //合同代码)。
   125  func (s *Sync) AddRawEntry(hash common.Hash, depth int, parent common.Hash) {
   126  //如果条目为空或已知,则短路
   127  	if hash == emptyState {
   128  		return
   129  	}
   130  	if _, ok := s.membatch.batch[hash]; ok {
   131  		return
   132  	}
   133  	if ok, _ := s.database.Has(hash.Bytes()); ok {
   134  		return
   135  	}
   136  //组装新的Sub-Trie同步请求
   137  	req := &request{
   138  		hash:  hash,
   139  		raw:   true,
   140  		depth: depth,
   141  	}
   142  //如果此子目录有指定的父目录,请将它们链接在一起
   143  	if parent != (common.Hash{}) {
   144  		ancestor := s.requests[parent]
   145  		if ancestor == nil {
   146  			panic(fmt.Sprintf("raw-entry ancestor not found: %x", parent))
   147  		}
   148  		ancestor.deps++
   149  		req.parents = append(req.parents, ancestor)
   150  	}
   151  	s.schedule(req)
   152  }
   153  
   154  //Missing从trie中检索已知的丢失节点以进行检索。
   155  func (s *Sync) Missing(max int) []common.Hash {
   156  	requests := []common.Hash{}
   157  	for !s.queue.Empty() && (max == 0 || len(requests) < max) {
   158  		requests = append(requests, s.queue.PopItem().(common.Hash))
   159  	}
   160  	return requests
   161  }
   162  
   163  //进程注入一批检索到的trie节点数据,如果有什么返回
   164  //已提交到数据库,如果处理
   165  //它失败了。
   166  func (s *Sync) Process(results []SyncResult) (bool, int, error) {
   167  	committed := false
   168  
   169  	for i, item := range results {
   170  //如果该项目没有被要求,请退出。
   171  		request := s.requests[item.Hash]
   172  		if request == nil {
   173  			return committed, i, ErrNotRequested
   174  		}
   175  		if request.data != nil {
   176  			return committed, i, ErrAlreadyProcessed
   177  		}
   178  //如果该项是原始输入请求,则直接提交
   179  		if request.raw {
   180  			request.data = item.Data
   181  			s.commit(request)
   182  			committed = true
   183  			continue
   184  		}
   185  //解码节点数据内容并更新请求
   186  		node, err := decodeNode(item.Hash[:], item.Data, 0)
   187  		if err != nil {
   188  			return committed, i, err
   189  		}
   190  		request.data = item.Data
   191  
   192  //为所有子节点创建和调度请求
   193  		requests, err := s.children(request, node)
   194  		if err != nil {
   195  			return committed, i, err
   196  		}
   197  		if len(requests) == 0 && request.deps == 0 {
   198  			s.commit(request)
   199  			committed = true
   200  			continue
   201  		}
   202  		request.deps += len(requests)
   203  		for _, child := range requests {
   204  			s.schedule(child)
   205  		}
   206  	}
   207  	return committed, 0, nil
   208  }
   209  
   210  //commit将存储在内部membatch中的数据刷新为persistent
   211  //存储,返回写入的项目数和发生的任何错误。
   212  func (s *Sync) Commit(dbw ethdb.Putter) (int, error) {
   213  //将membatch转储到数据库dbw中
   214  	for i, key := range s.membatch.order {
   215  		if err := dbw.Put(key[:], s.membatch.batch[key]); err != nil {
   216  			return i, err
   217  		}
   218  	}
   219  	written := len(s.membatch.order)
   220  
   221  //删除membatch数据并返回
   222  	s.membatch = newSyncMemBatch()
   223  	return written, nil
   224  }
   225  
   226  //Pending返回当前等待下载的状态条目数。
   227  func (s *Sync) Pending() int {
   228  	return len(s.requests)
   229  }
   230  
   231  //计划将新的状态检索请求插入提取队列。如果有
   232  //已经是此节点的挂起请求,新请求将被丢弃。
   233  //只有一个父引用添加到旧的引用中。
   234  func (s *Sync) schedule(req *request) {
   235  //如果我们已经请求这个节点,添加一个新的引用并停止
   236  	if old, ok := s.requests[req.hash]; ok {
   237  		old.parents = append(old.parents, req.parents...)
   238  		return
   239  	}
   240  //为以后的检索安排请求
   241  	s.queue.Push(req.hash, int64(req.depth))
   242  	s.requests[req.hash] = req
   243  }
   244  
   245  //children为将来检索一个state trie项中所有丢失的子项
   246  //检索调度。
   247  func (s *Sync) children(req *request, object node) ([]*request, error) {
   248  //收集节点的所有子节点,无论是否已知,都不相关
   249  	type child struct {
   250  		node  node
   251  		depth int
   252  	}
   253  	children := []child{}
   254  
   255  	switch node := (object).(type) {
   256  	case *shortNode:
   257  		children = []child{{
   258  			node:  node.Val,
   259  			depth: req.depth + len(node.Key),
   260  		}}
   261  	case *fullNode:
   262  		for i := 0; i < 17; i++ {
   263  			if node.Children[i] != nil {
   264  				children = append(children, child{
   265  					node:  node.Children[i],
   266  					depth: req.depth + 1,
   267  				})
   268  			}
   269  		}
   270  	default:
   271  		panic(fmt.Sprintf("unknown node: %+v", node))
   272  	}
   273  //循环访问子级,并请求所有未知的子级
   274  	requests := make([]*request, 0, len(children))
   275  	for _, child := range children {
   276  //通知任何外部观察程序新的键/值节点
   277  		if req.callback != nil {
   278  			if node, ok := (child.node).(valueNode); ok {
   279  				if err := req.callback(node, req.hash); err != nil {
   280  					return nil, err
   281  				}
   282  			}
   283  		}
   284  //如果子节点引用另一个节点,请解析或调度
   285  		if node, ok := (child.node).(hashNode); ok {
   286  //尝试从本地数据库解析节点
   287  			hash := common.BytesToHash(node)
   288  			if _, ok := s.membatch.batch[hash]; ok {
   289  				continue
   290  			}
   291  			if ok, _ := s.database.Has(node); ok {
   292  				continue
   293  			}
   294  //本地未知节点,检索计划
   295  			requests = append(requests, &request{
   296  				hash:     hash,
   297  				parents:  []*request{req},
   298  				depth:    child.depth,
   299  				callback: req.callback,
   300  			})
   301  		}
   302  	}
   303  	return requests, nil
   304  }
   305  
   306  //提交完成检索请求并将其存储到membatch中。如果有的话
   307  //在由于这个提交而完成的引用父请求中,它们也是
   308  //承诺自己。
   309  func (s *Sync) commit(req *request) (err error) {
   310  //将节点内容写入membatch
   311  	s.membatch.batch[req.hash] = req.data
   312  	s.membatch.order = append(s.membatch.order, req.hash)
   313  
   314  	delete(s.requests, req.hash)
   315  
   316  //检查所有家长是否完成
   317  	for _, parent := range req.parents {
   318  		parent.deps--
   319  		if parent.deps == 0 {
   320  			if err := s.commit(parent); err != nil {
   321  				return err
   322  			}
   323  		}
   324  	}
   325  	return nil
   326  }
   327