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