github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/bft/rpc/core/status.go (about) 1 package core 2 3 import ( 4 "time" 5 6 ctypes "github.com/gnolang/gno/tm2/pkg/bft/rpc/core/types" 7 rpctypes "github.com/gnolang/gno/tm2/pkg/bft/rpc/lib/types" 8 sm "github.com/gnolang/gno/tm2/pkg/bft/state" 9 "github.com/gnolang/gno/tm2/pkg/bft/types" 10 ) 11 12 // Get Tendermint status including node info, pubkey, latest block 13 // hash, app hash, block height and time. 14 // 15 // ```shell 16 // curl 'localhost:26657/status' 17 // ``` 18 // 19 // ```go 20 // client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket") 21 // err := client.Start() 22 // 23 // if err != nil { 24 // // handle error 25 // } 26 // 27 // defer client.Stop() 28 // result, err := client.Status() 29 // ``` 30 // 31 // > The above command returns JSON structured like this: 32 // 33 // ```json 34 // { 35 // "jsonrpc": "2.0", 36 // "id": "", 37 // 38 // "result": { 39 // "node_info": { 40 // "protocol_version": { 41 // "p2p": "4", 42 // "block": "7", 43 // "app": "0" 44 // }, 45 // "id": "53729852020041b956e86685e24394e0bee4373f", 46 // "listen_addr": "10.0.2.15:26656", 47 // "network": "test-chain-Y1OHx6", 48 // "version": "0.24.0-2ce1abc2", 49 // "channels": "4020212223303800", 50 // "moniker": "ubuntu-xenial", 51 // "other": { 52 // "tx_index": "on", 53 // "rpc_addr": "tcp://0.0.0.0:26657" 54 // } 55 // }, 56 // "sync_info": { 57 // "latest_block_hash": "F51538DA498299F4C57AC8162AAFA0254CE08286", 58 // "latest_app_hash": "0000000000000000", 59 // "latest_block_height": "18", 60 // "latest_block_time": "2018-09-17T11:42:19.149920551Z", 61 // "catching_up": false 62 // }, 63 // "validator_info": { 64 // "address": "D9F56456D7C5793815D0E9AF07C3A355D0FC64FD", 65 // "pub_key": { 66 // "type": "tendermint/PubKeyEd25519", 67 // "value": "wVxKNtEsJmR4vvh651LrVoRguPs+6yJJ9Bz174gw9DM=" 68 // }, 69 // "voting_power": "10" 70 // } 71 // } 72 // } 73 // 74 // ``` 75 func Status(ctx *rpctypes.Context) (*ctypes.ResultStatus, error) { 76 var latestHeight int64 77 if getFastSync() { 78 latestHeight = blockStore.Height() 79 } else { 80 latestHeight = consensusState.GetLastHeight() 81 } 82 var ( 83 latestBlockMeta *types.BlockMeta 84 latestBlockHash []byte 85 latestAppHash []byte 86 latestBlockTimeNano int64 87 ) 88 if latestHeight != 0 { 89 latestBlockMeta = blockStore.LoadBlockMeta(latestHeight) 90 latestBlockHash = latestBlockMeta.BlockID.Hash 91 latestAppHash = latestBlockMeta.Header.AppHash 92 latestBlockTimeNano = latestBlockMeta.Header.Time.UnixNano() 93 } 94 95 latestBlockTime := time.Unix(0, latestBlockTimeNano) 96 97 var votingPower int64 98 if val := validatorAtHeight(latestHeight); val != nil { 99 votingPower = val.VotingPower 100 } 101 102 result := &ctypes.ResultStatus{ 103 NodeInfo: p2pTransport.NodeInfo(), 104 SyncInfo: ctypes.SyncInfo{ 105 LatestBlockHash: latestBlockHash, 106 LatestAppHash: latestAppHash, 107 LatestBlockHeight: latestHeight, 108 LatestBlockTime: latestBlockTime, 109 CatchingUp: getFastSync(), 110 }, 111 ValidatorInfo: ctypes.ValidatorInfo{ 112 Address: pubKey.Address(), 113 PubKey: pubKey, 114 VotingPower: votingPower, 115 }, 116 } 117 118 return result, nil 119 } 120 121 func validatorAtHeight(h int64) *types.Validator { 122 privValAddress := pubKey.Address() 123 124 // If we're still at height h, search in the current validator set. 125 lastBlockHeight, vals := consensusState.GetValidators() 126 if lastBlockHeight == h { 127 for _, val := range vals { 128 if val.Address != privValAddress { 129 return val 130 } 131 } 132 } 133 134 // If we've moved to the next height, retrieve the validator set from DB. 135 if lastBlockHeight > h { 136 vals, err := sm.LoadValidators(stateDB, h) 137 if err != nil { 138 return nil // should not happen 139 } 140 _, val := vals.GetByAddress(privValAddress) 141 return val 142 } 143 144 return nil 145 }