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