c5751b75a9
Replace assignments to individual fields of wire.NetAddress with creating the entire object at once, as one would do if the type was immutable. In some places this replaces the creation of a NetAddress with a high-precision timestamp with a call to a 'constructor' that converts the timestamp to single second precision. For consistency, the tests have also been changed to use single-precision timestamps. Lastly, the number of allocations in readNetAddress have been reduced by reading the services directly into the NetAddress instead of first into a temporary variable.
149 lines
4.6 KiB
Go
149 lines
4.6 KiB
Go
// Copyright (c) 2013-2015 The btcsuite developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package wire
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"io"
|
|
"net"
|
|
"time"
|
|
)
|
|
|
|
// maxNetAddressPayload returns the max payload size for a bitcoin NetAddress
|
|
// based on the protocol version.
|
|
func maxNetAddressPayload(pver uint32) uint32 {
|
|
// Services 8 bytes + ip 16 bytes + port 2 bytes.
|
|
plen := uint32(26)
|
|
|
|
// NetAddressTimeVersion added a timestamp field.
|
|
if pver >= NetAddressTimeVersion {
|
|
// Timestamp 4 bytes.
|
|
plen += 4
|
|
}
|
|
|
|
return plen
|
|
}
|
|
|
|
// NetAddress defines information about a peer on the network including the time
|
|
// it was last seen, the services it supports, its IP address, and port.
|
|
type NetAddress struct {
|
|
// Last time the address was seen. This is, unfortunately, encoded as a
|
|
// uint32 on the wire and therefore is limited to 2106. This field is
|
|
// not present in the bitcoin version message (MsgVersion) nor was it
|
|
// added until protocol version >= NetAddressTimeVersion.
|
|
Timestamp time.Time
|
|
|
|
// Bitfield which identifies the services supported by the address.
|
|
Services ServiceFlag
|
|
|
|
// IP address of the peer.
|
|
IP net.IP
|
|
|
|
// Port the peer is using. This is encoded in big endian on the wire
|
|
// which differs from most everything else.
|
|
Port uint16
|
|
}
|
|
|
|
// HasService returns whether the specified service is supported by the address.
|
|
func (na *NetAddress) HasService(service ServiceFlag) bool {
|
|
return na.Services&service == service
|
|
}
|
|
|
|
// AddService adds service as a supported service by the peer generating the
|
|
// message.
|
|
func (na *NetAddress) AddService(service ServiceFlag) {
|
|
na.Services |= service
|
|
}
|
|
|
|
// NewNetAddressIPPort returns a new NetAddress using the provided IP, port, and
|
|
// supported services with defaults for the remaining fields.
|
|
func NewNetAddressIPPort(ip net.IP, port uint16, services ServiceFlag) *NetAddress {
|
|
return NewNetAddressTimestamp(time.Now(), services, ip, port)
|
|
}
|
|
|
|
// NewNetAddressTimestamp returns a new NetAddress using the provided
|
|
// timestamp, IP, port, and supported services. The timestamp is rounded to
|
|
// single second precision.
|
|
func NewNetAddressTimestamp(
|
|
timestamp time.Time, services ServiceFlag, ip net.IP, port uint16) *NetAddress {
|
|
// Limit the timestamp to one second precision since the protocol
|
|
// doesn't support better.
|
|
na := NetAddress{
|
|
Timestamp: time.Unix(timestamp.Unix(), 0),
|
|
Services: services,
|
|
IP: ip,
|
|
Port: port,
|
|
}
|
|
return &na
|
|
}
|
|
|
|
// NewNetAddress returns a new NetAddress using the provided TCP address and
|
|
// supported services with defaults for the remaining fields.
|
|
func NewNetAddress(addr *net.TCPAddr, services ServiceFlag) *NetAddress {
|
|
return NewNetAddressIPPort(addr.IP, uint16(addr.Port), services)
|
|
}
|
|
|
|
// readNetAddress reads an encoded NetAddress from r depending on the protocol
|
|
// version and whether or not the timestamp is included per ts. Some messages
|
|
// like version do not include the timestamp.
|
|
func readNetAddress(r io.Reader, pver uint32, na *NetAddress, ts bool) error {
|
|
var ip [16]byte
|
|
|
|
// NOTE: The bitcoin protocol uses a uint32 for the timestamp so it will
|
|
// stop working somewhere around 2106. Also timestamp wasn't added until
|
|
// protocol version >= NetAddressTimeVersion
|
|
if ts && pver >= NetAddressTimeVersion {
|
|
err := readElement(r, (*uint32Time)(&na.Timestamp))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
err := readElements(r, &na.Services, &ip)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// Sigh. Bitcoin protocol mixes little and big endian.
|
|
port, err := binarySerializer.Uint16(r, bigEndian)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
*na = NetAddress{
|
|
Timestamp: na.Timestamp,
|
|
Services: na.Services,
|
|
IP: net.IP(ip[:]),
|
|
Port: port,
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// writeNetAddress serializes a NetAddress to w depending on the protocol
|
|
// version and whether or not the timestamp is included per ts. Some messages
|
|
// like version do not include the timestamp.
|
|
func writeNetAddress(w io.Writer, pver uint32, na *NetAddress, ts bool) error {
|
|
// NOTE: The bitcoin protocol uses a uint32 for the timestamp so it will
|
|
// stop working somewhere around 2106. Also timestamp wasn't added until
|
|
// until protocol version >= NetAddressTimeVersion.
|
|
if ts && pver >= NetAddressTimeVersion {
|
|
err := writeElement(w, uint32(na.Timestamp.Unix()))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Ensure to always write 16 bytes even if the ip is nil.
|
|
var ip [16]byte
|
|
if na.IP != nil {
|
|
copy(ip[:], na.IP.To16())
|
|
}
|
|
err := writeElements(w, na.Services, ip)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Sigh. Bitcoin protocol mixes little and big endian.
|
|
return binary.Write(w, bigEndian, na.Port)
|
|
}
|