OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / btcsuite / btcd / wire / msgalert.go
1 // Copyright (c) 2013-2015 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 )
12
13 // MsgAlert contains a payload and a signature:
14 //
15 //        ===============================================
16 //        |   Field         |   Data Type   |   Size    |
17 //        ===============================================
18 //        |   payload       |   []uchar     |   ?       |
19 //        -----------------------------------------------
20 //        |   signature     |   []uchar     |   ?       |
21 //        -----------------------------------------------
22 //
23 // Here payload is an Alert serialized into a byte array to ensure that
24 // versions using incompatible alert formats can still relay
25 // alerts among one another.
26 //
27 // An Alert is the payload deserialized as follows:
28 //
29 //        ===============================================
30 //        |   Field         |   Data Type   |   Size    |
31 //        ===============================================
32 //        |   Version       |   int32       |   4       |
33 //        -----------------------------------------------
34 //        |   RelayUntil    |   int64       |   8       |
35 //        -----------------------------------------------
36 //        |   Expiration    |   int64       |   8       |
37 //        -----------------------------------------------
38 //        |   ID            |   int32       |   4       |
39 //        -----------------------------------------------
40 //        |   Cancel        |   int32       |   4       |
41 //        -----------------------------------------------
42 //        |   SetCancel     |   set<int32>  |   ?       |
43 //        -----------------------------------------------
44 //        |   MinVer        |   int32       |   4       |
45 //        -----------------------------------------------
46 //        |   MaxVer        |   int32       |   4       |
47 //        -----------------------------------------------
48 //        |   SetSubVer     |   set<string> |   ?       |
49 //        -----------------------------------------------
50 //        |   Priority      |   int32       |   4       |
51 //        -----------------------------------------------
52 //        |   Comment       |   string      |   ?       |
53 //        -----------------------------------------------
54 //        |   StatusBar     |   string      |   ?       |
55 //        -----------------------------------------------
56 //        |   Reserved      |   string      |   ?       |
57 //        -----------------------------------------------
58 //        |   Total  (Fixed)                |   45      |
59 //        -----------------------------------------------
60 //
61 // NOTE:
62 //      * string is a VarString i.e VarInt length followed by the string itself
63 //      * set<string> is a VarInt followed by as many number of strings
64 //      * set<int32> is a VarInt followed by as many number of ints
65 //      * fixedAlertSize = 40 + 5*min(VarInt)  = 40 + 5*1 = 45
66 //
67 // Now we can define bounds on Alert size, SetCancel and SetSubVer
68
69 // Fixed size of the alert payload
70 const fixedAlertSize = 45
71
72 // maxSignatureSize is the max size of an ECDSA signature.
73 // NOTE: Since this size is fixed and < 255, the size of VarInt required = 1.
74 const maxSignatureSize = 72
75
76 // maxAlertSize is the maximum size an alert.
77 //
78 // MessagePayload = VarInt(Alert) + Alert + VarInt(Signature) + Signature
79 // MaxMessagePayload = maxAlertSize + max(VarInt) + maxSignatureSize + 1
80 const maxAlertSize = MaxMessagePayload - maxSignatureSize - MaxVarIntPayload - 1
81
82 // maxCountSetCancel is the maximum number of cancel IDs that could possibly
83 // fit into a maximum size alert.
84 //
85 // maxAlertSize = fixedAlertSize + max(SetCancel) + max(SetSubVer) + 3*(string)
86 // for caculating maximum number of cancel IDs, set all other var  sizes to 0
87 // maxAlertSize = fixedAlertSize + (MaxVarIntPayload-1) + x*sizeOf(int32)
88 // x = (maxAlertSize - fixedAlertSize - MaxVarIntPayload + 1) / 4
89 const maxCountSetCancel = (maxAlertSize - fixedAlertSize - MaxVarIntPayload + 1) / 4
90
91 // maxCountSetSubVer is the maximum number of subversions that could possibly
92 // fit into a maximum size alert.
93 //
94 // maxAlertSize = fixedAlertSize + max(SetCancel) + max(SetSubVer) + 3*(string)
95 // for caculating maximum number of subversions, set all other var sizes to 0
96 // maxAlertSize = fixedAlertSize + (MaxVarIntPayload-1) + x*sizeOf(string)
97 // x = (maxAlertSize - fixedAlertSize - MaxVarIntPayload + 1) / sizeOf(string)
98 // subversion would typically be something like "/Satoshi:0.7.2/" (15 bytes)
99 // so assuming < 255 bytes, sizeOf(string) = sizeOf(uint8) + 255 = 256
100 const maxCountSetSubVer = (maxAlertSize - fixedAlertSize - MaxVarIntPayload + 1) / 256
101
102 // Alert contains the data deserialized from the MsgAlert payload.
103 type Alert struct {
104         // Alert format version
105         Version int32
106
107         // Timestamp beyond which nodes should stop relaying this alert
108         RelayUntil int64
109
110         // Timestamp beyond which this alert is no longer in effect and
111         // should be ignored
112         Expiration int64
113
114         // A unique ID number for this alert
115         ID int32
116
117         // All alerts with an ID less than or equal to this number should
118         // cancelled, deleted and not accepted in the future
119         Cancel int32
120
121         // All alert IDs contained in this set should be cancelled as above
122         SetCancel []int32
123
124         // This alert only applies to versions greater than or equal to this
125         // version. Other versions should still relay it.
126         MinVer int32
127
128         // This alert only applies to versions less than or equal to this version.
129         // Other versions should still relay it.
130         MaxVer int32
131
132         // If this set contains any elements, then only nodes that have their
133         // subVer contained in this set are affected by the alert. Other versions
134         // should still relay it.
135         SetSubVer []string
136
137         // Relative priority compared to other alerts
138         Priority int32
139
140         // A comment on the alert that is not displayed
141         Comment string
142
143         // The alert message that is displayed to the user
144         StatusBar string
145
146         // Reserved
147         Reserved string
148 }
149
150 // Serialize encodes the alert to w using the alert protocol encoding format.
151 func (alert *Alert) Serialize(w io.Writer, pver uint32) error {
152         err := writeElements(w, alert.Version, alert.RelayUntil,
153                 alert.Expiration, alert.ID, alert.Cancel)
154         if err != nil {
155                 return err
156         }
157
158         count := len(alert.SetCancel)
159         if count > maxCountSetCancel {
160                 str := fmt.Sprintf("too many cancel alert IDs for alert "+
161                         "[count %v, max %v]", count, maxCountSetCancel)
162                 return messageError("Alert.Serialize", str)
163         }
164         err = WriteVarInt(w, pver, uint64(count))
165         if err != nil {
166                 return err
167         }
168         for i := 0; i < count; i++ {
169                 err = writeElement(w, alert.SetCancel[i])
170                 if err != nil {
171                         return err
172                 }
173         }
174
175         err = writeElements(w, alert.MinVer, alert.MaxVer)
176         if err != nil {
177                 return err
178         }
179
180         count = len(alert.SetSubVer)
181         if count > maxCountSetSubVer {
182                 str := fmt.Sprintf("too many sub versions for alert "+
183                         "[count %v, max %v]", count, maxCountSetSubVer)
184                 return messageError("Alert.Serialize", str)
185         }
186         err = WriteVarInt(w, pver, uint64(count))
187         if err != nil {
188                 return err
189         }
190         for i := 0; i < count; i++ {
191                 err = WriteVarString(w, pver, alert.SetSubVer[i])
192                 if err != nil {
193                         return err
194                 }
195         }
196
197         err = writeElement(w, alert.Priority)
198         if err != nil {
199                 return err
200         }
201         err = WriteVarString(w, pver, alert.Comment)
202         if err != nil {
203                 return err
204         }
205         err = WriteVarString(w, pver, alert.StatusBar)
206         if err != nil {
207                 return err
208         }
209         return WriteVarString(w, pver, alert.Reserved)
210 }
211
212 // Deserialize decodes from r into the receiver using the alert protocol
213 // encoding format.
214 func (alert *Alert) Deserialize(r io.Reader, pver uint32) error {
215         err := readElements(r, &alert.Version, &alert.RelayUntil,
216                 &alert.Expiration, &alert.ID, &alert.Cancel)
217         if err != nil {
218                 return err
219         }
220
221         // SetCancel: first read a VarInt that contains
222         // count - the number of Cancel IDs, then
223         // iterate count times and read them
224         count, err := ReadVarInt(r, pver)
225         if err != nil {
226                 return err
227         }
228         if count > maxCountSetCancel {
229                 str := fmt.Sprintf("too many cancel alert IDs for alert "+
230                         "[count %v, max %v]", count, maxCountSetCancel)
231                 return messageError("Alert.Deserialize", str)
232         }
233         alert.SetCancel = make([]int32, count)
234         for i := 0; i < int(count); i++ {
235                 err := readElement(r, &alert.SetCancel[i])
236                 if err != nil {
237                         return err
238                 }
239         }
240
241         err = readElements(r, &alert.MinVer, &alert.MaxVer)
242         if err != nil {
243                 return err
244         }
245
246         // SetSubVer: similar to SetCancel
247         // but read count number of sub-version strings
248         count, err = ReadVarInt(r, pver)
249         if err != nil {
250                 return err
251         }
252         if count > maxCountSetSubVer {
253                 str := fmt.Sprintf("too many sub versions for alert "+
254                         "[count %v, max %v]", count, maxCountSetSubVer)
255                 return messageError("Alert.Deserialize", str)
256         }
257         alert.SetSubVer = make([]string, count)
258         for i := 0; i < int(count); i++ {
259                 alert.SetSubVer[i], err = ReadVarString(r, pver)
260                 if err != nil {
261                         return err
262                 }
263         }
264
265         err = readElement(r, &alert.Priority)
266         if err != nil {
267                 return err
268         }
269         alert.Comment, err = ReadVarString(r, pver)
270         if err != nil {
271                 return err
272         }
273         alert.StatusBar, err = ReadVarString(r, pver)
274         if err != nil {
275                 return err
276         }
277         alert.Reserved, err = ReadVarString(r, pver)
278         return err
279 }
280
281 // NewAlert returns an new Alert with values provided.
282 func NewAlert(version int32, relayUntil int64, expiration int64,
283         id int32, cancel int32, setCancel []int32, minVer int32,
284         maxVer int32, setSubVer []string, priority int32, comment string,
285         statusBar string) *Alert {
286         return &Alert{
287                 Version:    version,
288                 RelayUntil: relayUntil,
289                 Expiration: expiration,
290                 ID:         id,
291                 Cancel:     cancel,
292                 SetCancel:  setCancel,
293                 MinVer:     minVer,
294                 MaxVer:     maxVer,
295                 SetSubVer:  setSubVer,
296                 Priority:   priority,
297                 Comment:    comment,
298                 StatusBar:  statusBar,
299                 Reserved:   "",
300         }
301 }
302
303 // NewAlertFromPayload returns an Alert with values deserialized from the
304 // serialized payload.
305 func NewAlertFromPayload(serializedPayload []byte, pver uint32) (*Alert, error) {
306         var alert Alert
307         r := bytes.NewReader(serializedPayload)
308         err := alert.Deserialize(r, pver)
309         if err != nil {
310                 return nil, err
311         }
312         return &alert, nil
313 }
314
315 // MsgAlert  implements the Message interface and defines a bitcoin alert
316 // message.
317 //
318 // This is a signed message that provides notifications that the client should
319 // display if the signature matches the key.  bitcoind/bitcoin-qt only checks
320 // against a signature from the core developers.
321 type MsgAlert struct {
322         // SerializedPayload is the alert payload serialized as a string so that the
323         // version can change but the Alert can still be passed on by older
324         // clients.
325         SerializedPayload []byte
326
327         // Signature is the ECDSA signature of the message.
328         Signature []byte
329
330         // Deserialized Payload
331         Payload *Alert
332 }
333
334 // BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
335 // This is part of the Message interface implementation.
336 func (msg *MsgAlert) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
337         var err error
338
339         msg.SerializedPayload, err = ReadVarBytes(r, pver, MaxMessagePayload,
340                 "alert serialized payload")
341         if err != nil {
342                 return err
343         }
344
345         msg.Payload, err = NewAlertFromPayload(msg.SerializedPayload, pver)
346         if err != nil {
347                 msg.Payload = nil
348         }
349
350         msg.Signature, err = ReadVarBytes(r, pver, MaxMessagePayload,
351                 "alert signature")
352         return err
353 }
354
355 // BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
356 // This is part of the Message interface implementation.
357 func (msg *MsgAlert) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
358         var err error
359         var serializedpayload []byte
360         if msg.Payload != nil {
361                 // try to Serialize Payload if possible
362                 r := new(bytes.Buffer)
363                 err = msg.Payload.Serialize(r, pver)
364                 if err != nil {
365                         // Serialize failed - ignore & fallback
366                         // to SerializedPayload
367                         serializedpayload = msg.SerializedPayload
368                 } else {
369                         serializedpayload = r.Bytes()
370                 }
371         } else {
372                 serializedpayload = msg.SerializedPayload
373         }
374         slen := uint64(len(serializedpayload))
375         if slen == 0 {
376                 return messageError("MsgAlert.BtcEncode", "empty serialized payload")
377         }
378         err = WriteVarBytes(w, pver, serializedpayload)
379         if err != nil {
380                 return err
381         }
382         return WriteVarBytes(w, pver, msg.Signature)
383 }
384
385 // Command returns the protocol command string for the message.  This is part
386 // of the Message interface implementation.
387 func (msg *MsgAlert) Command() string {
388         return CmdAlert
389 }
390
391 // MaxPayloadLength returns the maximum length the payload can be for the
392 // receiver.  This is part of the Message interface implementation.
393 func (msg *MsgAlert) MaxPayloadLength(pver uint32) uint32 {
394         // Since this can vary depending on the message, make it the max
395         // size allowed.
396         return MaxMessagePayload
397 }
398
399 // NewMsgAlert returns a new bitcoin alert message that conforms to the Message
400 // interface.  See MsgAlert for details.
401 func NewMsgAlert(serializedPayload []byte, signature []byte) *MsgAlert {
402         return &MsgAlert{
403                 SerializedPayload: serializedPayload,
404                 Signature:         signature,
405                 Payload:           nil,
406         }
407 }