github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/wire/msgversion.go (about)

     1  // Copyright (c) 2013-2016 The btcsuite developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package wire
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"io"
    11  	"net"
    12  	"strings"
    13  	"time"
    14  )
    15  
    16  // MaxUserAgentLen is the maximum allowed length for the user agent field in a
    17  // version message (MsgVersion).
    18  const MaxUserAgentLen = 256
    19  
    20  // DefaultUserAgent for wire in the stack
    21  const DefaultUserAgent = "/btcwire:0.4.1/"
    22  
    23  // MsgVersion implements the Message interface and represents a bitcoin version
    24  // message.  It is used for a peer to advertise itself as soon as an outbound
    25  // connection is made.  The remote peer then uses this information along with
    26  // its own to negotiate.  The remote peer must then respond with a version
    27  // message of its own containing the negotiated values followed by a verack
    28  // message (MsgVerAck).  This exchange must take place before any further
    29  // communication is allowed to proceed.
    30  type MsgVersion struct {
    31  	// Version of the protocol the node is using.
    32  	ProtocolVersion int32
    33  
    34  	// Bitfield which identifies the enabled services.
    35  	Services ServiceFlag
    36  
    37  	// Time the message was generated.  This is encoded as an int64 on the wire.
    38  	Timestamp time.Time
    39  
    40  	// Address of the remote peer.
    41  	AddrYou NetAddress
    42  
    43  	// Address of the local peer.
    44  	AddrMe NetAddress
    45  
    46  	// Unique value associated with message that is used to detect self
    47  	// connections.
    48  	Nonce uint64
    49  
    50  	// The user agent that generated messsage.  This is a encoded as a varString
    51  	// on the wire.  This has a max length of MaxUserAgentLen.
    52  	UserAgent string
    53  
    54  	// Last block seen by the generator of the version message.
    55  	LastBlock int32
    56  
    57  	// Don't announce transactions to peer.
    58  	DisableRelayTx bool
    59  }
    60  
    61  // HasService returns whether the specified service is supported by the peer
    62  // that generated the message.
    63  func (msg *MsgVersion) HasService(service ServiceFlag) bool {
    64  	return msg.Services&service == service
    65  }
    66  
    67  // AddService adds service as a supported service by the peer generating the
    68  // message.
    69  func (msg *MsgVersion) AddService(service ServiceFlag) {
    70  	msg.Services |= service
    71  }
    72  
    73  // BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
    74  // The version message is special in that the protocol version hasn't been
    75  // negotiated yet.  As a result, the pver field is ignored and any fields which
    76  // are added in new versions are optional.  This also mean that r must be a
    77  // *bytes.Buffer so the number of remaining bytes can be ascertained.
    78  //
    79  // This is part of the Message interface implementation.
    80  func (msg *MsgVersion) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
    81  	buf, ok := r.(*bytes.Buffer)
    82  	if !ok {
    83  		return fmt.Errorf("MsgVersion.BtcDecode reader is not a " +
    84  			"*bytes.Buffer")
    85  	}
    86  
    87  	err := readElements(buf, &msg.ProtocolVersion, &msg.Services,
    88  		(*int64Time)(&msg.Timestamp))
    89  	if err != nil {
    90  		return err
    91  	}
    92  
    93  	err = readNetAddress(buf, pver, &msg.AddrYou, false)
    94  	if err != nil {
    95  		return err
    96  	}
    97  
    98  	// Protocol versions >= 106 added a from address, nonce, and user agent
    99  	// field and they are only considered present if there are bytes
   100  	// remaining in the message.
   101  	if buf.Len() > 0 {
   102  		err = readNetAddress(buf, pver, &msg.AddrMe, false)
   103  		if err != nil {
   104  			return err
   105  		}
   106  	}
   107  	if buf.Len() > 0 {
   108  		err = readElement(buf, &msg.Nonce)
   109  		if err != nil {
   110  			return err
   111  		}
   112  	}
   113  	if buf.Len() > 0 {
   114  		userAgent, err := ReadVarString(buf, pver)
   115  		if err != nil {
   116  			return err
   117  		}
   118  		err = validateUserAgent(userAgent)
   119  		if err != nil {
   120  			return err
   121  		}
   122  		msg.UserAgent = userAgent
   123  	}
   124  
   125  	// Protocol versions >= 209 added a last known block field.  It is only
   126  	// considered present if there are bytes remaining in the message.
   127  	if buf.Len() > 0 {
   128  		err = readElement(buf, &msg.LastBlock)
   129  		if err != nil {
   130  			return err
   131  		}
   132  	}
   133  
   134  	// There was no relay transactions field before BIP0037Version, but
   135  	// the default behavior prior to the addition of the field was to always
   136  	// relay transactions.
   137  	if buf.Len() > 0 {
   138  		// It's safe to ignore the error here since the buffer has at
   139  		// least one byte and that byte will result in a boolean value
   140  		// regardless of its value.  Also, the wire encoding for the
   141  		// field is true when transactions should be relayed, so reverse
   142  		// it for the DisableRelayTx field.
   143  		var relayTx bool
   144  		readElement(r, &relayTx)
   145  		msg.DisableRelayTx = !relayTx
   146  	}
   147  
   148  	return nil
   149  }
   150  
   151  // BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
   152  // This is part of the Message interface implementation.
   153  func (msg *MsgVersion) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
   154  	err := validateUserAgent(msg.UserAgent)
   155  	if err != nil {
   156  		return err
   157  	}
   158  
   159  	err = writeElements(w, msg.ProtocolVersion, msg.Services,
   160  		msg.Timestamp.Unix())
   161  	if err != nil {
   162  		return err
   163  	}
   164  
   165  	err = writeNetAddress(w, pver, &msg.AddrYou, false)
   166  	if err != nil {
   167  		return err
   168  	}
   169  
   170  	err = writeNetAddress(w, pver, &msg.AddrMe, false)
   171  	if err != nil {
   172  		return err
   173  	}
   174  
   175  	err = writeElement(w, msg.Nonce)
   176  	if err != nil {
   177  		return err
   178  	}
   179  
   180  	err = WriteVarString(w, pver, msg.UserAgent)
   181  	if err != nil {
   182  		return err
   183  	}
   184  
   185  	err = writeElement(w, msg.LastBlock)
   186  	if err != nil {
   187  		return err
   188  	}
   189  
   190  	// There was no relay transactions field before BIP0037Version.  Also,
   191  	// the wire encoding for the field is true when transactions should be
   192  	// relayed, so reverse it from the DisableRelayTx field.
   193  	if pver >= BIP0037Version {
   194  		err = writeElement(w, !msg.DisableRelayTx)
   195  		if err != nil {
   196  			return err
   197  		}
   198  	}
   199  	return nil
   200  }
   201  
   202  // Command returns the protocol command string for the message.  This is part
   203  // of the Message interface implementation.
   204  func (msg *MsgVersion) Command() string {
   205  	return CmdVersion
   206  }
   207  
   208  // MaxPayloadLength returns the maximum length the payload can be for the
   209  // receiver.  This is part of the Message interface implementation.
   210  func (msg *MsgVersion) MaxPayloadLength(pver uint32) uint32 {
   211  	// XXX: <= 106 different
   212  
   213  	// Protocol version 4 bytes + services 8 bytes + timestamp 8 bytes +
   214  	// remote and local net addresses + nonce 8 bytes + length of user
   215  	// agent (varInt) + max allowed useragent length + last block 4 bytes +
   216  	// relay transactions flag 1 byte.
   217  	return 33 + (maxNetAddressPayload(pver) * 2) + MaxVarIntPayload +
   218  		MaxUserAgentLen
   219  }
   220  
   221  // NewMsgVersion returns a new bitcoin version message that conforms to the
   222  // Message interface using the passed parameters and defaults for the remaining
   223  // fields.
   224  func NewMsgVersion(me *NetAddress, you *NetAddress, nonce uint64,
   225  	lastBlock int32) *MsgVersion {
   226  
   227  	// Limit the timestamp to one second precision since the protocol
   228  	// doesn't support better.
   229  	return &MsgVersion{
   230  		ProtocolVersion: int32(ProtocolVersion),
   231  		Services:        0,
   232  		Timestamp:       time.Unix(time.Now().Unix(), 0),
   233  		AddrYou:         *you,
   234  		AddrMe:          *me,
   235  		Nonce:           nonce,
   236  		UserAgent:       DefaultUserAgent,
   237  		LastBlock:       lastBlock,
   238  		DisableRelayTx:  false,
   239  	}
   240  }
   241  
   242  // NewMsgVersionFromConn is a convenience function that extracts the remote
   243  // and local address from conn and returns a new bitcoin version message that
   244  // conforms to the Message interface.  See NewMsgVersion.
   245  func NewMsgVersionFromConn(conn net.Conn, nonce uint64,
   246  	lastBlock int32) (*MsgVersion, error) {
   247  
   248  	// Don't assume any services until we know otherwise.
   249  	lna, err := NewNetAddress(conn.LocalAddr(), 0)
   250  	if err != nil {
   251  		return nil, err
   252  	}
   253  
   254  	// Don't assume any services until we know otherwise.
   255  	rna, err := NewNetAddress(conn.RemoteAddr(), 0)
   256  	if err != nil {
   257  		return nil, err
   258  	}
   259  
   260  	return NewMsgVersion(lna, rna, nonce, lastBlock), nil
   261  }
   262  
   263  // validateUserAgent checks userAgent length against MaxUserAgentLen
   264  func validateUserAgent(userAgent string) error {
   265  	if len(userAgent) > MaxUserAgentLen {
   266  		str := fmt.Sprintf("user agent too long [len %v, max %v]",
   267  			len(userAgent), MaxUserAgentLen)
   268  		return messageError("MsgVersion", str)
   269  	}
   270  	return nil
   271  }
   272  
   273  // AddUserAgent adds a user agent to the user agent string for the version
   274  // message.  The version string is not defined to any strict format, although
   275  // it is recommended to use the form "major.minor.revision" e.g. "2.6.41".
   276  func (msg *MsgVersion) AddUserAgent(name string, version string,
   277  	comments ...string) error {
   278  
   279  	newUserAgent := fmt.Sprintf("%s:%s", name, version)
   280  	if len(comments) != 0 {
   281  		newUserAgent = fmt.Sprintf("%s(%s)", newUserAgent,
   282  			strings.Join(comments, "; "))
   283  	}
   284  	newUserAgent = fmt.Sprintf("%s%s/", msg.UserAgent, newUserAgent)
   285  	err := validateUserAgent(newUserAgent)
   286  	if err != nil {
   287  		return err
   288  	}
   289  	msg.UserAgent = newUserAgent
   290  	return nil
   291  }