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