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