github.com/turingchain2020/turingchain@v1.1.21/blockchain/query_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 blockchain
     6  
     7  import (
     8  	"github.com/turingchain2020/turingchain/common"
     9  	"github.com/turingchain2020/turingchain/types"
    10  )
    11  
    12  //GetBlockByHashes 通过blockhash 获取对应的block信息
    13  //从数据库获取区块不能太多,防止内存异常。一次最多获取100M区块数据从数据库
    14  func (chain *BlockChain) GetBlockByHashes(hashes [][]byte) (respblocks *types.BlockDetails, err error) {
    15  	if int64(len(hashes)) > types.MaxBlockCountPerTime {
    16  		return nil, types.ErrMaxCountPerTime
    17  	}
    18  	var blocks types.BlockDetails
    19  	size := 0
    20  	for _, hash := range hashes {
    21  		block, err := chain.LoadBlockByHash(hash)
    22  		if err == nil && block != nil {
    23  			size += block.Size()
    24  			if size > types.MaxBlockSizePerTime {
    25  				chainlog.Error("GetBlockByHashes:overflow", "MaxBlockSizePerTime", types.MaxBlockSizePerTime)
    26  				return &blocks, nil
    27  			}
    28  			blocks.Items = append(blocks.Items, block)
    29  		} else {
    30  			blocks.Items = append(blocks.Items, new(types.BlockDetail))
    31  		}
    32  	}
    33  	return &blocks, nil
    34  }
    35  
    36  //ProcGetBlockHash 通过blockheight 获取blockhash
    37  func (chain *BlockChain) ProcGetBlockHash(height *types.ReqInt) (*types.ReplyHash, error) {
    38  	if height == nil || 0 > height.GetHeight() {
    39  		chainlog.Error("ProcGetBlockHash input err!")
    40  		return nil, types.ErrInvalidParam
    41  	}
    42  	CurHeight := chain.GetBlockHeight()
    43  	if height.GetHeight() > CurHeight {
    44  		chainlog.Error("ProcGetBlockHash input height err!")
    45  		return nil, types.ErrInvalidParam
    46  	}
    47  	var ReplyHash types.ReplyHash
    48  	var err error
    49  	ReplyHash.Hash, err = chain.blockStore.GetBlockHashByHeight(height.GetHeight())
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	return &ReplyHash, nil
    54  }
    55  
    56  //ProcGetBlockOverview 返回值
    57  // type  BlockOverview {
    58  //	Header head = 1;
    59  //	int64  txCount = 2;
    60  //	repeated bytes txHashes = 3;}
    61  //获取BlockOverview
    62  func (chain *BlockChain) ProcGetBlockOverview(ReqHash *types.ReqHash) (*types.BlockOverview, error) {
    63  	if ReqHash == nil {
    64  		chainlog.Error("ProcGetBlockOverview input err!")
    65  		return nil, types.ErrInvalidParam
    66  	}
    67  	var blockOverview types.BlockOverview
    68  	//通过height获取block
    69  	block, err := chain.LoadBlockByHash(ReqHash.Hash)
    70  	if err != nil || block == nil {
    71  		chainlog.Error("ProcGetBlockOverview", "GetBlock err ", err)
    72  		return nil, err
    73  	}
    74  
    75  	//获取header的信息从block中
    76  	var header types.Header
    77  	header.Version = block.Block.Version
    78  	header.ParentHash = block.Block.ParentHash
    79  	header.TxHash = block.Block.TxHash
    80  	header.StateHash = block.Block.StateHash
    81  	header.BlockTime = block.Block.BlockTime
    82  	header.Height = block.Block.Height
    83  	header.Hash = block.Block.Hash(chain.client.GetConfig())
    84  	header.TxCount = int64(len(block.Block.GetTxs()))
    85  	header.Difficulty = block.Block.Difficulty
    86  	header.Signature = block.Block.Signature
    87  
    88  	blockOverview.Head = &header
    89  
    90  	blockOverview.TxCount = int64(len(block.Block.GetTxs()))
    91  
    92  	txhashs := make([][]byte, blockOverview.TxCount)
    93  	for index, tx := range block.Block.Txs {
    94  		txhashs[index] = tx.Hash()
    95  	}
    96  	blockOverview.TxHashes = txhashs
    97  	chainlog.Debug("ProcGetBlockOverview", "blockOverview:", blockOverview.String())
    98  	return &blockOverview, nil
    99  }
   100  
   101  //ProcGetLastBlockMsg 获取最新区块信息
   102  func (chain *BlockChain) ProcGetLastBlockMsg() (respblock *types.Block, err error) {
   103  	block := chain.blockStore.LastBlock()
   104  	return block, nil
   105  }
   106  
   107  //ProcGetBlockByHashMsg 获取最新区块hash
   108  func (chain *BlockChain) ProcGetBlockByHashMsg(hash []byte) (respblock *types.BlockDetail, err error) {
   109  	blockdetail, err := chain.LoadBlockByHash(hash)
   110  	if err != nil {
   111  		return nil, err
   112  	}
   113  	return blockdetail, nil
   114  }
   115  
   116  //ProcGetHeadersMsg 返回值
   117  //type Header struct {
   118  //	Version    int64
   119  //	ParentHash []byte
   120  //	TxHash     []byte
   121  //	Height     int64
   122  //	BlockTime  int64
   123  //}
   124  func (chain *BlockChain) ProcGetHeadersMsg(requestblock *types.ReqBlocks) (respheaders *types.Headers, err error) {
   125  	blockhight := chain.GetBlockHeight()
   126  
   127  	if requestblock.GetStart() > requestblock.GetEnd() {
   128  		chainlog.Error("ProcGetHeadersMsg input must Start <= End:", "Startheight", requestblock.Start, "Endheight", requestblock.End)
   129  		return nil, types.ErrEndLessThanStartHeight
   130  	}
   131  	if requestblock.End-requestblock.Start >= types.MaxHeaderCountPerTime {
   132  		return nil, types.ErrMaxCountPerTime
   133  	}
   134  	if requestblock.Start > blockhight {
   135  		chainlog.Error("ProcGetHeadersMsg Startheight err", "startheight", requestblock.Start, "curheight", blockhight)
   136  		return nil, types.ErrStartHeight
   137  	}
   138  	end := requestblock.End
   139  	if requestblock.End > blockhight {
   140  		end = blockhight
   141  	}
   142  	start := requestblock.Start
   143  	count := end - start + 1
   144  	chainlog.Debug("ProcGetHeadersMsg", "headerscount", count)
   145  	if count < 1 {
   146  		chainlog.Error("ProcGetHeadersMsg count err", "startheight", requestblock.Start, "endheight", requestblock.End, "curheight", blockhight)
   147  		return nil, types.ErrEndLessThanStartHeight
   148  	}
   149  
   150  	var headers types.Headers
   151  	headers.Items = make([]*types.Header, count)
   152  	j := 0
   153  	for i := start; i <= end; i++ {
   154  		head, err := chain.blockStore.GetBlockHeaderByHeight(i)
   155  		if err == nil && head != nil {
   156  			headers.Items[j] = head
   157  		} else {
   158  			return nil, err
   159  		}
   160  		j++
   161  	}
   162  	chainlog.Debug("getHeaders", "len", len(headers.Items), "start", start, "end", end)
   163  	return &headers, nil
   164  }
   165  
   166  //ProcGetLastHeaderMsg 获取最新区块头信息
   167  func (chain *BlockChain) ProcGetLastHeaderMsg() (*types.Header, error) {
   168  	//首先从缓存中获取最新的blockheader
   169  	head := chain.blockStore.LastHeader()
   170  	if head == nil {
   171  		blockhight := chain.GetBlockHeight()
   172  		tmpHead, err := chain.blockStore.GetBlockHeaderByHeight(blockhight)
   173  		if err == nil && tmpHead != nil {
   174  			chainlog.Error("ProcGetLastHeaderMsg from cache is nil.", "blockhight", blockhight, "hash", common.ToHex(tmpHead.Hash))
   175  			return tmpHead, nil
   176  		}
   177  		return nil, err
   178  
   179  	}
   180  	return head, nil
   181  }
   182  
   183  /*
   184  ProcGetBlockDetailsMsg EventGetBlocks(types.RequestGetBlock): rpc 模块 会向 blockchain 模块发送 EventGetBlocks(types.RequestGetBlock) 消息,
   185  功能是查询 区块的信息, 回复消息是 EventBlocks(types.Blocks)
   186  type ReqBlocks struct {
   187  	Start int64 `protobuf:"varint,1,opt,name=start" json:"start,omitempty"`
   188  	End   int64 `protobuf:"varint,2,opt,name=end" json:"end,omitempty"`}
   189  type Blocks struct {Items []*Block `protobuf:"bytes,1,rep,name=items" json:"items,omitempty"`}
   190  */
   191  func (chain *BlockChain) ProcGetBlockDetailsMsg(requestblock *types.ReqBlocks) (respblocks *types.BlockDetails, err error) {
   192  	blockhight := chain.GetBlockHeight()
   193  	if requestblock.Start > blockhight {
   194  		chainlog.Error("ProcGetBlockDetailsMsg Startheight err", "startheight", requestblock.Start, "curheight", blockhight)
   195  		return nil, types.ErrStartHeight
   196  	}
   197  	if requestblock.GetStart() > requestblock.GetEnd() {
   198  		chainlog.Error("ProcGetBlockDetailsMsg input must Start <= End:", "Startheight", requestblock.Start, "Endheight", requestblock.End)
   199  		return nil, types.ErrEndLessThanStartHeight
   200  	}
   201  	if requestblock.End-requestblock.Start >= types.MaxBlockCountPerTime {
   202  		return nil, types.ErrMaxCountPerTime
   203  	}
   204  	chainlog.Debug("ProcGetBlockDetailsMsg", "Start", requestblock.Start, "End", requestblock.End, "Isdetail", requestblock.IsDetail)
   205  
   206  	end := requestblock.End
   207  	if requestblock.End > blockhight {
   208  		end = blockhight
   209  	}
   210  	start := requestblock.Start
   211  	count := end - start + 1
   212  	chainlog.Debug("ProcGetBlockDetailsMsg", "blockscount", count)
   213  
   214  	var blocks types.BlockDetails
   215  	blocks.Items = make([]*types.BlockDetail, count)
   216  	j := 0
   217  	for i := start; i <= end; i++ {
   218  		block, err := chain.GetBlock(i)
   219  		if err == nil && block != nil {
   220  			if requestblock.IsDetail {
   221  				blocks.Items[j] = block
   222  			} else {
   223  				var blockdetail types.BlockDetail
   224  				blockdetail.Block = block.Block
   225  				blockdetail.Receipts = nil
   226  				blocks.Items[j] = &blockdetail
   227  			}
   228  		} else {
   229  			return nil, err
   230  		}
   231  		j++
   232  	}
   233  	//print
   234  	if requestblock.IsDetail {
   235  		for _, blockinfo := range blocks.Items {
   236  			chainlog.Debug("ProcGetBlocksMsg", "blockinfo", blockinfo.String())
   237  		}
   238  	}
   239  	return &blocks, nil
   240  }
   241  
   242  //ProcAddBlockMsg 处理从peer对端同步过来的block消息
   243  func (chain *BlockChain) ProcAddBlockMsg(broadcast bool, blockdetail *types.BlockDetail, pid string) (*types.BlockDetail, error) {
   244  	beg := types.Now()
   245  	defer func() {
   246  		chainlog.Debug("ProcAddBlockMsg", "height", blockdetail.GetBlock().GetHeight(),
   247  			"txCount", len(blockdetail.GetBlock().GetTxs()), "recvFrom", pid, "cost", types.Since(beg))
   248  	}()
   249  
   250  	block := blockdetail.Block
   251  	if block == nil {
   252  		chainlog.Error("ProcAddBlockMsg input block is null")
   253  		return nil, types.ErrInvalidParam
   254  	}
   255  	b, ismain, isorphan, err := chain.ProcessBlock(broadcast, blockdetail, pid, true, -1)
   256  	if b != nil {
   257  		blockdetail = b
   258  	}
   259  
   260  	height := blockdetail.Block.GetHeight()
   261  	hash := blockdetail.Block.Hash(chain.client.GetConfig())
   262  
   263  	//更新广播block的高度,设置请求过来的区块已经处理完成
   264  	if broadcast {
   265  		chain.UpdateRcvCastBlkHeight(height)
   266  	} else {
   267  		//syncTask 运行时设置对应的blockdone
   268  		if chain.syncTask.InProgress() {
   269  			chain.syncTask.Done(height)
   270  		}
   271  		//downLoadTask 运行时设置对应的blockdone
   272  		if chain.downLoadTask.InProgress() {
   273  			chain.downLoadTask.Done(height)
   274  		}
   275  	}
   276  	if pid == "self" {
   277  		if err != nil {
   278  			return nil, err
   279  		}
   280  		if b == nil {
   281  			return nil, types.ErrExecBlockNil
   282  		}
   283  	}
   284  	chainlog.Debug("ProcAddBlockMsg result:", "height", height, "ismain", ismain, "isorphan", isorphan, "hash", common.ToHex(hash), "err", err)
   285  	return blockdetail, err
   286  }
   287  
   288  //getBlockHashes 获取指定height区间对应的blockhashes
   289  func (chain *BlockChain) getBlockHashes(startheight, endheight int64) types.ReqHashes {
   290  	var reqHashes types.ReqHashes
   291  	for i := startheight; i <= endheight; i++ {
   292  		hash, err := chain.blockStore.GetBlockHashByHeight(i)
   293  		if hash == nil || err != nil {
   294  			storeLog.Error("getBlockHashesByHeight", "height", i, "error", err)
   295  			reqHashes.Hashes = append(reqHashes.Hashes, nil)
   296  		} else {
   297  			reqHashes.Hashes = append(reqHashes.Hashes, hash)
   298  		}
   299  	}
   300  	return reqHashes
   301  }