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 }