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.
13 "github.com/btcsuite/btcd/chaincfg/chainhash"
16 // MessageHeaderSize is the number of bytes in a bitcoin message header.
17 // Bitcoin network (magic) 4 bytes + command 12 bytes + payload length 4 bytes +
19 const MessageHeaderSize = 24
21 // CommandSize is the fixed size of all commands in the common bitcoin message
22 // header. Shorter commands must be zero padded.
23 const CommandSize = 12
25 // MaxMessagePayload is the maximum bytes a message can be regardless of other
26 // individual limits imposed by messages themselves.
27 const MaxMessagePayload = (1024 * 1024 * 32) // 32MB
29 // Commands used in bitcoin message headers which describe the type of message.
31 CmdVersion = "version"
33 CmdGetAddr = "getaddr"
35 CmdGetBlocks = "getblocks"
37 CmdGetData = "getdata"
38 CmdNotFound = "notfound"
41 CmdGetHeaders = "getheaders"
42 CmdHeaders = "headers"
46 CmdMemPool = "mempool"
47 CmdFilterAdd = "filteradd"
48 CmdFilterClear = "filterclear"
49 CmdFilterLoad = "filterload"
50 CmdMerkleBlock = "merkleblock"
52 CmdSendHeaders = "sendheaders"
53 CmdFeeFilter = "feefilter"
56 // MessageEncoding represents the wire message encoding format to be used.
57 type MessageEncoding uint32
60 // BaseEncoding encodes all messages in the default format specified
61 // for the Bitcoin wire protocol.
62 BaseEncoding MessageEncoding = 1 << iota
64 // WitnessEncoding encodes all messages other than transaction messages
65 // using the default Bitcoin wire protocol specification. For transaction
66 // messages, the new encoding format detailed in BIP0144 will be used.
70 // LatestEncoding is the most recently specified encoding for the Bitcoin wire
72 var LatestEncoding = WitnessEncoding
74 // Message is an interface that describes a bitcoin message. A type that
75 // implements Message has complete control over the representation of its data
76 // and may therefore contain additional or fewer fields than those which
77 // are used directly in the protocol encoded message.
78 type Message interface {
79 BtcDecode(io.Reader, uint32, MessageEncoding) error
80 BtcEncode(io.Writer, uint32, MessageEncoding) error
82 MaxPayloadLength(uint32) uint32
85 // makeEmptyMessage creates a message of the appropriate concrete type based
87 func makeEmptyMessage(command string) (Message, error) {
103 msg = &MsgGetBlocks{}
127 msg = &MsgGetHeaders{}
139 msg = &MsgFilterAdd{}
142 msg = &MsgFilterClear{}
145 msg = &MsgFilterLoad{}
148 msg = &MsgMerkleBlock{}
154 msg = &MsgSendHeaders{}
157 msg = &MsgFeeFilter{}
160 return nil, fmt.Errorf("unhandled command [%s]", command)
165 // messageHeader defines the header structure for all bitcoin protocol messages.
166 type messageHeader struct {
167 magic BitcoinNet // 4 bytes
168 command string // 12 bytes
169 length uint32 // 4 bytes
170 checksum [4]byte // 4 bytes
173 // readMessageHeader reads a bitcoin message header from r.
174 func readMessageHeader(r io.Reader) (int, *messageHeader, error) {
175 // Since readElements doesn't return the amount of bytes read, attempt
176 // to read the entire header into a buffer first in case there is a
177 // short read so the proper amount of read bytes are known. This works
178 // since the header is a fixed size.
179 var headerBytes [MessageHeaderSize]byte
180 n, err := io.ReadFull(r, headerBytes[:])
184 hr := bytes.NewReader(headerBytes[:])
186 // Create and populate a messageHeader struct from the raw header bytes.
187 hdr := messageHeader{}
188 var command [CommandSize]byte
189 readElements(hr, &hdr.magic, &command, &hdr.length, &hdr.checksum)
191 // Strip trailing zeros from command string.
192 hdr.command = string(bytes.TrimRight(command[:], string(0)))
197 // discardInput reads n bytes from reader r in chunks and discards the read
198 // bytes. This is used to skip payloads when various errors occur and helps
199 // prevent rogue nodes from causing massive memory allocation through forging
201 func discardInput(r io.Reader, n uint32) {
202 maxSize := uint32(10 * 1024) // 10k at a time
203 numReads := n / maxSize
204 bytesRemaining := n % maxSize
206 buf := make([]byte, maxSize)
207 for i := uint32(0); i < numReads; i++ {
211 if bytesRemaining > 0 {
212 buf := make([]byte, bytesRemaining)
217 // WriteMessageN writes a bitcoin Message to w including the necessary header
218 // information and returns the number of bytes written. This function is the
219 // same as WriteMessage except it also returns the number of bytes written.
220 func WriteMessageN(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) (int, error) {
221 return WriteMessageWithEncodingN(w, msg, pver, btcnet, BaseEncoding)
224 // WriteMessage writes a bitcoin Message to w including the necessary header
225 // information. This function is the same as WriteMessageN except it doesn't
226 // doesn't return the number of bytes written. This function is mainly provided
227 // for backwards compatibility with the original API, but it's also useful for
228 // callers that don't care about byte counts.
229 func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) error {
230 _, err := WriteMessageN(w, msg, pver, btcnet)
234 // WriteMessageWithEncodingN writes a bitcoin Message to w including the
235 // necessary header information and returns the number of bytes written.
236 // This function is the same as WriteMessageN except it also allows the caller
237 // to specify the message encoding format to be used when serializing wire
239 func WriteMessageWithEncodingN(w io.Writer, msg Message, pver uint32,
240 btcnet BitcoinNet, encoding MessageEncoding) (int, error) {
244 // Enforce max command size.
245 var command [CommandSize]byte
247 if len(cmd) > CommandSize {
248 str := fmt.Sprintf("command [%s] is too long [max %v]",
250 return totalBytes, messageError("WriteMessage", str)
252 copy(command[:], []byte(cmd))
254 // Encode the message payload.
256 err := msg.BtcEncode(&bw, pver, encoding)
258 return totalBytes, err
260 payload := bw.Bytes()
263 // Enforce maximum overall message payload.
264 if lenp > MaxMessagePayload {
265 str := fmt.Sprintf("message payload is too large - encoded "+
266 "%d bytes, but maximum message payload is %d bytes",
267 lenp, MaxMessagePayload)
268 return totalBytes, messageError("WriteMessage", str)
271 // Enforce maximum message payload based on the message type.
272 mpl := msg.MaxPayloadLength(pver)
273 if uint32(lenp) > mpl {
274 str := fmt.Sprintf("message payload is too large - encoded "+
275 "%d bytes, but maximum message payload size for "+
276 "messages of type [%s] is %d.", lenp, cmd, mpl)
277 return totalBytes, messageError("WriteMessage", str)
280 // Create header for the message.
281 hdr := messageHeader{}
284 hdr.length = uint32(lenp)
285 copy(hdr.checksum[:], chainhash.DoubleHashB(payload)[0:4])
287 // Encode the header for the message. This is done to a buffer
288 // rather than directly to the writer since writeElements doesn't
289 // return the number of bytes written.
290 hw := bytes.NewBuffer(make([]byte, 0, MessageHeaderSize))
291 writeElements(hw, hdr.magic, command, hdr.length, hdr.checksum)
294 n, err := w.Write(hw.Bytes())
297 return totalBytes, err
301 n, err = w.Write(payload)
303 return totalBytes, err
306 // ReadMessageWithEncodingN reads, validates, and parses the next bitcoin Message
307 // from r for the provided protocol version and bitcoin network. It returns the
308 // number of bytes read in addition to the parsed Message and raw bytes which
309 // comprise the message. This function is the same as ReadMessageN except it
310 // allows the caller to specify which message encoding is to to consult when
311 // decoding wire messages.
312 func ReadMessageWithEncodingN(r io.Reader, pver uint32, btcnet BitcoinNet,
313 enc MessageEncoding) (int, Message, []byte, error) {
316 n, hdr, err := readMessageHeader(r)
319 return totalBytes, nil, nil, err
322 // Enforce maximum message payload.
323 if hdr.length > MaxMessagePayload {
324 str := fmt.Sprintf("message payload is too large - header "+
325 "indicates %d bytes, but max message payload is %d "+
326 "bytes.", hdr.length, MaxMessagePayload)
327 return totalBytes, nil, nil, messageError("ReadMessage", str)
331 // Check for messages from the wrong bitcoin network.
332 if hdr.magic != btcnet {
333 discardInput(r, hdr.length)
334 str := fmt.Sprintf("message from other network [%v]", hdr.magic)
335 return totalBytes, nil, nil, messageError("ReadMessage", str)
338 // Check for malformed commands.
339 command := hdr.command
340 if !utf8.ValidString(command) {
341 discardInput(r, hdr.length)
342 str := fmt.Sprintf("invalid command %v", []byte(command))
343 return totalBytes, nil, nil, messageError("ReadMessage", str)
346 // Create struct of appropriate message type based on the command.
347 msg, err := makeEmptyMessage(command)
349 discardInput(r, hdr.length)
350 return totalBytes, nil, nil, messageError("ReadMessage",
354 // Check for maximum length based on the message type as a malicious client
355 // could otherwise create a well-formed header and set the length to max
356 // numbers in order to exhaust the machine's memory.
357 mpl := msg.MaxPayloadLength(pver)
358 if hdr.length > mpl {
359 discardInput(r, hdr.length)
360 str := fmt.Sprintf("payload exceeds max length - header "+
361 "indicates %v bytes, but max payload size for "+
362 "messages of type [%v] is %v.", hdr.length, command, mpl)
363 return totalBytes, nil, nil, messageError("ReadMessage", str)
367 payload := make([]byte, hdr.length)
368 n, err = io.ReadFull(r, payload)
371 return totalBytes, nil, nil, err
375 checksum := chainhash.DoubleHashB(payload)[0:4]
376 if !bytes.Equal(checksum[:], hdr.checksum[:]) {
377 str := fmt.Sprintf("payload checksum failed - header "+
378 "indicates %v, but actual checksum is %v.",
379 hdr.checksum, checksum)
380 return totalBytes, nil, nil, messageError("ReadMessage", str)
383 // Unmarshal message. NOTE: This must be a *bytes.Buffer since the
384 // MsgVersion BtcDecode function requires it.
385 pr := bytes.NewBuffer(payload)
386 err = msg.BtcDecode(pr, pver, enc)
388 return totalBytes, nil, nil, err
391 return totalBytes, msg, payload, nil
394 // ReadMessageN reads, validates, and parses the next bitcoin Message from r for
395 // the provided protocol version and bitcoin network. It returns the number of
396 // bytes read in addition to the parsed Message and raw bytes which comprise the
397 // message. This function is the same as ReadMessage except it also returns the
398 // number of bytes read.
399 func ReadMessageN(r io.Reader, pver uint32, btcnet BitcoinNet) (int, Message, []byte, error) {
400 return ReadMessageWithEncodingN(r, pver, btcnet, BaseEncoding)
403 // ReadMessage reads, validates, and parses the next bitcoin Message from r for
404 // the provided protocol version and bitcoin network. It returns the parsed
405 // Message and raw bytes which comprise the message. This function only differs
406 // from ReadMessageN in that it doesn't return the number of bytes read. This
407 // function is mainly provided for backwards compatibility with the original
408 // API, but it's also useful for callers that don't care about byte counts.
409 func ReadMessage(r io.Reader, pver uint32, btcnet BitcoinNet) (Message, []byte, error) {
410 _, msg, buf, err := ReadMessageN(r, pver, btcnet)