github.com/turingchain2020/turingchain@v1.1.21/system/p2p/dht/protocol/broadcast/block.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 broadcast
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/hex"
    10  
    11  	"github.com/turingchain2020/turingchain/common/merkle"
    12  	"github.com/turingchain2020/turingchain/types"
    13  )
    14  
    15  func (p *broadcastProtocol) sendBlock(block *types.P2PBlock, p2pData *types.BroadCastData, pid string) (doSend bool) {
    16  	byteHash := block.Block.Hash(p.ChainCfg)
    17  	blockHash := hex.EncodeToString(byteHash)
    18  	//检测冗余发送
    19  	if addIgnoreSendPeerAtomic(p.blockSendFilter, blockHash, pid) {
    20  		return false
    21  	}
    22  	blockSize := types.Size(block.Block)
    23  	//log.Debug("P2PSendBlock", "blockHash", blockHash, "peerAddr", peerAddr, "blockSize(KB)", float32(blockSize)/1024)
    24  	//区块内交易采用哈希广播
    25  	if blockSize >= int(p.p2pCfg.MinLtBlockSize*1024) {
    26  		ltBlock := &types.LightBlock{}
    27  		ltBlock.Size = int64(blockSize)
    28  		ltBlock.Header = block.Block.GetHeader(p.ChainCfg)
    29  		ltBlock.Header.Hash = byteHash[:]
    30  		ltBlock.Header.Signature = block.Block.Signature
    31  		ltBlock.MinerTx = block.Block.Txs[0]
    32  		for _, tx := range block.Block.Txs[1:] {
    33  			//tx short hash
    34  			ltBlock.STxHashes = append(ltBlock.STxHashes, types.CalcTxShortHash(tx.Hash()))
    35  		}
    36  
    37  		p2pData.Value = &types.BroadCastData_LtBlock{LtBlock: ltBlock}
    38  	} else {
    39  		p2pData.Value = &types.BroadCastData_Block{Block: block}
    40  	}
    41  
    42  	return true
    43  }
    44  
    45  func (p *broadcastProtocol) recvBlock(block *types.P2PBlock, pid, peerAddr string) error {
    46  
    47  	if block.GetBlock() == nil {
    48  		return types.ErrInvalidParam
    49  	}
    50  	blockHash := hex.EncodeToString(block.GetBlock().Hash(p.ChainCfg))
    51  	//将节点id添加到发送过滤, 避免冗余发送
    52  	addIgnoreSendPeerAtomic(p.blockSendFilter, blockHash, pid)
    53  	//如果重复接收, 则不再发到blockchain执行
    54  	if p.blockFilter.AddWithCheckAtomic(blockHash, true) {
    55  		return nil
    56  	}
    57  	log.Debug("recvBlock", "height", block.GetBlock().GetHeight(), "size(KB)", float32(types.Size(block.GetBlock()))/1024)
    58  	//发送至blockchain执行
    59  	if err := p.postBlockChain(blockHash, pid, block.GetBlock()); err != nil {
    60  		log.Error("recvBlock", "send block to blockchain Error", err.Error())
    61  		return errSendBlockChain
    62  	}
    63  	return nil
    64  }
    65  
    66  func (p *broadcastProtocol) recvLtBlock(ltBlock *types.LightBlock, pid, peerAddr, version string) error {
    67  
    68  	blockHash := hex.EncodeToString(ltBlock.Header.Hash)
    69  	//将节点id添加到发送过滤, 避免冗余发送
    70  	addIgnoreSendPeerAtomic(p.blockSendFilter, blockHash, pid)
    71  	//检测是否已经收到此block
    72  	if p.blockFilter.AddWithCheckAtomic(blockHash, true) {
    73  		return nil
    74  	}
    75  
    76  	//组装block
    77  	block := &types.Block{}
    78  	block.TxHash = ltBlock.Header.TxHash
    79  	block.Signature = ltBlock.Header.Signature
    80  	block.ParentHash = ltBlock.Header.ParentHash
    81  	block.Height = ltBlock.Header.Height
    82  	block.BlockTime = ltBlock.Header.BlockTime
    83  	block.Difficulty = ltBlock.Header.Difficulty
    84  	block.Version = ltBlock.Header.Version
    85  	block.StateHash = ltBlock.Header.StateHash
    86  	//add miner tx
    87  	block.Txs = append(block.Txs, ltBlock.MinerTx)
    88  
    89  	txList := &types.ReplyTxList{}
    90  	ok := false
    91  	//get tx list from mempool
    92  	if len(ltBlock.STxHashes) > 0 {
    93  		resp, err := p.P2PEnv.QueryModule("mempool", types.EventTxListByHash,
    94  			&types.ReqTxHashList{Hashes: ltBlock.STxHashes, IsShortHash: true})
    95  		if err != nil {
    96  			log.Error("recvLtBlock", "queryTxListByHashErr", err)
    97  			return errRecvMempool
    98  		}
    99  
   100  		txList, ok = resp.(*types.ReplyTxList)
   101  		if !ok {
   102  			log.Error("recvLtBlock", "queryMemPool", "nilReplyTxList")
   103  		}
   104  	}
   105  	nilTxIndices := make([]int32, 0)
   106  	for i := 0; ok && i < len(txList.Txs); i++ {
   107  		tx := txList.Txs[i]
   108  		if tx == nil {
   109  			//tx not exist in mempool
   110  			nilTxIndices = append(nilTxIndices, int32(i+1))
   111  			tx = &types.Transaction{}
   112  		} else if count := tx.GetGroupCount(); count > 0 {
   113  
   114  			group, err := tx.GetTxGroup()
   115  			if err != nil {
   116  				log.Error("recvLtBlock", "getTxGroupErr", err)
   117  				//触发请求所有
   118  				nilTxIndices = nilTxIndices[:0]
   119  				break
   120  			}
   121  			block.Txs = append(block.Txs, group.Txs...)
   122  			//跳过遍历
   123  			i += len(group.Txs) - 1
   124  			continue
   125  		}
   126  		block.Txs = append(block.Txs, tx)
   127  	}
   128  	nilTxLen := len(nilTxIndices)
   129  
   130  	//需要比较交易根哈希是否一致, 不一致需要请求区块内所有的交易
   131  	if nilTxLen == 0 && bytes.Equal(block.TxHash, merkle.CalcMerkleRoot(p.ChainCfg, block.GetHeight(), block.Txs)) {
   132  
   133  		log.Debug("recvLtBlock", "height", block.GetHeight(), "txCount", ltBlock.Header.TxCount, "size(KB)", float32(ltBlock.Size)/1024)
   134  		//发送至blockchain执行
   135  		if err := p.postBlockChain(blockHash, pid, block); err != nil {
   136  			log.Error("recvLtBlock", "send block to blockchain Error", err.Error())
   137  			return errSendBlockChain
   138  		}
   139  		return nil
   140  	}
   141  	//本地缺失交易或者根哈希不同(nilTxLen==0)
   142  	log.Debug("recvLtBlock", "height", ltBlock.Header.Height, "hash", blockHash,
   143  		"txCount", ltBlock.Header.TxCount, "missTxCount", nilTxLen,
   144  		"blockSize(KB)", float32(ltBlock.Size)/1024, "buildBlockSize(KB)", float32(block.Size())/1024)
   145  	// 缺失的交易个数大于总数1/3 或者缺失数据大小大于2/3, 触发请求区块所有交易数据
   146  	if nilTxLen > 0 && (float32(nilTxLen) > float32(ltBlock.Header.TxCount)/3 ||
   147  		float32(block.Size()) < float32(ltBlock.Size)/3) {
   148  		//空的TxIndices表示请求区块内所有交易
   149  		nilTxIndices = nilTxIndices[:0]
   150  	}
   151  
   152  	// query not exist txs
   153  	query := &types.P2PQueryData{
   154  		Value: &types.P2PQueryData_BlockTxReq{
   155  			BlockTxReq: &types.P2PBlockTxReq{
   156  				BlockHash: blockHash,
   157  				TxIndices: nilTxIndices,
   158  			},
   159  		},
   160  	}
   161  
   162  	//需要将不完整的block预存
   163  	p.ltBlockCache.Add(blockHash, block, block.Size())
   164  	//query peer
   165  	if err := p.sendPeer(query, pid, version); err != nil {
   166  		log.Error("recvLtBlock", "pid", pid, "addr", peerAddr, "err", err)
   167  		p.blockFilter.Remove(blockHash)
   168  		p.ltBlockCache.Remove(blockHash)
   169  		return errSendPeer
   170  	}
   171  	return nil
   172  }