rpc: Transform /status result.node_info.other into map (#2417)

* [rpc] transform /status result.node_info.other into map
* amino does not support maps, duh

Refs #2391
This commit is contained in:
Anton Kaliaev 2018-09-17 20:39:52 +04:00 committed by Alexander Simmerl
parent 8ae3334423
commit fc7f9bcaf6
9 changed files with 128 additions and 76 deletions

View File

@ -7,6 +7,7 @@ BREAKING CHANGES:
* CLI/RPC/Config * CLI/RPC/Config
* Apps * Apps
[rpc] /status `result.node_info.other` became a map #[2391](https://github.com/tendermint/tendermint/issues/2391)
* Go API * Go API
* \#2310 Mempool.ReapMaxBytes -> Mempool.ReapMaxBytesMaxGas * \#2310 Mempool.ReapMaxBytes -> Mempool.ReapMaxBytesMaxGas

View File

@ -24,7 +24,10 @@ func BenchmarkEncodeStatusWire(b *testing.B) {
Network: "SOMENAME", Network: "SOMENAME",
ListenAddr: "SOMEADDR", ListenAddr: "SOMEADDR",
Version: "SOMEVER", Version: "SOMEVER",
Other: []string{"SOMESTRING", "OTHERSTRING"}, Other: p2p.NodeInfoOther{
AminoVersion: "SOMESTRING",
P2PVersion: "OTHERSTRING",
},
}, },
SyncInfo: ctypes.SyncInfo{ SyncInfo: ctypes.SyncInfo{
LatestBlockHash: []byte("SOMEBYTES"), LatestBlockHash: []byte("SOMEBYTES"),
@ -59,7 +62,10 @@ func BenchmarkEncodeNodeInfoWire(b *testing.B) {
Network: "SOMENAME", Network: "SOMENAME",
ListenAddr: "SOMEADDR", ListenAddr: "SOMEADDR",
Version: "SOMEVER", Version: "SOMEVER",
Other: []string{"SOMESTRING", "OTHERSTRING"}, Other: p2p.NodeInfoOther{
AminoVersion: "SOMESTRING",
P2PVersion: "OTHERSTRING",
},
} }
b.StartTimer() b.StartTimer()
@ -84,7 +90,10 @@ func BenchmarkEncodeNodeInfoBinary(b *testing.B) {
Network: "SOMENAME", Network: "SOMENAME",
ListenAddr: "SOMEADDR", ListenAddr: "SOMEADDR",
Version: "SOMEVER", Version: "SOMEVER",
Other: []string{"SOMESTRING", "OTHERSTRING"}, Other: p2p.NodeInfoOther{
AminoVersion: "SOMESTRING",
P2PVersion: "OTHERSTRING",
},
} }
b.StartTimer() b.StartTimer()

View File

@ -83,7 +83,15 @@ type NodeInfo struct {
Channels []int8 Channels []int8
Moniker string Moniker string
Other []string Other NodeInfoOther
}
type NodeInfoOther struct {
AminoVersion string
P2PVersion string
ConsensusVersion string
RPCVersion string
TxIndex string
} }
``` ```

View File

@ -690,12 +690,12 @@ func (n *Node) makeNodeInfo(nodeID p2p.ID) p2p.NodeInfo {
evidence.EvidenceChannel, evidence.EvidenceChannel,
}, },
Moniker: n.config.Moniker, Moniker: n.config.Moniker,
Other: []string{ Other: p2p.NodeInfoOther{
fmt.Sprintf("amino_version=%v", amino.Version), AminoVersion: amino.Version,
fmt.Sprintf("p2p_version=%v", p2p.Version), P2PVersion: p2p.Version,
fmt.Sprintf("consensus_version=%v", cs.Version), ConsensusVersion: cs.Version,
fmt.Sprintf("rpc_version=%v/%v", rpc.Version, rpccore.Version), RPCVersion: fmt.Sprintf("%v/%v", rpc.Version, rpccore.Version),
fmt.Sprintf("tx_index=%v", txIndexerStatus), TxIndex: txIndexerStatus,
}, },
} }
@ -704,7 +704,7 @@ func (n *Node) makeNodeInfo(nodeID p2p.ID) p2p.NodeInfo {
} }
rpcListenAddr := n.config.RPC.ListenAddress rpcListenAddr := n.config.RPC.ListenAddress
nodeInfo.Other = append(nodeInfo.Other, fmt.Sprintf("rpc_addr=%v", rpcListenAddr)) nodeInfo.Other.RPCAddress = rpcListenAddr
if !n.sw.IsListening() { if !n.sw.IsListening() {
return nodeInfo return nodeInfo

View File

@ -32,8 +32,29 @@ type NodeInfo struct {
Channels cmn.HexBytes `json:"channels"` // channels this node knows about Channels cmn.HexBytes `json:"channels"` // channels this node knows about
// ASCIIText fields // ASCIIText fields
Moniker string `json:"moniker"` // arbitrary moniker Moniker string `json:"moniker"` // arbitrary moniker
Other []string `json:"other"` // other application specific data Other NodeInfoOther `json:"other"` // other application specific data
}
// NodeInfoOther is the misc. applcation specific data
type NodeInfoOther struct {
AminoVersion string `json:"amino_version"`
P2PVersion string `json:"p2p_version"`
ConsensusVersion string `json:"consensus_version"`
RPCVersion string `json:"rpc_version"`
TxIndex string `json:"tx_index"`
RPCAddress string `json:"rpc_address"`
}
func (o NodeInfoOther) String() string {
return fmt.Sprintf(
"{amino_version: %v, p2p_version: %v, consensus_version: %v, rpc_version: %v, tx_index: %v}",
o.AminoVersion,
o.P2PVersion,
o.ConsensusVersion,
o.RPCVersion,
o.TxIndex,
)
} }
// Validate checks the self-reported NodeInfo is safe. // Validate checks the self-reported NodeInfo is safe.
@ -56,13 +77,28 @@ func (info NodeInfo) Validate() error {
// Sanitize ASCII text fields. // Sanitize ASCII text fields.
if !cmn.IsASCIIText(info.Moniker) || cmn.ASCIITrim(info.Moniker) == "" { if !cmn.IsASCIIText(info.Moniker) || cmn.ASCIITrim(info.Moniker) == "" {
return fmt.Errorf("info.Moniker must be valid non-empty ASCII text without tabs, but got %v.", info.Moniker) return fmt.Errorf("info.Moniker must be valid non-empty ASCII text without tabs, but got %v", info.Moniker)
} }
for i, s := range info.Other {
if !cmn.IsASCIIText(s) || cmn.ASCIITrim(s) == "" { // Sanitize versions
return fmt.Errorf("info.Other[%v] must be valid non-empty ASCII text without tabs, but got %v.", i, s) // XXX: Should we be more strict about version and address formats?
other := info.Other
versions := []string{other.AminoVersion,
other.AminoVersion,
other.P2PVersion,
other.ConsensusVersion,
other.RPCVersion}
for i, v := range versions {
if cmn.ASCIITrim(v) != "" && !cmn.IsASCIIText(v) {
return fmt.Errorf("info.Other[%d]=%v must be valid non-empty ASCII text without tabs", i, v)
} }
} }
if cmn.ASCIITrim(other.TxIndex) != "" && (other.TxIndex != "on" && other.TxIndex != "off") {
return fmt.Errorf("info.Other.TxIndex should be either 'on' or 'off', got '%v'", other.TxIndex)
}
if cmn.ASCIITrim(other.RPCAddress) != "" && !cmn.IsASCIIText(other.RPCAddress) {
return fmt.Errorf("info.Other.RPCAddress=%v must be valid non-empty ASCII text without tabs", other.RPCAddress)
}
channels := make(map[byte]struct{}) channels := make(map[byte]struct{})
for _, ch := range info.Channels { for _, ch := range info.Channels {

View File

@ -140,12 +140,21 @@ func MakeSwitch(cfg *config.P2PConfig, i int, network, version string, initSwitc
sw := NewSwitch(cfg) sw := NewSwitch(cfg)
sw.SetLogger(log.TestingLogger()) sw.SetLogger(log.TestingLogger())
sw = initSwitch(i, sw) sw = initSwitch(i, sw)
addr := fmt.Sprintf("127.0.0.1:%d", cmn.RandIntn(64512)+1023)
ni := NodeInfo{ ni := NodeInfo{
ID: nodeKey.ID(), ID: nodeKey.ID(),
Moniker: fmt.Sprintf("switch%d", i), Moniker: fmt.Sprintf("switch%d", i),
Network: network, Network: network,
Version: version, Version: version,
ListenAddr: fmt.Sprintf("127.0.0.1:%d", cmn.RandIntn(64512)+1023), ListenAddr: addr,
Other: NodeInfoOther{
AminoVersion: "1.0",
P2PVersion: "1.0",
ConsensusVersion: "1.0",
RPCVersion: "1.0",
TxIndex: "off",
RPCAddress: addr,
},
} }
for ch := range sw.reactorsByCh { for ch := range sw.reactorsByCh {
ni.Channels = append(ni.Channels, ch) ni.Channels = append(ni.Channels, ch)

View File

@ -25,43 +25,43 @@ import (
// > The above command returns JSON structured like this: // > The above command returns JSON structured like this:
// //
// ```json // ```json
//{ // {
// "jsonrpc": "2.0", // "jsonrpc": "2.0",
// "id": "", // "id": "",
// "result": { // "result": {
// "node_info": { // "node_info": {
// "id": "562dd7f579f0ecee8c94a11a3c1e378c1876f433", // "id": "53729852020041b956e86685e24394e0bee4373f",
// "listen_addr": "192.168.1.2:26656", // "listen_addr": "10.0.2.15:26656",
// "network": "test-chain-I6zScH", // "network": "test-chain-Y1OHx6",
// "version": "0.19.0", // "version": "0.24.0-2ce1abc2",
// "channels": "4020212223303800", // "channels": "4020212223303800",
// "moniker": "Ethans-MacBook-Pro.local", // "moniker": "ubuntu-xenial",
// "other": [ // "other": {
// "amino_version=0.9.8", // "amino_version": "0.12.0",
// "p2p_version=0.5.0", // "p2p_version": "0.5.0",
// "consensus_version=v1/0.2.2", // "consensus_version": "v1/0.2.2",
// "rpc_version=0.7.0/3", // "rpc_version": "0.7.0/3",
// "tx_index=on", // "tx_index": "on",
// "rpc_addr=tcp://0.0.0.0:26657" // "rpc_addr": "tcp://0.0.0.0:26657"
// ] // }
// }, // },
// "sync_info": { // "sync_info": {
// "latest_block_hash": "2D4D7055BE685E3CB2410603C92AD37AE557AC59", // "latest_block_hash": "F51538DA498299F4C57AC8162AAFA0254CE08286",
// "latest_app_hash": "0000000000000000", // "latest_app_hash": "0000000000000000",
// "latest_block_height": 231, // "latest_block_height": "18",
// "latest_block_time": "2018-04-27T23:18:08.459766485-04:00", // "latest_block_time": "2018-09-17T11:42:19.149920551Z",
// "catching_up": false // "catching_up": false
// }, // },
// "validator_info": { // "validator_info": {
// "address": "5875562FF0FFDECC895C20E32FC14988952E99E7", // "address": "D9F56456D7C5793815D0E9AF07C3A355D0FC64FD",
// "pub_key": { // "pub_key": {
// "type": "tendermint/PubKeyEd25519", // "type": "tendermint/PubKeyEd25519",
// "value": "PpDJRUrLG2RgFqYYjawfn/AcAgacSXpLFrmfYYQnuzE=" // "value": "wVxKNtEsJmR4vvh651LrVoRguPs+6yJJ9Bz174gw9DM="
// }, // },
// "voting_power": 10 // "voting_power": "10"
// } // }
// } // }
//} // }
// ``` // ```
func Status() (*ctypes.ResultStatus, error) { func Status() (*ctypes.ResultStatus, error) {
var latestHeight int64 = -1 var latestHeight int64 = -1

View File

@ -2,7 +2,6 @@ package core_types
import ( import (
"encoding/json" "encoding/json"
"strings"
"time" "time"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
@ -85,13 +84,7 @@ func (s *ResultStatus) TxIndexEnabled() bool {
if s == nil { if s == nil {
return false return false
} }
for _, s := range s.NodeInfo.Other { return s.NodeInfo.Other.TxIndex == "on"
info := strings.Split(s, "=")
if len(info) == 2 && info[0] == "tx_index" {
return info[1] == "on"
}
}
return false
} }
// Info about peer connections // Info about peer connections

View File

@ -9,31 +9,27 @@ import (
) )
func TestStatusIndexer(t *testing.T) { func TestStatusIndexer(t *testing.T) {
assert := assert.New(t)
var status *ResultStatus var status *ResultStatus
assert.False(status.TxIndexEnabled()) assert.False(t, status.TxIndexEnabled())
status = &ResultStatus{} status = &ResultStatus{}
assert.False(status.TxIndexEnabled()) assert.False(t, status.TxIndexEnabled())
status.NodeInfo = p2p.NodeInfo{} status.NodeInfo = p2p.NodeInfo{}
assert.False(status.TxIndexEnabled()) assert.False(t, status.TxIndexEnabled())
cases := []struct { cases := []struct {
expected bool expected bool
other []string other p2p.NodeInfoOther
}{ }{
{false, nil}, {false, p2p.NodeInfoOther{}},
{false, []string{}}, {false, p2p.NodeInfoOther{TxIndex: "aa"}},
{false, []string{"a=b"}}, {false, p2p.NodeInfoOther{TxIndex: "off"}},
{false, []string{"tx_indexiskv", "some=dood"}}, {true, p2p.NodeInfoOther{TxIndex: "on"}},
{true, []string{"tx_index=on", "tx_index=other"}},
{true, []string{"^(*^(", "tx_index=on", "a=n=b=d="}},
} }
for _, tc := range cases { for _, tc := range cases {
status.NodeInfo.Other = tc.other status.NodeInfo.Other = tc.other
assert.Equal(tc.expected, status.TxIndexEnabled()) assert.Equal(t, tc.expected, status.TxIndexEnabled())
} }
} }