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