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 &paraTxs, 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 &paraTxs, nil
   150  		}
   151  		paraTxs.Items = append(paraTxs.Items, paraTxDetail)
   152  	}
   153  	return &paraTxs, 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  }