tendermint/rpc/core/consensus.go
Ethan Buchman 882622ec10
Fixes tendermint/tendermint#3522
* OriginalAddr -> SocketAddr

OriginalAddr records the originally dialed address for outbound peers,
rather than the peer's self reported address. For inbound peers, it was
nil. Here, we rename it to SocketAddr and for inbound peers, set it to
the RemoteAddr of the connection.

* use SocketAddr

Numerous places in the code call peer.NodeInfo().NetAddress().
However, this call to NetAddress() may perform a DNS lookup if the
reported NodeInfo.ListenAddr includes a name. Failure of this lookup
returns a nil address, which can lead to panics in the code.

Instead, call peer.SocketAddr() to return the static address of the
connection.

* remove nodeInfo.NetAddress()

Expose `transport.NetAddress()`, a static result determined
when the transport is created. Removing NetAddress() from the nodeInfo
prevents accidental DNS lookups.

* fixes from review

* linter

* fixes from review
2019-04-01 19:59:57 -04:00

341 lines
9.1 KiB
Go

package core
import (
cm "github.com/tendermint/tendermint/consensus"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
rpctypes "github.com/tendermint/tendermint/rpc/lib/types"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
)
// Get the validator set at the given block height.
// If no height is provided, it will fetch the current validator set.
// Note the validators are sorted by their address - this is the canonical
// order for the validators in the set as used in computing their Merkle root.
//
// ```shell
// curl 'localhost:26657/validators'
// ```
//
// ```go
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
// err := client.Start()
// if err != nil {
// // handle error
// }
// defer client.Stop()
// state, err := client.Validators()
// ```
//
// The above command returns JSON structured like this:
//
// ```json
// {
// "error": "",
// "result": {
// "validators": [
// {
// "proposer_priority": "0",
// "voting_power": "10",
// "pub_key": {
// "data": "68DFDA7E50F82946E7E8546BED37944A422CD1B831E70DF66BA3B8430593944D",
// "type": "ed25519"
// },
// "address": "E89A51D60F68385E09E716D353373B11F8FACD62"
// }
// ],
// "block_height": "5241"
// },
// "id": "",
// "jsonrpc": "2.0"
// }
// ```
func Validators(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultValidators, error) {
// The latest validator that we know is the
// NextValidator of the last block.
height := consensusState.GetState().LastBlockHeight + 1
height, err := getHeight(height, heightPtr)
if err != nil {
return nil, err
}
validators, err := sm.LoadValidators(stateDB, height)
if err != nil {
return nil, err
}
return &ctypes.ResultValidators{
BlockHeight: height,
Validators: validators.Validators}, nil
}
// DumpConsensusState dumps consensus state.
// UNSTABLE
//
// ```shell
// curl 'localhost:26657/dump_consensus_state'
// ```
//
// ```go
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
// err := client.Start()
// if err != nil {
// // handle error
// }
// defer client.Stop()
// state, err := client.DumpConsensusState()
// ```
//
// The above command returns JSON structured like this:
//
// ```json
// {
// "jsonrpc": "2.0",
// "id": "",
// "result": {
// "round_state": {
// "height": "7185",
// "round": "0",
// "step": "1",
// "start_time": "2018-05-12T13:57:28.440293621-07:00",
// "commit_time": "2018-05-12T13:57:27.440293621-07:00",
// "validators": {
// "validators": [
// {
// "address": "B5B3D40BE53982AD294EF99FF5A34C0C3E5A3244",
// "pub_key": {
// "type": "tendermint/PubKeyEd25519",
// "value": "SBctdhRBcXtBgdI/8a/alTsUhGXqGs9k5ylV1u5iKHg="
// },
// "voting_power": "10",
// "proposer_priority": "0"
// }
// ],
// "proposer": {
// "address": "B5B3D40BE53982AD294EF99FF5A34C0C3E5A3244",
// "pub_key": {
// "type": "tendermint/PubKeyEd25519",
// "value": "SBctdhRBcXtBgdI/8a/alTsUhGXqGs9k5ylV1u5iKHg="
// },
// "voting_power": "10",
// "proposer_priority": "0"
// }
// },
// "proposal": null,
// "proposal_block": null,
// "proposal_block_parts": null,
// "locked_round": "0",
// "locked_block": null,
// "locked_block_parts": null,
// "valid_round": "0",
// "valid_block": null,
// "valid_block_parts": null,
// "votes": [
// {
// "round": "0",
// "prevotes": "_",
// "precommits": "_"
// }
// ],
// "commit_round": "-1",
// "last_commit": {
// "votes": [
// "Vote{0:B5B3D40BE539 7184/00/2(Precommit) 14F946FA7EF0 /702B1B1A602A.../ @ 2018-05-12T20:57:27.342Z}"
// ],
// "votes_bit_array": "x",
// "peer_maj_23s": {}
// },
// "last_validators": {
// "validators": [
// {
// "address": "B5B3D40BE53982AD294EF99FF5A34C0C3E5A3244",
// "pub_key": {
// "type": "tendermint/PubKeyEd25519",
// "value": "SBctdhRBcXtBgdI/8a/alTsUhGXqGs9k5ylV1u5iKHg="
// },
// "voting_power": "10",
// "proposer_priority": "0"
// }
// ],
// "proposer": {
// "address": "B5B3D40BE53982AD294EF99FF5A34C0C3E5A3244",
// "pub_key": {
// "type": "tendermint/PubKeyEd25519",
// "value": "SBctdhRBcXtBgdI/8a/alTsUhGXqGs9k5ylV1u5iKHg="
// },
// "voting_power": "10",
// "proposer_priority": "0"
// }
// }
// },
// "peers": [
// {
// "node_address": "30ad1854af22506383c3f0e57fb3c7f90984c5e8@172.16.63.221:26656",
// "peer_state": {
// "round_state": {
// "height": "7185",
// "round": "0",
// "step": "1",
// "start_time": "2018-05-12T13:57:27.438039872-07:00",
// "proposal": false,
// "proposal_block_parts_header": {
// "total": "0",
// "hash": ""
// },
// "proposal_block_parts": null,
// "proposal_pol_round": "-1",
// "proposal_pol": "_",
// "prevotes": "_",
// "precommits": "_",
// "last_commit_round": "0",
// "last_commit": "x",
// "catchup_commit_round": "-1",
// "catchup_commit": "_"
// },
// "stats": {
// "last_vote_height": "7184",
// "votes": "255",
// "last_block_part_height": "7184",
// "block_parts": "255"
// }
// }
// }
// ]
// }
// }
// ```
func DumpConsensusState(ctx *rpctypes.Context) (*ctypes.ResultDumpConsensusState, error) {
// Get Peer consensus states.
peers := p2pPeers.Peers().List()
peerStates := make([]ctypes.PeerStateInfo, len(peers))
for i, peer := range peers {
peerState, ok := peer.Get(types.PeerStateKey).(*cm.PeerState)
if !ok { // peer does not have a state yet
continue
}
peerStateJSON, err := peerState.ToJSON()
if err != nil {
return nil, err
}
peerStates[i] = ctypes.PeerStateInfo{
// Peer basic info.
NodeAddress: peer.SocketAddr().String(),
// Peer consensus state.
PeerState: peerStateJSON,
}
}
// Get self round state.
roundState, err := consensusState.GetRoundStateJSON()
if err != nil {
return nil, err
}
return &ctypes.ResultDumpConsensusState{
RoundState: roundState,
Peers: peerStates}, nil
}
// ConsensusState returns a concise summary of the consensus state.
// UNSTABLE
//
// ```shell
// curl 'localhost:26657/consensus_state'
// ```
//
// ```go
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
// err := client.Start()
// if err != nil {
// // handle error
// }
// defer client.Stop()
// state, err := client.ConsensusState()
// ```
//
// The above command returns JSON structured like this:
//
// ```json
//{
// "jsonrpc": "2.0",
// "id": "",
// "result": {
// "round_state": {
// "height/round/step": "9336/0/1",
// "start_time": "2018-05-14T10:25:45.72595357-04:00",
// "proposal_block_hash": "",
// "locked_block_hash": "",
// "valid_block_hash": "",
// "height_vote_set": [
// {
// "round": "0",
// "prevotes": [
// "nil-Vote"
// ],
// "prevotes_bit_array": "BA{1:_} 0/10 = 0.00",
// "precommits": [
// "nil-Vote"
// ],
// "precommits_bit_array": "BA{1:_} 0/10 = 0.00"
// }
// ]
// }
// }
//}
//```
func ConsensusState(ctx *rpctypes.Context) (*ctypes.ResultConsensusState, error) {
// Get self round state.
bz, err := consensusState.GetRoundStateSimpleJSON()
return &ctypes.ResultConsensusState{RoundState: bz}, err
}
// Get the consensus parameters at the given block height.
// If no height is provided, it will fetch the current consensus params.
//
// ```shell
// curl 'localhost:26657/consensus_params'
// ```
//
// ```go
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
// err := client.Start()
// if err != nil {
// // handle error
// }
// defer client.Stop()
// state, err := client.ConsensusParams()
// ```
//
// The above command returns JSON structured like this:
//
// ```json
// {
// "jsonrpc": "2.0",
// "id": "",
// "result": {
// "block_height": "1",
// "consensus_params": {
// "block_size_params": {
// "max_txs_bytes": "22020096",
// "max_gas": "-1"
// },
// "evidence_params": {
// "max_age": "100000"
// }
// }
// }
// }
// ```
func ConsensusParams(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultConsensusParams, error) {
height := consensusState.GetState().LastBlockHeight + 1
height, err := getHeight(height, heightPtr)
if err != nil {
return nil, err
}
consensusparams, err := sm.LoadConsensusParams(stateDB, height)
if err != nil {
return nil, err
}
return &ctypes.ResultConsensusParams{
BlockHeight: height,
ConsensusParams: consensusparams}, nil
}