github.com/palcoin-project/palcd@v1.0.0/wire/msgalert.go (about)

     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  }