github.com/btcsuite/btcd@v0.24.0/wire/msgblock.go (about)

     1  // Copyright (c) 2013-2016 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  	"github.com/btcsuite/btcd/chaincfg/chainhash"
    13  )
    14  
    15  // defaultTransactionAlloc is the default size used for the backing array
    16  // for transactions.  The transaction array will dynamically grow as needed, but
    17  // this figure is intended to provide enough space for the number of
    18  // transactions in the vast majority of blocks without needing to grow the
    19  // backing array multiple times.
    20  const defaultTransactionAlloc = 2048
    21  
    22  // MaxBlocksPerMsg is the maximum number of blocks allowed per message.
    23  const MaxBlocksPerMsg = 500
    24  
    25  // MaxBlockPayload is the maximum bytes a block message can be in bytes.
    26  // After Segregated Witness, the max block payload has been raised to 4MB.
    27  const MaxBlockPayload = 4000000
    28  
    29  // maxTxPerBlock is the maximum number of transactions that could
    30  // possibly fit into a block.
    31  const maxTxPerBlock = (MaxBlockPayload / minTxPayload) + 1
    32  
    33  // TxLoc holds locator data for the offset and length of where a transaction is
    34  // located within a MsgBlock data buffer.
    35  type TxLoc struct {
    36  	TxStart int
    37  	TxLen   int
    38  }
    39  
    40  // MsgBlock implements the Message interface and represents a bitcoin
    41  // block message.  It is used to deliver block and transaction information in
    42  // response to a getdata message (MsgGetData) for a given block hash.
    43  type MsgBlock struct {
    44  	Header       BlockHeader
    45  	Transactions []*MsgTx
    46  }
    47  
    48  // AddTransaction adds a transaction to the message.
    49  func (msg *MsgBlock) AddTransaction(tx *MsgTx) error {
    50  	msg.Transactions = append(msg.Transactions, tx)
    51  	return nil
    52  
    53  }
    54  
    55  // ClearTransactions removes all transactions from the message.
    56  func (msg *MsgBlock) ClearTransactions() {
    57  	msg.Transactions = make([]*MsgTx, 0, defaultTransactionAlloc)
    58  }
    59  
    60  // BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
    61  // This is part of the Message interface implementation.
    62  // See Deserialize for decoding blocks stored to disk, such as in a database, as
    63  // opposed to decoding blocks from the wire.
    64  func (msg *MsgBlock) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
    65  	buf := binarySerializer.Borrow()
    66  	defer binarySerializer.Return(buf)
    67  
    68  	err := readBlockHeaderBuf(r, pver, &msg.Header, buf)
    69  	if err != nil {
    70  		return err
    71  	}
    72  
    73  	txCount, err := ReadVarIntBuf(r, pver, buf)
    74  	if err != nil {
    75  		return err
    76  	}
    77  
    78  	// Prevent more transactions than could possibly fit into a block.
    79  	// It would be possible to cause memory exhaustion and panics without
    80  	// a sane upper bound on this count.
    81  	if txCount > maxTxPerBlock {
    82  		str := fmt.Sprintf("too many transactions to fit into a block "+
    83  			"[count %d, max %d]", txCount, maxTxPerBlock)
    84  		return messageError("MsgBlock.BtcDecode", str)
    85  	}
    86  
    87  	scriptBuf := scriptPool.Borrow()
    88  	defer scriptPool.Return(scriptBuf)
    89  
    90  	msg.Transactions = make([]*MsgTx, 0, txCount)
    91  	for i := uint64(0); i < txCount; i++ {
    92  		tx := MsgTx{}
    93  		err := tx.btcDecode(r, pver, enc, buf, scriptBuf[:])
    94  		if err != nil {
    95  			return err
    96  		}
    97  		msg.Transactions = append(msg.Transactions, &tx)
    98  	}
    99  
   100  	return nil
   101  }
   102  
   103  // Deserialize decodes a block from r into the receiver using a format that is
   104  // suitable for long-term storage such as a database while respecting the
   105  // Version field in the block.  This function differs from BtcDecode in that
   106  // BtcDecode decodes from the bitcoin wire protocol as it was sent across the
   107  // network.  The wire encoding can technically differ depending on the protocol
   108  // version and doesn't even really need to match the format of a stored block at
   109  // all.  As of the time this comment was written, the encoded block is the same
   110  // in both instances, but there is a distinct difference and separating the two
   111  // allows the API to be flexible enough to deal with changes.
   112  func (msg *MsgBlock) Deserialize(r io.Reader) error {
   113  	// At the current time, there is no difference between the wire encoding
   114  	// at protocol version 0 and the stable long-term storage format.  As
   115  	// a result, make use of BtcDecode.
   116  	//
   117  	// Passing an encoding type of WitnessEncoding to BtcEncode for the
   118  	// MessageEncoding parameter indicates that the transactions within the
   119  	// block are expected to be serialized according to the new
   120  	// serialization structure defined in BIP0141.
   121  	return msg.BtcDecode(r, 0, WitnessEncoding)
   122  }
   123  
   124  // DeserializeNoWitness decodes a block from r into the receiver similar to
   125  // Deserialize, however DeserializeWitness strips all (if any) witness data
   126  // from the transactions within the block before encoding them.
   127  func (msg *MsgBlock) DeserializeNoWitness(r io.Reader) error {
   128  	return msg.BtcDecode(r, 0, BaseEncoding)
   129  }
   130  
   131  // DeserializeTxLoc decodes r in the same manner Deserialize does, but it takes
   132  // a byte buffer instead of a generic reader and returns a slice containing the
   133  // start and length of each transaction within the raw data that is being
   134  // deserialized.
   135  func (msg *MsgBlock) DeserializeTxLoc(r *bytes.Buffer) ([]TxLoc, error) {
   136  	fullLen := r.Len()
   137  
   138  	buf := binarySerializer.Borrow()
   139  	defer binarySerializer.Return(buf)
   140  
   141  	// At the current time, there is no difference between the wire encoding
   142  	// at protocol version 0 and the stable long-term storage format.  As
   143  	// a result, make use of existing wire protocol functions.
   144  	err := readBlockHeaderBuf(r, 0, &msg.Header, buf)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  
   149  	txCount, err := ReadVarIntBuf(r, 0, buf)
   150  	if err != nil {
   151  		return nil, err
   152  	}
   153  
   154  	// Prevent more transactions than could possibly fit into a block.
   155  	// It would be possible to cause memory exhaustion and panics without
   156  	// a sane upper bound on this count.
   157  	if txCount > maxTxPerBlock {
   158  		str := fmt.Sprintf("too many transactions to fit into a block "+
   159  			"[count %d, max %d]", txCount, maxTxPerBlock)
   160  		return nil, messageError("MsgBlock.DeserializeTxLoc", str)
   161  	}
   162  
   163  	scriptBuf := scriptPool.Borrow()
   164  	defer scriptPool.Return(scriptBuf)
   165  
   166  	// Deserialize each transaction while keeping track of its location
   167  	// within the byte stream.
   168  	msg.Transactions = make([]*MsgTx, 0, txCount)
   169  	txLocs := make([]TxLoc, txCount)
   170  	for i := uint64(0); i < txCount; i++ {
   171  		txLocs[i].TxStart = fullLen - r.Len()
   172  		tx := MsgTx{}
   173  		err := tx.btcDecode(r, 0, WitnessEncoding, buf, scriptBuf[:])
   174  		if err != nil {
   175  			return nil, err
   176  		}
   177  		msg.Transactions = append(msg.Transactions, &tx)
   178  		txLocs[i].TxLen = (fullLen - r.Len()) - txLocs[i].TxStart
   179  	}
   180  
   181  	return txLocs, nil
   182  }
   183  
   184  // BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
   185  // This is part of the Message interface implementation.
   186  // See Serialize for encoding blocks to be stored to disk, such as in a
   187  // database, as opposed to encoding blocks for the wire.
   188  func (msg *MsgBlock) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
   189  	buf := binarySerializer.Borrow()
   190  	defer binarySerializer.Return(buf)
   191  
   192  	err := writeBlockHeaderBuf(w, pver, &msg.Header, buf)
   193  	if err != nil {
   194  		return err
   195  	}
   196  
   197  	err = WriteVarIntBuf(w, pver, uint64(len(msg.Transactions)), buf)
   198  	if err != nil {
   199  		return err
   200  	}
   201  
   202  	for _, tx := range msg.Transactions {
   203  		err = tx.btcEncode(w, pver, enc, buf)
   204  		if err != nil {
   205  			return err
   206  		}
   207  	}
   208  
   209  	return nil
   210  }
   211  
   212  // Serialize encodes the block to w using a format that suitable for long-term
   213  // storage such as a database while respecting the Version field in the block.
   214  // This function differs from BtcEncode in that BtcEncode encodes the block to
   215  // the bitcoin wire protocol in order to be sent across the network.  The wire
   216  // encoding can technically differ depending on the protocol version and doesn't
   217  // even really need to match the format of a stored block at all.  As of the
   218  // time this comment was written, the encoded block is the same in both
   219  // instances, but there is a distinct difference and separating the two allows
   220  // the API to be flexible enough to deal with changes.
   221  func (msg *MsgBlock) Serialize(w io.Writer) error {
   222  	// At the current time, there is no difference between the wire encoding
   223  	// at protocol version 0 and the stable long-term storage format.  As
   224  	// a result, make use of BtcEncode.
   225  	//
   226  	// Passing WitnessEncoding as the encoding type here indicates that
   227  	// each of the transactions should be serialized using the witness
   228  	// serialization structure defined in BIP0141.
   229  	return msg.BtcEncode(w, 0, WitnessEncoding)
   230  }
   231  
   232  // SerializeNoWitness encodes a block to w using an identical format to
   233  // Serialize, with all (if any) witness data stripped from all transactions.
   234  // This method is provided in additon to the regular Serialize, in order to
   235  // allow one to selectively encode transaction witness data to non-upgraded
   236  // peers which are unaware of the new encoding.
   237  func (msg *MsgBlock) SerializeNoWitness(w io.Writer) error {
   238  	return msg.BtcEncode(w, 0, BaseEncoding)
   239  }
   240  
   241  // SerializeSize returns the number of bytes it would take to serialize the
   242  // block, factoring in any witness data within transaction.
   243  func (msg *MsgBlock) SerializeSize() int {
   244  	// Block header bytes + Serialized varint size for the number of
   245  	// transactions.
   246  	n := blockHeaderLen + VarIntSerializeSize(uint64(len(msg.Transactions)))
   247  
   248  	for _, tx := range msg.Transactions {
   249  		n += tx.SerializeSize()
   250  	}
   251  
   252  	return n
   253  }
   254  
   255  // SerializeSizeStripped returns the number of bytes it would take to serialize
   256  // the block, excluding any witness data (if any).
   257  func (msg *MsgBlock) SerializeSizeStripped() int {
   258  	// Block header bytes + Serialized varint size for the number of
   259  	// transactions.
   260  	n := blockHeaderLen + VarIntSerializeSize(uint64(len(msg.Transactions)))
   261  
   262  	for _, tx := range msg.Transactions {
   263  		n += tx.SerializeSizeStripped()
   264  	}
   265  
   266  	return n
   267  }
   268  
   269  // Command returns the protocol command string for the message.  This is part
   270  // of the Message interface implementation.
   271  func (msg *MsgBlock) Command() string {
   272  	return CmdBlock
   273  }
   274  
   275  // MaxPayloadLength returns the maximum length the payload can be for the
   276  // receiver.  This is part of the Message interface implementation.
   277  func (msg *MsgBlock) MaxPayloadLength(pver uint32) uint32 {
   278  	// Block header at 80 bytes + transaction count + max transactions
   279  	// which can vary up to the MaxBlockPayload (including the block header
   280  	// and transaction count).
   281  	return MaxBlockPayload
   282  }
   283  
   284  // BlockHash computes the block identifier hash for this block.
   285  func (msg *MsgBlock) BlockHash() chainhash.Hash {
   286  	return msg.Header.BlockHash()
   287  }
   288  
   289  // TxHashes returns a slice of hashes of all of transactions in this block.
   290  func (msg *MsgBlock) TxHashes() ([]chainhash.Hash, error) {
   291  	hashList := make([]chainhash.Hash, 0, len(msg.Transactions))
   292  	for _, tx := range msg.Transactions {
   293  		hashList = append(hashList, tx.TxHash())
   294  	}
   295  	return hashList, nil
   296  }
   297  
   298  // NewMsgBlock returns a new bitcoin block message that conforms to the
   299  // Message interface.  See MsgBlock for details.
   300  func NewMsgBlock(blockHeader *BlockHeader) *MsgBlock {
   301  	return &MsgBlock{
   302  		Header:       *blockHeader,
   303  		Transactions: make([]*MsgTx, 0, defaultTransactionAlloc),
   304  	}
   305  }