package core import ( "bytes" "time" tmbytes "github.com/tendermint/tendermint/libs/bytes" "github.com/tendermint/tendermint/p2p" 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" ) // Status returns Tendermint status including node info, pubkey, latest block // hash, app hash, block height and time. // More: https://docs.tendermint.com/master/rpc/#/Info/status func Status(ctx *rpctypes.Context) (*ctypes.ResultStatus, error) { var ( earliestBlockMeta *types.BlockMeta earliestBlockHash tmbytes.HexBytes earliestAppHash tmbytes.HexBytes earliestBlockTimeNano int64 ) earliestBlockHeight := env.BlockStore.Base() earliestBlockMeta = env.BlockStore.LoadBlockMeta(earliestBlockHeight) if earliestBlockMeta != nil { earliestAppHash = earliestBlockMeta.Header.AppHash earliestBlockHash = earliestBlockMeta.BlockID.Hash earliestBlockTimeNano = earliestBlockMeta.Header.Time.UnixNano() } var latestHeight int64 if env.ConsensusReactor.WaitSync() { latestHeight = env.BlockStore.Height() } else { latestHeight = env.ConsensusState.GetLastHeight() } var ( latestBlockMeta *types.BlockMeta latestBlockHash tmbytes.HexBytes latestAppHash tmbytes.HexBytes latestBlockTimeNano int64 ) if latestHeight != 0 { latestBlockMeta = env.BlockStore.LoadBlockMeta(latestHeight) latestBlockHash = latestBlockMeta.BlockID.Hash latestAppHash = latestBlockMeta.Header.AppHash latestBlockTimeNano = latestBlockMeta.Header.Time.UnixNano() } var votingPower int64 if val := validatorAtHeight(latestHeight); val != nil { votingPower = val.VotingPower } result := &ctypes.ResultStatus{ NodeInfo: env.P2PTransport.NodeInfo().(p2p.DefaultNodeInfo), SyncInfo: ctypes.SyncInfo{ LatestBlockHash: latestBlockHash, LatestAppHash: latestAppHash, LatestBlockHeight: latestHeight, LatestBlockTime: time.Unix(0, latestBlockTimeNano), EarliestBlockHash: earliestBlockHash, EarliestAppHash: earliestAppHash, EarliestBlockHeight: earliestBlockHeight, EarliestBlockTime: time.Unix(0, earliestBlockTimeNano), CatchingUp: env.ConsensusReactor.WaitSync(), }, ValidatorInfo: ctypes.ValidatorInfo{ Address: env.PubKey.Address(), PubKey: env.PubKey, VotingPower: votingPower, }, } return result, nil } func validatorAtHeight(h int64) *types.Validator { privValAddress := env.PubKey.Address() // If we're still at height h, search in the current validator set. lastBlockHeight, vals := env.ConsensusState.GetValidators() 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(env.StateDB, h) if err != nil { return nil // should not happen } _, val := vals.GetByAddress(privValAddress) return val } return nil }