github.com/pokt-network/tendermint@v0.32.11-0.20230426215212-59310158d3e9/p2p/node_info.go (about) 1 package p2p 2 3 import ( 4 "fmt" 5 "reflect" 6 7 "github.com/tendermint/tendermint/libs/bytes" 8 tmstrings "github.com/tendermint/tendermint/libs/strings" 9 "github.com/tendermint/tendermint/version" 10 ) 11 12 const ( 13 maxNodeInfoSize = 10240 // 10KB 14 maxNumChannels = 16 // plenty of room for upgrades, for now 15 ) 16 17 // Max size of the NodeInfo struct 18 func MaxNodeInfoSize() int { 19 return maxNodeInfoSize 20 } 21 22 //------------------------------------------------------------- 23 24 // NodeInfo exposes basic info of a node 25 // and determines if we're compatible. 26 type NodeInfo interface { 27 ID() ID 28 nodeInfoAddress 29 nodeInfoTransport 30 } 31 32 type nodeInfoAddress interface { 33 NetAddress() (*NetAddress, error) 34 } 35 36 // nodeInfoTransport validates a nodeInfo and checks 37 // our compatibility with it. It's for use in the handshake. 38 type nodeInfoTransport interface { 39 Validate() error 40 CompatibleWith(other NodeInfo) error 41 } 42 43 //------------------------------------------------------------- 44 45 // ProtocolVersion contains the protocol versions for the software. 46 type ProtocolVersion struct { 47 P2P version.Protocol `json:"p2p"` 48 Block version.Protocol `json:"block"` 49 App version.Protocol `json:"app"` 50 } 51 52 // defaultProtocolVersion populates the Block and P2P versions using 53 // the global values, but not the App. 54 var defaultProtocolVersion = NewProtocolVersion( 55 version.P2PProtocol, 56 version.BlockProtocol, 57 0, 58 ) 59 60 // NewProtocolVersion returns a fully populated ProtocolVersion. 61 func NewProtocolVersion(p2p, block, app version.Protocol) ProtocolVersion { 62 return ProtocolVersion{ 63 P2P: p2p, 64 Block: block, 65 App: app, 66 } 67 } 68 69 //------------------------------------------------------------- 70 71 // Assert DefaultNodeInfo satisfies NodeInfo 72 var _ NodeInfo = DefaultNodeInfo{} 73 74 // DefaultNodeInfo is the basic node information exchanged 75 // between two peers during the Tendermint P2P handshake. 76 type DefaultNodeInfo struct { 77 ProtocolVersion ProtocolVersion `json:"protocol_version"` 78 79 // Authenticate 80 // TODO: replace with NetAddress 81 DefaultNodeID ID `json:"id"` // authenticated identifier 82 ListenAddr string `json:"listen_addr"` // accepting incoming 83 84 // Check compatibility. 85 // Channels are HexBytes so easier to read as JSON 86 Network string `json:"network"` // network/chain ID 87 Version string `json:"version"` // major.minor.revision 88 Channels bytes.HexBytes `json:"channels"` // channels this node knows about 89 90 // ASCIIText fields 91 Moniker string `json:"moniker"` // arbitrary moniker 92 Other DefaultNodeInfoOther `json:"other"` // other application specific data 93 } 94 95 // DefaultNodeInfoOther is the misc. applcation specific data 96 type DefaultNodeInfoOther struct { 97 TxIndex string `json:"tx_index"` 98 RPCAddress string `json:"rpc_address"` 99 } 100 101 // ID returns the node's peer ID. 102 func (info DefaultNodeInfo) ID() ID { 103 return info.DefaultNodeID 104 } 105 106 // Validate checks the self-reported DefaultNodeInfo is safe. 107 // It returns an error if there 108 // are too many Channels, if there are any duplicate Channels, 109 // if the ListenAddr is malformed, or if the ListenAddr is a host name 110 // that can not be resolved to some IP. 111 // TODO: constraints for Moniker/Other? Or is that for the UI ? 112 // JAE: It needs to be done on the client, but to prevent ambiguous 113 // unicode characters, maybe it's worth sanitizing it here. 114 // In the future we might want to validate these, once we have a 115 // name-resolution system up. 116 // International clients could then use punycode (or we could use 117 // url-encoding), and we just need to be careful with how we handle that in our 118 // clients. (e.g. off by default). 119 func (info DefaultNodeInfo) Validate() error { 120 121 // ID is already validated. 122 123 // Validate ListenAddr. 124 _, err := NewNetAddressString(IDAddressString(info.ID(), info.ListenAddr)) 125 if err != nil { 126 return err 127 } 128 129 // Network is validated in CompatibleWith. 130 131 // Validate Version 132 if len(info.Version) > 0 && 133 (!tmstrings.IsASCIIText(info.Version) || tmstrings.ASCIITrim(info.Version) == "") { 134 135 return fmt.Errorf("info.Version must be valid ASCII text without tabs, but got %v", info.Version) 136 } 137 138 // Validate Channels - ensure max and check for duplicates. 139 if len(info.Channels) > maxNumChannels { 140 return fmt.Errorf("info.Channels is too long (%v). Max is %v", len(info.Channels), maxNumChannels) 141 } 142 channels := make(map[byte]struct{}) 143 for _, ch := range info.Channels { 144 _, ok := channels[ch] 145 if ok { 146 return fmt.Errorf("info.Channels contains duplicate channel id %v", ch) 147 } 148 channels[ch] = struct{}{} 149 } 150 151 // Validate Moniker. 152 if !tmstrings.IsASCIIText(info.Moniker) || tmstrings.ASCIITrim(info.Moniker) == "" { 153 return fmt.Errorf("info.Moniker must be valid non-empty ASCII text without tabs, but got %v", info.Moniker) 154 } 155 156 // Validate Other. 157 other := info.Other 158 txIndex := other.TxIndex 159 switch txIndex { 160 case "", "on", "off": 161 default: 162 return fmt.Errorf("info.Other.TxIndex should be either 'on', 'off', or empty string, got '%v'", txIndex) 163 } 164 // XXX: Should we be more strict about address formats? 165 rpcAddr := other.RPCAddress 166 if len(rpcAddr) > 0 && (!tmstrings.IsASCIIText(rpcAddr) || tmstrings.ASCIITrim(rpcAddr) == "") { 167 return fmt.Errorf("info.Other.RPCAddress=%v must be valid ASCII text without tabs", rpcAddr) 168 } 169 170 return nil 171 } 172 173 // CompatibleWith checks if two DefaultNodeInfo are compatible with eachother. 174 // CONTRACT: two nodes are compatible if the Block version and network match 175 // and they have at least one channel in common. 176 func (info DefaultNodeInfo) CompatibleWith(otherInfo NodeInfo) error { 177 other, ok := otherInfo.(DefaultNodeInfo) 178 if !ok { 179 return fmt.Errorf("wrong NodeInfo type. Expected DefaultNodeInfo, got %v", reflect.TypeOf(otherInfo)) 180 } 181 182 if info.ProtocolVersion.Block != other.ProtocolVersion.Block { 183 return fmt.Errorf("peer is on a different Block version. Got %v, expected %v", 184 other.ProtocolVersion.Block, info.ProtocolVersion.Block) 185 } 186 187 // nodes must be on the same network 188 if info.Network != other.Network { 189 return fmt.Errorf("peer is on a different network. Got %v, expected %v", other.Network, info.Network) 190 } 191 192 // if we have no channels, we're just testing 193 if len(info.Channels) == 0 { 194 return nil 195 } 196 197 // for each of our channels, check if they have it 198 found := false 199 OUTER_LOOP: 200 for _, ch1 := range info.Channels { 201 for _, ch2 := range other.Channels { 202 if ch1 == ch2 { 203 found = true 204 break OUTER_LOOP // only need one 205 } 206 } 207 } 208 if !found { 209 return fmt.Errorf("peer has no common channels. Our channels: %v ; Peer channels: %v", info.Channels, other.Channels) 210 } 211 return nil 212 } 213 214 // NetAddress returns a NetAddress derived from the DefaultNodeInfo - 215 // it includes the authenticated peer ID and the self-reported 216 // ListenAddr. Note that the ListenAddr is not authenticated and 217 // may not match that address actually dialed if its an outbound peer. 218 func (info DefaultNodeInfo) NetAddress() (*NetAddress, error) { 219 idAddr := IDAddressString(info.ID(), info.ListenAddr) 220 return NewNetAddressString(idAddr) 221 } 222 223 //----------------------------------------------------------- 224 // These methods are for Protobuf Compatibility 225 226 // Size returns the size of the amino encoding, in bytes. 227 func (info *DefaultNodeInfo) Size() int { 228 bs, _ := info.Marshal() 229 return len(bs) 230 } 231 232 // Marshal returns the amino encoding. 233 func (info *DefaultNodeInfo) Marshal() ([]byte, error) { 234 return cdc.MarshalBinaryBare(info) 235 } 236 237 // MarshalTo calls Marshal and copies to the given buffer. 238 func (info *DefaultNodeInfo) MarshalTo(data []byte) (int, error) { 239 bs, err := info.Marshal() 240 if err != nil { 241 return -1, err 242 } 243 return copy(data, bs), nil 244 } 245 246 // Unmarshal deserializes from amino encoded form. 247 func (info *DefaultNodeInfo) Unmarshal(bs []byte) error { 248 return cdc.UnmarshalBinaryBare(bs, info) 249 }