p2p/enode: clean up DNS name support in Node

Remove methods Endpoint and NeedResolve, since they are kind of redundant.
Instead of adding a new constructor with a hostname parameter, provide method
WithHostname to attach a name to any node.
This commit is contained in:
Felix Lange 2024-12-12 18:08:26 +01:00
parent e67f38aa29
commit 42cb347ed7
3 changed files with 23 additions and 59 deletions

View file

@ -37,11 +37,14 @@ var errMissingPrefix = errors.New("missing 'enr:' prefix for base64-encoded reco
type Node struct { type Node struct {
r enr.Record r enr.Record
id ID id ID
// hostname tracks the DNS name of the node.
hostname string
// endpoint information // endpoint information
ip netip.Addr ip netip.Addr
udp uint16 udp uint16
tcp uint16 tcp uint16
hostname string
} }
// New wraps a node record. The record must be valid according to the given // New wraps a node record. The record must be valid according to the given
@ -185,20 +188,16 @@ func (n *Node) TCP() int {
return int(n.tcp) return int(n.tcp)
} }
// Endpoint returns the hostname of the node if set, otherwise the IP address. // WithHostname adds a DNS hostname to the node.
func (n *Node) Endpoint() string { func (n *Node) WithHostname(hostname string) *Node {
if n.hostname != "" { cpy := *n
return n.hostname cpy.hostname = hostname
} return &cpy
if n.ip.IsValid() {
return n.ip.String()
}
return ""
} }
// NeedResolve checks if the node requires DNS resolution. // Hostname returns the DNS name assigned by WithHostname.
func (n *Node) NeedResolve() bool { func (n *Node) Hostname() string {
return n.hostname != "" //TODO: Add check for n.ip.IsValid(), but we need to implement invalidation for the previous resolved IP return n.hostname
} }
// UDPEndpoint returns the announced UDP endpoint. // UDPEndpoint returns the announced UDP endpoint.
@ -246,9 +245,6 @@ func (n *Node) Record() *enr.Record {
cpy := n.r cpy := n.r
return &cpy return &cpy
} }
func (n *Node) Hostname() string {
return n.hostname
}
// ValidateComplete checks whether n has a valid IP and UDP port. // ValidateComplete checks whether n has a valid IP and UDP port.
// Deprecated: don't use this method. // Deprecated: don't use this method.

View file

@ -100,28 +100,6 @@ func NewV4(pubkey *ecdsa.PublicKey, ip net.IP, tcp, udp int) *Node {
return n return n
} }
func NewV4WithDNS(pubkey *ecdsa.PublicKey, ip net.IP, hostname string, tcp, udp int) *Node {
var r enr.Record
if tcp != 0 {
r.Set(enr.TCP(tcp))
}
if udp != 0 {
r.Set(enr.UDP(udp))
}
if len(ip) > 0 {
r.Set(enr.IP(ip))
}
signV4Compat(&r, pubkey)
n, err := New(v4CompatID{}, &r)
if err != nil {
panic(err)
}
n.tcp = uint16(tcp)
n.udp = uint16(udp)
n.hostname = hostname
return n
}
// isNewV4 returns true for nodes created by NewV4. // isNewV4 returns true for nodes created by NewV4.
func isNewV4(n *Node) bool { func isNewV4(n *Node) bool {
var k s256raw var k s256raw
@ -132,7 +110,6 @@ func parseComplete(rawurl string) (*Node, error) {
var ( var (
id *ecdsa.PublicKey id *ecdsa.PublicKey
tcpPort, udpPort uint64 tcpPort, udpPort uint64
node *Node
) )
u, err := url.Parse(rawurl) u, err := url.Parse(rawurl)
if err != nil { if err != nil {
@ -149,15 +126,8 @@ func parseComplete(rawurl string) (*Node, error) {
return nil, fmt.Errorf("invalid public key (%v)", err) return nil, fmt.Errorf("invalid public key (%v)", err)
} }
// Parse the IP address if its one. // Parse the IP and ports.
ip := net.ParseIP(u.Hostname()) ip := net.ParseIP(u.Hostname())
if ip != nil {
// Ensure the IP is 4 bytes long for IPv4 addresses.
if ipv4 := ip.To4(); ipv4 != nil {
ip = ipv4
}
}
// Parse the port numbers.
if tcpPort, err = strconv.ParseUint(u.Port(), 10, 16); err != nil { if tcpPort, err = strconv.ParseUint(u.Port(), 10, 16); err != nil {
return nil, errors.New("invalid port") return nil, errors.New("invalid port")
} }
@ -170,12 +140,11 @@ func parseComplete(rawurl string) (*Node, error) {
} }
} }
if ip != nil { // Create the node.
node = NewV4(id, ip, int(tcpPort), int(udpPort)) node := NewV4(id, ip, int(tcpPort), int(udpPort))
} else { if ip == nil && u.Hostname() != "" {
node = NewV4WithDNS(id, nil, u.Hostname(), int(tcpPort), int(udpPort)) node = node.WithHostname(u.Hostname())
} }
return node, nil return node, nil
} }
@ -207,7 +176,7 @@ func (n *Node) URLv4() string {
} }
u := url.URL{Scheme: "enode"} u := url.URL{Scheme: "enode"}
if n.Hostname() != "" { if n.Hostname() != "" {
// For DNS nodes: include DNS name, TCP port, and optional UDP port // For nodes with a DNS name: include DNS name, TCP port, and optional UDP port
u.User = url.User(nodeid) u.User = url.User(nodeid)
u.Host = fmt.Sprintf("%s:%d", n.Hostname(), n.TCP()) u.Host = fmt.Sprintf("%s:%d", n.Hostname(), n.TCP())
if n.UDP() != n.TCP() { if n.UDP() != n.TCP() {

View file

@ -79,13 +79,12 @@ var parseNodeTests = []struct {
}, },
{ {
input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@valid.:3", input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@valid.:3",
wantResult: NewV4WithDNS( wantResult: NewV4(
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
nil, nil,
"valid.",
3, 3,
3, 3,
), ).WithHostname("valid."),
}, },
{ {
input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150", input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150",