mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-25 06:42:16 +00:00
ADR-016: Add protocol Version to NodeInfo (#2654)
* p2p: add protocol Version to NodeInfo * update node pkg. remove extraneous version files * update changelog and docs * fix test * p2p: Version -> ProtocolVersion; more ValidateBasic and tests
This commit is contained in:
parent
455d34134c
commit
14c1baeb24
@ -14,6 +14,8 @@ BREAKING CHANGES:
|
|||||||
* [privval] \#2459 Split `SocketPVMsg`s implementations into Request and Response, where the Response may contain a error message (returned by the remote signer)
|
* [privval] \#2459 Split `SocketPVMsg`s implementations into Request and Response, where the Response may contain a error message (returned by the remote signer)
|
||||||
* [state] \#2644 Add Version field to State, breaking the format of State as
|
* [state] \#2644 Add Version field to State, breaking the format of State as
|
||||||
encoded on disk.
|
encoded on disk.
|
||||||
|
* [rpc] \#2654 Remove all `node_info.other.*_version` fields in `/status` and
|
||||||
|
`/net_info`
|
||||||
|
|
||||||
* Apps
|
* Apps
|
||||||
* [abci] \#2298 ResponseQuery.Proof is now a structured merkle.Proof, not just
|
* [abci] \#2298 ResponseQuery.Proof is now a structured merkle.Proof, not just
|
||||||
@ -43,6 +45,9 @@ BREAKING CHANGES:
|
|||||||
* [state] \#2644 Require block.Version to match state.Version
|
* [state] \#2644 Require block.Version to match state.Version
|
||||||
|
|
||||||
* P2P Protocol
|
* P2P Protocol
|
||||||
|
* [p2p] \#2654 Add `ProtocolVersion` struct with protocol versions to top of
|
||||||
|
DefaultNodeInfo and require `ProtocolVersion.Block` to match during peer handshake
|
||||||
|
|
||||||
|
|
||||||
FEATURES:
|
FEATURES:
|
||||||
- [crypto/merkle] \#2298 General Merkle Proof scheme for chaining various types of Merkle trees together
|
- [crypto/merkle] \#2298 General Merkle Proof scheme for chaining various types of Merkle trees together
|
||||||
|
@ -14,14 +14,15 @@ import (
|
|||||||
|
|
||||||
func testNodeInfo(id p2p.ID) p2p.DefaultNodeInfo {
|
func testNodeInfo(id p2p.ID) p2p.DefaultNodeInfo {
|
||||||
return p2p.DefaultNodeInfo{
|
return p2p.DefaultNodeInfo{
|
||||||
ID_: id,
|
ProtocolVersion: p2p.InitProtocolVersion,
|
||||||
Moniker: "SOMENAME",
|
ID_: id,
|
||||||
Network: "SOMENAME",
|
Moniker: "SOMENAME",
|
||||||
ListenAddr: "SOMEADDR",
|
Network: "SOMENAME",
|
||||||
Version: "SOMEVER",
|
ListenAddr: "SOMEADDR",
|
||||||
|
Version: "SOMEVER",
|
||||||
Other: p2p.DefaultNodeInfoOther{
|
Other: p2p.DefaultNodeInfoOther{
|
||||||
AminoVersion: "SOMESTRING",
|
TxIndex: "on",
|
||||||
P2PVersion: "OTHERSTRING",
|
RPCAddress: "0.0.0.0:26657",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
package consensus
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
// kind of arbitrary
|
|
||||||
var Spec = "1" // async
|
|
||||||
var Major = "0" //
|
|
||||||
var Minor = "2" // replay refactor
|
|
||||||
var Revision = "2" // validation -> commit
|
|
||||||
|
|
||||||
var Version = fmt.Sprintf("v%s/%s.%s.%s", Spec, Major, Minor, Revision)
|
|
@ -75,22 +75,25 @@ The Tendermint Version Handshake allows the peers to exchange their NodeInfo:
|
|||||||
|
|
||||||
```golang
|
```golang
|
||||||
type NodeInfo struct {
|
type NodeInfo struct {
|
||||||
|
Version p2p.Version
|
||||||
ID p2p.ID
|
ID p2p.ID
|
||||||
ListenAddr string
|
ListenAddr string
|
||||||
|
|
||||||
Network string
|
Network string
|
||||||
Version string
|
SoftwareVersion string
|
||||||
Channels []int8
|
Channels []int8
|
||||||
|
|
||||||
Moniker string
|
Moniker string
|
||||||
Other NodeInfoOther
|
Other NodeInfoOther
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Version struct {
|
||||||
|
P2P uint64
|
||||||
|
Block uint64
|
||||||
|
App uint64
|
||||||
|
}
|
||||||
|
|
||||||
type NodeInfoOther struct {
|
type NodeInfoOther struct {
|
||||||
AminoVersion string
|
|
||||||
P2PVersion string
|
|
||||||
ConsensusVersion string
|
|
||||||
RPCVersion string
|
|
||||||
TxIndex string
|
TxIndex string
|
||||||
RPCAddress string
|
RPCAddress string
|
||||||
}
|
}
|
||||||
@ -99,8 +102,7 @@ type NodeInfoOther struct {
|
|||||||
The connection is disconnected if:
|
The connection is disconnected if:
|
||||||
|
|
||||||
- `peer.NodeInfo.ID` is not equal `peerConn.ID`
|
- `peer.NodeInfo.ID` is not equal `peerConn.ID`
|
||||||
- `peer.NodeInfo.Version` is not formatted as `X.X.X` where X are integers known as Major, Minor, and Revision
|
- `peer.NodeInfo.Version.Block` does not match ours
|
||||||
- `peer.NodeInfo.Version` Major is not the same as ours
|
|
||||||
- `peer.NodeInfo.Network` is not the same as ours
|
- `peer.NodeInfo.Network` is not the same as ours
|
||||||
- `peer.Channels` does not intersect with our known Channels.
|
- `peer.Channels` does not intersect with our known Channels.
|
||||||
- `peer.NodeInfo.ListenAddr` is malformed or is a DNS host that cannot be
|
- `peer.NodeInfo.ListenAddr` is malformed or is a DNS host that cannot be
|
||||||
|
16
node/node.go
16
node/node.go
@ -32,7 +32,6 @@ import (
|
|||||||
rpccore "github.com/tendermint/tendermint/rpc/core"
|
rpccore "github.com/tendermint/tendermint/rpc/core"
|
||||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
grpccore "github.com/tendermint/tendermint/rpc/grpc"
|
grpccore "github.com/tendermint/tendermint/rpc/grpc"
|
||||||
"github.com/tendermint/tendermint/rpc/lib"
|
|
||||||
"github.com/tendermint/tendermint/rpc/lib/server"
|
"github.com/tendermint/tendermint/rpc/lib/server"
|
||||||
sm "github.com/tendermint/tendermint/state"
|
sm "github.com/tendermint/tendermint/state"
|
||||||
"github.com/tendermint/tendermint/state/txindex"
|
"github.com/tendermint/tendermint/state/txindex"
|
||||||
@ -771,9 +770,10 @@ func makeNodeInfo(
|
|||||||
txIndexerStatus = "off"
|
txIndexerStatus = "off"
|
||||||
}
|
}
|
||||||
nodeInfo := p2p.DefaultNodeInfo{
|
nodeInfo := p2p.DefaultNodeInfo{
|
||||||
ID_: nodeID,
|
ProtocolVersion: p2p.InitProtocolVersion,
|
||||||
Network: chainID,
|
ID_: nodeID,
|
||||||
Version: version.Version,
|
Network: chainID,
|
||||||
|
Version: version.TMCoreSemVer,
|
||||||
Channels: []byte{
|
Channels: []byte{
|
||||||
bc.BlockchainChannel,
|
bc.BlockchainChannel,
|
||||||
cs.StateChannel, cs.DataChannel, cs.VoteChannel, cs.VoteSetBitsChannel,
|
cs.StateChannel, cs.DataChannel, cs.VoteChannel, cs.VoteSetBitsChannel,
|
||||||
@ -782,12 +782,8 @@ func makeNodeInfo(
|
|||||||
},
|
},
|
||||||
Moniker: config.Moniker,
|
Moniker: config.Moniker,
|
||||||
Other: p2p.DefaultNodeInfoOther{
|
Other: p2p.DefaultNodeInfoOther{
|
||||||
AminoVersion: amino.Version,
|
TxIndex: txIndexerStatus,
|
||||||
P2PVersion: p2p.Version,
|
RPCAddress: config.RPC.ListenAddress,
|
||||||
ConsensusVersion: cs.Version,
|
|
||||||
RPCVersion: fmt.Sprintf("%v/%v", rpc.Version, rpccore.Version),
|
|
||||||
TxIndex: txIndexerStatus,
|
|
||||||
RPCAddress: config.RPC.ListenAddress,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
135
p2p/node_info.go
135
p2p/node_info.go
@ -3,9 +3,9 @@ package p2p
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
|
||||||
|
|
||||||
cmn "github.com/tendermint/tendermint/libs/common"
|
cmn "github.com/tendermint/tendermint/libs/common"
|
||||||
|
"github.com/tendermint/tendermint/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -18,8 +18,10 @@ func MaxNodeInfoSize() int {
|
|||||||
return maxNodeInfoSize
|
return maxNodeInfoSize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------
|
||||||
|
|
||||||
// NodeInfo exposes basic info of a node
|
// NodeInfo exposes basic info of a node
|
||||||
// and determines if we're compatible
|
// and determines if we're compatible.
|
||||||
type NodeInfo interface {
|
type NodeInfo interface {
|
||||||
nodeInfoAddress
|
nodeInfoAddress
|
||||||
nodeInfoTransport
|
nodeInfoTransport
|
||||||
@ -31,16 +33,38 @@ type nodeInfoAddress interface {
|
|||||||
NetAddress() *NetAddress
|
NetAddress() *NetAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
// nodeInfoTransport is validates a nodeInfo and checks
|
// nodeInfoTransport validates a nodeInfo and checks
|
||||||
// our compatibility with it. It's for use in the handshake.
|
// our compatibility with it. It's for use in the handshake.
|
||||||
type nodeInfoTransport interface {
|
type nodeInfoTransport interface {
|
||||||
ValidateBasic() error
|
ValidateBasic() error
|
||||||
CompatibleWith(other NodeInfo) error
|
CompatibleWith(other NodeInfo) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------
|
||||||
|
|
||||||
|
// ProtocolVersion contains the protocol versions for the software.
|
||||||
|
type ProtocolVersion struct {
|
||||||
|
P2P version.Protocol `json:"p2p"`
|
||||||
|
Block version.Protocol `json:"block"`
|
||||||
|
App version.Protocol `json:"app"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var InitProtocolVersion = ProtocolVersion{
|
||||||
|
P2P: version.P2PProtocol,
|
||||||
|
Block: version.BlockProtocol,
|
||||||
|
App: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------
|
||||||
|
|
||||||
|
// Assert DefaultNodeInfo satisfies NodeInfo
|
||||||
|
var _ NodeInfo = DefaultNodeInfo{}
|
||||||
|
|
||||||
// DefaultNodeInfo is the basic node information exchanged
|
// DefaultNodeInfo is the basic node information exchanged
|
||||||
// between two peers during the Tendermint P2P handshake.
|
// between two peers during the Tendermint P2P handshake.
|
||||||
type DefaultNodeInfo struct {
|
type DefaultNodeInfo struct {
|
||||||
|
ProtocolVersion ProtocolVersion `json:"protocol_version"`
|
||||||
|
|
||||||
// Authenticate
|
// Authenticate
|
||||||
// TODO: replace with NetAddress
|
// TODO: replace with NetAddress
|
||||||
ID_ ID `json:"id"` // authenticated identifier
|
ID_ ID `json:"id"` // authenticated identifier
|
||||||
@ -59,12 +83,8 @@ type DefaultNodeInfo struct {
|
|||||||
|
|
||||||
// DefaultNodeInfoOther is the misc. applcation specific data
|
// DefaultNodeInfoOther is the misc. applcation specific data
|
||||||
type DefaultNodeInfoOther struct {
|
type DefaultNodeInfoOther struct {
|
||||||
AminoVersion string `json:"amino_version"`
|
TxIndex string `json:"tx_index"`
|
||||||
P2PVersion string `json:"p2p_version"`
|
RPCAddress string `json:"rpc_address"`
|
||||||
ConsensusVersion string `json:"consensus_version"`
|
|
||||||
RPCVersion string `json:"rpc_version"`
|
|
||||||
TxIndex string `json:"tx_index"`
|
|
||||||
RPCAddress string `json:"rpc_address"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ID returns the node's peer ID.
|
// ID returns the node's peer ID.
|
||||||
@ -86,35 +106,28 @@ func (info DefaultNodeInfo) ID() ID {
|
|||||||
// url-encoding), and we just need to be careful with how we handle that in our
|
// url-encoding), and we just need to be careful with how we handle that in our
|
||||||
// clients. (e.g. off by default).
|
// clients. (e.g. off by default).
|
||||||
func (info DefaultNodeInfo) ValidateBasic() error {
|
func (info DefaultNodeInfo) ValidateBasic() error {
|
||||||
|
|
||||||
|
// ID is already validated.
|
||||||
|
|
||||||
|
// Validate ListenAddr.
|
||||||
|
_, err := NewNetAddressString(IDAddressString(info.ID(), info.ListenAddr))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Network is validated in CompatibleWith.
|
||||||
|
|
||||||
|
// Validate Version
|
||||||
|
if len(info.Version) > 0 &&
|
||||||
|
(!cmn.IsASCIIText(info.Version) || cmn.ASCIITrim(info.Version) == "") {
|
||||||
|
|
||||||
|
return fmt.Errorf("info.Version must be valid ASCII text without tabs, but got %v", info.Version)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate Channels - ensure max and check for duplicates.
|
||||||
if len(info.Channels) > maxNumChannels {
|
if len(info.Channels) > maxNumChannels {
|
||||||
return fmt.Errorf("info.Channels is too long (%v). Max is %v", len(info.Channels), maxNumChannels)
|
return fmt.Errorf("info.Channels is too long (%v). Max is %v", len(info.Channels), maxNumChannels)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanitize ASCII text fields.
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sanitize versions
|
|
||||||
// XXX: Should we be more strict about version and address formats?
|
|
||||||
other := info.Other
|
|
||||||
versions := []string{
|
|
||||||
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 {
|
||||||
_, ok := channels[ch]
|
_, ok := channels[ch]
|
||||||
@ -124,13 +137,30 @@ func (info DefaultNodeInfo) ValidateBasic() error {
|
|||||||
channels[ch] = struct{}{}
|
channels[ch] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure ListenAddr is good
|
// Validate Moniker.
|
||||||
_, err := NewNetAddressString(IDAddressString(info.ID(), info.ListenAddr))
|
if !cmn.IsASCIIText(info.Moniker) || cmn.ASCIITrim(info.Moniker) == "" {
|
||||||
return err
|
return fmt.Errorf("info.Moniker must be valid non-empty ASCII text without tabs, but got %v", info.Moniker)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate Other.
|
||||||
|
other := info.Other
|
||||||
|
txIndex := other.TxIndex
|
||||||
|
switch txIndex {
|
||||||
|
case "", "on", "off":
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("info.Other.TxIndex should be either 'on' or 'off', got '%v'", txIndex)
|
||||||
|
}
|
||||||
|
// XXX: Should we be more strict about address formats?
|
||||||
|
rpcAddr := other.RPCAddress
|
||||||
|
if len(rpcAddr) > 0 && (!cmn.IsASCIIText(rpcAddr) || cmn.ASCIITrim(rpcAddr) == "") {
|
||||||
|
return fmt.Errorf("info.Other.RPCAddress=%v must be valid ASCII text without tabs", rpcAddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompatibleWith checks if two DefaultNodeInfo are compatible with eachother.
|
// CompatibleWith checks if two DefaultNodeInfo are compatible with eachother.
|
||||||
// CONTRACT: two nodes are compatible if the major version matches and network match
|
// CONTRACT: two nodes are compatible if the Block version and network match
|
||||||
// and they have at least one channel in common.
|
// and they have at least one channel in common.
|
||||||
func (info DefaultNodeInfo) CompatibleWith(other_ NodeInfo) error {
|
func (info DefaultNodeInfo) CompatibleWith(other_ NodeInfo) error {
|
||||||
other, ok := other_.(DefaultNodeInfo)
|
other, ok := other_.(DefaultNodeInfo)
|
||||||
@ -138,22 +168,9 @@ func (info DefaultNodeInfo) CompatibleWith(other_ NodeInfo) error {
|
|||||||
return fmt.Errorf("wrong NodeInfo type. Expected DefaultNodeInfo, got %v", reflect.TypeOf(other_))
|
return fmt.Errorf("wrong NodeInfo type. Expected DefaultNodeInfo, got %v", reflect.TypeOf(other_))
|
||||||
}
|
}
|
||||||
|
|
||||||
iMajor, _, _, iErr := splitVersion(info.Version)
|
if info.ProtocolVersion.Block != other.ProtocolVersion.Block {
|
||||||
oMajor, _, _, oErr := splitVersion(other.Version)
|
return fmt.Errorf("Peer is on a different Block version. Got %v, expected %v",
|
||||||
|
other.ProtocolVersion.Block, info.ProtocolVersion.Block)
|
||||||
// if our own version number is not formatted right, we messed up
|
|
||||||
if iErr != nil {
|
|
||||||
return iErr
|
|
||||||
}
|
|
||||||
|
|
||||||
// version number must be formatted correctly ("x.x.x")
|
|
||||||
if oErr != nil {
|
|
||||||
return oErr
|
|
||||||
}
|
|
||||||
|
|
||||||
// major version must match
|
|
||||||
if iMajor != oMajor {
|
|
||||||
return fmt.Errorf("Peer is on a different major version. Got %v, expected %v", oMajor, iMajor)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// nodes must be on the same network
|
// nodes must be on the same network
|
||||||
@ -201,11 +218,3 @@ func (info DefaultNodeInfo) NetAddress() *NetAddress {
|
|||||||
}
|
}
|
||||||
return netAddr
|
return netAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
func splitVersion(version string) (string, string, string, error) {
|
|
||||||
spl := strings.Split(version, ".")
|
|
||||||
if len(spl) != 3 {
|
|
||||||
return "", "", "", fmt.Errorf("Invalid version format %v", version)
|
|
||||||
}
|
|
||||||
return spl[0], spl[1], spl[2], nil
|
|
||||||
}
|
|
||||||
|
123
p2p/node_info_test.go
Normal file
123
p2p/node_info_test.go
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
package p2p
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNodeInfoValidate(t *testing.T) {
|
||||||
|
|
||||||
|
// empty fails
|
||||||
|
ni := DefaultNodeInfo{}
|
||||||
|
assert.Error(t, ni.ValidateBasic())
|
||||||
|
|
||||||
|
channels := make([]byte, maxNumChannels)
|
||||||
|
for i := 0; i < maxNumChannels; i++ {
|
||||||
|
channels[i] = byte(i)
|
||||||
|
}
|
||||||
|
dupChannels := make([]byte, 5)
|
||||||
|
copy(dupChannels[:], channels[:5])
|
||||||
|
dupChannels = append(dupChannels, testCh)
|
||||||
|
|
||||||
|
nonAscii := "¢§µ"
|
||||||
|
emptyTab := fmt.Sprintf("\t")
|
||||||
|
emptySpace := fmt.Sprintf(" ")
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
testName string
|
||||||
|
malleateNodeInfo func(*DefaultNodeInfo)
|
||||||
|
expectErr bool
|
||||||
|
}{
|
||||||
|
{"Too Many Channels", func(ni *DefaultNodeInfo) { ni.Channels = append(channels, byte(maxNumChannels)) }, true},
|
||||||
|
{"Duplicate Channel", func(ni *DefaultNodeInfo) { ni.Channels = dupChannels }, true},
|
||||||
|
{"Good Channels", func(ni *DefaultNodeInfo) { ni.Channels = ni.Channels[:5] }, false},
|
||||||
|
|
||||||
|
{"Invalid NetAddress", func(ni *DefaultNodeInfo) { ni.ListenAddr = "not-an-address" }, true},
|
||||||
|
{"Good NetAddress", func(ni *DefaultNodeInfo) { ni.ListenAddr = "0.0.0.0:26656" }, false},
|
||||||
|
|
||||||
|
{"Non-ASCII Version", func(ni *DefaultNodeInfo) { ni.Version = nonAscii }, true},
|
||||||
|
{"Empty tab Version", func(ni *DefaultNodeInfo) { ni.Version = emptyTab }, true},
|
||||||
|
{"Empty space Version", func(ni *DefaultNodeInfo) { ni.Version = emptySpace }, true},
|
||||||
|
{"Empty Version", func(ni *DefaultNodeInfo) { ni.Version = "" }, false},
|
||||||
|
|
||||||
|
{"Non-ASCII Moniker", func(ni *DefaultNodeInfo) { ni.Moniker = nonAscii }, true},
|
||||||
|
{"Empty tab Moniker", func(ni *DefaultNodeInfo) { ni.Moniker = emptyTab }, true},
|
||||||
|
{"Empty space Moniker", func(ni *DefaultNodeInfo) { ni.Moniker = emptySpace }, true},
|
||||||
|
{"Empty Moniker", func(ni *DefaultNodeInfo) { ni.Moniker = "" }, true},
|
||||||
|
{"Good Moniker", func(ni *DefaultNodeInfo) { ni.Moniker = "hey its me" }, false},
|
||||||
|
|
||||||
|
{"Non-ASCII TxIndex", func(ni *DefaultNodeInfo) { ni.Other.TxIndex = nonAscii }, true},
|
||||||
|
{"Empty tab TxIndex", func(ni *DefaultNodeInfo) { ni.Other.TxIndex = emptyTab }, true},
|
||||||
|
{"Empty space TxIndex", func(ni *DefaultNodeInfo) { ni.Other.TxIndex = emptySpace }, true},
|
||||||
|
{"Empty TxIndex", func(ni *DefaultNodeInfo) { ni.Other.TxIndex = "" }, false},
|
||||||
|
{"Off TxIndex", func(ni *DefaultNodeInfo) { ni.Other.TxIndex = "off" }, false},
|
||||||
|
|
||||||
|
{"Non-ASCII RPCAddress", func(ni *DefaultNodeInfo) { ni.Other.RPCAddress = nonAscii }, true},
|
||||||
|
{"Empty tab RPCAddress", func(ni *DefaultNodeInfo) { ni.Other.RPCAddress = emptyTab }, true},
|
||||||
|
{"Empty space RPCAddress", func(ni *DefaultNodeInfo) { ni.Other.RPCAddress = emptySpace }, true},
|
||||||
|
{"Empty RPCAddress", func(ni *DefaultNodeInfo) { ni.Other.RPCAddress = "" }, false},
|
||||||
|
{"Good RPCAddress", func(ni *DefaultNodeInfo) { ni.Other.RPCAddress = "0.0.0.0:26657" }, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeKey := NodeKey{PrivKey: ed25519.GenPrivKey()}
|
||||||
|
name := "testing"
|
||||||
|
|
||||||
|
// test case passes
|
||||||
|
ni = testNodeInfo(nodeKey.ID(), name).(DefaultNodeInfo)
|
||||||
|
ni.Channels = channels
|
||||||
|
assert.NoError(t, ni.ValidateBasic())
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
ni := testNodeInfo(nodeKey.ID(), name).(DefaultNodeInfo)
|
||||||
|
ni.Channels = channels
|
||||||
|
tc.malleateNodeInfo(&ni)
|
||||||
|
err := ni.ValidateBasic()
|
||||||
|
if tc.expectErr {
|
||||||
|
assert.Error(t, err, tc.testName)
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err, tc.testName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNodeInfoCompatible(t *testing.T) {
|
||||||
|
|
||||||
|
nodeKey1 := NodeKey{PrivKey: ed25519.GenPrivKey()}
|
||||||
|
nodeKey2 := NodeKey{PrivKey: ed25519.GenPrivKey()}
|
||||||
|
name := "testing"
|
||||||
|
|
||||||
|
var newTestChannel byte = 0x2
|
||||||
|
|
||||||
|
// test NodeInfo is compatible
|
||||||
|
ni1 := testNodeInfo(nodeKey1.ID(), name).(DefaultNodeInfo)
|
||||||
|
ni2 := testNodeInfo(nodeKey2.ID(), name).(DefaultNodeInfo)
|
||||||
|
assert.NoError(t, ni1.CompatibleWith(ni2))
|
||||||
|
|
||||||
|
// add another channel; still compatible
|
||||||
|
ni2.Channels = []byte{newTestChannel, testCh}
|
||||||
|
assert.NoError(t, ni1.CompatibleWith(ni2))
|
||||||
|
|
||||||
|
// wrong NodeInfo type is not compatible
|
||||||
|
_, netAddr := CreateRoutableAddr()
|
||||||
|
ni3 := mockNodeInfo{netAddr}
|
||||||
|
assert.Error(t, ni1.CompatibleWith(ni3))
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
testName string
|
||||||
|
malleateNodeInfo func(*DefaultNodeInfo)
|
||||||
|
}{
|
||||||
|
{"Wrong block version", func(ni *DefaultNodeInfo) { ni.ProtocolVersion.Block += 1 }},
|
||||||
|
{"Wrong network", func(ni *DefaultNodeInfo) { ni.Network += "-wrong" }},
|
||||||
|
{"No common channels", func(ni *DefaultNodeInfo) { ni.Channels = []byte{newTestChannel} }},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
ni := testNodeInfo(nodeKey2.ID(), name).(DefaultNodeInfo)
|
||||||
|
tc.malleateNodeInfo(&ni)
|
||||||
|
assert.Error(t, ni1.CompatibleWith(ni))
|
||||||
|
}
|
||||||
|
}
|
@ -207,11 +207,12 @@ func (rp *remotePeer) accept(l net.Listener) {
|
|||||||
|
|
||||||
func (rp *remotePeer) nodeInfo(l net.Listener) NodeInfo {
|
func (rp *remotePeer) nodeInfo(l net.Listener) NodeInfo {
|
||||||
return DefaultNodeInfo{
|
return DefaultNodeInfo{
|
||||||
ID_: rp.Addr().ID,
|
ProtocolVersion: InitProtocolVersion,
|
||||||
Moniker: "remote_peer",
|
ID_: rp.Addr().ID,
|
||||||
Network: "testing",
|
ListenAddr: l.Addr().String(),
|
||||||
Version: "123.123.123",
|
Network: "testing",
|
||||||
ListenAddr: l.Addr().String(),
|
Version: "1.2.3-rc0-deadbeef",
|
||||||
Channels: rp.channels,
|
Channels: rp.channels,
|
||||||
|
Moniker: "remote_peer",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -247,11 +247,16 @@ func testNodeInfo(id ID, name string) NodeInfo {
|
|||||||
|
|
||||||
func testNodeInfoWithNetwork(id ID, name, network string) NodeInfo {
|
func testNodeInfoWithNetwork(id ID, name, network string) NodeInfo {
|
||||||
return DefaultNodeInfo{
|
return DefaultNodeInfo{
|
||||||
ID_: id,
|
ProtocolVersion: InitProtocolVersion,
|
||||||
ListenAddr: fmt.Sprintf("127.0.0.1:%d", cmn.RandIntn(64512)+1023),
|
ID_: id,
|
||||||
Moniker: name,
|
ListenAddr: fmt.Sprintf("127.0.0.1:%d", cmn.RandIntn(64512)+1023),
|
||||||
Network: network,
|
Network: network,
|
||||||
Version: "123.123.123",
|
Version: "1.2.3-rc0-deadbeef",
|
||||||
Channels: []byte{testCh},
|
Channels: []byte{testCh},
|
||||||
|
Moniker: name,
|
||||||
|
Other: DefaultNodeInfoOther{
|
||||||
|
TxIndex: "on",
|
||||||
|
RPCAddress: fmt.Sprintf("127.0.0.1:%d", cmn.RandIntn(64512)+1023),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
package p2p
|
|
||||||
|
|
||||||
const Version = "0.5.0"
|
|
@ -31,6 +31,11 @@ import (
|
|||||||
// "id": "",
|
// "id": "",
|
||||||
// "result": {
|
// "result": {
|
||||||
// "node_info": {
|
// "node_info": {
|
||||||
|
// "protocol_version": {
|
||||||
|
// "p2p": "4",
|
||||||
|
// "block": "7",
|
||||||
|
// "app": "0"
|
||||||
|
// },
|
||||||
// "id": "53729852020041b956e86685e24394e0bee4373f",
|
// "id": "53729852020041b956e86685e24394e0bee4373f",
|
||||||
// "listen_addr": "10.0.2.15:26656",
|
// "listen_addr": "10.0.2.15:26656",
|
||||||
// "network": "test-chain-Y1OHx6",
|
// "network": "test-chain-Y1OHx6",
|
||||||
@ -38,10 +43,6 @@ import (
|
|||||||
// "channels": "4020212223303800",
|
// "channels": "4020212223303800",
|
||||||
// "moniker": "ubuntu-xenial",
|
// "moniker": "ubuntu-xenial",
|
||||||
// "other": {
|
// "other": {
|
||||||
// "amino_version": "0.12.0",
|
|
||||||
// "p2p_version": "0.5.0",
|
|
||||||
// "consensus_version": "v1/0.2.2",
|
|
||||||
// "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"
|
||||||
// }
|
// }
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
package core
|
|
||||||
|
|
||||||
// a single integer is sufficient here
|
|
||||||
|
|
||||||
const Version = "3" // rpc routes for profiling, setting config
|
|
@ -1,7 +0,0 @@
|
|||||||
package rpc
|
|
||||||
|
|
||||||
const Maj = "0"
|
|
||||||
const Min = "7"
|
|
||||||
const Fix = "0"
|
|
||||||
|
|
||||||
const Version = Maj + "." + Min + "." + Fix
|
|
Loading…
x
Reference in New Issue
Block a user