mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-06 05:25:35 +00:00
* rpc: add chunked rpc interface (#6445)
(cherry picked from commit d9134063e7)
# Conflicts:
# light/proxy/routes.go
# node/node.go
# rpc/core/net.go
# rpc/core/routes.go
* fix conflicts
Co-authored-by: Sam Kleinman <garen@tychoish.com>
Co-authored-by: marbar3778 <marbar3778@yahoo.com>
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/consensus"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
tmjson "github.com/tendermint/tendermint/libs/json"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
mempl "github.com/tendermint/tendermint/mempool"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
@@ -25,6 +27,10 @@ const (
|
||||
// SubscribeTimeout is the maximum time we wait to subscribe for an event.
|
||||
// must be less than the server's write timeout (see rpcserver.DefaultConfig)
|
||||
SubscribeTimeout = 5 * time.Second
|
||||
|
||||
// genesisChunkSize is the maximum size, in bytes, of each
|
||||
// chunk in the genesis structure for the chunked API
|
||||
genesisChunkSize = 16 * 1024 * 1024 // 16
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -91,6 +97,9 @@ type Environment struct {
|
||||
Logger log.Logger
|
||||
|
||||
Config cfg.RPCConfig
|
||||
|
||||
// cache of chunked genesis data.
|
||||
genChunks []string
|
||||
}
|
||||
|
||||
//----------------------------------------------
|
||||
@@ -130,6 +139,35 @@ func validatePerPage(perPagePtr *int) int {
|
||||
return perPage
|
||||
}
|
||||
|
||||
// InitGenesisChunks configures the environment and should be called on service
|
||||
// startup.
|
||||
func InitGenesisChunks() error {
|
||||
if env.genChunks != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if env.GenDoc == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
data, err := tmjson.Marshal(env.GenDoc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(data); i += genesisChunkSize {
|
||||
end := i + genesisChunkSize
|
||||
|
||||
if end > len(data) {
|
||||
end = len(data)
|
||||
}
|
||||
|
||||
env.genChunks = append(env.genChunks, base64.StdEncoding.EncodeToString(data[i:end]))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateSkipCount(page, perPage int) int {
|
||||
skipCount := (page - 1) * perPage
|
||||
if skipCount < 0 {
|
||||
|
||||
@@ -94,9 +94,35 @@ func UnsafeDialPeers(ctx *rpctypes.Context, peers []string, persistent, uncondit
|
||||
// Genesis returns genesis file.
|
||||
// More: https://docs.tendermint.com/master/rpc/#/Info/genesis
|
||||
func Genesis(ctx *rpctypes.Context) (*ctypes.ResultGenesis, error) {
|
||||
if len(env.genChunks) > 1 {
|
||||
return nil, errors.New("genesis response is large, please use the genesis_chunked API instead")
|
||||
}
|
||||
|
||||
return &ctypes.ResultGenesis{Genesis: env.GenDoc}, nil
|
||||
}
|
||||
|
||||
func GenesisChunked(ctx *rpctypes.Context, chunk uint) (*ctypes.ResultGenesisChunk, error) {
|
||||
if env.genChunks == nil {
|
||||
return nil, fmt.Errorf("service configuration error, genesis chunks are not initialized")
|
||||
}
|
||||
|
||||
if len(env.genChunks) == 0 {
|
||||
return nil, fmt.Errorf("service configuration error, there are no chunks")
|
||||
}
|
||||
|
||||
id := int(chunk)
|
||||
|
||||
if id > len(env.genChunks)-1 {
|
||||
return nil, fmt.Errorf("there are %d chunks, %d is invalid", len(env.genChunks)-1, id)
|
||||
}
|
||||
|
||||
return &ctypes.ResultGenesisChunk{
|
||||
TotalChunks: len(env.genChunks),
|
||||
ChunkNumber: id,
|
||||
Data: env.genChunks[id],
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getIDs(peers []string) ([]string, error) {
|
||||
ids := make([]string, 0, len(peers))
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ var Routes = map[string]*rpc.RPCFunc{
|
||||
"net_info": rpc.NewRPCFunc(NetInfo, ""),
|
||||
"blockchain": rpc.NewRPCFunc(BlockchainInfo, "minHeight,maxHeight"),
|
||||
"genesis": rpc.NewRPCFunc(Genesis, ""),
|
||||
"genesis_chunked": rpc.NewRPCFunc(GenesisChunked, "chunk"),
|
||||
"block": rpc.NewRPCFunc(Block, "height"),
|
||||
"block_by_hash": rpc.NewRPCFunc(BlockByHash, "hash"),
|
||||
"block_results": rpc.NewRPCFunc(BlockResults, "height"),
|
||||
|
||||
@@ -23,6 +23,16 @@ type ResultGenesis struct {
|
||||
Genesis *types.GenesisDoc `json:"genesis"`
|
||||
}
|
||||
|
||||
// ResultGenesisChunk is the output format for the chunked/paginated
|
||||
// interface. These chunks are produced by converting the genesis
|
||||
// document to JSON and then splitting the resulting payload into
|
||||
// 16 megabyte blocks and then base64 encoding each block.
|
||||
type ResultGenesisChunk struct {
|
||||
ChunkNumber int `json:"chunk"`
|
||||
TotalChunks int `json:"total"`
|
||||
Data string `json:"data"`
|
||||
}
|
||||
|
||||
// Single block (with meta)
|
||||
type ResultBlock struct {
|
||||
BlockID types.BlockID `json:"block_id"`
|
||||
|
||||
Reference in New Issue
Block a user