msgversion.go raw

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