p2p/enr: updates for discovery v4 compatibility (#16679)

This applies spec changes from ethereum/EIPs#1049 and adds support for
pluggable identity schemes.

Some care has been taken to make the "v4" scheme standalone. It uses
public APIs only and could be moved out of package enr at any time.

A couple of minor changes were needed to make identity schemes work:

- The sequence number is now updated in Set instead of when signing.
- Record is now copy-safe, i.e. calling Set on a shallow copy doesn't
  modify the record it was copied from.
This commit is contained in:
Felix Lange
2018-05-17 15:11:27 +02:00
committed by GitHub
parent f6bc65fc68
commit 6286c255f1
5 changed files with 277 additions and 154 deletions

View File

@ -57,59 +57,43 @@ func WithEntry(k string, v interface{}) Entry {
return &generic{key: k, value: v}
}
// DiscPort is the "discv5" key, which holds the UDP port for discovery v5.
type DiscPort uint16
// TCP is the "tcp" key, which holds the TCP port of the node.
type TCP uint16
func (v DiscPort) ENRKey() string { return "discv5" }
func (v TCP) ENRKey() string { return "tcp" }
// UDP is the "udp" key, which holds the UDP port of the node.
type UDP uint16
func (v UDP) ENRKey() string { return "udp" }
// ID is the "id" key, which holds the name of the identity scheme.
type ID string
const IDv4 = ID("v4") // the default identity scheme
func (v ID) ENRKey() string { return "id" }
// IP4 is the "ip4" key, which holds a 4-byte IPv4 address.
type IP4 net.IP
// IP is the "ip" key, which holds the IP address of the node.
type IP net.IP
func (v IP4) ENRKey() string { return "ip4" }
func (v IP) ENRKey() string { return "ip" }
// EncodeRLP implements rlp.Encoder.
func (v IP4) EncodeRLP(w io.Writer) error {
ip4 := net.IP(v).To4()
if ip4 == nil {
return fmt.Errorf("invalid IPv4 address: %v", v)
func (v IP) EncodeRLP(w io.Writer) error {
if ip4 := net.IP(v).To4(); ip4 != nil {
return rlp.Encode(w, ip4)
}
return rlp.Encode(w, ip4)
return rlp.Encode(w, net.IP(v))
}
// DecodeRLP implements rlp.Decoder.
func (v *IP4) DecodeRLP(s *rlp.Stream) error {
func (v *IP) DecodeRLP(s *rlp.Stream) error {
if err := s.Decode((*net.IP)(v)); err != nil {
return err
}
if len(*v) != 4 {
return fmt.Errorf("invalid IPv4 address, want 4 bytes: %v", *v)
}
return nil
}
// IP6 is the "ip6" key, which holds a 16-byte IPv6 address.
type IP6 net.IP
func (v IP6) ENRKey() string { return "ip6" }
// EncodeRLP implements rlp.Encoder.
func (v IP6) EncodeRLP(w io.Writer) error {
ip6 := net.IP(v)
return rlp.Encode(w, ip6)
}
// DecodeRLP implements rlp.Decoder.
func (v *IP6) DecodeRLP(s *rlp.Stream) error {
if err := s.Decode((*net.IP)(v)); err != nil {
return err
}
if len(*v) != 16 {
return fmt.Errorf("invalid IPv6 address, want 16 bytes: %v", *v)
if len(*v) != 4 && len(*v) != 16 {
return fmt.Errorf("invalid IP address, want 4 or 16 bytes: %v", *v)
}
return nil
}