github.com/aidoskuneen/adk-node@v0.0.0-20220315131952-2e32567cb7f4/p2p/discover/v4wire/v4wire.go (about)

     1  // Copyright 2021 The adkgo Authors
     2  // This file is part of the adkgo library (adapted for adkgo from go--ethereum v1.10.8).
     3  //
     4  // the adkgo library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // the adkgo library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the adkgo library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package v4wire implements the Discovery v4 Wire Protocol.
    18  package v4wire
    19  
    20  import (
    21  	"bytes"
    22  	"crypto/ecdsa"
    23  	"crypto/elliptic"
    24  	"errors"
    25  	"fmt"
    26  	"math/big"
    27  	"net"
    28  	"time"
    29  
    30  	"github.com/aidoskuneen/adk-node/common/math"
    31  	"github.com/aidoskuneen/adk-node/crypto"
    32  	"github.com/aidoskuneen/adk-node/p2p/enode"
    33  	"github.com/aidoskuneen/adk-node/p2p/enr"
    34  	"github.com/aidoskuneen/adk-node/rlp"
    35  )
    36  
    37  // RPC packet types
    38  const (
    39  	PingPacket = iota + 1 // zero is 'reserved'
    40  	PongPacket
    41  	FindnodePacket
    42  	NeighborsPacket
    43  	ENRRequestPacket
    44  	ENRResponsePacket
    45  )
    46  
    47  // RPC request structures
    48  type (
    49  	Ping struct {
    50  		Version    uint
    51  		From, To   Endpoint
    52  		Expiration uint64
    53  		ENRSeq     uint64 `rlp:"optional"` // Sequence number of local record, added by EIP-868.
    54  
    55  		// Ignore additional fields (for forward compatibility).
    56  		Rest []rlp.RawValue `rlp:"tail"`
    57  	}
    58  
    59  	// Pong is the reply to ping.
    60  	Pong struct {
    61  		// This field should mirror the UDP envelope address
    62  		// of the ping packet, which provides a way to discover the
    63  		// the external address (after NAT).
    64  		To         Endpoint
    65  		ReplyTok   []byte // This contains the hash of the ping packet.
    66  		Expiration uint64 // Absolute timestamp at which the packet becomes invalid.
    67  		ENRSeq     uint64 `rlp:"optional"` // Sequence number of local record, added by EIP-868.
    68  
    69  		// Ignore additional fields (for forward compatibility).
    70  		Rest []rlp.RawValue `rlp:"tail"`
    71  	}
    72  
    73  	// Findnode is a query for nodes close to the given target.
    74  	Findnode struct {
    75  		Target     Pubkey
    76  		Expiration uint64
    77  		// Ignore additional fields (for forward compatibility).
    78  		Rest []rlp.RawValue `rlp:"tail"`
    79  	}
    80  
    81  	// Neighbors is the reply to findnode.
    82  	Neighbors struct {
    83  		Nodes      []Node
    84  		Expiration uint64
    85  		// Ignore additional fields (for forward compatibility).
    86  		Rest []rlp.RawValue `rlp:"tail"`
    87  	}
    88  
    89  	// enrRequest queries for the remote node's record.
    90  	ENRRequest struct {
    91  		Expiration uint64
    92  		// Ignore additional fields (for forward compatibility).
    93  		Rest []rlp.RawValue `rlp:"tail"`
    94  	}
    95  
    96  	// enrResponse is the reply to enrRequest.
    97  	ENRResponse struct {
    98  		ReplyTok []byte // Hash of the enrRequest packet.
    99  		Record   enr.Record
   100  		// Ignore additional fields (for forward compatibility).
   101  		Rest []rlp.RawValue `rlp:"tail"`
   102  	}
   103  )
   104  
   105  // This number is the maximum number of neighbor nodes in a Neigbors packet.
   106  const MaxNeighbors = 12
   107  
   108  // This code computes the MaxNeighbors constant value.
   109  
   110  // func init() {
   111  // 	var maxNeighbors int
   112  // 	p := Neighbors{Expiration: ^uint64(0)}
   113  // 	maxSizeNode := Node{IP: make(net.IP, 16), UDP: ^uint16(0), TCP: ^uint16(0)}
   114  // 	for n := 0; ; n++ {
   115  // 		p.Nodes = append(p.Nodes, maxSizeNode)
   116  // 		size, _, err := rlp.EncodeToReader(p)
   117  // 		if err != nil {
   118  // 			// If this ever happens, it will be caught by the unit tests.
   119  // 			panic("cannot encode: " + err.Error())
   120  // 		}
   121  // 		if headSize+size+1 >= 1280 {
   122  // 			maxNeighbors = n
   123  // 			break
   124  // 		}
   125  // 	}
   126  // 	fmt.Println("maxNeighbors", maxNeighbors)
   127  // }
   128  
   129  // Pubkey represents an encoded 64-byte secp256k1 public key.
   130  type Pubkey [64]byte
   131  
   132  // ID returns the node ID corresponding to the public key.
   133  func (e Pubkey) ID() enode.ID {
   134  	return enode.ID(crypto.Keccak256Hash(e[:]))
   135  }
   136  
   137  // Node represents information about a node.
   138  type Node struct {
   139  	IP  net.IP // len 4 for IPv4 or 16 for IPv6
   140  	UDP uint16 // for discovery protocol
   141  	TCP uint16 // for RLPx protocol
   142  	ID  Pubkey
   143  }
   144  
   145  // Endpoint represents a network endpoint.
   146  type Endpoint struct {
   147  	IP  net.IP // len 4 for IPv4 or 16 for IPv6
   148  	UDP uint16 // for discovery protocol
   149  	TCP uint16 // for RLPx protocol
   150  }
   151  
   152  // NewEndpoint creates an endpoint.
   153  func NewEndpoint(addr *net.UDPAddr, tcpPort uint16) Endpoint {
   154  	ip := net.IP{}
   155  	if ip4 := addr.IP.To4(); ip4 != nil {
   156  		ip = ip4
   157  	} else if ip6 := addr.IP.To16(); ip6 != nil {
   158  		ip = ip6
   159  	}
   160  	return Endpoint{IP: ip, UDP: uint16(addr.Port), TCP: tcpPort}
   161  }
   162  
   163  type Packet interface {
   164  	// packet name and type for logging purposes.
   165  	Name() string
   166  	Kind() byte
   167  }
   168  
   169  func (req *Ping) Name() string { return "PING/v4" }
   170  func (req *Ping) Kind() byte   { return PingPacket }
   171  
   172  func (req *Pong) Name() string { return "PONG/v4" }
   173  func (req *Pong) Kind() byte   { return PongPacket }
   174  
   175  func (req *Findnode) Name() string { return "FINDNODE/v4" }
   176  func (req *Findnode) Kind() byte   { return FindnodePacket }
   177  
   178  func (req *Neighbors) Name() string { return "NEIGHBORS/v4" }
   179  func (req *Neighbors) Kind() byte   { return NeighborsPacket }
   180  
   181  func (req *ENRRequest) Name() string { return "ENRREQUEST/v4" }
   182  func (req *ENRRequest) Kind() byte   { return ENRRequestPacket }
   183  
   184  func (req *ENRResponse) Name() string { return "ENRRESPONSE/v4" }
   185  func (req *ENRResponse) Kind() byte   { return ENRResponsePacket }
   186  
   187  // Expired checks whether the given UNIX time stamp is in the past.
   188  func Expired(ts uint64) bool {
   189  	return time.Unix(int64(ts), 0).Before(time.Now())
   190  }
   191  
   192  // Encoder/decoder.
   193  
   194  const (
   195  	macSize  = 32
   196  	sigSize  = crypto.SignatureLength
   197  	headSize = macSize + sigSize // space of packet frame data
   198  )
   199  
   200  var (
   201  	ErrPacketTooSmall = errors.New("too small")
   202  	ErrBadHash        = errors.New("bad hash")
   203  	ErrBadPoint       = errors.New("invalid curve point")
   204  )
   205  
   206  var headSpace = make([]byte, headSize)
   207  
   208  // Decode reads a discovery v4 packet.
   209  func Decode(input []byte) (Packet, Pubkey, []byte, error) {
   210  	if len(input) < headSize+1 {
   211  		return nil, Pubkey{}, nil, ErrPacketTooSmall
   212  	}
   213  	hash, sig, sigdata := input[:macSize], input[macSize:headSize], input[headSize:]
   214  	shouldhash := crypto.Keccak256(input[macSize:])
   215  	if !bytes.Equal(hash, shouldhash) {
   216  		return nil, Pubkey{}, nil, ErrBadHash
   217  	}
   218  	fromKey, err := recoverNodeKey(crypto.Keccak256(input[headSize:]), sig)
   219  	if err != nil {
   220  		return nil, fromKey, hash, err
   221  	}
   222  
   223  	var req Packet
   224  	switch ptype := sigdata[0]; ptype {
   225  	case PingPacket:
   226  		req = new(Ping)
   227  	case PongPacket:
   228  		req = new(Pong)
   229  	case FindnodePacket:
   230  		req = new(Findnode)
   231  	case NeighborsPacket:
   232  		req = new(Neighbors)
   233  	case ENRRequestPacket:
   234  		req = new(ENRRequest)
   235  	case ENRResponsePacket:
   236  		req = new(ENRResponse)
   237  	default:
   238  		return nil, fromKey, hash, fmt.Errorf("unknown type: %d", ptype)
   239  	}
   240  	s := rlp.NewStream(bytes.NewReader(sigdata[1:]), 0)
   241  	err = s.Decode(req)
   242  	return req, fromKey, hash, err
   243  }
   244  
   245  // Encode encodes a discovery packet.
   246  func Encode(priv *ecdsa.PrivateKey, req Packet) (packet, hash []byte, err error) {
   247  	b := new(bytes.Buffer)
   248  	b.Write(headSpace)
   249  	b.WriteByte(req.Kind())
   250  	if err := rlp.Encode(b, req); err != nil {
   251  		return nil, nil, err
   252  	}
   253  	packet = b.Bytes()
   254  	sig, err := crypto.Sign(crypto.Keccak256(packet[headSize:]), priv)
   255  	if err != nil {
   256  		return nil, nil, err
   257  	}
   258  	copy(packet[macSize:], sig)
   259  	// Add the hash to the front. Note: this doesn't protect the packet in any way.
   260  	hash = crypto.Keccak256(packet[macSize:])
   261  	copy(packet, hash)
   262  	return packet, hash, nil
   263  }
   264  
   265  // recoverNodeKey computes the public key used to sign the given hash from the signature.
   266  func recoverNodeKey(hash, sig []byte) (key Pubkey, err error) {
   267  	pubkey, err := crypto.Ecrecover(hash, sig)
   268  	if err != nil {
   269  		return key, err
   270  	}
   271  	copy(key[:], pubkey[1:])
   272  	return key, nil
   273  }
   274  
   275  // EncodePubkey encodes a secp256k1 public key.
   276  func EncodePubkey(key *ecdsa.PublicKey) Pubkey {
   277  	var e Pubkey
   278  	math.ReadBits(key.X, e[:len(e)/2])
   279  	math.ReadBits(key.Y, e[len(e)/2:])
   280  	return e
   281  }
   282  
   283  // DecodePubkey reads an encoded secp256k1 public key.
   284  func DecodePubkey(curve elliptic.Curve, e Pubkey) (*ecdsa.PublicKey, error) {
   285  	p := &ecdsa.PublicKey{Curve: curve, X: new(big.Int), Y: new(big.Int)}
   286  	half := len(e) / 2
   287  	p.X.SetBytes(e[:half])
   288  	p.Y.SetBytes(e[half:])
   289  	if !p.Curve.IsOnCurve(p.X, p.Y) {
   290  		return nil, ErrBadPoint
   291  	}
   292  	return p, nil
   293  }