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  }