github.com/turingchain2020/turingchain@v1.1.21/blockchain/orphanpool.go (about)

     1  // Copyright Turing Corp. 2018 All Rights Reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package blockchain
     6  
     7  import (
     8  	"bytes"
     9  	"sync"
    10  	"time"
    11  
    12  	"github.com/turingchain2020/turingchain/common"
    13  	"github.com/turingchain2020/turingchain/types"
    14  )
    15  
    16  var (
    17  	maxOrphanBlocks = 10240 //最大孤儿block数量,考虑到同步阶段孤儿block会很多
    18  )
    19  
    20  const orphanExpirationTime = time.Second * 600 // 孤儿过期时间设置为10分钟
    21  
    22  //孤儿节点,就是本节点的父节点未知的block
    23  type orphanBlock struct {
    24  	block      *types.Block
    25  	expiration time.Time
    26  	broadcast  bool
    27  	pid        string
    28  	sequence   int64
    29  }
    30  
    31  //OrphanPool 孤儿节点的存储以blockhash作为map的索引。hash转换成string
    32  type OrphanPool struct {
    33  	orphanLock   sync.RWMutex
    34  	orphans      map[string]*orphanBlock
    35  	prevOrphans  map[string][]*orphanBlock
    36  	oldestOrphan *orphanBlock
    37  	param        *types.TuringchainConfig
    38  }
    39  
    40  //NewOrphanPool new
    41  func NewOrphanPool(param *types.TuringchainConfig) *OrphanPool {
    42  	op := &OrphanPool{
    43  		orphans:     make(map[string]*orphanBlock),
    44  		prevOrphans: make(map[string][]*orphanBlock),
    45  		param:       param,
    46  	}
    47  	return op
    48  }
    49  
    50  //IsKnownOrphan 判断本节点是不是已知的孤儿节点
    51  func (op *OrphanPool) IsKnownOrphan(hash []byte) bool {
    52  	op.orphanLock.RLock()
    53  	_, exists := op.orphans[string(hash)]
    54  	op.orphanLock.RUnlock()
    55  
    56  	return exists
    57  }
    58  
    59  //GetOrphanRoot 获取本孤儿节点的祖先节点hash在孤儿链中,没有的话就返回孤儿节点本身hash
    60  func (op *OrphanPool) GetOrphanRoot(hash []byte) []byte {
    61  	op.orphanLock.RLock()
    62  	defer op.orphanLock.RUnlock()
    63  
    64  	// Keep looping while the parent of each orphaned block is known and is an orphan itself.
    65  	orphanRoot := hash
    66  	prevHash := hash
    67  	for {
    68  		orphan, exists := op.orphans[string(prevHash)]
    69  		if !exists {
    70  			break
    71  		}
    72  		orphanRoot = prevHash
    73  		prevHash = orphan.block.GetParentHash()
    74  	}
    75  
    76  	return orphanRoot
    77  }
    78  
    79  //RemoveOrphanBlockByHash 通过指定的区块hash
    80  //删除孤儿区块从OrphanPool中,以及prevOrphans中的index.
    81  func (op *OrphanPool) RemoveOrphanBlockByHash(hash []byte) {
    82  	op.orphanLock.Lock()
    83  	defer op.orphanLock.Unlock()
    84  
    85  	orphan, exists := op.orphans[string(hash)]
    86  	if exists && orphan != nil {
    87  		chainlog.Debug("RemoveOrphanBlockByHash:", "height", orphan.block.Height, "hash", common.ToHex(hash))
    88  		op.removeOrphanBlock(orphan)
    89  	}
    90  }
    91  
    92  //RemoveOrphanBlock 删除孤儿节点从OrphanPool中,以及prevOrphans中的index
    93  func (op *OrphanPool) RemoveOrphanBlock(orphan *orphanBlock) {
    94  	op.orphanLock.Lock()
    95  	defer op.orphanLock.Unlock()
    96  
    97  	chainlog.Debug("RemoveOrphanBlock:", "height", orphan.block.Height, "hash", common.ToHex(orphan.block.Hash(op.param)))
    98  
    99  	op.removeOrphanBlock(orphan)
   100  }
   101  
   102  //RemoveOrphanBlock2 删除孤儿节点从OrphanPool中,以及prevOrphans中的index
   103  func (op *OrphanPool) RemoveOrphanBlock2(block *types.Block, expiration time.Time, broadcast bool, pid string, sequence int64) {
   104  	b := &orphanBlock{
   105  		block:      block,
   106  		expiration: expiration,
   107  		broadcast:  broadcast,
   108  		pid:        pid,
   109  		sequence:   sequence,
   110  	}
   111  	op.RemoveOrphanBlock(b)
   112  }
   113  
   114  // 删除孤儿节点从OrphanPool中,以及prevOrphans中的index
   115  func (op *OrphanPool) removeOrphanBlock(orphan *orphanBlock) {
   116  	chainlog.Debug("removeOrphanBlock:", "orphan.block.height", orphan.block.Height, "orphan.block.hash", common.ToHex(orphan.block.Hash(op.param)))
   117  
   118  	// 从orphan pool中删除孤儿节点
   119  	orphanHash := orphan.block.Hash(op.param)
   120  	delete(op.orphans, string(orphanHash))
   121  
   122  	// 删除parent hash中本孤儿节点的index
   123  	prevHash := orphan.block.GetParentHash()
   124  	orphans := op.prevOrphans[string(prevHash)]
   125  	for i := 0; i < len(orphans); i++ {
   126  		hash := orphans[i].block.Hash(op.param)
   127  		if bytes.Equal(hash, orphanHash) {
   128  			copy(orphans[i:], orphans[i+1:])
   129  			orphans[len(orphans)-1] = nil
   130  			orphans = orphans[:len(orphans)-1]
   131  			i--
   132  		}
   133  	}
   134  	op.prevOrphans[string(prevHash)] = orphans
   135  
   136  	// parent hash对应的子孤儿节点都已经删除,也需要删除本parent hash
   137  	if len(op.prevOrphans[string(prevHash)]) == 0 {
   138  		delete(op.prevOrphans, string(prevHash))
   139  	}
   140  }
   141  
   142  // AddOrphanBlock adds the passed block (which is already determined to be
   143  // an orphan prior calling this function) to the orphan pool.  It lazily cleans
   144  // up any expired blocks so a separate cleanup poller doesn't need to be run.
   145  // It also imposes a maximum limit on the number of outstanding orphan
   146  // blocks and will remove the oldest received orphan block if the limit is
   147  // exceeded.
   148  func (op *OrphanPool) AddOrphanBlock(broadcast bool, block *types.Block, pid string, sequence int64) {
   149  
   150  	chainlog.Debug("addOrphanBlock:", "block.height", block.Height, "block.hash", common.ToHex(block.Hash(op.param)))
   151  
   152  	op.orphanLock.Lock()
   153  	defer op.orphanLock.Unlock()
   154  
   155  	// 删除过期的孤儿节点从孤儿池中
   156  	for _, oBlock := range op.orphans {
   157  		if types.Now().After(oBlock.expiration) {
   158  			chainlog.Debug("addOrphanBlock:removeOrphanBlock expiration", "block.height", oBlock.block.Height, "block.hash", common.ToHex(oBlock.block.Hash(op.param)))
   159  
   160  			op.removeOrphanBlock(oBlock)
   161  			continue
   162  		}
   163  		// 更新最早的孤儿block
   164  		if op.oldestOrphan == nil || oBlock.expiration.Before(op.oldestOrphan.expiration) {
   165  			op.oldestOrphan = oBlock
   166  		}
   167  	}
   168  
   169  	// 孤儿池超过最大限制时,删除最早的一个孤儿block
   170  	if (len(op.orphans) + 1) > maxOrphanBlocks {
   171  		op.removeOrphanBlock(op.oldestOrphan)
   172  		chainlog.Debug("addOrphanBlock:removeOrphanBlock maxOrphanBlocks ", "block.height", op.oldestOrphan.block.Height, "block.hash", common.ToHex(op.oldestOrphan.block.Hash(op.param)))
   173  
   174  		op.oldestOrphan = nil
   175  	}
   176  
   177  	// 将本孤儿节点插入孤儿池中,并启动过期定时器
   178  	expiration := types.Now().Add(orphanExpirationTime)
   179  	oBlock := &orphanBlock{
   180  		block:      block,
   181  		expiration: expiration,
   182  		broadcast:  broadcast,
   183  		pid:        pid,
   184  		sequence:   sequence,
   185  	}
   186  	op.orphans[string(block.Hash(op.param))] = oBlock
   187  
   188  	// 将本孤儿节点添加到其父hash对应的map列表中,方便快速查找
   189  	prevHash := block.GetParentHash()
   190  	op.prevOrphans[string(prevHash)] = append(op.prevOrphans[string(prevHash)], oBlock)
   191  }
   192  
   193  //getChildOrphanCount 获取父hash对应的子孤儿节点的个数,内部函数
   194  func (op *OrphanPool) getChildOrphanCount(hash string) int {
   195  	return len(op.prevOrphans[hash])
   196  }
   197  
   198  //getChildOrphan 获取子孤儿连,内部函数
   199  func (op *OrphanPool) getChildOrphan(hash string, index int) *orphanBlock {
   200  	if index >= len(op.prevOrphans[hash]) {
   201  		return nil
   202  	}
   203  	return op.prevOrphans[hash][index]
   204  }
   205  
   206  //ProcessOrphans 孤儿链的处理,将本hash对应的子block插入chain中
   207  func (op *OrphanPool) ProcessOrphans(hash []byte, b *BlockChain) error {
   208  	chainlog.Debug("ProcessOrphans:parent", "hash", common.ToHex(hash))
   209  	op.orphanLock.Lock()
   210  	defer op.orphanLock.Unlock()
   211  
   212  	processHashes := make([]string, 0, 100)
   213  	processHashes = append(processHashes, string(hash))
   214  	for len(processHashes) > 0 {
   215  		processHash := processHashes[0]
   216  		processHashes[0] = "" // Prevent GC leak.
   217  		processHashes = processHashes[1:]
   218  
   219  		//  处理以processHash为父hash的所有子block
   220  		count := b.orphanPool.getChildOrphanCount(processHash)
   221  		for i := 0; i < count; i++ {
   222  			orphan := b.orphanPool.getChildOrphan(processHash, i)
   223  			if orphan == nil {
   224  				chainlog.Debug("ProcessOrphans", "Found a nil entry at index", i, "orphan dependency list for block", common.ToHex([]byte(processHash)))
   225  				continue
   226  			}
   227  
   228  			// 从孤儿池中删除此孤儿节点
   229  			orphanHash := orphan.block.Hash(op.param)
   230  			b.orphanPool.removeOrphanBlock(orphan)
   231  			i--
   232  
   233  			chainlog.Debug("processOrphans:maybeAcceptBlock", "height", orphan.block.GetHeight(), "hash", common.ToHex(orphan.block.Hash(op.param)))
   234  			// 尝试将此孤儿节点添加到主链
   235  			_, _, err := b.maybeAcceptBlock(orphan.broadcast, &types.BlockDetail{Block: orphan.block}, orphan.pid, orphan.sequence)
   236  			if err != nil {
   237  				return err
   238  			}
   239  			processHashes = append(processHashes, string(orphanHash))
   240  		}
   241  	}
   242  	return nil
   243  }