OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / btcsuite / btcd / wire / message.go
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         "unicode/utf8"
12
13         "github.com/btcsuite/btcd/chaincfg/chainhash"
14 )
15
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 +
18 // checksum 4 bytes.
19 const MessageHeaderSize = 24
20
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
24
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
28
29 // Commands used in bitcoin message headers which describe the type of message.
30 const (
31         CmdVersion     = "version"
32         CmdVerAck      = "verack"
33         CmdGetAddr     = "getaddr"
34         CmdAddr        = "addr"
35         CmdGetBlocks   = "getblocks"
36         CmdInv         = "inv"
37         CmdGetData     = "getdata"
38         CmdNotFound    = "notfound"
39         CmdBlock       = "block"
40         CmdTx          = "tx"
41         CmdGetHeaders  = "getheaders"
42         CmdHeaders     = "headers"
43         CmdPing        = "ping"
44         CmdPong        = "pong"
45         CmdAlert       = "alert"
46         CmdMemPool     = "mempool"
47         CmdFilterAdd   = "filteradd"
48         CmdFilterClear = "filterclear"
49         CmdFilterLoad  = "filterload"
50         CmdMerkleBlock = "merkleblock"
51         CmdReject      = "reject"
52         CmdSendHeaders = "sendheaders"
53         CmdFeeFilter   = "feefilter"
54 )
55
56 // MessageEncoding represents the wire message encoding format to be used.
57 type MessageEncoding uint32
58
59 const (
60         // BaseEncoding encodes all messages in the default format specified
61         // for the Bitcoin wire protocol.
62         BaseEncoding MessageEncoding = 1 << iota
63
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.
67         WitnessEncoding
68 )
69
70 // LatestEncoding is the most recently specified encoding for the Bitcoin wire
71 // protocol.
72 var LatestEncoding = WitnessEncoding
73
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
81         Command() string
82         MaxPayloadLength(uint32) uint32
83 }
84
85 // makeEmptyMessage creates a message of the appropriate concrete type based
86 // on the command.
87 func makeEmptyMessage(command string) (Message, error) {
88         var msg Message
89         switch command {
90         case CmdVersion:
91                 msg = &MsgVersion{}
92
93         case CmdVerAck:
94                 msg = &MsgVerAck{}
95
96         case CmdGetAddr:
97                 msg = &MsgGetAddr{}
98
99         case CmdAddr:
100                 msg = &MsgAddr{}
101
102         case CmdGetBlocks:
103                 msg = &MsgGetBlocks{}
104
105         case CmdBlock:
106                 msg = &MsgBlock{}
107
108         case CmdInv:
109                 msg = &MsgInv{}
110
111         case CmdGetData:
112                 msg = &MsgGetData{}
113
114         case CmdNotFound:
115                 msg = &MsgNotFound{}
116
117         case CmdTx:
118                 msg = &MsgTx{}
119
120         case CmdPing:
121                 msg = &MsgPing{}
122
123         case CmdPong:
124                 msg = &MsgPong{}
125
126         case CmdGetHeaders:
127                 msg = &MsgGetHeaders{}
128
129         case CmdHeaders:
130                 msg = &MsgHeaders{}
131
132         case CmdAlert:
133                 msg = &MsgAlert{}
134
135         case CmdMemPool:
136                 msg = &MsgMemPool{}
137
138         case CmdFilterAdd:
139                 msg = &MsgFilterAdd{}
140
141         case CmdFilterClear:
142                 msg = &MsgFilterClear{}
143
144         case CmdFilterLoad:
145                 msg = &MsgFilterLoad{}
146
147         case CmdMerkleBlock:
148                 msg = &MsgMerkleBlock{}
149
150         case CmdReject:
151                 msg = &MsgReject{}
152
153         case CmdSendHeaders:
154                 msg = &MsgSendHeaders{}
155
156         case CmdFeeFilter:
157                 msg = &MsgFeeFilter{}
158
159         default:
160                 return nil, fmt.Errorf("unhandled command [%s]", command)
161         }
162         return msg, nil
163 }
164
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
171 }
172
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[:])
181         if err != nil {
182                 return n, nil, err
183         }
184         hr := bytes.NewReader(headerBytes[:])
185
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)
190
191         // Strip trailing zeros from command string.
192         hdr.command = string(bytes.TrimRight(command[:], string(0)))
193
194         return n, &hdr, nil
195 }
196
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
200 // header length.
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
205         if n > 0 {
206                 buf := make([]byte, maxSize)
207                 for i := uint32(0); i < numReads; i++ {
208                         io.ReadFull(r, buf)
209                 }
210         }
211         if bytesRemaining > 0 {
212                 buf := make([]byte, bytesRemaining)
213                 io.ReadFull(r, buf)
214         }
215 }
216
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)
222 }
223
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)
231         return err
232 }
233
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
238 // messages.
239 func WriteMessageWithEncodingN(w io.Writer, msg Message, pver uint32,
240         btcnet BitcoinNet, encoding MessageEncoding) (int, error) {
241
242         totalBytes := 0
243
244         // Enforce max command size.
245         var command [CommandSize]byte
246         cmd := msg.Command()
247         if len(cmd) > CommandSize {
248                 str := fmt.Sprintf("command [%s] is too long [max %v]",
249                         cmd, CommandSize)
250                 return totalBytes, messageError("WriteMessage", str)
251         }
252         copy(command[:], []byte(cmd))
253
254         // Encode the message payload.
255         var bw bytes.Buffer
256         err := msg.BtcEncode(&bw, pver, encoding)
257         if err != nil {
258                 return totalBytes, err
259         }
260         payload := bw.Bytes()
261         lenp := len(payload)
262
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)
269         }
270
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)
278         }
279
280         // Create header for the message.
281         hdr := messageHeader{}
282         hdr.magic = btcnet
283         hdr.command = cmd
284         hdr.length = uint32(lenp)
285         copy(hdr.checksum[:], chainhash.DoubleHashB(payload)[0:4])
286
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)
292
293         // Write header.
294         n, err := w.Write(hw.Bytes())
295         totalBytes += n
296         if err != nil {
297                 return totalBytes, err
298         }
299
300         // Write payload.
301         n, err = w.Write(payload)
302         totalBytes += n
303         return totalBytes, err
304 }
305
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) {
314
315         totalBytes := 0
316         n, hdr, err := readMessageHeader(r)
317         totalBytes += n
318         if err != nil {
319                 return totalBytes, nil, nil, err
320         }
321
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)
328
329         }
330
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)
336         }
337
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)
344         }
345
346         // Create struct of appropriate message type based on the command.
347         msg, err := makeEmptyMessage(command)
348         if err != nil {
349                 discardInput(r, hdr.length)
350                 return totalBytes, nil, nil, messageError("ReadMessage",
351                         err.Error())
352         }
353
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)
364         }
365
366         // Read payload.
367         payload := make([]byte, hdr.length)
368         n, err = io.ReadFull(r, payload)
369         totalBytes += n
370         if err != nil {
371                 return totalBytes, nil, nil, err
372         }
373
374         // Test checksum.
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)
381         }
382
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)
387         if err != nil {
388                 return totalBytes, nil, nil, err
389         }
390
391         return totalBytes, msg, payload, nil
392 }
393
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)
401 }
402
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)
411         return msg, buf, err
412 }