package types import ( "bytes" "encoding/binary" "fmt" fasthex "github.com/tmthrgd/go-hex" "net/netip" ) func IsPeerVersionInformation(addr netip.AddrPort) bool { if addr.Port() != 0xFFFF { return false } rawIp := addr.Addr().As16() return bytes.Compare(rawIp[12:], []byte{0xFF, 0xFF, 0xFF, 0xFF}) == 0 } // ProtocolFeature List of features to check to not depend on hardcoded protocol versions. // Use PeerVersionInformation.SupportsFeature() to query these. type ProtocolFeature int const ( // FeaturePeerInformationReceive Backwards compatible, can be sent to all clients FeaturePeerInformationReceive = ProtocolFeature(iota) FeaturePeerInformationExchange FeaturePrunedBroadcast FeatureCompactBroadcast FeatureBlockNotify ) type PeerVersionInformation struct { Protocol ProtocolVersion SoftwareVersion SoftwareVersion SoftwareId SoftwareId } func (i *PeerVersionInformation) SupportsFeature(feature ProtocolFeature) bool { switch feature { case FeaturePeerInformationReceive: return i.Protocol == ProtocolVersion_0_0 || i.Protocol >= ProtocolVersion_1_0 case FeaturePeerInformationExchange: return i.Protocol >= ProtocolVersion_1_0 case FeaturePrunedBroadcast: return i.Protocol == ProtocolVersion_0_0 || i.Protocol >= ProtocolVersion_1_0 case FeatureCompactBroadcast: return i.Protocol >= ProtocolVersion_1_1 case FeatureBlockNotify: return i.Protocol >= ProtocolVersion_1_2 default: return false } } func (i *PeerVersionInformation) String() string { // Empty information if i.Protocol == 0 && i.SoftwareVersion == 0 && i.SoftwareId == 0 { return "Unknown" } return fmt.Sprintf("%s %s (protocol %s)", i.SoftwareId.String(), i.SoftwareVersion.String(), i.Protocol.String()) } func (i *PeerVersionInformation) ToAddrPort() netip.AddrPort { var addr [16]byte binary.LittleEndian.PutUint32(addr[:], uint32(i.Protocol)) binary.LittleEndian.PutUint32(addr[4:], uint32(i.SoftwareVersion)) binary.LittleEndian.PutUint32(addr[8:], uint32(i.SoftwareId)) binary.LittleEndian.PutUint32(addr[12:], 0xFFFFFFFF) return netip.AddrPortFrom(netip.AddrFrom16(addr), 0xFFFF) } type ProtocolVersion SemanticVersion func (v ProtocolVersion) Major() uint16 { return SemanticVersion(v).Major() } func (v ProtocolVersion) Minor() uint16 { return SemanticVersion(v).Minor() } func (v ProtocolVersion) String() string { return SemanticVersion(v).String() } const ( ProtocolVersion_0_0 ProtocolVersion = (0 << 16) | 0 ProtocolVersion_1_0 ProtocolVersion = (1 << 16) | 0 ProtocolVersion_1_1 ProtocolVersion = (1 << 16) | 1 ProtocolVersion_1_2 ProtocolVersion = (1 << 16) | 2 ) type SoftwareVersion SemanticVersion func (v SoftwareVersion) Major() uint16 { return SemanticVersion(v).Major() } func (v SoftwareVersion) Minor() uint16 { return SemanticVersion(v).Minor() } func (v SoftwareVersion) String() string { return SemanticVersion(v).String() } const SupportedProtocolVersion = ProtocolVersion_1_2 const CurrentSoftwareVersionMajor = 3 & 0xFFFF const CurrentSoftwareVersionMinor = 6 & 0xFFFF const CurrentSoftwareVersion SoftwareVersion = (CurrentSoftwareVersionMajor << 16) | CurrentSoftwareVersionMinor const CurrentSoftwareId = SoftwareIdGoObserver type SoftwareId uint32 func (c SoftwareId) String() string { switch c { case SoftwareIdP2Pool: return "P2Pool" case SoftwareIdGoObserver: return "GoObserver" default: var buf = [17]byte{'U', 'n', 'k', 'n', 'o', 'w', 'n', '(', 0, 0, 0, 0, 0, 0, 0, 0, ')'} var intBuf [4]byte binary.LittleEndian.PutUint32(intBuf[:], uint32(c)) fasthex.Encode(buf[8:], intBuf[:]) return string(buf[:]) } } const ( SoftwareIdP2Pool SoftwareId = 0x00000000 SoftwareIdGoObserver SoftwareId = 0x624F6F47 //GoOb, little endian )