Browse Source

rpc: add method block_by_hash (#4257)

* added RPC method block_by_hash

* created hash => height

* changes typings

* block_by_hash changes

* Update store/store.go

Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com>

* Update store/store.go

Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com>

* Update store/store.go

Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com>

* Update store/store.go

Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com>

Co-authored-by: Marko <marbar3778@yahoo.com>
Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
pull/4283/head
Prince Sinha 5 years ago
committed by Anton Kaliaev
parent
commit
7be74c73b7
8 changed files with 73 additions and 0 deletions
  1. +1
    -0
      CHANGELOG_PENDING.md
  2. +3
    -0
      consensus/replay_test.go
  3. +10
    -0
      rpc/core/blocks.go
  4. +1
    -0
      rpc/core/blocks_test.go
  5. +1
    -0
      rpc/core/routes.go
  6. +29
    -0
      rpc/swagger/swagger.yaml
  7. +1
    -0
      state/services.go
  8. +27
    -0
      store/store.go

+ 1
- 0
CHANGELOG_PENDING.md View File

@ -113,6 +113,7 @@ program](https://hackerone.com/tendermint).
- [cli] \#4234 Add `--db_backend and --db_dir` flags (@princesinha19)
- [cli] \#4113 Add optional `--genesis_hash` flag to check genesis hash upon startup
- [config] \#3831 Add support for [RocksDB](https://rocksdb.org/) (@Stumble)
- [rpc] \#3985 Add new `/block_by_hash` endpoint, which allows to fetch a block by its hash (@princesinha19)
- [metrics] \#4263 Add
- `consensus_validator_power`: track your validators power
- `consensus_validator_last_signed_height`: track at which height the validator last signed


+ 3
- 0
consensus/replay_test.go View File

@ -1062,6 +1062,9 @@ func newMockBlockStore(config *cfg.Config, params types.ConsensusParams) *mockBl
func (bs *mockBlockStore) Height() int64 { return int64(len(bs.chain)) }
func (bs *mockBlockStore) LoadBlock(height int64) *types.Block { return bs.chain[height-1] }
func (bs *mockBlockStore) LoadBlockByHash(hash []byte) *types.Block {
return bs.chain[int64(len(bs.chain))-1]
}
func (bs *mockBlockStore) LoadBlockMeta(height int64) *types.BlockMeta {
block := bs.chain[height-1]
return &types.BlockMeta{


+ 10
- 0
rpc/core/blocks.go View File

@ -81,6 +81,16 @@ func Block(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultBlock, error)
return &ctypes.ResultBlock{BlockID: blockMeta.BlockID, Block: block}, nil
}
// BlockByHash gets block by hash.
// More: https://tendermint.com/rpc/#/Info/block_by_hash
func BlockByHash(ctx *rpctypes.Context, hash []byte) (*ctypes.ResultBlock, error) {
block := blockStore.LoadBlockByHash(hash)
height := block.Height
blockMeta := blockStore.LoadBlockMeta(height)
return &ctypes.ResultBlock{BlockID: blockMeta.BlockID, Block: block}, nil
}
// Commit gets block commit at a given height.
// If no height is provided, it will fetch the commit for the latest block.
// More: https://tendermint.com/rpc/#/Info/commit


+ 1
- 0
rpc/core/blocks_test.go View File

@ -114,6 +114,7 @@ type mockBlockStore struct {
func (store mockBlockStore) Height() int64 { return store.height }
func (mockBlockStore) LoadBlockMeta(height int64) *types.BlockMeta { return nil }
func (mockBlockStore) LoadBlock(height int64) *types.Block { return nil }
func (mockBlockStore) LoadBlockByHash(hash []byte) *types.Block { return nil }
func (mockBlockStore) LoadBlockPart(height int64, index int) *types.Part { return nil }
func (mockBlockStore) LoadBlockCommit(height int64) *types.Commit { return nil }
func (mockBlockStore) LoadSeenCommit(height int64) *types.Commit { return nil }


+ 1
- 0
rpc/core/routes.go View File

@ -19,6 +19,7 @@ var Routes = map[string]*rpc.RPCFunc{
"blockchain": rpc.NewRPCFunc(BlockchainInfo, "minHeight,maxHeight"),
"genesis": rpc.NewRPCFunc(Genesis, ""),
"block": rpc.NewRPCFunc(Block, "height"),
"block_by_hash": rpc.NewRPCFunc(BlockByHash, "hash"),
"block_results": rpc.NewRPCFunc(BlockResults, "height"),
"commit": rpc.NewRPCFunc(Commit, "height"),
"tx": rpc.NewRPCFunc(Tx, "hash,prove"),


+ 29
- 0
rpc/swagger/swagger.yaml View File

@ -550,6 +550,35 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/block_by_hash:
get:
summary: Get block by hash
operationId: block_by_hash
parameters:
- in: query
name: hash
description: block hash
required: true
schema:
type: string
example: "0xD70952032620CC4E2737EB8AC379806359D8E0B17B0488F627997A0B043ABDED"
tags:
- Info
description: |
Get Block By Hash.
responses:
200:
description: Block informations.
content:
application/json:
schema:
$ref: "#/components/schemas/BlockResponse"
500:
description: Error
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/block_results:
get:
summary: Get block results at a specified height


+ 1
- 0
state/services.go View File

@ -18,6 +18,7 @@ type BlockStoreRPC interface {
LoadBlockMeta(height int64) *types.BlockMeta
LoadBlock(height int64) *types.Block
LoadBlockByHash(hash []byte) *types.Block
LoadBlockPart(height int64, index int) *types.Part
LoadBlockCommit(height int64) *types.Commit


+ 27
- 0
store/store.go View File

@ -2,6 +2,7 @@ package store
import (
"fmt"
"strconv"
"sync"
"github.com/pkg/errors"
@ -73,6 +74,24 @@ func (bs *BlockStore) LoadBlock(height int64) *types.Block {
return block
}
// LoadBlockByHash returns the block with the given hash.
// If no block is found for that hash, it returns nil.
// Panics if it fails to parse height associated with the given hash.
func (bs *BlockStore) LoadBlockByHash(hash []byte) *types.Block {
bz := bs.db.Get(calcBlockHashKey(hash))
if len(bz) == 0 {
return nil
}
s := string(bz)
height, err := strconv.ParseInt(s, 10, 64)
if err != nil {
panic(errors.Wrapf(err, "failed to extract height from %s", s))
}
return bs.LoadBlock(height)
}
// LoadBlockPart returns the Part at the given index
// from the block at the given height.
// If no part is found for the given height and index, it returns nil.
@ -147,7 +166,10 @@ func (bs *BlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, s
if block == nil {
panic("BlockStore can only save a non-nil block")
}
height := block.Height
hash := block.Hash()
if g, w := height, bs.Height()+1; g != w {
panic(fmt.Sprintf("BlockStore can only save contiguous blocks. Wanted %v, got %v", w, g))
}
@ -159,6 +181,7 @@ func (bs *BlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, s
blockMeta := types.NewBlockMeta(block, blockParts)
metaBytes := cdc.MustMarshalBinaryBare(blockMeta)
bs.db.Set(calcBlockMetaKey(height), metaBytes)
bs.db.Set(calcBlockHashKey(hash), []byte(fmt.Sprintf("%d", height)))
// Save block parts
for i := 0; i < blockParts.Total(); i++ {
@ -213,6 +236,10 @@ func calcSeenCommitKey(height int64) []byte {
return []byte(fmt.Sprintf("SC:%v", height))
}
func calcBlockHashKey(hash []byte) []byte {
return []byte(fmt.Sprintf("BH:%x", hash))
}
//-----------------------------------------------------------------------------
var blockStoreKey = []byte("blockStore")


Loading…
Cancel
Save