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