github.com/dashpay/godash@v0.0.0-20160726055534-e038a21e0e3d/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  }