github.com/turingchain2020/turingchain@v1.1.21/blockchain/process.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  	"container/list"
    10  	"math/big"
    11  	"sync/atomic"
    12  
    13  	"github.com/turingchain2020/turingchain/client/api"
    14  	"github.com/turingchain2020/turingchain/common"
    15  	"github.com/turingchain2020/turingchain/common/difficulty"
    16  	"github.com/turingchain2020/turingchain/types"
    17  	"github.com/turingchain2020/turingchain/util"
    18  )
    19  
    20  //ProcessBlock 处理共识模块过来的blockdetail,peer广播过来的block,以及从peer同步过来的block
    21  // 共识模块和peer广播过来的block需要广播出去
    22  //共识模块过来的Receipts不为空,广播和同步过来的Receipts为空
    23  // 返回参数说明:是否主链,是否孤儿节点,具体err
    24  func (chain *BlockChain) ProcessBlock(broadcast bool, block *types.BlockDetail, pid string, addBlock bool, sequence int64) (*types.BlockDetail, bool, bool, error) {
    25  	chainlog.Debug("ProcessBlock:Processing", "height", block.Block.Height, "blockHash", common.ToHex(block.Block.Hash(chain.client.GetConfig())))
    26  
    27  	//blockchain close 时不再处理block
    28  	if atomic.LoadInt32(&chain.isclosed) == 1 {
    29  		return nil, false, false, types.ErrIsClosed
    30  	}
    31  	cfg := chain.client.GetConfig()
    32  	if block.Block.Height > 0 {
    33  		var lastBlockHash []byte
    34  		if addBlock {
    35  			lastBlockHash = block.Block.GetParentHash()
    36  		} else {
    37  			lastBlockHash = block.Block.Hash(cfg)
    38  		}
    39  		if pid == "self" && !bytes.Equal(lastBlockHash, chain.bestChain.Tip().hash) {
    40  			chainlog.Error("addBlockDetail parent hash no match", "err", types.ErrBlockHashNoMatch,
    41  				"bestHash", common.ToHex(chain.bestChain.Tip().hash), "blockHash", common.ToHex(lastBlockHash),
    42  				"addBlock", addBlock, "height", block.Block.Height)
    43  			return nil, false, false, types.ErrBlockHashNoMatch
    44  		}
    45  	}
    46  	blockHash := block.Block.Hash(cfg)
    47  
    48  	//目前只支持删除平行链的block处理,主链不支持删除block的操作
    49  	if !addBlock {
    50  		if chain.isParaChain {
    51  			return chain.ProcessDelParaChainBlock(broadcast, block, pid, sequence)
    52  		}
    53  		return nil, false, false, types.ErrNotSupport
    54  	}
    55  	//判断本block是否已经存在主链或者侧链中
    56  	//如果此block已经存在,并且已经被记录执行不过,
    57  	//将此block的源peer节点添加到故障peerlist中
    58  	exists := chain.blockExists(blockHash)
    59  	if exists {
    60  		is, err := chain.IsErrExecBlock(block.Block.Height, blockHash)
    61  		if is {
    62  			chain.RecordFaultPeer(pid, block.Block.Height, blockHash, err)
    63  		}
    64  		chainlog.Debug("ProcessBlock already have block", "blockHash", common.ToHex(blockHash))
    65  		return nil, false, false, types.ErrBlockExist
    66  	}
    67  
    68  	// 判断本区块是否已经存在孤儿链中
    69  	exists = chain.orphanPool.IsKnownOrphan(blockHash)
    70  	if exists {
    71  		//本区块已经存在孤儿链中,但是自己的父区块也已经存在主链中
    72  		//此时可能是上次加载父区块的过程中,刚好子区块过来导致子区块被存入到孤儿链中了没有及时处理
    73  		//本次需要删除孤儿连中本区块的信息,尝试将此区块添加到主链上
    74  		if chain.blockExists(block.Block.GetParentHash()) {
    75  			chain.orphanPool.RemoveOrphanBlockByHash(blockHash)
    76  			chainlog.Debug("ProcessBlock:maybe Accept Orphan Block", "blockHash", common.ToHex(blockHash))
    77  		} else {
    78  			chainlog.Debug("ProcessBlock already have block(orphan)", "blockHash", common.ToHex(blockHash))
    79  			return nil, false, false, types.ErrBlockExist
    80  		}
    81  	}
    82  
    83  	//判断本block的父block是否存在,如果不存在就将此block添加到孤儿链中
    84  	//创世块0需要做一些特殊的判断
    85  	var prevHashExists bool
    86  	prevHash := block.Block.GetParentHash()
    87  	if 0 == block.Block.GetHeight() {
    88  		if bytes.Equal(prevHash, make([]byte, sha256Len)) {
    89  			prevHashExists = true
    90  		}
    91  	} else {
    92  		prevHashExists = chain.blockExists(prevHash)
    93  	}
    94  	if !prevHashExists {
    95  		chainlog.Debug("ProcessBlock:AddOrphanBlock", "height", block.Block.GetHeight(), "blockHash", common.ToHex(blockHash), "prevHash", common.ToHex(prevHash))
    96  		chain.orphanPool.AddOrphanBlock(broadcast, block.Block, pid, sequence)
    97  		return nil, false, true, nil
    98  	}
    99  
   100  	// 基本检测通过之后尝试添加block到主链上
   101  	return chain.maybeAddBestChain(broadcast, block, pid, sequence)
   102  }
   103  
   104  //基本检测通过之后尝试将此block添加到主链上
   105  func (chain *BlockChain) maybeAddBestChain(broadcast bool, block *types.BlockDetail, pid string, sequence int64) (*types.BlockDetail, bool, bool, error) {
   106  	chain.chainLock.Lock()
   107  	defer chain.chainLock.Unlock()
   108  
   109  	blockHash := block.Block.Hash(chain.client.GetConfig())
   110  	exists := chain.blockExists(blockHash)
   111  	if exists {
   112  		return nil, false, false, types.ErrBlockExist
   113  	}
   114  	chainlog.Debug("maybeAddBestChain", "height", block.Block.GetHeight(), "blockHash", common.ToHex(blockHash))
   115  	blockdetail, isMainChain, err := chain.maybeAcceptBlock(broadcast, block, pid, sequence)
   116  
   117  	if err != nil {
   118  		return nil, false, false, err
   119  	}
   120  	// 尝试处理blockHash对应的孤儿子节点
   121  	err = chain.orphanPool.ProcessOrphans(blockHash, chain)
   122  	if err != nil {
   123  		return nil, false, false, err
   124  	}
   125  	return blockdetail, isMainChain, false, nil
   126  }
   127  
   128  //检查block是否已经存在index或者数据库中
   129  func (chain *BlockChain) blockExists(hash []byte) bool {
   130  	// Check block index first (could be main chain or side chain blocks).
   131  	if chain.index.HaveBlock(hash) {
   132  		return true
   133  	}
   134  
   135  	// 检测数据库中是否存在,通过hash获取blockheader,不存在就返回false。
   136  	blockheader, err := chain.blockStore.GetBlockHeaderByHash(hash)
   137  	if blockheader == nil || err != nil {
   138  		return false
   139  	}
   140  	//block存在数据库中时,需要确认是否在主链上。不在主链上返回false
   141  	height, err := chain.blockStore.GetHeightByBlockHash(hash)
   142  	if err != nil {
   143  		return false
   144  	}
   145  	return height != -1
   146  }
   147  
   148  // 尝试接受此block
   149  func (chain *BlockChain) maybeAcceptBlock(broadcast bool, block *types.BlockDetail, pid string, sequence int64) (*types.BlockDetail, bool, error) {
   150  	// 首先判断本block的Parent block是否存在index中
   151  	prevHash := block.Block.GetParentHash()
   152  	prevNode := chain.index.LookupNode(prevHash)
   153  	if prevNode == nil {
   154  		chainlog.Debug("maybeAcceptBlock", "previous block is unknown", common.ToHex(prevHash))
   155  		return nil, false, types.ErrParentBlockNoExist
   156  	}
   157  
   158  	blockHeight := block.Block.GetHeight()
   159  	if blockHeight != prevNode.height+1 {
   160  		chainlog.Debug("maybeAcceptBlock height err", "blockHeight", blockHeight, "prevHeight", prevNode.height)
   161  		return nil, false, types.ErrBlockHeightNoMatch
   162  	}
   163  
   164  	//将此block存储到db中,方便后面blockchain重组时使用,加入到主链saveblock时通过hash重新覆盖即可
   165  	sync := true
   166  	if atomic.LoadInt32(&chain.isbatchsync) == 0 {
   167  		sync = false
   168  	}
   169  
   170  	err := chain.blockStore.dbMaybeStoreBlock(block, sync)
   171  	if err != nil {
   172  		if err == types.ErrDataBaseDamage {
   173  			chainlog.Error("dbMaybeStoreBlock newbatch.Write", "err", err)
   174  			go util.ReportErrEventToFront(chainlog, chain.client, "blockchain", "wallet", types.ErrDataBaseDamage)
   175  		}
   176  		return nil, false, err
   177  	}
   178  	// 创建一个node并添加到内存中index
   179  	cfg := chain.client.GetConfig()
   180  	newNode := newBlockNode(cfg, broadcast, block.Block, pid, sequence)
   181  	if prevNode != nil {
   182  		newNode.parent = prevNode
   183  	}
   184  	chain.index.AddNode(newNode)
   185  
   186  	// 将本block添加到主链中
   187  	var isMainChain bool
   188  	block, isMainChain, err = chain.connectBestChain(newNode, block)
   189  	if err != nil {
   190  		return nil, false, err
   191  	}
   192  
   193  	return block, isMainChain, nil
   194  }
   195  
   196  //将block添加到主链中
   197  func (chain *BlockChain) connectBestChain(node *blockNode, block *types.BlockDetail) (*types.BlockDetail, bool, error) {
   198  
   199  	enBestBlockCmp := chain.client.GetConfig().GetModuleConfig().Consensus.EnableBestBlockCmp
   200  	parentHash := block.Block.GetParentHash()
   201  	tip := chain.bestChain.Tip()
   202  	cfg := chain.client.GetConfig()
   203  
   204  	// 将此block添加到主链中,tip节点刚好是插入block的父节点.
   205  	if bytes.Equal(parentHash, tip.hash) {
   206  		var err error
   207  		block, err = chain.connectBlock(node, block)
   208  		if err != nil {
   209  			return nil, false, err
   210  		}
   211  		return block, true, nil
   212  	}
   213  	chainlog.Debug("connectBestChain", "parentHash", common.ToHex(parentHash), "bestChain.Tip().hash", common.ToHex(tip.hash))
   214  
   215  	// 获取tip节点的block总难度tipid
   216  	tiptd, Err := chain.blockStore.GetTdByBlockHash(tip.hash)
   217  	if tiptd == nil || Err != nil {
   218  		chainlog.Error("connectBestChain tiptd is not exits!", "height", tip.height, "b.bestChain.Tip().hash", common.ToHex(tip.hash))
   219  		return nil, false, Err
   220  	}
   221  	parenttd, Err := chain.blockStore.GetTdByBlockHash(parentHash)
   222  	if parenttd == nil || Err != nil {
   223  		chainlog.Error("connectBestChain parenttd is not exits!", "height", block.Block.Height, "parentHash", common.ToHex(parentHash), "block.Block.hash", common.ToHex(block.Block.Hash(cfg)))
   224  		return nil, false, types.ErrParentTdNoExist
   225  	}
   226  	blocktd := new(big.Int).Add(node.Difficulty, parenttd)
   227  
   228  	chainlog.Debug("connectBestChain tip:", "hash", common.ToHex(tip.hash), "height", tip.height, "TD", difficulty.BigToCompact(tiptd))
   229  	chainlog.Debug("connectBestChain node:", "hash", common.ToHex(node.hash), "height", node.height, "TD", difficulty.BigToCompact(blocktd))
   230  
   231  	//优先选择总难度系数大的区块
   232  	//总难度系数,区块高度,出块时间以及父区块一致并开启最优区块比较功能时,通过共识模块来确定最优区块
   233  	iSideChain := blocktd.Cmp(tiptd) <= 0
   234  	if enBestBlockCmp && blocktd.Cmp(tiptd) == 0 && node.height == tip.height && util.CmpBestBlock(chain.client, block.Block, tip.hash) {
   235  		iSideChain = false
   236  	}
   237  	if iSideChain {
   238  		fork := chain.bestChain.FindFork(node)
   239  		if fork != nil && bytes.Equal(parentHash, fork.hash) {
   240  			chainlog.Info("connectBestChain FORK:", "Block hash", common.ToHex(node.hash), "fork.height", fork.height, "fork.hash", common.ToHex(fork.hash))
   241  		} else {
   242  			chainlog.Info("connectBestChain extends a side chain:", "Block hash", common.ToHex(node.hash), "fork.height", fork.height, "fork.hash", common.ToHex(fork.hash))
   243  		}
   244  		return nil, false, nil
   245  	}
   246  
   247  	//print
   248  	chainlog.Debug("connectBestChain tip", "height", tip.height, "hash", common.ToHex(tip.hash))
   249  	chainlog.Debug("connectBestChain node", "height", node.height, "hash", common.ToHex(node.hash), "parentHash", common.ToHex(parentHash))
   250  	chainlog.Debug("connectBestChain block", "height", block.Block.Height, "hash", common.ToHex(block.Block.Hash(cfg)))
   251  
   252  	// 获取需要重组的block node
   253  	detachNodes, attachNodes := chain.getReorganizeNodes(node)
   254  
   255  	// Reorganize the chain.
   256  	err := chain.reorganizeChain(detachNodes, attachNodes)
   257  	if err != nil {
   258  		return nil, false, err
   259  	}
   260  
   261  	return nil, true, nil
   262  }
   263  
   264  //将本block信息存储到数据库中,并更新bestchain的tip节点
   265  func (chain *BlockChain) connectBlock(node *blockNode, blockdetail *types.BlockDetail) (*types.BlockDetail, error) {
   266  	//blockchain close 时不再处理block
   267  	if atomic.LoadInt32(&chain.isclosed) == 1 {
   268  		return nil, types.ErrIsClosed
   269  	}
   270  
   271  	// Make sure it's extending the end of the best chain.
   272  	parentHash := blockdetail.Block.GetParentHash()
   273  	if !bytes.Equal(parentHash, chain.bestChain.Tip().hash) {
   274  		chainlog.Error("connectBlock hash err", "height", blockdetail.Block.Height, "Tip.height", chain.bestChain.Tip().height)
   275  		return nil, types.ErrBlockHashNoMatch
   276  	}
   277  
   278  	sync := true
   279  	if atomic.LoadInt32(&chain.isbatchsync) == 0 {
   280  		sync = false
   281  	}
   282  
   283  	var err error
   284  	var lastSequence int64
   285  
   286  	block := blockdetail.Block
   287  	prevStateHash := chain.bestChain.Tip().statehash
   288  	errReturn := (node.pid != "self")
   289  	blockdetail, _, err = execBlock(chain.client, prevStateHash, block, errReturn, sync)
   290  	if err != nil {
   291  		//记录执行出错的block信息,需要过滤掉一些特殊的错误,不计入故障中,尝试再次执行
   292  		//快速下载时执行失败的区块不需要记录错误信息,并删除index中此区块的信息尝试通过普通模式再次下载执行
   293  		ok := IsRecordFaultErr(err)
   294  
   295  		if node.pid == "download" || (!ok && node.pid == "self") {
   296  			// 本节点产生的block由于api或者queue导致执行失败需要删除block在index中的记录,
   297  			// 返回错误信息给共识模块,由共识模块尝试再次发起block的执行
   298  			// 同步或者广播过来的情况会在下一个区块过来后重新触发此block的执行
   299  			chainlog.Debug("connectBlock DelNode!", "height", block.Height, "node.hash", common.ToHex(node.hash), "err", err)
   300  			chain.index.DelNode(node.hash)
   301  		} else {
   302  			chain.RecordFaultPeer(node.pid, block.Height, node.hash, err)
   303  		}
   304  		chainlog.Error("connectBlock ExecBlock is err!", "height", block.Height, "err", err)
   305  		return nil, err
   306  	}
   307  	cfg := chain.client.GetConfig()
   308  	//要更新node的信息
   309  	if node.pid == "self" {
   310  		prevhash := node.hash
   311  		node.statehash = blockdetail.Block.GetStateHash()
   312  		node.hash = blockdetail.Block.Hash(cfg)
   313  		chain.index.UpdateNode(prevhash, node)
   314  	}
   315  
   316  	// 写入磁盘 批量将block信息写入磁盘
   317  	newbatch := chain.blockStore.batch
   318  	newbatch.Reset()
   319  	newbatch.UpdateWriteSync(sync)
   320  	//保存tx信息到db中
   321  	beg := types.Now()
   322  	err = chain.blockStore.AddTxs(newbatch, blockdetail)
   323  	if err != nil {
   324  		chainlog.Error("connectBlock indexTxs:", "height", block.Height, "err", err)
   325  		return nil, err
   326  	}
   327  	txCost := types.Since(beg)
   328  	beg = types.Now()
   329  	//保存block信息到db中
   330  	lastSequence, err = chain.blockStore.SaveBlock(newbatch, blockdetail, node.sequence)
   331  	if err != nil {
   332  		chainlog.Error("connectBlock SaveBlock:", "height", block.Height, "err", err)
   333  		return nil, err
   334  	}
   335  	saveBlkCost := types.Since(beg)
   336  	//hashCache new add block
   337  	beg = types.Now()
   338  	chain.AddCacheBlock(blockdetail)
   339  	cacheCost := types.Since(beg)
   340  
   341  	//保存block的总难度到db中
   342  	difficulty := difficulty.CalcWork(block.Difficulty)
   343  	var blocktd *big.Int
   344  	if block.Height == 0 {
   345  		blocktd = difficulty
   346  	} else {
   347  		parenttd, err := chain.blockStore.GetTdByBlockHash(parentHash)
   348  		if err != nil {
   349  			chainlog.Error("connectBlock GetTdByBlockHash", "height", block.Height, "parentHash", common.ToHex(parentHash))
   350  			return nil, err
   351  		}
   352  		blocktd = new(big.Int).Add(difficulty, parenttd)
   353  	}
   354  
   355  	err = chain.blockStore.SaveTdByBlockHash(newbatch, blockdetail.Block.Hash(cfg), blocktd)
   356  	if err != nil {
   357  		chainlog.Error("connectBlock SaveTdByBlockHash:", "height", block.Height, "err", err)
   358  		return nil, err
   359  	}
   360  	beg = types.Now()
   361  	err = newbatch.Write()
   362  	if err != nil {
   363  		chainlog.Error("connectBlock newbatch.Write", "err", err)
   364  		panic(err)
   365  	}
   366  	writeCost := types.Since(beg)
   367  	chainlog.Debug("ConnectBlock", "execLocal", txCost, "saveBlk", saveBlkCost, "cacheBlk", cacheCost, "writeBatch", writeCost)
   368  	chainlog.Debug("connectBlock info", "height", block.Height, "batchsync", sync, "hash", common.ToHex(blockdetail.Block.Hash(cfg)))
   369  
   370  	// 更新最新的高度和header
   371  	chain.blockStore.UpdateHeight2(blockdetail.GetBlock().GetHeight())
   372  	chain.blockStore.UpdateLastBlock2(blockdetail.Block)
   373  
   374  	// 更新 best chain的tip节点
   375  	chain.bestChain.SetTip(node)
   376  
   377  	chain.query.updateStateHash(blockdetail.GetBlock().GetStateHash())
   378  
   379  	err = chain.SendAddBlockEvent(blockdetail)
   380  	if err != nil {
   381  		chainlog.Debug("connectBlock SendAddBlockEvent", "err", err)
   382  	}
   383  	// 通知此block已经处理完,主要处理孤儿节点时需要设置
   384  	chain.syncTask.Done(blockdetail.Block.GetHeight())
   385  
   386  	//广播此block到全网络
   387  	if node.broadcast && !chain.cfg.DisableBlockBroadcast {
   388  		if blockdetail.Block.BlockTime-types.Now().Unix() > FutureBlockDelayTime {
   389  			//将此block添加到futureblocks中延时广播
   390  			chain.futureBlocks.Add(string(blockdetail.Block.Hash(cfg)), blockdetail)
   391  			chainlog.Debug("connectBlock futureBlocks.Add", "height", block.Height, "hash", common.ToHex(blockdetail.Block.Hash(cfg)), "blocktime", blockdetail.Block.BlockTime, "curtime", types.Now().Unix())
   392  		} else {
   393  			chain.SendBlockBroadcast(blockdetail)
   394  		}
   395  	}
   396  
   397  	//目前非平行链并开启isRecordBlockSequence功能和enablePushSubscribe
   398  	if chain.isRecordBlockSequence && chain.enablePushSubscribe {
   399  		chain.push.UpdateSeq(lastSequence)
   400  		chainlog.Debug("isRecordBlockSequence", "lastSequence", lastSequence, "height", block.Height)
   401  	}
   402  	return blockdetail, nil
   403  }
   404  
   405  //从主链中删除blocks
   406  func (chain *BlockChain) disconnectBlock(node *blockNode, blockdetail *types.BlockDetail, sequence int64) error {
   407  	var lastSequence int64
   408  	// 只能从 best chain tip节点开始删除
   409  	if !bytes.Equal(node.hash, chain.bestChain.Tip().hash) {
   410  		chainlog.Error("disconnectBlock:", "height", blockdetail.Block.Height, "node.hash", common.ToHex(node.hash), "bestChain.top.hash", common.ToHex(chain.bestChain.Tip().hash))
   411  		return types.ErrBlockHashNoMatch
   412  	}
   413  
   414  	//批量删除block的信息从磁盘中
   415  	newbatch := chain.blockStore.NewBatch(true)
   416  
   417  	//从db中删除tx相关的信息
   418  	err := chain.blockStore.DelTxs(newbatch, blockdetail)
   419  	if err != nil {
   420  		chainlog.Error("disconnectBlock DelTxs:", "height", blockdetail.Block.Height, "err", err)
   421  		return err
   422  	}
   423  	//优先删除缓存中的block信息
   424  	chain.DelCacheBlock(blockdetail.Block.Height, node.hash)
   425  
   426  	//从db中删除block相关的信息
   427  	lastSequence, err = chain.blockStore.DelBlock(newbatch, blockdetail, sequence)
   428  	if err != nil {
   429  		chainlog.Error("disconnectBlock DelBlock:", "height", blockdetail.Block.Height, "err", err)
   430  		return err
   431  	}
   432  	err = newbatch.Write()
   433  	if err != nil {
   434  		chainlog.Error("disconnectBlock newbatch.Write", "err", err)
   435  		panic(err)
   436  	}
   437  	//更新最新的高度和header为上一个块
   438  	chain.blockStore.UpdateHeight()
   439  	chain.blockStore.UpdateLastBlock(blockdetail.Block.ParentHash)
   440  
   441  	// 删除主链的tip节点,将其父节点升级成tip节点
   442  	chain.bestChain.DelTip(node)
   443  
   444  	//通知共识,mempool和钱包删除block
   445  	err = chain.SendDelBlockEvent(blockdetail)
   446  	if err != nil {
   447  		chainlog.Error("disconnectBlock SendDelBlockEvent", "err", err)
   448  	}
   449  	chain.query.updateStateHash(node.parent.statehash)
   450  
   451  	//确定node的父节点升级成tip节点
   452  	newtipnode := chain.bestChain.Tip()
   453  
   454  	if newtipnode != node.parent {
   455  		chainlog.Error("disconnectBlock newtipnode err:", "newtipnode.height", newtipnode.height, "node.parent.height", node.parent.height)
   456  	}
   457  	if !bytes.Equal(blockdetail.Block.GetParentHash(), chain.bestChain.Tip().hash) {
   458  		chainlog.Error("disconnectBlock", "newtipnode.height", newtipnode.height, "node.parent.height", node.parent.height)
   459  		chainlog.Error("disconnectBlock", "newtipnode.hash", common.ToHex(newtipnode.hash), "delblock.parent.hash", common.ToHex(blockdetail.Block.GetParentHash()))
   460  	}
   461  
   462  	chainlog.Debug("disconnectBlock success", "newtipnode.height", newtipnode.height, "node.parent.height", node.parent.height)
   463  	chainlog.Debug("disconnectBlock success", "newtipnode.hash", common.ToHex(newtipnode.hash), "delblock.parent.hash", common.ToHex(blockdetail.Block.GetParentHash()))
   464  
   465  	//目前非平行链并开启isRecordBlockSequence功能和enablePushSubscribe
   466  	if chain.isRecordBlockSequence && chain.enablePushSubscribe {
   467  		chain.push.UpdateSeq(lastSequence)
   468  		chainlog.Debug("isRecordBlockSequence", "lastSequence", lastSequence, "height", blockdetail.Block.Height)
   469  	}
   470  
   471  	return nil
   472  }
   473  
   474  //获取重组blockchain需要删除和添加节点
   475  func (chain *BlockChain) getReorganizeNodes(node *blockNode) (*list.List, *list.List) {
   476  	attachNodes := list.New()
   477  	detachNodes := list.New()
   478  
   479  	// 查找到分叉的节点,并将分叉之后的block从index链push到attachNodes中
   480  	forkNode := chain.bestChain.FindFork(node)
   481  	for n := node; n != nil && n != forkNode; n = n.parent {
   482  		attachNodes.PushFront(n)
   483  	}
   484  
   485  	// 查找到分叉的节点,并将分叉之后的block从bestchain链push到attachNodes中
   486  	for n := chain.bestChain.Tip(); n != nil && n != forkNode; n = n.parent {
   487  		detachNodes.PushBack(n)
   488  	}
   489  
   490  	return detachNodes, attachNodes
   491  }
   492  
   493  //LoadBlockByHash 根据hash值从缓存中查询区块
   494  func (chain *BlockChain) LoadBlockByHash(hash []byte) (block *types.BlockDetail, err error) {
   495  
   496  	//从缓存的最新区块中获取
   497  	block = chain.blockCache.GetBlockByHash(hash)
   498  	if block != nil {
   499  		return block, err
   500  	}
   501  
   502  	//从缓存的活跃区块中获取
   503  	block, _ = chain.blockStore.GetActiveBlock(string(hash))
   504  	if block != nil {
   505  		return block, err
   506  	}
   507  
   508  	//从数据库中获取
   509  	block, err = chain.blockStore.LoadBlockByHash(hash)
   510  
   511  	//如果是主链区块需要添加到活跃区块的缓存中
   512  	if block != nil {
   513  		mainHash, _ := chain.blockStore.GetBlockHashByHeight(block.Block.GetHeight())
   514  		if mainHash != nil && bytes.Equal(mainHash, hash) {
   515  			chain.blockStore.AddActiveBlock(string(hash), block)
   516  		}
   517  	}
   518  	return block, err
   519  }
   520  
   521  //重组blockchain
   522  func (chain *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error {
   523  	detachBlocks := make([]*types.BlockDetail, 0, detachNodes.Len())
   524  	attachBlocks := make([]*types.BlockDetail, 0, attachNodes.Len())
   525  
   526  	//通过node中的blockhash获取block信息从db中
   527  	cfg := chain.client.GetConfig()
   528  	for e := detachNodes.Front(); e != nil; e = e.Next() {
   529  		n := e.Value.(*blockNode)
   530  		block, err := chain.LoadBlockByHash(n.hash)
   531  
   532  		// 需要删除的blocks
   533  		if block != nil && err == nil {
   534  			detachBlocks = append(detachBlocks, block)
   535  			chainlog.Debug("reorganizeChain detachBlocks ", "height", block.Block.Height, "hash", common.ToHex(block.Block.Hash(cfg)))
   536  		} else {
   537  			chainlog.Error("reorganizeChain detachBlocks fail", "height", n.height, "hash", common.ToHex(n.hash), "err", err)
   538  			return err
   539  		}
   540  	}
   541  
   542  	for e := attachNodes.Front(); e != nil; e = e.Next() {
   543  		n := e.Value.(*blockNode)
   544  		block, err := chain.LoadBlockByHash(n.hash)
   545  
   546  		// 需要加载到db的blocks
   547  		if block != nil && err == nil {
   548  			attachBlocks = append(attachBlocks, block)
   549  			chainlog.Debug("reorganizeChain attachBlocks ", "height", block.Block.Height, "hash", common.ToHex(block.Block.Hash(cfg)))
   550  		} else {
   551  			chainlog.Error("reorganizeChain attachBlocks fail", "height", n.height, "hash", common.ToHex(n.hash), "err", err)
   552  			return err
   553  		}
   554  	}
   555  
   556  	// Disconnect blocks from the main chain.
   557  	for i, e := 0, detachNodes.Front(); e != nil; i, e = i+1, e.Next() {
   558  		n := e.Value.(*blockNode)
   559  		block := detachBlocks[i]
   560  
   561  		// Update the database and chain state.
   562  		err := chain.disconnectBlock(n, block, n.sequence)
   563  		if err != nil {
   564  			return err
   565  		}
   566  	}
   567  
   568  	// Connect the new best chain blocks.
   569  	for i, e := 0, attachNodes.Front(); e != nil; i, e = i+1, e.Next() {
   570  		n := e.Value.(*blockNode)
   571  		block := attachBlocks[i]
   572  
   573  		// Update the database and chain state.
   574  		_, err := chain.connectBlock(n, block)
   575  		if err != nil {
   576  			return err
   577  		}
   578  	}
   579  
   580  	// Log the point where the chain forked and old and new best chain
   581  	// heads.
   582  	if attachNodes.Front() != nil {
   583  		firstAttachNode := attachNodes.Front().Value.(*blockNode)
   584  		chainlog.Debug("REORGANIZE: Chain forks at hash", "hash", common.ToHex(firstAttachNode.parent.hash), "height", firstAttachNode.parent.height)
   585  
   586  	}
   587  	if detachNodes.Front() != nil {
   588  		firstDetachNode := detachNodes.Front().Value.(*blockNode)
   589  		chainlog.Debug("REORGANIZE: Old best chain head was hash", "hash", common.ToHex(firstDetachNode.hash), "height", firstDetachNode.parent.height)
   590  
   591  	}
   592  	if attachNodes.Back() != nil {
   593  		lastAttachNode := attachNodes.Back().Value.(*blockNode)
   594  		chainlog.Debug("REORGANIZE: New best chain head is hash", "hash", common.ToHex(lastAttachNode.hash), "height", lastAttachNode.parent.height)
   595  	}
   596  	return nil
   597  }
   598  
   599  //ProcessDelParaChainBlock 只能从 best chain tip节点开始删除,目前只提供给平行链使用
   600  func (chain *BlockChain) ProcessDelParaChainBlock(broadcast bool, blockdetail *types.BlockDetail, pid string, sequence int64) (*types.BlockDetail, bool, bool, error) {
   601  
   602  	//获取当前的tip节点
   603  	tipnode := chain.bestChain.Tip()
   604  	blockHash := blockdetail.Block.Hash(chain.client.GetConfig())
   605  
   606  	if !bytes.Equal(blockHash, chain.bestChain.Tip().hash) {
   607  		chainlog.Error("ProcessDelParaChainBlock:", "delblockheight", blockdetail.Block.Height, "delblockHash", common.ToHex(blockHash), "bestChain.top.hash", common.ToHex(chain.bestChain.Tip().hash))
   608  		return nil, false, false, types.ErrBlockHashNoMatch
   609  	}
   610  	err := chain.disconnectBlock(tipnode, blockdetail, sequence)
   611  	if err != nil {
   612  		return nil, false, false, err
   613  	}
   614  	//平行链回滚可能出现 向同一高度写哈希相同的区块,
   615  	// 主链中对应的节点信息已经在disconnectBlock处理函数中删除了
   616  	// 这里还需要删除index链中对应的节点信息
   617  	chain.index.DelNode(blockHash)
   618  
   619  	return nil, true, false, nil
   620  }
   621  
   622  // IsRecordFaultErr 检测此错误是否要记录到故障错误中
   623  func IsRecordFaultErr(err error) bool {
   624  	return err != types.ErrFutureBlock && !api.IsGrpcError(err) && !api.IsQueueError(err)
   625  }