github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/wire/msgblock.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  // defaultTransactionAlloc is the default size used for the backing array
    15  // for transactions.  The transaction array will dynamically grow as needed, but
    16  // this figure is intended to provide enough space for the number of
    17  // transactions in the vast majority of blocks without needing to grow the
    18  // backing array multiple times.
    19  const defaultTransactionAlloc = 2048
    20  
    21  // MaxBlocksPerMsg is the maximum number of blocks allowed per message.
    22  const MaxBlocksPerMsg = 500
    23  
    24  // MaxBlockPayload is the maximum bytes a block message can be in bytes.
    25  const MaxBlockPayload = 1000000 // Not actually 1MB which would be 1024 * 1024
    26  
    27  // maxTxPerBlock is the maximum number of transactions that could
    28  // possibly fit into a block.
    29  const maxTxPerBlock = (MaxBlockPayload / minTxPayload) + 1
    30  
    31  // TxLoc holds locator data for the offset and length of where a transaction is
    32  // located within a MsgBlock data buffer.
    33  type TxLoc struct {
    34  	TxStart int
    35  	TxLen   int
    36  }
    37  
    38  // MsgBlock implements the Message interface and represents a bitcoin
    39  // block message.  It is used to deliver block and transaction information in
    40  // response to a getdata message (MsgGetData) for a given block hash.
    41  type MsgBlock struct {
    42  	Header       BlockHeader
    43  	Transactions []*MsgTx
    44  }
    45  
    46  // AddTransaction adds a transaction to the message.
    47  func (msg *MsgBlock) AddTransaction(tx *MsgTx) error {
    48  	msg.Transactions = append(msg.Transactions, tx)
    49  	return nil
    50  
    51  }
    52  
    53  // ClearTransactions removes all transactions from the message.
    54  func (msg *MsgBlock) ClearTransactions() {
    55  	msg.Transactions = make([]*MsgTx, 0, defaultTransactionAlloc)
    56  }
    57  
    58  // BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
    59  // This is part of the Message interface implementation.
    60  // See Deserialize for decoding blocks stored to disk, such as in a database, as
    61  // opposed to decoding blocks from the wire.
    62  func (msg *MsgBlock) BtcDecode(r io.Reader, pver uint32) error {
    63  	err := readBlockHeader(r, pver, &msg.Header)
    64  	if err != nil {
    65  		return err
    66  	}
    67  
    68  	txCount, err := ReadVarInt(r, pver)
    69  	if err != nil {
    70  		return err
    71  	}
    72  
    73  	// Prevent more transactions than could possibly fit into a block.
    74  	// It would be possible to cause memory exhaustion and panics without
    75  	// a sane upper bound on this count.
    76  	if txCount > maxTxPerBlock {
    77  		str := fmt.Sprintf("too many transactions to fit into a block "+
    78  			"[count %d, max %d]", txCount, maxTxPerBlock)
    79  		return messageError("MsgBlock.BtcDecode", str)
    80  	}
    81  
    82  	msg.Transactions = make([]*MsgTx, 0, txCount)
    83  	for i := uint64(0); i < txCount; i++ {
    84  		tx := MsgTx{}
    85  		err := tx.BtcDecode(r, pver)
    86  		if err != nil {
    87  			return err
    88  		}
    89  		msg.Transactions = append(msg.Transactions, &tx)
    90  	}
    91  
    92  	return nil
    93  }
    94  
    95  // Deserialize decodes a block from r into the receiver using a format that is
    96  // suitable for long-term storage such as a database while respecting the
    97  // Version field in the block.  This function differs from BtcDecode in that
    98  // BtcDecode decodes from the bitcoin wire protocol as it was sent across the
    99  // network.  The wire encoding can technically differ depending on the protocol
   100  // version and doesn't even really need to match the format of a stored block at
   101  // all.  As of the time this comment was written, the encoded block is the same
   102  // in both instances, but there is a distinct difference and separating the two
   103  // allows the API to be flexible enough to deal with changes.
   104  func (msg *MsgBlock) Deserialize(r io.Reader) error {
   105  	// At the current time, there is no difference between the wire encoding
   106  	// at protocol version 0 and the stable long-term storage format.  As
   107  	// a result, make use of BtcDecode.
   108  	return msg.BtcDecode(r, 0)
   109  }
   110  
   111  // DeserializeTxLoc decodes r in the same manner Deserialize does, but it takes
   112  // a byte buffer instead of a generic reader and returns a slice containing the
   113  // start and length of each transaction within the raw data that is being
   114  // deserialized.
   115  func (msg *MsgBlock) DeserializeTxLoc(r *bytes.Buffer) ([]TxLoc, error) {
   116  	fullLen := r.Len()
   117  
   118  	// At the current time, there is no difference between the wire encoding
   119  	// at protocol version 0 and the stable long-term storage format.  As
   120  	// a result, make use of existing wire protocol functions.
   121  	err := readBlockHeader(r, 0, &msg.Header)
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  
   126  	txCount, err := ReadVarInt(r, 0)
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  
   131  	// Prevent more transactions than could possibly fit into a block.
   132  	// It would be possible to cause memory exhaustion and panics without
   133  	// a sane upper bound on this count.
   134  	if txCount > maxTxPerBlock {
   135  		str := fmt.Sprintf("too many transactions to fit into a block "+
   136  			"[count %d, max %d]", txCount, maxTxPerBlock)
   137  		return nil, messageError("MsgBlock.DeserializeTxLoc", str)
   138  	}
   139  
   140  	// Deserialize each transaction while keeping track of its location
   141  	// within the byte stream.
   142  	msg.Transactions = make([]*MsgTx, 0, txCount)
   143  	txLocs := make([]TxLoc, txCount)
   144  	for i := uint64(0); i < txCount; i++ {
   145  		txLocs[i].TxStart = fullLen - r.Len()
   146  		tx := MsgTx{}
   147  		err := tx.Deserialize(r)
   148  		if err != nil {
   149  			return nil, err
   150  		}
   151  		msg.Transactions = append(msg.Transactions, &tx)
   152  		txLocs[i].TxLen = (fullLen - r.Len()) - txLocs[i].TxStart
   153  	}
   154  
   155  	return txLocs, nil
   156  }
   157  
   158  // BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
   159  // This is part of the Message interface implementation.
   160  // See Serialize for encoding blocks to be stored to disk, such as in a
   161  // database, as opposed to encoding blocks for the wire.
   162  func (msg *MsgBlock) BtcEncode(w io.Writer, pver uint32) error {
   163  	err := writeBlockHeader(w, pver, &msg.Header)
   164  	if err != nil {
   165  		return err
   166  	}
   167  
   168  	err = WriteVarInt(w, pver, uint64(len(msg.Transactions)))
   169  	if err != nil {
   170  		return err
   171  	}
   172  
   173  	for _, tx := range msg.Transactions {
   174  		err = tx.BtcEncode(w, pver)
   175  		if err != nil {
   176  			return err
   177  		}
   178  	}
   179  
   180  	return nil
   181  }
   182  
   183  // Serialize encodes the block to w using a format that suitable for long-term
   184  // storage such as a database while respecting the Version field in the block.
   185  // This function differs from BtcEncode in that BtcEncode encodes the block to
   186  // the bitcoin wire protocol in order to be sent across the network.  The wire
   187  // encoding can technically differ depending on the protocol version and doesn't
   188  // even really need to match the format of a stored block at all.  As of the
   189  // time this comment was written, the encoded block is the same in both
   190  // instances, but there is a distinct difference and separating the two allows
   191  // the API to be flexible enough to deal with changes.
   192  func (msg *MsgBlock) Serialize(w io.Writer) error {
   193  	// At the current time, there is no difference between the wire encoding
   194  	// at protocol version 0 and the stable long-term storage format.  As
   195  	// a result, make use of BtcEncode.
   196  	return msg.BtcEncode(w, 0)
   197  }
   198  
   199  // SerializeSize returns the number of bytes it would take to serialize the
   200  // the block.
   201  func (msg *MsgBlock) SerializeSize() int {
   202  	// Block header bytes + Serialized varint size for the number of
   203  	// transactions.
   204  	n := blockHeaderLen + VarIntSerializeSize(uint64(len(msg.Transactions)))
   205  
   206  	for _, tx := range msg.Transactions {
   207  		n += tx.SerializeSize()
   208  	}
   209  
   210  	return n
   211  }
   212  
   213  // Command returns the protocol command string for the message.  This is part
   214  // of the Message interface implementation.
   215  func (msg *MsgBlock) Command() string {
   216  	return CmdBlock
   217  }
   218  
   219  // MaxPayloadLength returns the maximum length the payload can be for the
   220  // receiver.  This is part of the Message interface implementation.
   221  func (msg *MsgBlock) MaxPayloadLength(pver uint32) uint32 {
   222  	// Block header at 80 bytes + transaction count + max transactions
   223  	// which can vary up to the MaxBlockPayload (including the block header
   224  	// and transaction count).
   225  	return MaxBlockPayload
   226  }
   227  
   228  // BlockSha computes the block identifier hash for this block.
   229  func (msg *MsgBlock) BlockSha() ShaHash {
   230  	return msg.Header.BlockSha()
   231  }
   232  
   233  // TxShas returns a slice of hashes of all of transactions in this block.
   234  func (msg *MsgBlock) TxShas() ([]ShaHash, error) {
   235  	shaList := make([]ShaHash, 0, len(msg.Transactions))
   236  	for _, tx := range msg.Transactions {
   237  		shaList = append(shaList, tx.TxSha())
   238  	}
   239  	return shaList, nil
   240  }
   241  
   242  // NewMsgBlock returns a new bitcoin block message that conforms to the
   243  // Message interface.  See MsgBlock for details.
   244  func NewMsgBlock(blockHeader *BlockHeader) *MsgBlock {
   245  	return &MsgBlock{
   246  		Header:       *blockHeader,
   247  		Transactions: make([]*MsgTx, 0, defaultTransactionAlloc),
   248  	}
   249  }