github.com/turingchain2020/turingchain@v1.1.21/blockchain/filter_paratx.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 "strings" 10 11 "github.com/turingchain2020/turingchain/common/merkle" 12 "github.com/turingchain2020/turingchain/types" 13 ) 14 15 var ( 16 filterlog = chainlog.New("submodule", "filter") 17 ) 18 19 //GetParaTxByTitle 通过seq以及title获取对应平行连的交易 20 func (chain *BlockChain) GetParaTxByTitle(seq *types.ReqParaTxByTitle) (*types.ParaTxDetails, error) { 21 22 //入参数校验 23 err := chain.checkInputParam(seq) 24 if err != nil { 25 return nil, err 26 } 27 28 //对获取区块的起始和结束值做校验,最多一次取1000个区块,防止取的数据过大导致内存异常 29 if seq.End > seq.Start && (seq.End-seq.Start > types.MaxBlockCountPerTime) { 30 seq.End = seq.Start + types.MaxBlockCountPerTime - 1 31 } 32 var reqHashes types.ReqHashes 33 var sequences *types.BlockSequences 34 if seq.IsSeq { 35 req := &types.ReqBlocks{Start: seq.Start, End: seq.End, IsDetail: false, Pid: []string{}} 36 sequences, err = chain.GetBlockSequences(req) 37 if err != nil { 38 filterlog.Error("GetParaTxByTitle:GetBlockSequences", "err", err.Error()) 39 return nil, err 40 } 41 for _, item := range sequences.Items { 42 if item != nil { 43 reqHashes.Hashes = append(reqHashes.Hashes, item.GetHash()) 44 } 45 } 46 } else { 47 reqHashes = chain.getBlockHashes(seq.Start, seq.End) 48 } 49 50 //通过区块hash获取区块信息 51 blocks, err := chain.GetBlockByHashes(reqHashes.Hashes) 52 if err != nil { 53 filterlog.Error("GetParaTxByTitle:GetBlockByHashes", "err", err) 54 return nil, err 55 } 56 57 cfg := chain.client.GetConfig() 58 //通过指定的title过滤对应平行链的交易 59 var paraTxs types.ParaTxDetails 60 var paraTx *types.ParaTxDetail 61 for i, block := range blocks.Items { 62 if block != nil { 63 paraTx = block.FilterParaTxsByTitle(cfg, seq.Title) 64 if seq.IsSeq { 65 paraTx.Type = sequences.Items[i].GetType() 66 } else { 67 paraTx.Type = types.AddBlock 68 } 69 height := block.Block.GetHeight() 70 blockhash := block.Block.Hash(cfg) 71 if cfg.IsFork(height, "ForkRootHash") { 72 branch, childHash, index := chain.getChildChainProofs(height, blockhash, seq.Title, block.Block.GetTxs()) 73 paraTx.ChildHash = childHash 74 paraTx.Index = index 75 paraTx.Proofs = branch 76 } 77 } else { 78 paraTx = nil 79 } 80 paraTxs.Items = append(paraTxs.Items, paraTx) 81 } 82 return ¶Txs, nil 83 } 84 85 //checkInputParam 入参检测,主要检测req的end的值以及title是否合法 86 func (chain *BlockChain) checkInputParam(req *types.ReqParaTxByTitle) error { 87 var err error 88 var lastblock int64 89 90 if req.GetStart() > req.GetEnd() { 91 chainlog.Error("checkInputParam input must Start <= End:", "Start", req.Start, "End", req.End) 92 return types.ErrEndLessThanStartHeight 93 } 94 95 //需要区分是通过seq/height来获取平行链交易 96 if req.IsSeq { 97 lastblock, err = chain.blockStore.LoadBlockLastSequence() 98 } else { 99 lastblock = chain.GetBlockHeight() 100 } 101 if err != nil || req.End > lastblock || lastblock < 0 || !strings.HasPrefix(req.Title, types.ParaKeyX) { 102 filterlog.Error("checkInputParam", "lastblock", lastblock, "req", req, "err", err) 103 return types.ErrInvalidParam 104 } 105 return nil 106 } 107 108 //GetParaTxByHeight 通过height以及title获取对应平行连的交易 109 func (chain *BlockChain) GetParaTxByHeight(req *types.ReqParaTxByHeight) (*types.ParaTxDetails, error) { 110 //入参数校验 111 if req == nil { 112 return nil, types.ErrInvalidParam 113 } 114 count := len(req.Items) 115 if int64(count) > types.MaxBlockCountPerTime { 116 return nil, types.ErrInvalidParam 117 } 118 lastheight := chain.GetBlockHeight() 119 if req.Items[0] < 0 || req.Items[count-1] > lastheight { 120 return nil, types.ErrInvalidParam 121 } 122 if !strings.HasPrefix(req.Title, types.ParaKeyX) { 123 return nil, types.ErrInvalidParam 124 } 125 cfg := chain.client.GetConfig() 126 var paraTxs types.ParaTxDetails 127 var paraTxDetail *types.ParaTxDetail 128 size := 0 129 for _, height := range req.Items { 130 block, err := chain.GetBlock(height) 131 if err != nil { 132 filterlog.Error("GetParaTxByHeight:GetBlock", "height", height, "err", err) 133 } else { 134 paraTxDetail = block.FilterParaTxsByTitle(cfg, req.Title) 135 if paraTxDetail != nil { 136 paraTxDetail.Type = types.AddBlock 137 blockHash := block.Block.Hash(cfg) 138 if cfg.IsFork(height, "ForkRootHash") { 139 branch, childHash, index := chain.getChildChainProofs(height, blockHash, req.Title, block.Block.GetTxs()) 140 paraTxDetail.ChildHash = childHash 141 paraTxDetail.Index = index 142 paraTxDetail.Proofs = branch 143 } 144 } 145 } 146 size += paraTxDetail.Size() 147 if size > types.MaxBlockSizePerTime { 148 chainlog.Info("GetParaTxByHeight:overflow", "MaxBlockSizePerTime", types.MaxBlockSizePerTime) 149 return ¶Txs, nil 150 } 151 paraTxs.Items = append(paraTxs.Items, paraTxDetail) 152 } 153 return ¶Txs, nil 154 } 155 156 //获取指定title子链roothash在指定高度上的路径证明 157 func (chain *BlockChain) getChildChainProofs(height int64, blockHash []byte, title string, txs []*types.Transaction) ([][]byte, []byte, uint32) { 158 var branch [][]byte 159 var childHash []byte 160 var index uint32 161 var hashes [][]byte 162 var exist bool 163 //主链直接从数据库获取对应的子链根hash 164 paraTxs, err := chain.LoadParaTxByHeight(height, "", 0, 1) 165 if err == nil && len(paraTxs.Items) > 0 && bytes.Equal(paraTxs.Items[0].GetHash(), blockHash) { 166 for _, paratx := range paraTxs.Items { 167 if title == paratx.Title { 168 index = paratx.ChildHashIndex 169 childHash = paratx.ChildHash 170 exist = true 171 } 172 hashes = append(hashes, paratx.ChildHash) 173 } 174 if exist { 175 branch = merkle.GetMerkleBranch(hashes, index) 176 return branch, childHash, index 177 } 178 return nil, nil, 0 179 } 180 //侧链的需要重新计算 181 cfg := chain.client.GetConfig() 182 _, childChains := merkle.CalcMultiLayerMerkleInfo(cfg, height, txs) 183 for i, childchain := range childChains { 184 hashes = append(hashes, childchain.ChildHash) 185 if childchain.Title == title { 186 index = uint32(i) 187 childHash = childchain.ChildHash 188 exist = true 189 } 190 } 191 if exist { 192 branch = merkle.GetMerkleBranch(hashes, index) 193 return branch, childHash, index 194 } 195 return nil, nil, 0 196 } 197 198 //LoadParaTxByTitle 通过title获取本平行链交易所在的区块高度信息前后翻页 199 func (chain *BlockChain) LoadParaTxByTitle(req *types.ReqHeightByTitle) (*types.ReplyHeightByTitle, error) { 200 var primaryKey []byte 201 202 //入参合法性检测 203 if req == nil || int64(req.Count) > types.MaxHeaderCountPerTime { 204 return nil, types.ErrInvalidParam 205 } 206 if req.GetDirection() != 0 && req.GetDirection() != 1 { 207 return nil, types.ErrInvalidParam 208 } 209 curHeight := chain.GetBlockHeight() 210 if req.Height > curHeight || len(req.Title) == 0 || !strings.HasPrefix(req.Title, types.ParaKeyX) { 211 return nil, types.ErrInvalidParam 212 } 213 if req.Height != -1 { 214 primaryKey = calcHeightTitleKey(req.Height, req.Title) 215 } else { 216 primaryKey = nil 217 } 218 paraInfos, err := getParaTxByIndex(chain.blockStore.db, "title", []byte(req.Title), primaryKey, req.Count, req.Direction) 219 if err != nil { 220 return nil, err 221 } 222 223 var reply types.ReplyHeightByTitle 224 reply.Title = req.Title 225 for _, para := range paraInfos.Items { 226 reply.Items = append(reply.Items, &types.BlockInfo{Height: para.GetHeight(), Hash: para.GetHash()}) 227 } 228 return &reply, nil 229 } 230 231 //LoadParaTxByHeight 通过height获取本高度上的平行链title前后翻页;预留接口 232 func (chain *BlockChain) LoadParaTxByHeight(height int64, title string, count, direction int32) (*types.HeightParas, error) { 233 //入参合法性检测 234 curHeight := chain.GetBlockHeight() 235 if height > curHeight || height < 0 { 236 return nil, types.ErrInvalidParam 237 } 238 239 var primaryKey []byte 240 if len(title) == 0 { 241 primaryKey = nil 242 } else if !strings.HasPrefix(title, types.ParaKeyX) { 243 return nil, types.ErrInvalidParam 244 } else { 245 primaryKey = calcHeightTitleKey(height, title) 246 } 247 return getParaTxByIndex(chain.blockStore.db, "height", calcHeightParaKey(height), primaryKey, count, direction) 248 }