mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-11 23:32:50 +00:00
Compare commits
24 Commits
cal/defaul
...
rpc-header
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d06b4392b3 | ||
|
|
0461633b9a | ||
|
|
b9829f07d8 | ||
|
|
ff203833ac | ||
|
|
c1ac294146 | ||
|
|
bd4d38f433 | ||
|
|
eb16789d70 | ||
|
|
95a00b08e2 | ||
|
|
4f55193a32 | ||
|
|
3f0118105c | ||
|
|
4bf6d69090 | ||
|
|
2e28427dab | ||
|
|
3e6da20f83 | ||
|
|
a2bc85144c | ||
|
|
5e107589cb | ||
|
|
2a8f1df887 | ||
|
|
0a7be048f0 | ||
|
|
692dcef140 | ||
|
|
2adeb74cb5 | ||
|
|
3b4196b2da | ||
|
|
f9552f9f62 | ||
|
|
025e861dca | ||
|
|
91adc68f56 | ||
|
|
91b2a73833 |
@@ -14,12 +14,13 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi
|
||||
|
||||
- [abci/counter] \#6684 Delete counter example app
|
||||
- [txResults] \#9175 Remove `gas_used` & `gas_wanted` from being merkelized in the lastresulthash in the header
|
||||
- [abci] \#5783 Make length delimiter encoding consistent (`uint64`) between ABCI and P2P wire-level protocols
|
||||
|
||||
- P2P Protocol
|
||||
|
||||
- Go API
|
||||
|
||||
- [all] [#9144] Change spelling from British English to American (@cmwaters)
|
||||
- [all] \#9144 Change spelling from British English to American (@cmwaters)
|
||||
- Rename "Subscription.Cancelled()" to "Subscription.Canceled()" in libs/pubsub
|
||||
|
||||
- Blockchain Protocol
|
||||
|
||||
17
UPGRADING.md
17
UPGRADING.md
@@ -1,6 +1,21 @@
|
||||
# Upgrading Tendermint Core
|
||||
|
||||
This guide provides instructions for upgrading to specific versions of Tendermint Core.
|
||||
This guide provides instructions for upgrading to specific versions of
|
||||
Tendermint Core.
|
||||
|
||||
## v0.37 (Unreleased)
|
||||
|
||||
This version requires a coordinated network upgrade. It alters the elements in
|
||||
the predigest of the `LastResultsHash` and thus all nodes must upgrade together
|
||||
(see [\#9175](https://github.com/tendermint/tendermint/pull/9175)).
|
||||
|
||||
NOTE: v0.35 was recalled and v0.36 was skipped
|
||||
|
||||
### ABCI Changes
|
||||
|
||||
* In v0.34, messages on the wire used to be length-delimited with `int64` varint
|
||||
values, which was inconsistent with the `uint64` varint length delimiters used
|
||||
in the P2P layer. Both now consistently use `uint64` varint length delimiters.
|
||||
|
||||
|
||||
## v0.37 (Unreleased)
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/tendermint/tendermint/libs/protoio"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -14,57 +13,19 @@ const (
|
||||
|
||||
// WriteMessage writes a varint length-delimited protobuf message.
|
||||
func WriteMessage(msg proto.Message, w io.Writer) error {
|
||||
bz, err := proto.Marshal(msg)
|
||||
protoWriter := protoio.NewDelimitedWriter(w)
|
||||
_, err := protoWriter.WriteMsg(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return encodeByteSlice(w, bz)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadMessage reads a varint length-delimited protobuf message.
|
||||
func ReadMessage(r io.Reader, msg proto.Message) error {
|
||||
return readProtoMsg(r, msg, maxMsgSize)
|
||||
}
|
||||
|
||||
func readProtoMsg(r io.Reader, msg proto.Message, maxSize int) error {
|
||||
// binary.ReadVarint takes an io.ByteReader, eg. a bufio.Reader
|
||||
reader, ok := r.(*bufio.Reader)
|
||||
if !ok {
|
||||
reader = bufio.NewReader(r)
|
||||
}
|
||||
length64, err := binary.ReadVarint(reader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
length := int(length64)
|
||||
if length < 0 || length > maxSize {
|
||||
return io.ErrShortBuffer
|
||||
}
|
||||
buf := make([]byte, length)
|
||||
if _, err := io.ReadFull(reader, buf); err != nil {
|
||||
return err
|
||||
}
|
||||
return proto.Unmarshal(buf, msg)
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// NOTE: we copied wire.EncodeByteSlice from go-wire rather than keep
|
||||
// go-wire as a dep
|
||||
|
||||
func encodeByteSlice(w io.Writer, bz []byte) (err error) {
|
||||
err = encodeVarint(w, int64(len(bz)))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = w.Write(bz)
|
||||
return
|
||||
}
|
||||
|
||||
func encodeVarint(w io.Writer, i int64) (err error) {
|
||||
var buf [10]byte
|
||||
n := binary.PutVarint(buf[:], i)
|
||||
_, err = w.Write(buf[0:n])
|
||||
return
|
||||
_, err := protoio.NewDelimitedReader(r, maxMsgSize).ReadMsg(msg)
|
||||
return err
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
@@ -1181,6 +1181,7 @@ func (bs *mockBlockStore) LoadBlock(height int64) *types.Block { return bs.chain
|
||||
func (bs *mockBlockStore) LoadBlockByHash(hash []byte) *types.Block {
|
||||
return bs.chain[int64(len(bs.chain))-1]
|
||||
}
|
||||
func (bs *mockBlockStore) LoadBlockMetaByHash(hash []byte) *types.BlockMeta { return nil }
|
||||
func (bs *mockBlockStore) LoadBlockMeta(height int64) *types.BlockMeta {
|
||||
block := bs.chain[height-1]
|
||||
return &types.BlockMeta{
|
||||
|
||||
2
go.mod
2
go.mod
@@ -267,3 +267,5 @@ require (
|
||||
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect
|
||||
mvdan.cc/unparam v0.0.0-20220706161116-678bad134442 // indirect
|
||||
)
|
||||
|
||||
retract [v0.35.0, v0.35.9] // See https://github.com/tendermint/tendermint/discussions/9155
|
||||
|
||||
@@ -25,6 +25,8 @@ func RPCRoutes(c *lrpc.Client) map[string]*rpcserver.RPCFunc {
|
||||
"genesis": rpcserver.NewRPCFunc(makeGenesisFunc(c), ""),
|
||||
"genesis_chunked": rpcserver.NewRPCFunc(makeGenesisChunkedFunc(c), ""),
|
||||
"block": rpcserver.NewRPCFunc(makeBlockFunc(c), "height"),
|
||||
"header": rpcserver.NewRPCFunc(makeHeaderFunc(c), "height"),
|
||||
"header_by_hash": rpcserver.NewRPCFunc(makeHeaderByHashFunc(c), "hash"),
|
||||
"block_by_hash": rpcserver.NewRPCFunc(makeBlockByHashFunc(c), "hash"),
|
||||
"block_results": rpcserver.NewRPCFunc(makeBlockResultsFunc(c), "height"),
|
||||
"commit": rpcserver.NewRPCFunc(makeCommitFunc(c), "height"),
|
||||
@@ -109,6 +111,22 @@ func makeBlockFunc(c *lrpc.Client) rpcBlockFunc {
|
||||
}
|
||||
}
|
||||
|
||||
type rpcHeaderFunc func(ctx *rpctypes.Context, height *int64) (*ctypes.ResultHeader, error)
|
||||
|
||||
func makeHeaderFunc(c *lrpc.Client) rpcHeaderFunc {
|
||||
return func(ctx *rpctypes.Context, height *int64) (*ctypes.ResultHeader, error) {
|
||||
return c.Header(ctx.Context(), height)
|
||||
}
|
||||
}
|
||||
|
||||
type rpcHeaderByHashFunc func(ctx *rpctypes.Context, hash []byte) (*ctypes.ResultHeader, error)
|
||||
|
||||
func makeHeaderByHashFunc(c *lrpc.Client) rpcHeaderByHashFunc {
|
||||
return func(ctx *rpctypes.Context, hash []byte) (*ctypes.ResultHeader, error) {
|
||||
return c.HeaderByHash(ctx.Context(), hash)
|
||||
}
|
||||
}
|
||||
|
||||
type rpcBlockByHashFunc func(ctx *rpctypes.Context, hash []byte) (*ctypes.ResultBlock, error)
|
||||
|
||||
func makeBlockByHashFunc(c *lrpc.Client) rpcBlockByHashFunc {
|
||||
|
||||
@@ -440,6 +440,40 @@ func (c *Client) BlockResults(ctx context.Context, height *int64) (*ctypes.Resul
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Header fetches and verifies the header directly via the light client
|
||||
func (c *Client) Header(ctx context.Context, height *int64) (*ctypes.ResultHeader, error) {
|
||||
lb, err := c.updateLightClientIfNeededTo(ctx, height)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ctypes.ResultHeader{Header: lb.Header}, nil
|
||||
}
|
||||
|
||||
// HeaderByHash calls rpcclient#HeaderByHash and updates the client if it's falling behind.
|
||||
func (c *Client) HeaderByHash(ctx context.Context, hash tmbytes.HexBytes) (*ctypes.ResultHeader, error) {
|
||||
res, err := c.next.HeaderByHash(ctx, hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := res.Header.ValidateBasic(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lb, err := c.updateLightClientIfNeededTo(ctx, &res.Header.Height)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !bytes.Equal(lb.Header.Hash(), res.Header.Hash()) {
|
||||
return nil, fmt.Errorf("primary header hash does not match trusted header hash. (%X != %X)",
|
||||
lb.Header.Hash(), res.Header.Hash())
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (c *Client) Commit(ctx context.Context, height *int64) (*ctypes.ResultCommit, error) {
|
||||
// Update the light client if we're behind and retrieve the light block at the requested height
|
||||
// or at the latest height if no height is provided.
|
||||
|
||||
@@ -98,9 +98,11 @@ type baseRPCClient struct {
|
||||
caller jsonrpcclient.Caller
|
||||
}
|
||||
|
||||
var _ rpcClient = (*HTTP)(nil)
|
||||
var _ rpcClient = (*BatchHTTP)(nil)
|
||||
var _ rpcClient = (*baseRPCClient)(nil)
|
||||
var (
|
||||
_ rpcClient = (*HTTP)(nil)
|
||||
_ rpcClient = (*BatchHTTP)(nil)
|
||||
_ rpcClient = (*baseRPCClient)(nil)
|
||||
)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// HTTP
|
||||
@@ -444,6 +446,31 @@ func (c *baseRPCClient) BlockResults(
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *baseRPCClient) Header(ctx context.Context, height *int64) (*ctypes.ResultHeader, error) {
|
||||
result := new(ctypes.ResultHeader)
|
||||
params := make(map[string]interface{})
|
||||
if height != nil {
|
||||
params["height"] = height
|
||||
}
|
||||
_, err := c.caller.Call(ctx, "header", params, result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *baseRPCClient) HeaderByHash(ctx context.Context, hash bytes.HexBytes) (*ctypes.ResultHeader, error) {
|
||||
result := new(ctypes.ResultHeader)
|
||||
params := map[string]interface{}{
|
||||
"hash": hash,
|
||||
}
|
||||
_, err := c.caller.Call(ctx, "header_by_hash", params, result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *baseRPCClient) Commit(ctx context.Context, height *int64) (*ctypes.ResultCommit, error) {
|
||||
result := new(ctypes.ResultCommit)
|
||||
params := make(map[string]interface{})
|
||||
|
||||
@@ -67,6 +67,8 @@ type SignClient interface {
|
||||
Block(ctx context.Context, height *int64) (*ctypes.ResultBlock, error)
|
||||
BlockByHash(ctx context.Context, hash []byte) (*ctypes.ResultBlock, error)
|
||||
BlockResults(ctx context.Context, height *int64) (*ctypes.ResultBlockResults, error)
|
||||
Header(ctx context.Context, height *int64) (*ctypes.ResultHeader, error)
|
||||
HeaderByHash(ctx context.Context, hash bytes.HexBytes) (*ctypes.ResultHeader, error)
|
||||
Commit(ctx context.Context, height *int64) (*ctypes.ResultCommit, error)
|
||||
Validators(ctx context.Context, height *int64, page, perPage *int) (*ctypes.ResultValidators, error)
|
||||
Tx(ctx context.Context, hash []byte, prove bool) (*ctypes.ResultTx, error)
|
||||
|
||||
@@ -169,6 +169,14 @@ func (c *Local) BlockResults(ctx context.Context, height *int64) (*ctypes.Result
|
||||
return core.BlockResults(c.ctx, height)
|
||||
}
|
||||
|
||||
func (c *Local) Header(ctx context.Context, height *int64) (*ctypes.ResultHeader, error) {
|
||||
return core.Header(c.ctx, height)
|
||||
}
|
||||
|
||||
func (c *Local) HeaderByHash(ctx context.Context, hash bytes.HexBytes) (*ctypes.ResultHeader, error) {
|
||||
return core.HeaderByHash(c.ctx, hash)
|
||||
}
|
||||
|
||||
func (c *Local) Commit(ctx context.Context, height *int64) (*ctypes.ResultCommit, error) {
|
||||
return core.Commit(c.ctx, height)
|
||||
}
|
||||
|
||||
@@ -458,6 +458,51 @@ func (_m *Client) GenesisChunked(_a0 context.Context, _a1 uint) (*coretypes.Resu
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
// Header provides a mock function with given fields: ctx, height
|
||||
func (_m *Client) Header(ctx context.Context, height *int64) (*coretypes.ResultHeader, error) {
|
||||
ret := _m.Called(ctx, height)
|
||||
|
||||
var r0 *coretypes.ResultHeader
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *int64) *coretypes.ResultHeader); ok {
|
||||
r0 = rf(ctx, height)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*coretypes.ResultHeader)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *int64) error); ok {
|
||||
r1 = rf(ctx, height)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// HeaderByHash provides a mock function with given fields: ctx, hash
|
||||
func (_m *Client) HeaderByHash(ctx context.Context, hash bytes.HexBytes) (*coretypes.ResultHeader, error) {
|
||||
ret := _m.Called(ctx, hash)
|
||||
|
||||
var r0 *coretypes.ResultHeader
|
||||
if rf, ok := ret.Get(0).(func(context.Context, bytes.HexBytes) *coretypes.ResultHeader); ok {
|
||||
r0 = rf(ctx, hash)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*coretypes.ResultHeader)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, bytes.HexBytes) error); ok {
|
||||
r1 = rf(ctx, hash)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Health provides a mock function with given fields: _a0
|
||||
func (_m *Client) Health(_a0 context.Context) (*coretypes.ResultHealth, error) {
|
||||
|
||||
@@ -285,6 +285,15 @@ func TestAppCalls(t *testing.T) {
|
||||
require.NoError(err)
|
||||
require.Equal(block, blockByHash)
|
||||
|
||||
// check that the header matches the block hash
|
||||
header, err := c.Header(context.Background(), &apph)
|
||||
require.NoError(err)
|
||||
require.Equal(block.Block.Header, *header.Header)
|
||||
|
||||
headerByHash, err := c.HeaderByHash(context.Background(), block.BlockID.Hash)
|
||||
require.NoError(err)
|
||||
require.Equal(header, headerByHash)
|
||||
|
||||
// now check the results
|
||||
blockResults, err := c.BlockResults(context.Background(), &txh)
|
||||
require.Nil(err, "%d: %+v", i, err)
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/tendermint/tendermint/libs/bytes"
|
||||
tmmath "github.com/tendermint/tendermint/libs/math"
|
||||
tmquery "github.com/tendermint/tendermint/libs/pubsub/query"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
@@ -75,6 +76,38 @@ func filterMinMax(base, height, min, max, limit int64) (int64, int64, error) {
|
||||
return min, max, nil
|
||||
}
|
||||
|
||||
// Header gets block header at a given height.
|
||||
// If no height is provided, it will fetch the latest header.
|
||||
// More: https://docs.tendermint.com/master/rpc/#/Info/header
|
||||
func Header(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultHeader, error) {
|
||||
height, err := getHeight(env.BlockStore.Height(), heightPtr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
blockMeta := env.BlockStore.LoadBlockMeta(height)
|
||||
if blockMeta == nil {
|
||||
return &ctypes.ResultHeader{}, nil
|
||||
}
|
||||
|
||||
return &ctypes.ResultHeader{Header: &blockMeta.Header}, nil
|
||||
}
|
||||
|
||||
// HeaderByHash gets header by hash.
|
||||
// More: https://docs.tendermint.com/master/rpc/#/Info/header_by_hash
|
||||
func HeaderByHash(ctx *rpctypes.Context, hash bytes.HexBytes) (*ctypes.ResultHeader, error) {
|
||||
// N.B. The hash parameter is HexBytes so that the reflective parameter
|
||||
// decoding logic in the HTTP service will correctly translate from JSON.
|
||||
// See https://github.com/tendermint/tendermint/issues/6802 for context.
|
||||
|
||||
blockMeta := env.BlockStore.LoadBlockMetaByHash(hash)
|
||||
if blockMeta == nil {
|
||||
return &ctypes.ResultHeader{}, nil
|
||||
}
|
||||
|
||||
return &ctypes.ResultHeader{Header: &blockMeta.Header}, nil
|
||||
}
|
||||
|
||||
// Block gets block at a given height.
|
||||
// If no height is provided, it will fetch the latest block.
|
||||
// More: https://docs.tendermint.com/master/rpc/#/Info/block
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types"
|
||||
sm "github.com/tendermint/tendermint/state"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
"github.com/tendermint/tendermint/state/mocks"
|
||||
)
|
||||
|
||||
func TestBlockchainInfo(t *testing.T) {
|
||||
@@ -84,7 +84,10 @@ func TestBlockResults(t *testing.T) {
|
||||
env.StateStore = sm.NewStore(dbm.NewMemDB())
|
||||
err := env.StateStore.SaveABCIResponses(100, results)
|
||||
require.NoError(t, err)
|
||||
env.BlockStore = mockBlockStore{height: 100}
|
||||
mockstore := &mocks.BlockStore{}
|
||||
mockstore.On("Height").Return(int64(100))
|
||||
mockstore.On("Base").Return(int64(1))
|
||||
env.BlockStore = mockstore
|
||||
|
||||
testCases := []struct {
|
||||
height int64
|
||||
@@ -114,21 +117,3 @@ func TestBlockResults(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type mockBlockStore struct {
|
||||
height int64
|
||||
}
|
||||
|
||||
func (mockBlockStore) Base() int64 { return 1 }
|
||||
func (store mockBlockStore) Height() int64 { return store.height }
|
||||
func (store mockBlockStore) Size() int64 { return store.height }
|
||||
func (mockBlockStore) LoadBaseMeta() *types.BlockMeta { return nil }
|
||||
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 }
|
||||
func (mockBlockStore) PruneBlocks(height int64) (uint64, error) { return 0, nil }
|
||||
func (mockBlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, seenCommit *types.Commit) {
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ var Routes = map[string]*rpc.RPCFunc{
|
||||
"block_by_hash": rpc.NewRPCFunc(BlockByHash, "hash"),
|
||||
"block_results": rpc.NewRPCFunc(BlockResults, "height"),
|
||||
"commit": rpc.NewRPCFunc(Commit, "height"),
|
||||
"header": rpc.NewRPCFunc(Header, "height"),
|
||||
"header_by_hash": rpc.NewRPCFunc(HeaderByHash, "hash"),
|
||||
"check_tx": rpc.NewRPCFunc(CheckTx, "tx"),
|
||||
"tx": rpc.NewRPCFunc(Tx, "hash,prove"),
|
||||
"tx_search": rpc.NewRPCFunc(TxSearch, "query,prove,page,per_page,order_by"),
|
||||
|
||||
@@ -39,6 +39,11 @@ type ResultBlock struct {
|
||||
Block *types.Block `json:"block"`
|
||||
}
|
||||
|
||||
// ResultHeader represents the response for a Header RPC Client query
|
||||
type ResultHeader struct {
|
||||
Header *types.Header `json:"header"`
|
||||
}
|
||||
|
||||
// Commit and Header
|
||||
type ResultCommit struct {
|
||||
types.SignedHeader `json:"signed_header"`
|
||||
|
||||
@@ -500,7 +500,7 @@ paths:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
/net_info:
|
||||
get:
|
||||
summary: Network informations
|
||||
summary: Network information
|
||||
operationId: net_info
|
||||
tags:
|
||||
- Info
|
||||
@@ -637,6 +637,64 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
/header:
|
||||
get:
|
||||
summary: Get header at a specified height
|
||||
operationId: header
|
||||
parameters:
|
||||
- in: query
|
||||
name: height
|
||||
schema:
|
||||
type: integer
|
||||
default: 0
|
||||
example: 1
|
||||
description: height to return. If no height is provided, it will fetch the latest header.
|
||||
tags:
|
||||
- Info
|
||||
description: |
|
||||
Get Header.
|
||||
responses:
|
||||
"200":
|
||||
description: Header informations.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/HeaderResponse"
|
||||
"500":
|
||||
description: Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
/header_by_hash:
|
||||
get:
|
||||
summary: Get header by hash
|
||||
operationId: header_by_hash
|
||||
parameters:
|
||||
- in: query
|
||||
name: hash
|
||||
description: header hash
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
example: "0xD70952032620CC4E2737EB8AC379806359D8E0B17B0488F627997A0B043ABDED"
|
||||
tags:
|
||||
- Info
|
||||
description: |
|
||||
Get Header By Hash.
|
||||
responses:
|
||||
"200":
|
||||
description: Header informations.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/HeaderResponse"
|
||||
"500":
|
||||
description: Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
/block:
|
||||
get:
|
||||
summary: Get block at a specified height
|
||||
|
||||
@@ -66,25 +66,28 @@ Note the length-prefixing used in the socket implementation (TSP) does not apply
|
||||
|
||||
### TSP
|
||||
|
||||
Tendermint Socket Protocol is an asynchronous, raw socket server which provides ordered message passing over unix or tcp.
|
||||
Messages are serialized using Protobuf3 and length-prefixed with a [signed Varint](https://developers.google.com/protocol-buffers/docs/encoding?csw=1#signed-integers)
|
||||
Tendermint Socket Protocol is an asynchronous, raw socket server which provides
|
||||
ordered message passing over unix or tcp. Messages are serialized using
|
||||
Protobuf3 and length-prefixed with an [unsigned
|
||||
varint](https://developers.google.com/protocol-buffers/docs/encoding?csw=1#varints)
|
||||
|
||||
If GRPC is not available in your language, or you require higher
|
||||
performance, or otherwise enjoy programming, you may implement your own
|
||||
ABCI server using the Tendermint Socket Protocol. The first step is still to auto-generate the relevant data
|
||||
types and codec in your language using `protoc`. In addition to being proto3 encoded, messages coming over
|
||||
the socket are length-prefixed to facilitate use as a streaming protocol. proto3 doesn't have an
|
||||
official length-prefix standard, so we use our own. The first byte in
|
||||
the prefix represents the length of the Big Endian encoded length. The
|
||||
remaining bytes in the prefix are the Big Endian encoded length.
|
||||
If GRPC is not available in your language, or you require higher performance, or
|
||||
otherwise enjoy programming, you may implement your own ABCI server using the
|
||||
Tendermint Socket Protocol. The first step is still to auto-generate the
|
||||
relevant data types and codec in your language using `protoc`. In addition to
|
||||
being proto3 encoded, messages coming over the socket are length-prefixed to
|
||||
facilitate use as a streaming protocol. proto3 doesn't have an official
|
||||
length-prefix standard, so we use our own. The first byte in the prefix
|
||||
represents the length of the Big Endian encoded length. The remaining bytes in
|
||||
the prefix are the Big Endian encoded length.
|
||||
|
||||
For example, if the proto3 encoded ABCI message is 0xDEADBEEF (4
|
||||
bytes), the length-prefixed message is 0x0104DEADBEEF. If the proto3
|
||||
encoded ABCI message is 65535 bytes long, the length-prefixed message
|
||||
would be like 0x02FFFF....
|
||||
For example, if the proto3 encoded ABCI message is 0xDEADBEEF (4 bytes), the
|
||||
length-prefixed message is 0x0104DEADBEEF. If the proto3 encoded ABCI message is
|
||||
65535 bytes long, the length-prefixed message would be like 0x02FFFF....
|
||||
|
||||
The benefit of using this `varint` encoding over the old version (where integers were encoded as `<len of len><big endian len>` is that
|
||||
it is the standard way to encode integers in Protobuf. It is also generally shorter.
|
||||
The benefit of using this `varint` encoding over the old version (where integers
|
||||
were encoded as `<len of len><big endian len>` is that it is the common way to
|
||||
encode integers in Protobuf. It is also generally shorter.
|
||||
|
||||
As noted above, this prefixing does not apply for GRPC.
|
||||
|
||||
|
||||
@@ -121,6 +121,22 @@ func (_m *BlockStore) LoadBlockMeta(height int64) *types.BlockMeta {
|
||||
return r0
|
||||
}
|
||||
|
||||
// LoadBlockMetaByHash provides a mock function with given fields: hash
|
||||
func (_m *BlockStore) LoadBlockMetaByHash(hash []byte) *types.BlockMeta {
|
||||
ret := _m.Called(hash)
|
||||
|
||||
var r0 *types.BlockMeta
|
||||
if rf, ok := ret.Get(0).(func([]byte) *types.BlockMeta); ok {
|
||||
r0 = rf(hash)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*types.BlockMeta)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// LoadBlockPart provides a mock function with given fields: height, index
|
||||
func (_m *BlockStore) LoadBlockPart(height int64, index int) *types.Part {
|
||||
ret := _m.Called(height, index)
|
||||
|
||||
@@ -29,6 +29,7 @@ type BlockStore interface {
|
||||
PruneBlocks(height int64) (uint64, error)
|
||||
|
||||
LoadBlockByHash(hash []byte) *types.Block
|
||||
LoadBlockMetaByHash(hash []byte) *types.BlockMeta
|
||||
LoadBlockPart(height int64, index int) *types.Part
|
||||
|
||||
LoadBlockCommit(height int64) *types.Commit
|
||||
|
||||
@@ -196,6 +196,26 @@ func (bs *BlockStore) LoadBlockMeta(height int64) *types.BlockMeta {
|
||||
return blockMeta
|
||||
}
|
||||
|
||||
// LoadBlockMetaByHash returns the blockmeta who's header corresponds to the given
|
||||
// hash. If none is found, returns nil.
|
||||
func (bs *BlockStore) LoadBlockMetaByHash(hash []byte) *types.BlockMeta {
|
||||
bz, err := bs.db.Get(calcBlockHashKey(hash))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if len(bz) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
s := string(bz)
|
||||
height, err := strconv.ParseInt(s, 10, 64)
|
||||
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to extract height from %s: %v", s, err))
|
||||
}
|
||||
return bs.LoadBlockMeta(height)
|
||||
}
|
||||
|
||||
// LoadBlockCommit returns the Commit for the given height.
|
||||
// This commit consists of the +2/3 and other Precommit-votes for block at `height`,
|
||||
// and it comes from the block.LastCommit for `height+1`.
|
||||
|
||||
Reference in New Issue
Block a user