package coretypes
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"time"
|
|
|
|
abci "github.com/tendermint/tendermint/abci/types"
|
|
"github.com/tendermint/tendermint/crypto"
|
|
"github.com/tendermint/tendermint/internal/jsontypes"
|
|
"github.com/tendermint/tendermint/libs/bytes"
|
|
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
|
"github.com/tendermint/tendermint/types"
|
|
)
|
|
|
|
// List of standardized errors used across RPC
|
|
var (
|
|
ErrZeroOrNegativePerPage = errors.New("zero or negative per_page")
|
|
ErrPageOutOfRange = errors.New("page should be within range")
|
|
ErrZeroOrNegativeHeight = errors.New("height must be greater than zero")
|
|
ErrHeightExceedsChainHead = errors.New("height must be less than or equal to the head of the node's blockchain")
|
|
ErrHeightNotAvailable = errors.New("height is not available")
|
|
// ErrInvalidRequest is used as a wrapper to cover more specific cases where the user has
|
|
// made an invalid request
|
|
ErrInvalidRequest = errors.New("invalid request")
|
|
)
|
|
|
|
// List of blocks
|
|
type ResultBlockchainInfo struct {
|
|
LastHeight int64 `json:"last_height,string"`
|
|
BlockMetas []*types.BlockMeta `json:"block_metas"`
|
|
}
|
|
|
|
// Genesis file
|
|
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,string"`
|
|
TotalChunks int `json:"total,string"`
|
|
Data string `json:"data"`
|
|
}
|
|
|
|
// Single block (with meta)
|
|
type ResultBlock struct {
|
|
BlockID types.BlockID `json:"block_id"`
|
|
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"`
|
|
CanonicalCommit bool `json:"canonical"`
|
|
}
|
|
|
|
// ABCI results from a block
|
|
type ResultBlockResults struct {
|
|
Height int64 `json:"height,string"`
|
|
TxsResults []*abci.ExecTxResult `json:"txs_results"`
|
|
TotalGasUsed int64 `json:"total_gas_used,string"`
|
|
FinalizeBlockEvents []abci.Event `json:"finalize_block_events"`
|
|
ValidatorUpdates []abci.ValidatorUpdate `json:"validator_updates"`
|
|
ConsensusParamUpdates *tmproto.ConsensusParams `json:"consensus_param_updates"`
|
|
}
|
|
|
|
// NewResultCommit is a helper to initialize the ResultCommit with
|
|
// the embedded struct
|
|
func NewResultCommit(header *types.Header, commit *types.Commit,
|
|
canonical bool) *ResultCommit {
|
|
|
|
return &ResultCommit{
|
|
SignedHeader: types.SignedHeader{
|
|
Header: header,
|
|
Commit: commit,
|
|
},
|
|
CanonicalCommit: canonical,
|
|
}
|
|
}
|
|
|
|
// Info about the node's syncing state
|
|
type SyncInfo struct {
|
|
LatestBlockHash bytes.HexBytes `json:"latest_block_hash"`
|
|
LatestAppHash bytes.HexBytes `json:"latest_app_hash"`
|
|
LatestBlockHeight int64 `json:"latest_block_height,string"`
|
|
LatestBlockTime time.Time `json:"latest_block_time"`
|
|
|
|
EarliestBlockHash bytes.HexBytes `json:"earliest_block_hash"`
|
|
EarliestAppHash bytes.HexBytes `json:"earliest_app_hash"`
|
|
EarliestBlockHeight int64 `json:"earliest_block_height,string"`
|
|
EarliestBlockTime time.Time `json:"earliest_block_time"`
|
|
|
|
MaxPeerBlockHeight int64 `json:"max_peer_block_height,string"`
|
|
|
|
CatchingUp bool `json:"catching_up"`
|
|
|
|
TotalSyncedTime time.Duration `json:"total_synced_time,string"`
|
|
RemainingTime time.Duration `json:"remaining_time,string"`
|
|
|
|
TotalSnapshots int64 `json:"total_snapshots,string"`
|
|
ChunkProcessAvgTime time.Duration `json:"chunk_process_avg_time,string"`
|
|
SnapshotHeight int64 `json:"snapshot_height,string"`
|
|
SnapshotChunksCount int64 `json:"snapshot_chunks_count,string"`
|
|
SnapshotChunksTotal int64 `json:"snapshot_chunks_total,string"`
|
|
BackFilledBlocks int64 `json:"backfilled_blocks,string"`
|
|
BackFillBlocksTotal int64 `json:"backfill_blocks_total,string"`
|
|
}
|
|
|
|
type ApplicationInfo struct {
|
|
Version string `json:"version"`
|
|
}
|
|
|
|
// Info about the node's validator
|
|
type ValidatorInfo struct {
|
|
Address bytes.HexBytes
|
|
PubKey crypto.PubKey
|
|
VotingPower int64
|
|
}
|
|
|
|
type validatorInfoJSON struct {
|
|
Address bytes.HexBytes `json:"address"`
|
|
PubKey json.RawMessage `json:"pub_key"`
|
|
VotingPower int64 `json:"voting_power,string"`
|
|
}
|
|
|
|
func (v ValidatorInfo) MarshalJSON() ([]byte, error) {
|
|
pk, err := jsontypes.Marshal(v.PubKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return json.Marshal(validatorInfoJSON{
|
|
Address: v.Address, PubKey: pk, VotingPower: v.VotingPower,
|
|
})
|
|
}
|
|
|
|
func (v *ValidatorInfo) UnmarshalJSON(data []byte) error {
|
|
var val validatorInfoJSON
|
|
if err := json.Unmarshal(data, &val); err != nil {
|
|
return err
|
|
}
|
|
if err := jsontypes.Unmarshal(val.PubKey, &v.PubKey); err != nil {
|
|
return err
|
|
}
|
|
v.Address = val.Address
|
|
v.VotingPower = val.VotingPower
|
|
return nil
|
|
}
|
|
|
|
// Node Status
|
|
type ResultStatus struct {
|
|
NodeInfo types.NodeInfo `json:"node_info"`
|
|
ApplicationInfo ApplicationInfo `json:"application_info,omitempty"`
|
|
SyncInfo SyncInfo `json:"sync_info"`
|
|
ValidatorInfo ValidatorInfo `json:"validator_info"`
|
|
LightClientInfo types.LightClientInfo `json:"light_client_info,omitempty"`
|
|
}
|
|
|
|
// Is TxIndexing enabled
|
|
func (s *ResultStatus) TxIndexEnabled() bool {
|
|
if s == nil {
|
|
return false
|
|
}
|
|
return s.NodeInfo.Other.TxIndex == "on"
|
|
}
|
|
|
|
// Info about peer connections
|
|
type ResultNetInfo struct {
|
|
Listening bool `json:"listening"`
|
|
Listeners []string `json:"listeners"`
|
|
NPeers int `json:"n_peers,string"`
|
|
Peers []Peer `json:"peers"`
|
|
}
|
|
|
|
// Log from dialing seeds
|
|
type ResultDialSeeds struct {
|
|
Log string `json:"log"`
|
|
}
|
|
|
|
// Log from dialing peers
|
|
type ResultDialPeers struct {
|
|
Log string `json:"log"`
|
|
}
|
|
|
|
// A peer
|
|
type Peer struct {
|
|
ID types.NodeID `json:"node_id"`
|
|
URL string `json:"url"`
|
|
}
|
|
|
|
// Validators for a height.
|
|
type ResultValidators struct {
|
|
BlockHeight int64 `json:"block_height,string"`
|
|
Validators []*types.Validator `json:"validators"`
|
|
|
|
Count int `json:"count,string"` // Count of actual validators in this result
|
|
Total int `json:"total,string"` // Total number of validators
|
|
}
|
|
|
|
// ConsensusParams for given height
|
|
type ResultConsensusParams struct {
|
|
BlockHeight int64 `json:"block_height,string"`
|
|
ConsensusParams types.ConsensusParams `json:"consensus_params"`
|
|
}
|
|
|
|
// Info about the consensus state.
|
|
// UNSTABLE
|
|
type ResultDumpConsensusState struct {
|
|
RoundState json.RawMessage `json:"round_state"`
|
|
Peers []PeerStateInfo `json:"peers"`
|
|
}
|
|
|
|
// UNSTABLE
|
|
type PeerStateInfo struct {
|
|
NodeAddress string `json:"node_address"`
|
|
PeerState json.RawMessage `json:"peer_state"`
|
|
}
|
|
|
|
// UNSTABLE
|
|
type ResultConsensusState struct {
|
|
RoundState json.RawMessage `json:"round_state"`
|
|
}
|
|
|
|
// CheckTx result
|
|
type ResultBroadcastTx struct {
|
|
Code uint32 `json:"code"`
|
|
Data bytes.HexBytes `json:"data"`
|
|
Log string `json:"log"`
|
|
Codespace string `json:"codespace"`
|
|
MempoolError string `json:"mempool_error"`
|
|
Hash bytes.HexBytes `json:"hash"`
|
|
}
|
|
|
|
// CheckTx and DeliverTx results
|
|
type ResultBroadcastTxCommit struct {
|
|
CheckTx abci.ResponseCheckTx `json:"check_tx"`
|
|
TxResult abci.ExecTxResult `json:"tx_result"`
|
|
Hash bytes.HexBytes `json:"hash"`
|
|
Height int64 `json:"height,string"`
|
|
}
|
|
|
|
// ResultCheckTx wraps abci.ResponseCheckTx.
|
|
type ResultCheckTx struct {
|
|
abci.ResponseCheckTx
|
|
}
|
|
|
|
// Result of querying for a tx
|
|
type ResultTx struct {
|
|
Hash bytes.HexBytes `json:"hash"`
|
|
Height int64 `json:"height,string"`
|
|
Index uint32 `json:"index"`
|
|
TxResult abci.ExecTxResult `json:"tx_result"`
|
|
Tx types.Tx `json:"tx"`
|
|
Proof types.TxProof `json:"proof,omitempty"`
|
|
}
|
|
|
|
// Result of searching for txs
|
|
type ResultTxSearch struct {
|
|
Txs []*ResultTx `json:"txs"`
|
|
TotalCount int `json:"total_count,string"`
|
|
}
|
|
|
|
// ResultBlockSearch defines the RPC response type for a block search by events.
|
|
type ResultBlockSearch struct {
|
|
Blocks []*ResultBlock `json:"blocks"`
|
|
TotalCount int `json:"total_count,string"`
|
|
}
|
|
|
|
// List of mempool txs
|
|
type ResultUnconfirmedTxs struct {
|
|
Count int `json:"n_txs,string"`
|
|
Total int `json:"total,string"`
|
|
TotalBytes int64 `json:"total_bytes,string"`
|
|
Txs []types.Tx `json:"txs"`
|
|
}
|
|
|
|
// Info abci msg
|
|
type ResultABCIInfo struct {
|
|
Response abci.ResponseInfo `json:"response"`
|
|
}
|
|
|
|
// Query abci msg
|
|
type ResultABCIQuery struct {
|
|
Response abci.ResponseQuery `json:"response"`
|
|
}
|
|
|
|
// Result of broadcasting evidence
|
|
type ResultBroadcastEvidence struct {
|
|
Hash []byte `json:"hash"`
|
|
}
|
|
|
|
// empty results
|
|
type (
|
|
ResultUnsafeFlushMempool struct{}
|
|
ResultUnsafeProfile struct{}
|
|
ResultSubscribe struct{}
|
|
ResultUnsubscribe struct{}
|
|
ResultHealth struct{}
|
|
)
|
|
|
|
// Event data from a subscription
|
|
type ResultEvent struct {
|
|
SubscriptionID string
|
|
Query string
|
|
Data types.EventData
|
|
Events []abci.Event
|
|
}
|
|
|
|
type resultEventJSON struct {
|
|
SubscriptionID string `json:"subscription_id"`
|
|
Query string `json:"query"`
|
|
Data json.RawMessage `json:"data"`
|
|
Events []abci.Event `json:"events"`
|
|
}
|
|
|
|
func (r ResultEvent) MarshalJSON() ([]byte, error) {
|
|
evt, err := jsontypes.Marshal(r.Data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return json.Marshal(resultEventJSON{
|
|
SubscriptionID: r.SubscriptionID,
|
|
Query: r.Query,
|
|
Data: evt,
|
|
Events: r.Events,
|
|
})
|
|
}
|
|
|
|
func (r *ResultEvent) UnmarshalJSON(data []byte) error {
|
|
var res resultEventJSON
|
|
if err := json.Unmarshal(data, &res); err != nil {
|
|
return err
|
|
}
|
|
if err := jsontypes.Unmarshal(res.Data, &r.Data); err != nil {
|
|
return err
|
|
}
|
|
r.SubscriptionID = res.SubscriptionID
|
|
r.Query = res.Query
|
|
r.Events = res.Events
|
|
return nil
|
|
}
|
|
|
|
// Evidence is an argument wrapper for a types.Evidence value, that handles
|
|
// encoding and decoding through JSON.
|
|
type Evidence struct {
|
|
Value types.Evidence
|
|
}
|
|
|
|
func (e Evidence) MarshalJSON() ([]byte, error) { return jsontypes.Marshal(e.Value) }
|
|
func (e *Evidence) UnmarshalJSON(data []byte) error { return jsontypes.Unmarshal(data, &e.Value) }
|
|
|
|
// RequestEvents is the argument for the "/events" RPC endpoint.
|
|
type RequestEvents struct {
|
|
// Optional filter spec. If nil or empty, all items are eligible.
|
|
Filter *EventFilter `json:"filter"`
|
|
|
|
// The maximum number of eligible items to return.
|
|
// If zero or negative, the server will report a default number.
|
|
MaxItems int `json:"maxItems"`
|
|
|
|
// Return only items after this cursor. If empty, the limit is just
|
|
// before the the beginning of the event log.
|
|
After string `json:"after"`
|
|
|
|
// Return only items before this cursor. If empty, the limit is just
|
|
// after the head of the event log.
|
|
Before string `json:"before"`
|
|
|
|
// Wait for up to this long for events to be available.
|
|
WaitTime time.Duration `json:"waitTime"`
|
|
}
|
|
|
|
// An EventFilter specifies which events are selected by an /events request.
|
|
type EventFilter struct {
|
|
Query string `json:"query"`
|
|
}
|
|
|
|
// ResultEvents is the response from the "/events" RPC endpoint.
|
|
type ResultEvents struct {
|
|
// The items matching the request parameters, from newest
|
|
// to oldest, if any were available within the timeout.
|
|
Items []*EventItem `json:"items"`
|
|
|
|
// This is true if there is at least one older matching item
|
|
// available in the log that was not returned.
|
|
More bool `json:"more"`
|
|
|
|
// The cursor of the oldest item in the log at the time of this reply,
|
|
// or "" if the log is empty.
|
|
Oldest string `json:"oldest"`
|
|
|
|
// The cursor of the newest item in the log at the time of this reply,
|
|
// or "" if the log is empty.
|
|
Newest string `json:"newest"`
|
|
}
|
|
|
|
type EventItem struct {
|
|
// The cursor of this item.
|
|
Cursor string `json:"cursor"`
|
|
|
|
// The event label of this item (for example, "Vote").
|
|
Event string `json:"event,omitempty"`
|
|
|
|
// The encoded event data for this item. The content is a JSON object with
|
|
// the following structure:
|
|
//
|
|
// {
|
|
// "type": "type-tag",
|
|
// "value": <json-encoded-value>
|
|
// }
|
|
//
|
|
// The known type tags are defined by the tendermint/types package.
|
|
Data json.RawMessage `json:"data"`
|
|
}
|