1use core::{convert, fmt, mem};
9#[cfg(feature = "std")]
10use std::error;
11
12use hashes::{sha256, siphash24, Hash};
13use internals::impl_array_newtype;
14use io::{Read, Write};
15
16use crate::consensus::encode::{self, Decodable, Encodable, VarInt};
17use crate::internal_macros::{impl_bytes_newtype, impl_consensus_encoding};
18use crate::prelude::*;
19use crate::{block, Block, BlockHash, Transaction};
20
21#[derive(Debug, Clone, PartialEq, Eq)]
23#[non_exhaustive]
24pub enum Error {
25 UnknownVersion,
27 InvalidPrefill,
29}
30
31internals::impl_from_infallible!(Error);
32
33impl fmt::Display for Error {
34 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35 match *self {
36 Error::UnknownVersion => write!(f, "an unknown version number was used"),
37 Error::InvalidPrefill => write!(f, "the prefill slice provided was invalid"),
38 }
39 }
40}
41
42#[cfg(feature = "std")]
43impl std::error::Error for Error {
44 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
45 use self::Error::*;
46
47 match *self {
48 UnknownVersion | InvalidPrefill => None,
49 }
50 }
51}
52
53#[derive(PartialEq, Eq, Clone, Debug, PartialOrd, Ord, Hash)]
56pub struct PrefilledTransaction {
57 pub idx: u16,
68 pub tx: Transaction,
70}
71
72impl convert::AsRef<Transaction> for PrefilledTransaction {
73 fn as_ref(&self) -> &Transaction { &self.tx }
74}
75
76impl Encodable for PrefilledTransaction {
77 #[inline]
78 fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
79 Ok(VarInt::from(self.idx).consensus_encode(w)? + self.tx.consensus_encode(w)?)
80 }
81}
82
83impl Decodable for PrefilledTransaction {
84 #[inline]
85 fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
86 let idx = VarInt::consensus_decode(r)?.0;
87 let idx = u16::try_from(idx)
88 .map_err(|_| encode::Error::ParseFailed("BIP152 prefilled tx index out of bounds"))?;
89 let tx = Transaction::consensus_decode(r)?;
90 Ok(PrefilledTransaction { idx, tx })
91 }
92}
93
94#[derive(PartialEq, Eq, Clone, Copy, Hash, Default, PartialOrd, Ord)]
96pub struct ShortId([u8; 6]);
97impl_array_newtype!(ShortId, u8, 6);
98impl_bytes_newtype!(ShortId, 6);
99
100impl ShortId {
101 pub fn calculate_siphash_keys(header: &block::Header, nonce: u64) -> (u64, u64) {
103 let h = {
105 let mut engine = sha256::Hash::engine();
106 header.consensus_encode(&mut engine).expect("engines don't error");
107 nonce.consensus_encode(&mut engine).expect("engines don't error");
108 sha256::Hash::from_engine(engine)
109 };
110
111 (
114 u64::from_le_bytes(h[0..8].try_into().expect("8 byte slice")),
115 u64::from_le_bytes(h[8..16].try_into().expect("8 byte slice")),
116 )
117 }
118
119 pub fn with_siphash_keys<T: AsRef<[u8]>>(txid: &T, siphash_keys: (u64, u64)) -> ShortId {
121 let hash = siphash24::Hash::hash_with_keys(siphash_keys.0, siphash_keys.1, txid.as_ref());
124
125 let mut id = ShortId([0; 6]);
127 id.0.copy_from_slice(&hash[0..6]);
128 id
129 }
130}
131
132impl Encodable for ShortId {
133 #[inline]
134 fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
135 self.0.consensus_encode(w)
136 }
137}
138
139impl Decodable for ShortId {
140 #[inline]
141 fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<ShortId, encode::Error> {
142 Ok(ShortId(Decodable::consensus_decode(r)?))
143 }
144}
145
146#[derive(PartialEq, Eq, Clone, Debug, PartialOrd, Ord, Hash)]
152pub struct HeaderAndShortIds {
153 pub header: block::Header,
155 pub nonce: u64,
157 pub short_ids: Vec<ShortId>,
160 pub prefilled_txs: Vec<PrefilledTransaction>,
163}
164impl_consensus_encoding!(HeaderAndShortIds, header, nonce, short_ids, prefilled_txs);
165
166impl HeaderAndShortIds {
167 pub fn from_block(
178 block: &Block,
179 nonce: u64,
180 version: u32,
181 mut prefill: &[usize],
182 ) -> Result<HeaderAndShortIds, Error> {
183 if version != 1 && version != 2 {
184 return Err(Error::UnknownVersion);
185 }
186
187 let siphash_keys = ShortId::calculate_siphash_keys(&block.header, nonce);
188
189 let mut prefilled = Vec::with_capacity(prefill.len() + 1); let mut short_ids = Vec::with_capacity(block.txdata.len() - prefill.len());
191 let mut last_prefill = 0;
192 for (idx, tx) in block.txdata.iter().enumerate() {
193 let prefill_tx = if prefill.first() == Some(&idx) {
195 prefill = &prefill[1..];
196 true
197 } else {
198 idx == 0 };
200
201 if prefill_tx {
202 let diff_idx = idx - last_prefill;
203 last_prefill = idx + 1;
204 prefilled.push(PrefilledTransaction {
205 idx: diff_idx as u16,
206 tx: match version {
207 1 => {
209 let mut no_witness = tx.clone();
211 no_witness.input.iter_mut().for_each(|i| i.witness.clear());
212 no_witness
213 }
214 2 => tx.clone(),
219 _ => unreachable!(),
220 },
221 });
222 } else {
223 short_ids.push(ShortId::with_siphash_keys(
224 &match version {
225 1 => tx.compute_txid().to_raw_hash(),
226 2 => tx.compute_wtxid().to_raw_hash(),
227 _ => unreachable!(),
228 },
229 siphash_keys,
230 ));
231 }
232 }
233
234 if !prefill.is_empty() {
235 return Err(Error::InvalidPrefill);
236 }
237
238 Ok(HeaderAndShortIds {
239 header: block.header,
240 nonce,
241 prefilled_txs: prefilled,
243 short_ids,
244 })
245 }
246}
247
248#[derive(PartialEq, Eq, Clone, Debug, PartialOrd, Ord, Hash)]
251pub struct BlockTransactionsRequest {
252 pub block_hash: BlockHash,
254 pub indexes: Vec<u64>,
258}
259
260impl Encodable for BlockTransactionsRequest {
261 fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
266 let mut len = self.block_hash.consensus_encode(w)?;
267 len += VarInt(self.indexes.len() as u64).consensus_encode(w)?;
269 let mut last_idx = 0;
270 for idx in &self.indexes {
271 len += VarInt(*idx - last_idx).consensus_encode(w)?;
272 last_idx = *idx + 1; }
274 Ok(len)
275 }
276}
277
278impl Decodable for BlockTransactionsRequest {
279 fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
280 Ok(BlockTransactionsRequest {
281 block_hash: BlockHash::consensus_decode(r)?,
282 indexes: {
283 let nb_indexes = VarInt::consensus_decode(r)?.0 as usize;
285
286 let byte_size = (nb_indexes)
290 .checked_mul(mem::size_of::<Transaction>())
291 .ok_or(encode::Error::ParseFailed("Invalid length"))?;
292 if byte_size > encode::MAX_VEC_SIZE {
293 return Err(encode::Error::OversizedVectorAllocation {
294 requested: byte_size,
295 max: encode::MAX_VEC_SIZE,
296 });
297 }
298
299 let mut indexes = Vec::with_capacity(nb_indexes);
300 let mut last_index: u64 = 0;
301 for _ in 0..nb_indexes {
302 let differential: VarInt = Decodable::consensus_decode(r)?;
303 last_index = match last_index.checked_add(differential.0) {
304 Some(i) => i,
305 None => return Err(encode::Error::ParseFailed("block index overflow")),
306 };
307 indexes.push(last_index);
308 last_index = match last_index.checked_add(1) {
309 Some(i) => i,
310 None => return Err(encode::Error::ParseFailed("block index overflow")),
311 };
312 }
313 indexes
314 },
315 })
316 }
317}
318
319#[derive(Debug, Clone, PartialEq, Eq)]
322#[non_exhaustive]
323pub struct TxIndexOutOfRangeError(u64);
324
325impl fmt::Display for TxIndexOutOfRangeError {
326 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
327 write!(
328 f,
329 "a transaction index is requested that is \
330 out of range from the corresponding block: {}",
331 self.0,
332 )
333 }
334}
335
336#[cfg(feature = "std")]
337impl error::Error for TxIndexOutOfRangeError {
338 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
339}
340
341#[derive(PartialEq, Eq, Clone, Debug, PartialOrd, Ord, Hash)]
344pub struct BlockTransactions {
345 pub block_hash: BlockHash,
347 pub transactions: Vec<Transaction>,
349}
350impl_consensus_encoding!(BlockTransactions, block_hash, transactions);
351
352impl BlockTransactions {
353 pub fn from_request(
356 request: &BlockTransactionsRequest,
357 block: &Block,
358 ) -> Result<BlockTransactions, TxIndexOutOfRangeError> {
359 Ok(BlockTransactions {
360 block_hash: request.block_hash,
361 transactions: {
362 let mut txs = Vec::with_capacity(request.indexes.len());
363 for idx in &request.indexes {
364 if *idx >= block.txdata.len() as u64 {
365 return Err(TxIndexOutOfRangeError(*idx));
366 }
367 txs.push(block.txdata[*idx as usize].clone());
368 }
369 txs
370 },
371 })
372 }
373}
374
375#[cfg(test)]
376mod test {
377 use hex::FromHex;
378
379 use super::*;
380 use crate::blockdata::block::TxMerkleNode;
381 use crate::blockdata::locktime::absolute;
382 use crate::blockdata::transaction;
383 use crate::consensus::encode::{deserialize, serialize};
384 use crate::{Amount, CompactTarget, OutPoint, ScriptBuf, Sequence, TxIn, TxOut, Txid, Witness};
385
386 fn dummy_tx(nonce: &[u8]) -> Transaction {
387 Transaction {
388 version: transaction::Version::ONE,
389 lock_time: absolute::LockTime::from_consensus(2),
390 input: vec![TxIn {
391 previous_output: OutPoint::new(Txid::hash(nonce), 0),
392 script_sig: ScriptBuf::new(),
393 sequence: Sequence(1),
394 witness: Witness::new(),
395 }],
396 output: vec![TxOut { value: Amount::ONE_SAT, script_pubkey: ScriptBuf::new() }],
397 }
398 }
399
400 fn dummy_block() -> Block {
401 Block {
402 header: block::Header {
403 version: block::Version::ONE,
404 prev_blockhash: BlockHash::hash(&[0]),
405 merkle_root: TxMerkleNode::hash(&[1]),
406 time: 2,
407 bits: CompactTarget::from_consensus(3),
408 nonce: 4,
409 },
410 txdata: vec![dummy_tx(&[2]), dummy_tx(&[3]), dummy_tx(&[4])],
411 }
412 }
413
414 #[test]
415 fn test_header_and_short_ids_from_block() {
416 let block = dummy_block();
417
418 let compact = HeaderAndShortIds::from_block(&block, 42, 2, &[]).unwrap();
419 assert_eq!(compact.nonce, 42);
420 assert_eq!(compact.short_ids.len(), 2);
421 assert_eq!(compact.prefilled_txs.len(), 1);
422 assert_eq!(compact.prefilled_txs[0].idx, 0);
423 assert_eq!(&compact.prefilled_txs[0].tx, &block.txdata[0]);
424
425 let compact = HeaderAndShortIds::from_block(&block, 42, 2, &[0, 1, 2]).unwrap();
426 let idxs = compact.prefilled_txs.iter().map(|t| t.idx).collect::<Vec<_>>();
427 assert_eq!(idxs, vec![0, 0, 0]);
428
429 let compact = HeaderAndShortIds::from_block(&block, 42, 2, &[2]).unwrap();
430 let idxs = compact.prefilled_txs.iter().map(|t| t.idx).collect::<Vec<_>>();
431 assert_eq!(idxs, vec![0, 1]);
432 }
433
434 #[test]
435 fn test_compact_block_vector() {
436 let raw_block = Vec::<u8>::from_hex("000000206c750a364035aefd5f81508a08769975116d9195312ee4520dceac39e1fdc62c4dc67473b8e354358c1e610afeaff7410858bd45df43e2940f8a62bd3d5e3ac943c2975cffff7f200000000002020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04016b0101ffffffff020006062a0100000001510000000000000000266a24aa21a9ed4a3d9f3343dafcc0d6f6d4310f2ee5ce273ed34edca6c75db3a73e7f368734200120000000000000000000000000000000000000000000000000000000000000000000000000020000000001021fc20ba2bd745507b8e00679e3b362558f9457db374ca28ffa5243f4c23a4d5f00000000171600147c9dea14ffbcaec4b575e03f05ceb7a81cd3fcbffdffffff915d689be87b43337f42e26033df59807b768223368f189a023d0242d837768900000000171600147c9dea14ffbcaec4b575e03f05ceb7a81cd3fcbffdffffff0200cdf5050000000017a9146803c72d9154a6a20f404bed6d3dcee07986235a8700e1f5050000000017a9144e6a4c7cb5b5562904843bdf816342f4db9f5797870247304402205e9bf6e70eb0e4b495bf483fd8e6e02da64900f290ef8aaa64bb32600d973c450220670896f5d0e5f33473e5f399ab680cc1d25c2d2afd15abd722f04978f28be887012103e4e4d9312b2261af508b367d8ba9be4f01b61d6d6e78bec499845b4f410bcf2702473044022045ac80596a6ac9c8c572f94708709adaf106677221122e08daf8b9741a04f66a022003ccd52a3b78f8fd08058fc04fc0cffa5f4c196c84eae9e37e2a85babe731b57012103e4e4d9312b2261af508b367d8ba9be4f01b61d6d6e78bec499845b4f410bcf276a000000").unwrap();
438 let raw_compact = Vec::<u8>::from_hex("000000206c750a364035aefd5f81508a08769975116d9195312ee4520dceac39e1fdc62c4dc67473b8e354358c1e610afeaff7410858bd45df43e2940f8a62bd3d5e3ac943c2975cffff7f2000000000a4df3c3744da89fa010a6979e971450100020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04016b0101ffffffff020006062a0100000001510000000000000000266a24aa21a9ed4a3d9f3343dafcc0d6f6d4310f2ee5ce273ed34edca6c75db3a73e7f368734200120000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
439
440 let block: Block = deserialize(&raw_block).unwrap();
441 let nonce = 18053200567810711460;
442 let compact = HeaderAndShortIds::from_block(&block, nonce, 2, &[]).unwrap();
443 let compact_expected = deserialize(&raw_compact).unwrap();
444
445 assert_eq!(compact, compact_expected);
446 }
447
448 #[test]
449 fn test_getblocktx_differential_encoding_de_and_serialization() {
450 let testcases = vec![
451 (vec![4, 0, 5, 1, 10], vec![0, 6, 8, 19]),
453 (vec![1, 0], vec![0]),
454 (vec![5, 0, 0, 0, 0, 0], vec![0, 1, 2, 3, 4]),
455 (vec![3, 1, 1, 1], vec![1, 3, 5]),
456 (vec![3, 0, 0, 253, 0, 1], vec![0, 1, 258]), ];
458 let deser_errorcases = vec![
459 vec![2, 255, 254, 255, 255, 255, 255, 255, 255, 255, 0], vec![1, 255, 255, 255, 255, 255, 255, 255, 255, 255], ];
462 for testcase in testcases {
463 {
464 let mut raw: Vec<u8> = [0u8; 32].to_vec();
466 raw.extend(testcase.0.clone());
467 let btr: BlockTransactionsRequest = deserialize(&raw.to_vec()).unwrap();
468 assert_eq!(testcase.1, btr.indexes);
469 }
470 {
471 let raw: Vec<u8> = serialize(&BlockTransactionsRequest {
473 block_hash: Hash::all_zeros(),
474 indexes: testcase.1,
475 });
476 let mut expected_raw: Vec<u8> = [0u8; 32].to_vec();
477 expected_raw.extend(testcase.0);
478 assert_eq!(expected_raw, raw);
479 }
480 }
481 for errorcase in deser_errorcases {
482 {
483 let mut raw: Vec<u8> = [0u8; 32].to_vec();
485 raw.extend(errorcase);
486 assert!(deserialize::<BlockTransactionsRequest>(&raw.to_vec()).is_err());
487 }
488 }
489 }
490
491 #[test]
492 #[cfg(debug_assertions)]
493 #[should_panic] fn test_getblocktx_panic_when_encoding_u64_max() {
495 serialize(&BlockTransactionsRequest {
496 block_hash: Hash::all_zeros(),
497 indexes: vec![u64::MAX],
498 });
499 }
500}