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 }