|
|
- package core
-
- import (
- "bytes"
- "time"
-
- cmn "github.com/tendermint/tendermint/libs/common"
- ctypes "github.com/tendermint/tendermint/rpc/core/types"
- sm "github.com/tendermint/tendermint/state"
- "github.com/tendermint/tendermint/types"
- )
-
- // Get Tendermint status including node info, pubkey, latest block
- // hash, app hash, block height and time.
- //
- // ```shell
- // curl 'localhost:26657/status'
- // ```
- //
- // ```go
- // client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
- // result, err := client.Status()
- // ```
- //
- // > The above command returns JSON structured like this:
- //
- // ```json
- //{
- // "jsonrpc": "2.0",
- // "id": "",
- // "result": {
- // "node_info": {
- // "id": "562dd7f579f0ecee8c94a11a3c1e378c1876f433",
- // "listen_addr": "192.168.1.2:26656",
- // "network": "test-chain-I6zScH",
- // "version": "0.19.0",
- // "channels": "4020212223303800",
- // "moniker": "Ethans-MacBook-Pro.local",
- // "other": [
- // "amino_version=0.9.8",
- // "p2p_version=0.5.0",
- // "consensus_version=v1/0.2.2",
- // "rpc_version=0.7.0/3",
- // "tx_index=on",
- // "rpc_addr=tcp://0.0.0.0:26657"
- // ]
- // },
- // "sync_info": {
- // "latest_block_hash": "2D4D7055BE685E3CB2410603C92AD37AE557AC59",
- // "latest_app_hash": "0000000000000000",
- // "latest_block_height": 231,
- // "latest_block_time": "2018-04-27T23:18:08.459766485-04:00",
- // "catching_up": false
- // },
- // "validator_info": {
- // "address": "5875562FF0FFDECC895C20E32FC14988952E99E7",
- // "pub_key": {
- // "type": "tendermint/PubKeyEd25519",
- // "value": "PpDJRUrLG2RgFqYYjawfn/AcAgacSXpLFrmfYYQnuzE="
- // },
- // "voting_power": 10
- // }
- // }
- //}
- // ```
- func Status() (*ctypes.ResultStatus, error) {
- latestHeight := blockStore.Height()
- var (
- latestBlockMeta *types.BlockMeta
- latestBlockHash cmn.HexBytes
- latestAppHash cmn.HexBytes
- latestBlockTimeNano int64
- )
- if latestHeight != 0 {
- latestBlockMeta = blockStore.LoadBlockMeta(latestHeight)
- latestBlockHash = latestBlockMeta.BlockID.Hash
- latestAppHash = latestBlockMeta.Header.AppHash
- latestBlockTimeNano = latestBlockMeta.Header.Time.UnixNano()
- }
-
- latestBlockTime := time.Unix(0, latestBlockTimeNano)
-
- var votingPower int64
- if val := validatorAtHeight(latestHeight); val != nil {
- votingPower = val.VotingPower
- }
-
- result := &ctypes.ResultStatus{
- NodeInfo: p2pSwitch.NodeInfo(),
- SyncInfo: ctypes.SyncInfo{
- LatestBlockHash: latestBlockHash,
- LatestAppHash: latestAppHash,
- LatestBlockHeight: latestHeight,
- LatestBlockTime: latestBlockTime,
- CatchingUp: consensusReactor.FastSync(),
- },
- ValidatorInfo: ctypes.ValidatorInfo{
- Address: pubKey.Address(),
- PubKey: pubKey,
- VotingPower: votingPower,
- },
- }
-
- return result, nil
- }
-
- const consensusTimeout = time.Second
-
- func validatorAtHeight(h int64) *types.Validator {
- lastBlockHeight, vals := getValidatorsWithTimeout(
- consensusState,
- consensusTimeout,
- )
-
- if lastBlockHeight == -1 {
- return nil
- }
-
- privValAddress := pubKey.Address()
-
- // if we're still at height h, search in the current validator set
- if lastBlockHeight == h {
- for _, val := range vals {
- if bytes.Equal(val.Address, privValAddress) {
- return val
- }
- }
- }
-
- // if we've moved to the next height, retrieve the validator set from DB
- if lastBlockHeight > h {
- vals, err := sm.LoadValidators(stateDB, h)
- if err != nil {
- // should not happen
- return nil
- }
- _, val := vals.GetByAddress(privValAddress)
- return val
- }
-
- return nil
- }
-
- type validatorRetriever interface {
- GetValidators() (int64, []*types.Validator)
- }
-
- // NOTE: Consensus might halt, but we still need to process RPC requests (at
- // least for endpoints whole output does not depend on consensus state).
- func getValidatorsWithTimeout(
- vr validatorRetriever,
- t time.Duration,
- ) (int64, []*types.Validator) {
- resultCh := make(chan struct {
- lastBlockHeight int64
- vals []*types.Validator
- })
- go func() {
- h, v := vr.GetValidators()
- resultCh <- struct {
- lastBlockHeight int64
- vals []*types.Validator
- }{h, v}
- }()
- select {
- case res := <-resultCh:
- return res.lastBlockHeight, res.vals
- case <-time.After(t):
- if logger != nil {
- logger.Error("Timed out querying validators from consensus", "timeout", t)
- }
- return -1, []*types.Validator{}
- }
- }
|