github.com/franono/tendermint@v0.32.2-0.20200527150959-749313264ce9/rpc/core/blocks.go (about)

     1  package core
     2  
     3  import (
     4  	"fmt"
     5  
     6  	tmmath "github.com/franono/tendermint/libs/math"
     7  	ctypes "github.com/franono/tendermint/rpc/core/types"
     8  	rpctypes "github.com/franono/tendermint/rpc/jsonrpc/types"
     9  	sm "github.com/franono/tendermint/state"
    10  	"github.com/franono/tendermint/types"
    11  )
    12  
    13  // BlockchainInfo gets block headers for minHeight <= height <= maxHeight.
    14  // Block headers are returned in descending order (highest first).
    15  // More: https://docs.tendermint.com/master/rpc/#/Info/blockchain
    16  func BlockchainInfo(ctx *rpctypes.Context, minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) {
    17  	// maximum 20 block metas
    18  	const limit int64 = 20
    19  	var err error
    20  	minHeight, maxHeight, err = filterMinMax(
    21  		env.BlockStore.Base(),
    22  		env.BlockStore.Height(),
    23  		minHeight,
    24  		maxHeight,
    25  		limit)
    26  	if err != nil {
    27  		return nil, err
    28  	}
    29  	env.Logger.Debug("BlockchainInfoHandler", "maxHeight", maxHeight, "minHeight", minHeight)
    30  
    31  	blockMetas := []*types.BlockMeta{}
    32  	for height := maxHeight; height >= minHeight; height-- {
    33  		blockMeta := env.BlockStore.LoadBlockMeta(height)
    34  		blockMetas = append(blockMetas, blockMeta)
    35  	}
    36  
    37  	return &ctypes.ResultBlockchainInfo{
    38  		LastHeight: env.BlockStore.Height(),
    39  		BlockMetas: blockMetas}, nil
    40  }
    41  
    42  // error if either min or max are negative or min > max
    43  // if 0, use blockstore base for min, latest block height for max
    44  // enforce limit.
    45  func filterMinMax(base, height, min, max, limit int64) (int64, int64, error) {
    46  	// filter negatives
    47  	if min < 0 || max < 0 {
    48  		return min, max, fmt.Errorf("heights must be non-negative")
    49  	}
    50  
    51  	// adjust for default values
    52  	if min == 0 {
    53  		min = 1
    54  	}
    55  	if max == 0 {
    56  		max = height
    57  	}
    58  
    59  	// limit max to the height
    60  	max = tmmath.MinInt64(height, max)
    61  
    62  	// limit min to the base
    63  	min = tmmath.MaxInt64(base, min)
    64  
    65  	// limit min to within `limit` of max
    66  	// so the total number of blocks returned will be `limit`
    67  	min = tmmath.MaxInt64(min, max-limit+1)
    68  
    69  	if min > max {
    70  		return min, max, fmt.Errorf("min height %d can't be greater than max height %d", min, max)
    71  	}
    72  	return min, max, nil
    73  }
    74  
    75  // Block gets block at a given height.
    76  // If no height is provided, it will fetch the latest block.
    77  // More: https://docs.tendermint.com/master/rpc/#/Info/block
    78  func Block(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultBlock, error) {
    79  	height, err := getHeight(env.BlockStore.Height(), heightPtr)
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  
    84  	block := env.BlockStore.LoadBlock(height)
    85  	blockMeta := env.BlockStore.LoadBlockMeta(height)
    86  	if blockMeta == nil {
    87  		return &ctypes.ResultBlock{BlockID: types.BlockID{}, Block: block}, nil
    88  	}
    89  	return &ctypes.ResultBlock{BlockID: blockMeta.BlockID, Block: block}, nil
    90  }
    91  
    92  // BlockByHash gets block by hash.
    93  // More: https://docs.tendermint.com/master/rpc/#/Info/block_by_hash
    94  func BlockByHash(ctx *rpctypes.Context, hash []byte) (*ctypes.ResultBlock, error) {
    95  	block := env.BlockStore.LoadBlockByHash(hash)
    96  	if block == nil {
    97  		return &ctypes.ResultBlock{BlockID: types.BlockID{}, Block: nil}, nil
    98  	}
    99  	// If block is not nil, then blockMeta can't be nil.
   100  	blockMeta := env.BlockStore.LoadBlockMeta(block.Height)
   101  	return &ctypes.ResultBlock{BlockID: blockMeta.BlockID, Block: block}, nil
   102  }
   103  
   104  // Commit gets block commit at a given height.
   105  // If no height is provided, it will fetch the commit for the latest block.
   106  // More: https://docs.tendermint.com/master/rpc/#/Info/commit
   107  func Commit(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultCommit, error) {
   108  	height, err := getHeight(env.BlockStore.Height(), heightPtr)
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  
   113  	blockMeta := env.BlockStore.LoadBlockMeta(height)
   114  	if blockMeta == nil {
   115  		return nil, nil
   116  	}
   117  	header := blockMeta.Header
   118  
   119  	// If the next block has not been committed yet,
   120  	// use a non-canonical commit
   121  	if height == env.BlockStore.Height() {
   122  		commit := env.BlockStore.LoadSeenCommit(height)
   123  		return ctypes.NewResultCommit(&header, commit, false), nil
   124  	}
   125  
   126  	// Return the canonical commit (comes from the block at height+1)
   127  	commit := env.BlockStore.LoadBlockCommit(height)
   128  	return ctypes.NewResultCommit(&header, commit, true), nil
   129  }
   130  
   131  // BlockResults gets ABCIResults at a given height.
   132  // If no height is provided, it will fetch results for the latest block.
   133  //
   134  // Results are for the height of the block containing the txs.
   135  // Thus response.results.deliver_tx[5] is the results of executing
   136  // getBlock(h).Txs[5]
   137  // More: https://docs.tendermint.com/master/rpc/#/Info/block_results
   138  func BlockResults(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultBlockResults, error) {
   139  	height, err := getHeight(env.BlockStore.Height(), heightPtr)
   140  	if err != nil {
   141  		return nil, err
   142  	}
   143  
   144  	results, err := sm.LoadABCIResponses(env.StateDB, height)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  
   149  	return &ctypes.ResultBlockResults{
   150  		Height:                height,
   151  		TxsResults:            results.DeliverTxs,
   152  		BeginBlockEvents:      results.BeginBlock.Events,
   153  		EndBlockEvents:        results.EndBlock.Events,
   154  		ValidatorUpdates:      results.EndBlock.ValidatorUpdates,
   155  		ConsensusParamUpdates: results.EndBlock.ConsensusParamUpdates,
   156  	}, nil
   157  }