+++ /dev/null
-// Copyright (c) 2013-2016 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 (
- "bytes"
- "fmt"
- "io"
- "strings"
- "time"
-)
-
-// MaxUserAgentLen is the maximum allowed length for the user agent field in a
-// version message (MsgVersion).
-const MaxUserAgentLen = 256
-
-// DefaultUserAgent for wire in the stack
-const DefaultUserAgent = "/btcwire:0.5.0/"
-
-// MsgVersion implements the Message interface and represents a bitcoin version
-// message. It is used for a peer to advertise itself as soon as an outbound
-// connection is made. The remote peer then uses this information along with
-// its own to negotiate. The remote peer must then respond with a version
-// message of its own containing the negotiated values followed by a verack
-// message (MsgVerAck). This exchange must take place before any further
-// communication is allowed to proceed.
-type MsgVersion struct {
- // Version of the protocol the node is using.
- ProtocolVersion int32
-
- // Bitfield which identifies the enabled services.
- Services ServiceFlag
-
- // Time the message was generated. This is encoded as an int64 on the wire.
- Timestamp time.Time
-
- // Address of the remote peer.
- AddrYou NetAddress
-
- // Address of the local peer.
- AddrMe NetAddress
-
- // Unique value associated with message that is used to detect self
- // connections.
- Nonce uint64
-
- // The user agent that generated messsage. This is a encoded as a varString
- // on the wire. This has a max length of MaxUserAgentLen.
- UserAgent string
-
- // Last block seen by the generator of the version message.
- LastBlock int32
-
- // Don't announce transactions to peer.
- DisableRelayTx bool
-}
-
-// HasService returns whether the specified service is supported by the peer
-// that generated the message.
-func (msg *MsgVersion) HasService(service ServiceFlag) bool {
- return msg.Services&service == service
-}
-
-// AddService adds service as a supported service by the peer generating the
-// message.
-func (msg *MsgVersion) AddService(service ServiceFlag) {
- msg.Services |= service
-}
-
-// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
-// The version message is special in that the protocol version hasn't been
-// negotiated yet. As a result, the pver field is ignored and any fields which
-// are added in new versions are optional. This also mean that r must be a
-// *bytes.Buffer so the number of remaining bytes can be ascertained.
-//
-// This is part of the Message interface implementation.
-func (msg *MsgVersion) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
- buf, ok := r.(*bytes.Buffer)
- if !ok {
- return fmt.Errorf("MsgVersion.BtcDecode reader is not a " +
- "*bytes.Buffer")
- }
-
- err := readElements(buf, &msg.ProtocolVersion, &msg.Services,
- (*int64Time)(&msg.Timestamp))
- if err != nil {
- return err
- }
-
- err = readNetAddress(buf, pver, &msg.AddrYou, false)
- if err != nil {
- return err
- }
-
- // Protocol versions >= 106 added a from address, nonce, and user agent
- // field and they are only considered present if there are bytes
- // remaining in the message.
- if buf.Len() > 0 {
- err = readNetAddress(buf, pver, &msg.AddrMe, false)
- if err != nil {
- return err
- }
- }
- if buf.Len() > 0 {
- err = readElement(buf, &msg.Nonce)
- if err != nil {
- return err
- }
- }
- if buf.Len() > 0 {
- userAgent, err := ReadVarString(buf, pver)
- if err != nil {
- return err
- }
- err = validateUserAgent(userAgent)
- if err != nil {
- return err
- }
- msg.UserAgent = userAgent
- }
-
- // Protocol versions >= 209 added a last known block field. It is only
- // considered present if there are bytes remaining in the message.
- if buf.Len() > 0 {
- err = readElement(buf, &msg.LastBlock)
- if err != nil {
- return err
- }
- }
-
- // There was no relay transactions field before BIP0037Version, but
- // the default behavior prior to the addition of the field was to always
- // relay transactions.
- if buf.Len() > 0 {
- // It's safe to ignore the error here since the buffer has at
- // least one byte and that byte will result in a boolean value
- // regardless of its value. Also, the wire encoding for the
- // field is true when transactions should be relayed, so reverse
- // it for the DisableRelayTx field.
- var relayTx bool
- readElement(r, &relayTx)
- msg.DisableRelayTx = !relayTx
- }
-
- return nil
-}
-
-// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
-// This is part of the Message interface implementation.
-func (msg *MsgVersion) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
- err := validateUserAgent(msg.UserAgent)
- if err != nil {
- return err
- }
-
- err = writeElements(w, msg.ProtocolVersion, msg.Services,
- msg.Timestamp.Unix())
- if err != nil {
- return err
- }
-
- err = writeNetAddress(w, pver, &msg.AddrYou, false)
- if err != nil {
- return err
- }
-
- err = writeNetAddress(w, pver, &msg.AddrMe, false)
- if err != nil {
- return err
- }
-
- err = writeElement(w, msg.Nonce)
- if err != nil {
- return err
- }
-
- err = WriteVarString(w, pver, msg.UserAgent)
- if err != nil {
- return err
- }
-
- err = writeElement(w, msg.LastBlock)
- if err != nil {
- return err
- }
-
- // There was no relay transactions field before BIP0037Version. Also,
- // the wire encoding for the field is true when transactions should be
- // relayed, so reverse it from the DisableRelayTx field.
- if pver >= BIP0037Version {
- err = writeElement(w, !msg.DisableRelayTx)
- if err != nil {
- return err
- }
- }
- return nil
-}
-
-// Command returns the protocol command string for the message. This is part
-// of the Message interface implementation.
-func (msg *MsgVersion) Command() string {
- return CmdVersion
-}
-
-// MaxPayloadLength returns the maximum length the payload can be for the
-// receiver. This is part of the Message interface implementation.
-func (msg *MsgVersion) MaxPayloadLength(pver uint32) uint32 {
- // XXX: <= 106 different
-
- // Protocol version 4 bytes + services 8 bytes + timestamp 8 bytes +
- // remote and local net addresses + nonce 8 bytes + length of user
- // agent (varInt) + max allowed useragent length + last block 4 bytes +
- // relay transactions flag 1 byte.
- return 33 + (maxNetAddressPayload(pver) * 2) + MaxVarIntPayload +
- MaxUserAgentLen
-}
-
-// NewMsgVersion returns a new bitcoin version message that conforms to the
-// Message interface using the passed parameters and defaults for the remaining
-// fields.
-func NewMsgVersion(me *NetAddress, you *NetAddress, nonce uint64,
- lastBlock int32) *MsgVersion {
-
- // Limit the timestamp to one second precision since the protocol
- // doesn't support better.
- return &MsgVersion{
- ProtocolVersion: int32(ProtocolVersion),
- Services: 0,
- Timestamp: time.Unix(time.Now().Unix(), 0),
- AddrYou: *you,
- AddrMe: *me,
- Nonce: nonce,
- UserAgent: DefaultUserAgent,
- LastBlock: lastBlock,
- DisableRelayTx: false,
- }
-}
-
-// validateUserAgent checks userAgent length against MaxUserAgentLen
-func validateUserAgent(userAgent string) error {
- if len(userAgent) > MaxUserAgentLen {
- str := fmt.Sprintf("user agent too long [len %v, max %v]",
- len(userAgent), MaxUserAgentLen)
- return messageError("MsgVersion", str)
- }
- return nil
-}
-
-// AddUserAgent adds a user agent to the user agent string for the version
-// message. The version string is not defined to any strict format, although
-// it is recommended to use the form "major.minor.revision" e.g. "2.6.41".
-func (msg *MsgVersion) AddUserAgent(name string, version string,
- comments ...string) error {
-
- newUserAgent := fmt.Sprintf("%s:%s", name, version)
- if len(comments) != 0 {
- newUserAgent = fmt.Sprintf("%s(%s)", newUserAgent,
- strings.Join(comments, "; "))
- }
- newUserAgent = fmt.Sprintf("%s%s/", msg.UserAgent, newUserAgent)
- err := validateUserAgent(newUserAgent)
- if err != nil {
- return err
- }
- msg.UserAgent = newUserAgent
- return nil
-}