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 }