github.com/lbryio/lbcd@v0.22.119/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/lbryio/lbcd/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 8MB.
    27  const MaxBlockPayload = 8000000
    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  	err := readBlockHeader(r, pver, &msg.Header)
    66  	if err != nil {
    67  		return err
    68  	}
    69  
    70  	txCount, err := ReadVarInt(r, pver)
    71  	if err != nil {
    72  		return err
    73  	}
    74  
    75  	// Prevent more transactions than could possibly fit into a block.
    76  	// It would be possible to cause memory exhaustion and panics without
    77  	// a sane upper bound on this count.
    78  	if txCount > maxTxPerBlock {
    79  		str := fmt.Sprintf("too many transactions to fit into a block "+
    80  			"[count %d, max %d]", txCount, maxTxPerBlock)
    81  		return messageError("MsgBlock.BtcDecode", str)
    82  	}
    83  
    84  	msg.Transactions = make([]*MsgTx, 0, txCount)
    85  	for i := uint64(0); i < txCount; i++ {
    86  		tx := MsgTx{}
    87  		err := tx.BtcDecode(r, pver, enc)
    88  		if err != nil {
    89  			return err
    90  		}
    91  		msg.Transactions = append(msg.Transactions, &tx)
    92  	}
    93  
    94  	return nil
    95  }
    96  
    97  // Deserialize decodes a block from r into the receiver using a format that is
    98  // suitable for long-term storage such as a database while respecting the
    99  // Version field in the block.  This function differs from BtcDecode in that
   100  // BtcDecode decodes from the bitcoin wire protocol as it was sent across the
   101  // network.  The wire encoding can technically differ depending on the protocol
   102  // version and doesn't even really need to match the format of a stored block at
   103  // all.  As of the time this comment was written, the encoded block is the same
   104  // in both instances, but there is a distinct difference and separating the two
   105  // allows the API to be flexible enough to deal with changes.
   106  func (msg *MsgBlock) Deserialize(r io.Reader) error {
   107  	// At the current time, there is no difference between the wire encoding
   108  	// at protocol version 0 and the stable long-term storage format.  As
   109  	// a result, make use of BtcDecode.
   110  	//
   111  	// Passing an encoding type of WitnessEncoding to BtcEncode for the
   112  	// MessageEncoding parameter indicates that the transactions within the
   113  	// block are expected to be serialized according to the new
   114  	// serialization structure defined in BIP0141.
   115  	return msg.BtcDecode(r, 0, WitnessEncoding)
   116  }
   117  
   118  // DeserializeNoWitness decodes a block from r into the receiver similar to
   119  // Deserialize, however DeserializeWitness strips all (if any) witness data
   120  // from the transactions within the block before encoding them.
   121  func (msg *MsgBlock) DeserializeNoWitness(r io.Reader) error {
   122  	return msg.BtcDecode(r, 0, BaseEncoding)
   123  }
   124  
   125  // DeserializeTxLoc decodes r in the same manner Deserialize does, but it takes
   126  // a byte buffer instead of a generic reader and returns a slice containing the
   127  // start and length of each transaction within the raw data that is being
   128  // deserialized.
   129  func (msg *MsgBlock) DeserializeTxLoc(r *bytes.Buffer) ([]TxLoc, error) {
   130  	fullLen := r.Len()
   131  
   132  	// At the current time, there is no difference between the wire encoding
   133  	// at protocol version 0 and the stable long-term storage format.  As
   134  	// a result, make use of existing wire protocol functions.
   135  	err := readBlockHeader(r, 0, &msg.Header)
   136  	if err != nil {
   137  		return nil, err
   138  	}
   139  
   140  	txCount, err := ReadVarInt(r, 0)
   141  	if err != nil {
   142  		return nil, err
   143  	}
   144  
   145  	// Prevent more transactions than could possibly fit into a block.
   146  	// It would be possible to cause memory exhaustion and panics without
   147  	// a sane upper bound on this count.
   148  	if txCount > maxTxPerBlock {
   149  		str := fmt.Sprintf("too many transactions to fit into a block "+
   150  			"[count %d, max %d]", txCount, maxTxPerBlock)
   151  		return nil, messageError("MsgBlock.DeserializeTxLoc", str)
   152  	}
   153  
   154  	// Deserialize each transaction while keeping track of its location
   155  	// within the byte stream.
   156  	msg.Transactions = make([]*MsgTx, 0, txCount)
   157  	txLocs := make([]TxLoc, txCount)
   158  	for i := uint64(0); i < txCount; i++ {
   159  		txLocs[i].TxStart = fullLen - r.Len()
   160  		tx := MsgTx{}
   161  		err := tx.Deserialize(r)
   162  		if err != nil {
   163  			return nil, err
   164  		}
   165  		msg.Transactions = append(msg.Transactions, &tx)
   166  		txLocs[i].TxLen = (fullLen - r.Len()) - txLocs[i].TxStart
   167  	}
   168  
   169  	return txLocs, nil
   170  }
   171  
   172  // BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
   173  // This is part of the Message interface implementation.
   174  // See Serialize for encoding blocks to be stored to disk, such as in a
   175  // database, as opposed to encoding blocks for the wire.
   176  func (msg *MsgBlock) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
   177  	err := writeBlockHeader(w, pver, &msg.Header)
   178  	if err != nil {
   179  		return err
   180  	}
   181  
   182  	err = WriteVarInt(w, pver, uint64(len(msg.Transactions)))
   183  	if err != nil {
   184  		return err
   185  	}
   186  
   187  	for _, tx := range msg.Transactions {
   188  		err = tx.BtcEncode(w, pver, enc)
   189  		if err != nil {
   190  			return err
   191  		}
   192  	}
   193  
   194  	return nil
   195  }
   196  
   197  // Serialize encodes the block to w using a format that suitable for long-term
   198  // storage such as a database while respecting the Version field in the block.
   199  // This function differs from BtcEncode in that BtcEncode encodes the block to
   200  // the bitcoin wire protocol in order to be sent across the network.  The wire
   201  // encoding can technically differ depending on the protocol version and doesn't
   202  // even really need to match the format of a stored block at all.  As of the
   203  // time this comment was written, the encoded block is the same in both
   204  // instances, but there is a distinct difference and separating the two allows
   205  // the API to be flexible enough to deal with changes.
   206  func (msg *MsgBlock) Serialize(w io.Writer) error {
   207  	// At the current time, there is no difference between the wire encoding
   208  	// at protocol version 0 and the stable long-term storage format.  As
   209  	// a result, make use of BtcEncode.
   210  	//
   211  	// Passing WitnessEncoding as the encoding type here indicates that
   212  	// each of the transactions should be serialized using the witness
   213  	// serialization structure defined in BIP0141.
   214  	return msg.BtcEncode(w, 0, WitnessEncoding)
   215  }
   216  
   217  // SerializeNoWitness encodes a block to w using an identical format to
   218  // Serialize, with all (if any) witness data stripped from all transactions.
   219  // This method is provided in additon to the regular Serialize, in order to
   220  // allow one to selectively encode transaction witness data to non-upgraded
   221  // peers which are unaware of the new encoding.
   222  func (msg *MsgBlock) SerializeNoWitness(w io.Writer) error {
   223  	return msg.BtcEncode(w, 0, BaseEncoding)
   224  }
   225  
   226  // SerializeSize returns the number of bytes it would take to serialize the
   227  // block, factoring in any witness data within transaction.
   228  func (msg *MsgBlock) SerializeSize() int {
   229  	// Block header bytes + Serialized varint size for the number of
   230  	// transactions.
   231  	n := blockHeaderLen + VarIntSerializeSize(uint64(len(msg.Transactions)))
   232  
   233  	for _, tx := range msg.Transactions {
   234  		n += tx.SerializeSize()
   235  	}
   236  
   237  	return n
   238  }
   239  
   240  // SerializeSizeStripped returns the number of bytes it would take to serialize
   241  // the block, excluding any witness data (if any).
   242  func (msg *MsgBlock) SerializeSizeStripped() int {
   243  	// Block header bytes + Serialized varint size for the number of
   244  	// transactions.
   245  	n := blockHeaderLen + VarIntSerializeSize(uint64(len(msg.Transactions)))
   246  
   247  	for _, tx := range msg.Transactions {
   248  		n += tx.SerializeSizeStripped()
   249  	}
   250  
   251  	return n
   252  }
   253  
   254  // Command returns the protocol command string for the message.  This is part
   255  // of the Message interface implementation.
   256  func (msg *MsgBlock) Command() string {
   257  	return CmdBlock
   258  }
   259  
   260  // MaxPayloadLength returns the maximum length the payload can be for the
   261  // receiver.  This is part of the Message interface implementation.
   262  func (msg *MsgBlock) MaxPayloadLength(pver uint32) uint32 {
   263  	// Block header at 80 bytes + transaction count + max transactions
   264  	// which can vary up to the MaxBlockPayload (including the block header
   265  	// and transaction count).
   266  	return MaxBlockPayload
   267  }
   268  
   269  // BlockHash computes the block identifier hash for this block.
   270  func (msg *MsgBlock) BlockHash() chainhash.Hash {
   271  	return msg.Header.BlockHash()
   272  }
   273  
   274  // TxHashes returns a slice of hashes of all of transactions in this block.
   275  func (msg *MsgBlock) TxHashes() ([]chainhash.Hash, error) {
   276  	hashList := make([]chainhash.Hash, 0, len(msg.Transactions))
   277  	for _, tx := range msg.Transactions {
   278  		hashList = append(hashList, tx.TxHash())
   279  	}
   280  	return hashList, nil
   281  }
   282  
   283  // NewMsgBlock returns a new bitcoin block message that conforms to the
   284  // Message interface.  See MsgBlock for details.
   285  func NewMsgBlock(blockHeader *BlockHeader) *MsgBlock {
   286  	return &MsgBlock{
   287  		Header:       *blockHeader,
   288  		Transactions: make([]*MsgTx, 0, defaultTransactionAlloc),
   289  	}
   290  }