msgblock.go raw

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