github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/bmt/bmt.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:43</date>
    10  //</624450112587829248>
    11  
    12  
    13  //包bmt提供了一个用于swarm块散列的二进制merkle树实现
    14  package bmt
    15  
    16  import (
    17  	"fmt"
    18  	"hash"
    19  	"strings"
    20  	"sync"
    21  	"sync/atomic"
    22  )
    23  
    24  /*
    25  binary merkle tree hash是一个针对有限大小的任意数据块的哈希函数。
    26  它被定义为在固定大小的段上构建的二进制merkle树的根散列
    27  使用任何基哈希函数(例如,keccak 256 sha3)的底层块。
    28  数据长度小于固定大小的块被散列,就像它们没有填充一样。
    29  
    30  BMT散列被用作群中的块散列函数,而块散列函数又是
    31  128分支群哈希http://swarm guide.readthedocs.io/en/latest/architecture.html swarm哈希
    32  
    33  BMT最适合提供紧凑的包含证明,即证明
    34  段是从特定偏移量开始的块的子字符串。
    35  基础段的大小固定为基哈希(称为分辨率)的大小
    36  在bmt散列中),使用keccak256 sha3散列为32个字节,evm字大小为链上bmt验证优化。
    37  以及群散列的Merkle树中包含证明的最佳散列大小。
    38  
    39  提供了两种实现:
    40  
    41  *refhasher针对代码简单性进行了优化,是一种参考实现。
    42    这很容易理解
    43  *哈希优化了速度,利用了最低限度的并发性
    44    协调并发例程的控制结构
    45  
    46    bmt hasher实现以下接口
    47   *标准golang hash.hash-同步,可重复使用
    48   *swarmhash-提供跨度
    49   *IO.WRITER-从左到右同步数据编写器
    50   *AsyncWriter-并发节写入和异步SUM调用
    51  **/
    52  
    53  
    54  const (
    55  //池大小是散列程序使用的最大BMT树数,即,
    56  //由同一哈希程序执行的最大并发BMT哈希操作数
    57  	PoolSize = 8
    58  )
    59  
    60  //basehasherfunc是用于bmt的基哈希的hash.hash构造函数函数。
    61  //由keccak256 sha3.newlegacykeccak256实施
    62  type BaseHasherFunc func() hash.Hash
    63  
    64  //hasher用于表示BMT的固定最大大小块的可重用hasher
    65  //-实现hash.hash接口
    66  //-重新使用一个树池进行缓冲内存分配和资源控制
    67  //-支持顺序不可知的并发段写入和段(双段)写入
    68  //以及顺序读写
    69  //-不能对多个块同时调用同一哈希实例
    70  //-同一哈希实例可同步重用
    71  //-SUM将树还给游泳池并保证离开
    72  //树及其自身处于可重用的状态,用于散列新块
    73  //-生成和验证段包含证明(TODO:)
    74  type Hasher struct {
    75  pool *TreePool //BMT资源池
    76  bmt  *tree     //用于流程控制和验证的预建BMT资源
    77  }
    78  
    79  //new创建一个可重用的bmt散列器,
    80  //从资源池中提取新的树,以便对每个块进行哈希处理
    81  func New(p *TreePool) *Hasher {
    82  	return &Hasher{
    83  		pool: p,
    84  	}
    85  }
    86  
    87  //Treepool提供了BMT哈希程序用作资源的一个树池。
    88  //从池中弹出的一棵树保证处于干净状态。
    89  //用于散列新块。
    90  type TreePool struct {
    91  	lock         sync.Mutex
    92  c            chan *tree     //从池中获取资源的通道
    93  hasher       BaseHasherFunc //用于BMT级别的基本哈希器
    94  SegmentSize  int            //叶段的大小,规定为=哈希大小
    95  SegmentCount int            //BMT基准面上的段数
    96  Capacity     int            //池容量,控制并发性
    97  Depth        int            //bmt树的深度=int(log2(segmentcount))+1
    98  Size         int            //数据的总长度(计数*大小)
    99  count        int            //当前(曾经)分配的资源计数
   100  zerohashes   [][]byte       //所有级别的可预测填充子树的查找表
   101  }
   102  
   103  //newtreepool创建一个树池,其中包含哈希、段大小、段计数和容量
   104  //在hasher.gettree上,它重用空闲的树,或者在未达到容量时创建一个新的树。
   105  func NewTreePool(hasher BaseHasherFunc, segmentCount, capacity int) *TreePool {
   106  //初始化零哈希查找表
   107  	depth := calculateDepthFor(segmentCount)
   108  	segmentSize := hasher().Size()
   109  	zerohashes := make([][]byte, depth+1)
   110  	zeros := make([]byte, segmentSize)
   111  	zerohashes[0] = zeros
   112  	h := hasher()
   113  	for i := 1; i < depth+1; i++ {
   114  		zeros = doSum(h, nil, zeros, zeros)
   115  		zerohashes[i] = zeros
   116  	}
   117  	return &TreePool{
   118  		c:            make(chan *tree, capacity),
   119  		hasher:       hasher,
   120  		SegmentSize:  segmentSize,
   121  		SegmentCount: segmentCount,
   122  		Capacity:     capacity,
   123  		Size:         segmentCount * segmentSize,
   124  		Depth:        depth,
   125  		zerohashes:   zerohashes,
   126  	}
   127  }
   128  
   129  //排干水池中的水,直到其资源不超过n个。
   130  func (p *TreePool) Drain(n int) {
   131  	p.lock.Lock()
   132  	defer p.lock.Unlock()
   133  	for len(p.c) > n {
   134  		<-p.c
   135  		p.count--
   136  	}
   137  }
   138  
   139  //保留正在阻止,直到它返回可用的树
   140  //它重用空闲的树,或者在未达到大小时创建一个新的树。
   141  //TODO:应在此处使用上下文
   142  func (p *TreePool) reserve() *tree {
   143  	p.lock.Lock()
   144  	defer p.lock.Unlock()
   145  	var t *tree
   146  	if p.count == p.Capacity {
   147  		return <-p.c
   148  	}
   149  	select {
   150  	case t = <-p.c:
   151  	default:
   152  		t = newTree(p.SegmentSize, p.Depth, p.hasher)
   153  		p.count++
   154  	}
   155  	return t
   156  }
   157  
   158  //释放会将树放回池中。
   159  //此树保证处于可重用状态
   160  func (p *TreePool) release(t *tree) {
   161  p.c <- t //永远不会失败…
   162  }
   163  
   164  //树是表示BMT的可重用控制结构
   165  //以二叉树组织
   166  //散列器使用treepool为每个块散列获取树
   167  //树不在池中时被“锁定”
   168  type tree struct {
   169  leaves  []*node     //树的叶节点,通过父链接可访问的其他节点
   170  cursor  int         //当前最右侧打开段的索引
   171  offset  int         //当前打开段内的偏移量(光标位置)
   172  section []byte      //最右边的开口段(双段)
   173  result  chan []byte //结果通道
   174  span    []byte      //包含在块下的数据范围
   175  }
   176  
   177  //节点是表示BMT中节点的可重用段散列器。
   178  type node struct {
   179  isLeft      bool      //是否为父双段的左侧
   180  parent      *node     //指向BMT中父节点的指针
   181  state       int32     //原子增量impl并发布尔切换
   182  left, right []byte    //这是写两个孩子部分的地方
   183  hasher      hash.Hash //节点上的预构造哈希
   184  }
   185  
   186  //newnode在bmt中构造一个段散列器节点(由newtree使用)
   187  func newNode(index int, parent *node, hasher hash.Hash) *node {
   188  	return &node{
   189  		parent: parent,
   190  		isLeft: index%2 == 0,
   191  		hasher: hasher,
   192  	}
   193  }
   194  
   195  //抽签抽BMT(不好)
   196  func (t *tree) draw(hash []byte) string {
   197  	var left, right []string
   198  	var anc []*node
   199  	for i, n := range t.leaves {
   200  		left = append(left, fmt.Sprintf("%v", hashstr(n.left)))
   201  		if i%2 == 0 {
   202  			anc = append(anc, n.parent)
   203  		}
   204  		right = append(right, fmt.Sprintf("%v", hashstr(n.right)))
   205  	}
   206  	anc = t.leaves
   207  	var hashes [][]string
   208  	for l := 0; len(anc) > 0; l++ {
   209  		var nodes []*node
   210  		hash := []string{""}
   211  		for i, n := range anc {
   212  			hash = append(hash, fmt.Sprintf("%v|%v", hashstr(n.left), hashstr(n.right)))
   213  			if i%2 == 0 && n.parent != nil {
   214  				nodes = append(nodes, n.parent)
   215  			}
   216  		}
   217  		hash = append(hash, "")
   218  		hashes = append(hashes, hash)
   219  		anc = nodes
   220  	}
   221  	hashes = append(hashes, []string{"", fmt.Sprintf("%v", hashstr(hash)), ""})
   222  	total := 60
   223  	del := "                             "
   224  	var rows []string
   225  	for i := len(hashes) - 1; i >= 0; i-- {
   226  		var textlen int
   227  		hash := hashes[i]
   228  		for _, s := range hash {
   229  			textlen += len(s)
   230  		}
   231  		if total < textlen {
   232  			total = textlen + len(hash)
   233  		}
   234  		delsize := (total - textlen) / (len(hash) - 1)
   235  		if delsize > len(del) {
   236  			delsize = len(del)
   237  		}
   238  		row := fmt.Sprintf("%v: %v", len(hashes)-i-1, strings.Join(hash, del[:delsize]))
   239  		rows = append(rows, row)
   240  
   241  	}
   242  	rows = append(rows, strings.Join(left, "  "))
   243  	rows = append(rows, strings.Join(right, "  "))
   244  	return strings.Join(rows, "\n") + "\n"
   245  }
   246  
   247  //NewTree通过构建BMT的节点初始化树
   248  //-段大小规定为哈希的大小
   249  func newTree(segmentSize, depth int, hashfunc func() hash.Hash) *tree {
   250  	n := newNode(0, nil, hashfunc())
   251  	prevlevel := []*node{n}
   252  //迭代级别并创建2^(深度级别)节点
   253  //0级位于双段段,因此我们从深度-2开始,因为
   254  	count := 2
   255  	for level := depth - 2; level >= 0; level-- {
   256  		nodes := make([]*node, count)
   257  		for i := 0; i < count; i++ {
   258  			parent := prevlevel[i/2]
   259  			var hasher hash.Hash
   260  			if level == 0 {
   261  				hasher = hashfunc()
   262  			}
   263  			nodes[i] = newNode(i, parent, hasher)
   264  		}
   265  		prevlevel = nodes
   266  		count *= 2
   267  	}
   268  //datanode级别是最后一级的节点
   269  	return &tree{
   270  		leaves:  prevlevel,
   271  		result:  make(chan []byte),
   272  		section: make([]byte, 2*segmentSize),
   273  	}
   274  }
   275  
   276  //实现hash.hash所需的方法
   277  
   278  //SIZE返回大小
   279  func (h *Hasher) Size() int {
   280  	return h.pool.SegmentSize
   281  }
   282  
   283  //块大小返回块大小
   284  func (h *Hasher) BlockSize() int {
   285  	return 2 * h.pool.SegmentSize
   286  }
   287  
   288  //sum返回缓冲区的bmt根哈希
   289  //使用SUM预先假定顺序同步写入(io.writer接口)
   290  //hash.hash接口sum方法将字节片附加到基础
   291  //在计算和返回块散列之前的数据
   292  //调用方必须确保SUM不与WRITE、WRITESECTION同时调用
   293  func (h *Hasher) Sum(b []byte) (s []byte) {
   294  	t := h.getTree()
   295  //将最后一节的final标志设置为true
   296  	go h.writeSection(t.cursor, t.section, true, true)
   297  //等待结果
   298  	s = <-t.result
   299  	span := t.span
   300  //将树资源释放回池
   301  	h.releaseTree()
   302  //B+Sha3(SPAN+BMT(纯块)
   303  	if len(span) == 0 {
   304  		return append(b, s...)
   305  	}
   306  	return doSum(h.pool.hasher(), b, span, s)
   307  }
   308  
   309  //实现swarmhash和io.writer接口所需的方法
   310  
   311  //按顺序写入调用,添加到要散列的缓冲区,
   312  //在Go例程中的每个完整段调用中都有writesection
   313  func (h *Hasher) Write(b []byte) (int, error) {
   314  	l := len(b)
   315  	if l == 0 || l > h.pool.Size {
   316  		return 0, nil
   317  	}
   318  	t := h.getTree()
   319  	secsize := 2 * h.pool.SegmentSize
   320  //计算缺失位的长度以完成当前开放段
   321  	smax := secsize - t.offset
   322  //如果在块的开头或节的中间
   323  	if t.offset < secsize {
   324  //从缓冲区填充当前段
   325  		copy(t.section[t.offset:], b)
   326  //如果输入缓冲区被占用,并且打开的部分不完整,则
   327  //提前抵销和返还
   328  		if smax == 0 {
   329  			smax = secsize
   330  		}
   331  		if l <= smax {
   332  			t.offset += l
   333  			return l, nil
   334  		}
   335  	} else {
   336  //如果节的结尾
   337  		if t.cursor == h.pool.SegmentCount*2 {
   338  			return 0, nil
   339  		}
   340  	}
   341  //从输入缓冲区读取完整部分和最后一个可能的部分部分。
   342  	for smax < l {
   343  //部分完成;异步推到树
   344  		go h.writeSection(t.cursor, t.section, true, false)
   345  //复位段
   346  		t.section = make([]byte, secsize)
   347  //从smax的输入缓冲区复制到节的右半部分
   348  		copy(t.section, b[smax:])
   349  //前进光标
   350  		t.cursor++
   351  //此处的smax表示输入缓冲区中的连续偏移量
   352  		smax += secsize
   353  	}
   354  	t.offset = l - smax + secsize
   355  	return l, nil
   356  }
   357  
   358  //在写入哈希之前需要调用Reset。
   359  func (h *Hasher) Reset() {
   360  	h.releaseTree()
   361  }
   362  
   363  //实现swarmhash接口所需的方法
   364  
   365  //在写入哈希之前需要调用ResetWithLength
   366  //参数应该是的字节片二进制表示。
   367  //哈希下包含的数据长度,即跨度
   368  func (h *Hasher) ResetWithLength(span []byte) {
   369  	h.Reset()
   370  	h.getTree().span = span
   371  }
   372  
   373  //releasetree将树放回池中解锁
   374  //它重置树、段和索引
   375  func (h *Hasher) releaseTree() {
   376  	t := h.bmt
   377  	if t == nil {
   378  		return
   379  	}
   380  	h.bmt = nil
   381  	go func() {
   382  		t.cursor = 0
   383  		t.offset = 0
   384  		t.span = nil
   385  		t.section = make([]byte, h.pool.SegmentSize*2)
   386  		select {
   387  		case <-t.result:
   388  		default:
   389  		}
   390  		h.pool.release(t)
   391  	}()
   392  }
   393  
   394  //NewAsyncWriter使用一个接口扩展哈希,用于并发段/节写入
   395  func (h *Hasher) NewAsyncWriter(double bool) *AsyncHasher {
   396  	secsize := h.pool.SegmentSize
   397  	if double {
   398  		secsize *= 2
   399  	}
   400  	write := func(i int, section []byte, final bool) {
   401  		h.writeSection(i, section, double, final)
   402  	}
   403  	return &AsyncHasher{
   404  		Hasher:  h,
   405  		double:  double,
   406  		secsize: secsize,
   407  		write:   write,
   408  	}
   409  }
   410  
   411  //节编写器是异步段/节编写器接口
   412  type SectionWriter interface {
   413  Reset()                                       //在重用前调用标准init
   414  Write(index int, data []byte)                 //写入索引部分
   415  Sum(b []byte, length int, span []byte) []byte //返回缓冲区的哈希值
   416  SectionSize() int                             //要使用的异步节单元的大小
   417  }
   418  
   419  //AsyncHasher使用异步段/节编写器接口扩展BMT哈希器
   420  //AsyncHasher不安全,不检查索引和节数据长度
   421  //它必须与正确的索引和长度以及正确的节数一起使用
   422  //
   423  //如果
   424  //*非最终截面比secsize短或长
   425  //*如果最后一部分与长度不匹配
   426  //*编写索引大于长度/秒大小的节
   427  //*当length/secsize<maxsec时,在sum调用中设置长度
   428  //
   429  //*如果未对完全写入的哈希表调用sum()。
   430  //一个进程将阻塞,可通过重置终止。
   431  //*如果不是所有部分都写了,但它会阻塞,则不会泄漏进程。
   432  //并保留可释放的资源,调用reset()。
   433  type AsyncHasher struct {
   434  *Hasher            //扩展哈希
   435  mtx     sync.Mutex //锁定光标访问
   436  double  bool       //是否使用双段(调用hasher.writesection)
   437  secsize int        //基节大小(哈希或双精度大小)
   438  	write   func(i int, section []byte, final bool)
   439  }
   440  
   441  //实现AsyncWriter所需的方法
   442  
   443  //SECTIONSIZE返回要使用的异步节单元的大小
   444  func (sw *AsyncHasher) SectionSize() int {
   445  	return sw.secsize
   446  }
   447  
   448  //写入BMT基的第i部分
   449  //此函数可以并打算同时调用
   450  //它安全地设置最大段
   451  func (sw *AsyncHasher) Write(i int, section []byte) {
   452  	sw.mtx.Lock()
   453  	defer sw.mtx.Unlock()
   454  	t := sw.getTree()
   455  //光标跟踪迄今为止写入的最右边的部分
   456  //如果索引低于光标,则只需按原样编写非最终部分。
   457  	if i < t.cursor {
   458  //如果索引不是最右边的,则可以安全地写入节
   459  		go sw.write(i, section, false)
   460  		return
   461  	}
   462  //如果有上一个最右边的节可安全写入
   463  	if t.offset > 0 {
   464  		if i == t.cursor {
   465  //i==cursor表示游标是通过哈希调用设置的,因此我们可以将节写入最后一个节。
   466  //因为它可能更短,所以我们首先将它复制到填充缓冲区
   467  			t.section = make([]byte, sw.secsize)
   468  			copy(t.section, section)
   469  			go sw.write(i, t.section, true)
   470  			return
   471  		}
   472  //最右边的部分刚刚改变,所以我们把前一部分写为非最终部分。
   473  		go sw.write(t.cursor, t.section, false)
   474  	}
   475  //将i设置为迄今为止编写的最基本部分的索引
   476  //将t.offset设置为cursor*secsize+1
   477  	t.cursor = i
   478  	t.offset = i*sw.secsize + 1
   479  	t.section = make([]byte, sw.secsize)
   480  	copy(t.section, section)
   481  }
   482  
   483  //一旦长度和跨度已知,可以随时调用sum。
   484  //甚至在所有段都被写入之前
   485  //在这种情况下,SUM将阻塞,直到所有段都存在,并且
   486  //可以计算长度的哈希值。
   487  //
   488  //B:摘要附加到B
   489  //长度:输入的已知长度(不安全;超出范围时未定义)
   490  //meta:要与最终摘要的bmt根一起哈希的元数据
   491  //例如,防止存在伪造的跨度
   492  func (sw *AsyncHasher) Sum(b []byte, length int, meta []byte) (s []byte) {
   493  	sw.mtx.Lock()
   494  	t := sw.getTree()
   495  	if length == 0 {
   496  		sw.mtx.Unlock()
   497  		s = sw.pool.zerohashes[sw.pool.Depth]
   498  	} else {
   499  //对于非零输入,最右边的部分异步写入树
   500  //如果写入了实际的最后一节(t.cursor==length/t.secsize)
   501  		maxsec := (length - 1) / sw.secsize
   502  		if t.offset > 0 {
   503  			go sw.write(t.cursor, t.section, maxsec == t.cursor)
   504  		}
   505  //将光标设置为maxsec,以便在最后一节到达时写入它
   506  		t.cursor = maxsec
   507  		t.offset = length
   508  		result := t.result
   509  		sw.mtx.Unlock()
   510  //等待结果或重置
   511  		s = <-result
   512  	}
   513  //把树放回水池里
   514  	sw.releaseTree()
   515  //如果没有给定元,只需将摘要附加到b
   516  	if len(meta) == 0 {
   517  		return append(b, s...)
   518  	}
   519  //使用池一起散列meta和bmt根散列
   520  	return doSum(sw.pool.hasher(), b, meta, s)
   521  }
   522  
   523  //WriteSection将第i个节的哈希写入BMT树的1级节点
   524  func (h *Hasher) writeSection(i int, section []byte, double bool, final bool) {
   525  //选择节的叶节点
   526  	var n *node
   527  	var isLeft bool
   528  	var hasher hash.Hash
   529  	var level int
   530  	t := h.getTree()
   531  	if double {
   532  		level++
   533  		n = t.leaves[i]
   534  		hasher = n.hasher
   535  		isLeft = n.isLeft
   536  		n = n.parent
   537  //散列该节
   538  		section = doSum(hasher, nil, section)
   539  	} else {
   540  		n = t.leaves[i/2]
   541  		hasher = n.hasher
   542  		isLeft = i%2 == 0
   543  	}
   544  //将哈希写入父节点
   545  	if final {
   546  //对于最后一段,使用writefinalnode
   547  		h.writeFinalNode(level, n, hasher, isLeft, section)
   548  	} else {
   549  		h.writeNode(n, hasher, isLeft, section)
   550  	}
   551  }
   552  
   553  //WriteNode将数据推送到节点
   554  //如果是两个姐妹中的第一个写的,程序就终止了
   555  //如果是第二个,则计算散列并写入散列
   556  //递归到父节点
   557  //由于对父对象进行哈希操作是同步的,因此可以使用相同的哈希操作。
   558  func (h *Hasher) writeNode(n *node, bh hash.Hash, isLeft bool, s []byte) {
   559  	level := 1
   560  	for {
   561  //在bmt的根目录下,只需将结果写入结果通道
   562  		if n == nil {
   563  			h.getTree().result <- s
   564  			return
   565  		}
   566  //否则,将子哈希赋给左或右段
   567  		if isLeft {
   568  			n.left = s
   569  		} else {
   570  			n.right = s
   571  		}
   572  //首先到达的子线程将终止
   573  		if n.toggle() {
   574  			return
   575  		}
   576  //现在第二个线程可以确保左孩子和右孩子都被写入
   577  //所以它计算左右的散列值并将其推送到父对象
   578  		s = doSum(bh, nil, n.left, n.right)
   579  		isLeft = n.isLeft
   580  		n = n.parent
   581  		level++
   582  	}
   583  }
   584  
   585  //WriteFinalNode正在沿着从最终数据集到
   586  //通过父级的bmt根
   587  //对于不平衡树,它使用
   588  //所有零部分的bmt子树根散列的池查找表
   589  //否则行为类似于“writenode”
   590  func (h *Hasher) writeFinalNode(level int, n *node, bh hash.Hash, isLeft bool, s []byte) {
   591  
   592  	for {
   593  //在bmt的根目录下,只需将结果写入结果通道
   594  		if n == nil {
   595  			if s != nil {
   596  				h.getTree().result <- s
   597  			}
   598  			return
   599  		}
   600  		var noHash bool
   601  		if isLeft {
   602  //来自左姊妹枝
   603  //当最后一节的路径经过左子节点时
   604  //我们为正确的级别包含一个全零子树散列并切换节点。
   605  			n.right = h.pool.zerohashes[level]
   606  			if s != nil {
   607  				n.left = s
   608  //如果左最后一个节点带有哈希,则它必须是第一个(并且只能是线程)
   609  //所以开关已经处于被动状态,不需要呼叫
   610  //然而线程需要继续向父线程推送哈希
   611  				noHash = false
   612  			} else {
   613  //如果再次是第一个线程,那么传播nil并计算no hash
   614  				noHash = n.toggle()
   615  			}
   616  		} else {
   617  //右姐妹支
   618  			if s != nil {
   619  //如果从右子节点推送哈希,则写入右段更改状态
   620  				n.right = s
   621  //如果toggle为true,则我们首先到达,因此不需要散列,只需将nil推送到父级
   622  				noHash = n.toggle()
   623  
   624  			} else {
   625  //如果s为nil,那么线程首先到达前一个节点,这里将有两个,
   626  //所以不需要做任何事情,保持s=nil作为家长
   627  				noHash = true
   628  			}
   629  		}
   630  //第一个到达的子线程将继续重置为nil
   631  //第二条线索现在可以确定左、右两个孩子都写了
   632  //它计算左右的哈希并将其推送到父级
   633  		if noHash {
   634  			s = nil
   635  		} else {
   636  			s = doSum(bh, nil, n.left, n.right)
   637  		}
   638  //迭代到父级
   639  		isLeft = n.isLeft
   640  		n = n.parent
   641  		level++
   642  	}
   643  }
   644  
   645  //gettree通过从池中保留一个bmt资源并将其分配给bmt字段来获取bmt资源
   646  func (h *Hasher) getTree() *tree {
   647  	if h.bmt != nil {
   648  		return h.bmt
   649  	}
   650  	t := h.pool.reserve()
   651  	h.bmt = t
   652  	return t
   653  }
   654  
   655  //实现并发可重用2状态对象的原子布尔切换
   656  //具有%2的原子加载项实现原子布尔切换
   657  //如果切换开关刚刚将其置于活动/等待状态,则返回true。
   658  func (n *node) toggle() bool {
   659  	return atomic.AddInt32(&n.state, 1)%2 == 1
   660  }
   661  
   662  //使用hash.hash计算数据的哈希
   663  func doSum(h hash.Hash, b []byte, data ...[]byte) []byte {
   664  	h.Reset()
   665  	for _, v := range data {
   666  		h.Write(v)
   667  	}
   668  	return h.Sum(b)
   669  }
   670  
   671  //hashstr是用于tree.draw中字节的漂亮打印机
   672  func hashstr(b []byte) string {
   673  	end := len(b)
   674  	if end > 4 {
   675  		end = 4
   676  	}
   677  	return fmt.Sprintf("%x", b[:end])
   678  }
   679  
   680  //CalculateDepthfor计算BMT树中的深度(层数)
   681  func calculateDepthFor(n int) (d int) {
   682  	c := 2
   683  	for ; c < n; c *= 2 {
   684  		d++
   685  	}
   686  	return d + 1
   687  }
   688