github.com/number571/tendermint@v0.34.11-gost/rpc/core/blocks.go (about) 1 package core 2 3 import ( 4 "fmt" 5 "sort" 6 7 tmmath "github.com/number571/tendermint/libs/math" 8 tmquery "github.com/number571/tendermint/libs/pubsub/query" 9 ctypes "github.com/number571/tendermint/rpc/core/types" 10 rpctypes "github.com/number571/tendermint/rpc/jsonrpc/types" 11 "github.com/number571/tendermint/state/indexer" 12 "github.com/number571/tendermint/types" 13 ) 14 15 // BlockchainInfo gets block headers for minHeight <= height <= maxHeight. 16 // 17 // If maxHeight does not yet exist, blocks up to the current height will be 18 // returned. If minHeight does not exist (due to pruning), earliest existing 19 // height will be used. 20 // 21 // At most 20 items will be returned. Block headers are returned in descending 22 // order (highest first). 23 // 24 // More: https://docs.tendermint.com/master/rpc/#/Info/blockchain 25 func (env *Environment) BlockchainInfo( 26 ctx *rpctypes.Context, 27 minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) { 28 29 const limit int64 = 20 30 31 var err error 32 minHeight, maxHeight, err = filterMinMax( 33 env.BlockStore.Base(), 34 env.BlockStore.Height(), 35 minHeight, 36 maxHeight, 37 limit) 38 if err != nil { 39 return nil, err 40 } 41 env.Logger.Debug("BlockchainInfo", "maxHeight", maxHeight, "minHeight", minHeight) 42 43 blockMetas := make([]*types.BlockMeta, 0, maxHeight-minHeight+1) 44 for height := maxHeight; height >= minHeight; height-- { 45 blockMeta := env.BlockStore.LoadBlockMeta(height) 46 if blockMeta != nil { 47 blockMetas = append(blockMetas, blockMeta) 48 } 49 } 50 51 return &ctypes.ResultBlockchainInfo{ 52 LastHeight: env.BlockStore.Height(), 53 BlockMetas: blockMetas}, nil 54 } 55 56 // error if either min or max are negative or min > max 57 // if 0, use blockstore base for min, latest block height for max 58 // enforce limit. 59 func filterMinMax(base, height, min, max, limit int64) (int64, int64, error) { 60 // filter negatives 61 if min < 0 || max < 0 { 62 return min, max, ctypes.ErrZeroOrNegativeHeight 63 } 64 65 // adjust for default values 66 if min == 0 { 67 min = 1 68 } 69 if max == 0 { 70 max = height 71 } 72 73 // limit max to the height 74 max = tmmath.MinInt64(height, max) 75 76 // limit min to the base 77 min = tmmath.MaxInt64(base, min) 78 79 // limit min to within `limit` of max 80 // so the total number of blocks returned will be `limit` 81 min = tmmath.MaxInt64(min, max-limit+1) 82 83 if min > max { 84 return min, max, fmt.Errorf("%w: min height %d can't be greater than max height %d", 85 ctypes.ErrInvalidRequest, min, max) 86 } 87 return min, max, nil 88 } 89 90 // Block gets block at a given height. 91 // If no height is provided, it will fetch the latest block. 92 // More: https://docs.tendermint.com/master/rpc/#/Info/block 93 func (env *Environment) Block(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultBlock, error) { 94 height, err := env.getHeight(env.BlockStore.Height(), heightPtr) 95 if err != nil { 96 return nil, err 97 } 98 99 blockMeta := env.BlockStore.LoadBlockMeta(height) 100 if blockMeta == nil { 101 return &ctypes.ResultBlock{BlockID: types.BlockID{}, Block: nil}, nil 102 } 103 104 block := env.BlockStore.LoadBlock(height) 105 return &ctypes.ResultBlock{BlockID: blockMeta.BlockID, Block: block}, nil 106 } 107 108 // BlockByHash gets block by hash. 109 // More: https://docs.tendermint.com/master/rpc/#/Info/block_by_hash 110 func (env *Environment) BlockByHash(ctx *rpctypes.Context, hash []byte) (*ctypes.ResultBlock, error) { 111 block := env.BlockStore.LoadBlockByHash(hash) 112 if block == nil { 113 return &ctypes.ResultBlock{BlockID: types.BlockID{}, Block: nil}, nil 114 } 115 // If block is not nil, then blockMeta can't be nil. 116 blockMeta := env.BlockStore.LoadBlockMeta(block.Height) 117 return &ctypes.ResultBlock{BlockID: blockMeta.BlockID, Block: block}, nil 118 } 119 120 // Commit gets block commit at a given height. 121 // If no height is provided, it will fetch the commit for the latest block. 122 // More: https://docs.tendermint.com/master/rpc/#/Info/commit 123 func (env *Environment) Commit(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultCommit, error) { 124 height, err := env.getHeight(env.BlockStore.Height(), heightPtr) 125 if err != nil { 126 return nil, err 127 } 128 129 blockMeta := env.BlockStore.LoadBlockMeta(height) 130 if blockMeta == nil { 131 return nil, nil 132 } 133 header := blockMeta.Header 134 135 // If the next block has not been committed yet, 136 // use a non-canonical commit 137 if height == env.BlockStore.Height() { 138 commit := env.BlockStore.LoadSeenCommit(height) 139 return ctypes.NewResultCommit(&header, commit, false), nil 140 } 141 142 // Return the canonical commit (comes from the block at height+1) 143 commit := env.BlockStore.LoadBlockCommit(height) 144 return ctypes.NewResultCommit(&header, commit, true), nil 145 } 146 147 // BlockResults gets ABCIResults at a given height. 148 // If no height is provided, it will fetch results for the latest block. 149 // 150 // Results are for the height of the block containing the txs. 151 // Thus response.results.deliver_tx[5] is the results of executing 152 // getBlock(h).Txs[5] 153 // More: https://docs.tendermint.com/master/rpc/#/Info/block_results 154 func (env *Environment) BlockResults(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultBlockResults, error) { 155 height, err := env.getHeight(env.BlockStore.Height(), heightPtr) 156 if err != nil { 157 return nil, err 158 } 159 160 results, err := env.StateStore.LoadABCIResponses(height) 161 if err != nil { 162 return nil, err 163 } 164 165 var totalGasUsed int64 166 for _, tx := range results.GetDeliverTxs() { 167 totalGasUsed += tx.GetGasUsed() 168 } 169 170 return &ctypes.ResultBlockResults{ 171 Height: height, 172 TxsResults: results.DeliverTxs, 173 TotalGasUsed: totalGasUsed, 174 BeginBlockEvents: results.BeginBlock.Events, 175 EndBlockEvents: results.EndBlock.Events, 176 ValidatorUpdates: results.EndBlock.ValidatorUpdates, 177 ConsensusParamUpdates: results.EndBlock.ConsensusParamUpdates, 178 }, nil 179 } 180 181 // BlockSearch searches for a paginated set of blocks matching BeginBlock and 182 // EndBlock event search criteria. 183 func (env *Environment) BlockSearch( 184 ctx *rpctypes.Context, 185 query string, 186 pagePtr, perPagePtr *int, 187 orderBy string, 188 ) (*ctypes.ResultBlockSearch, error) { 189 190 if !indexer.KVSinkEnabled(env.EventSinks) { 191 return nil, fmt.Errorf("block searching is disabled due to no kvEventSink") 192 } 193 194 q, err := tmquery.New(query) 195 if err != nil { 196 return nil, err 197 } 198 199 var kvsink indexer.EventSink 200 for _, sink := range env.EventSinks { 201 if sink.Type() == indexer.KV { 202 kvsink = sink 203 } 204 } 205 206 results, err := kvsink.SearchBlockEvents(ctx.Context(), q) 207 if err != nil { 208 return nil, err 209 } 210 211 // sort results (must be done before pagination) 212 switch orderBy { 213 case "desc", "": 214 sort.Slice(results, func(i, j int) bool { return results[i] > results[j] }) 215 216 case "asc": 217 sort.Slice(results, func(i, j int) bool { return results[i] < results[j] }) 218 219 default: 220 return nil, fmt.Errorf("expected order_by to be either `asc` or `desc` or empty: %w", ctypes.ErrInvalidRequest) 221 } 222 223 // paginate results 224 totalCount := len(results) 225 perPage := env.validatePerPage(perPagePtr) 226 227 page, err := validatePage(pagePtr, perPage, totalCount) 228 if err != nil { 229 return nil, err 230 } 231 232 skipCount := validateSkipCount(page, perPage) 233 pageSize := tmmath.MinInt(perPage, totalCount-skipCount) 234 235 apiResults := make([]*ctypes.ResultBlock, 0, pageSize) 236 for i := skipCount; i < skipCount+pageSize; i++ { 237 block := env.BlockStore.LoadBlock(results[i]) 238 if block != nil { 239 blockMeta := env.BlockStore.LoadBlockMeta(block.Height) 240 if blockMeta != nil { 241 apiResults = append(apiResults, &ctypes.ResultBlock{ 242 Block: block, 243 BlockID: blockMeta.BlockID, 244 }) 245 } 246 } 247 } 248 249 return &ctypes.ResultBlockSearch{Blocks: apiResults, TotalCount: totalCount}, nil 250 }