Put the `MerkleBlock` struct at the top of the file
The `MerkleBlock` struct is the main type in this file, put it at the top of the file. This leaves the next most important type, `PartialMerkleTree` below that. Refactor only, no logic changes.
This commit is contained in:
parent
f0d968197a
commit
861fdd6ab1
|
@ -51,6 +51,115 @@ use crate::io;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use self::MerkleBlockError::*;
|
use self::MerkleBlockError::*;
|
||||||
|
|
||||||
|
/// Data structure that represents a block header paired to a partial merkle tree.
|
||||||
|
///
|
||||||
|
/// NOTE: This assumes that the given Block has *at least* 1 transaction. If the Block has 0 txs,
|
||||||
|
/// it will hit an assertion.
|
||||||
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||||
|
pub struct MerkleBlock {
|
||||||
|
/// The block header
|
||||||
|
pub header: block::Header,
|
||||||
|
/// Transactions making up a partial merkle tree
|
||||||
|
pub txn: PartialMerkleTree,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MerkleBlock {
|
||||||
|
/// Create a MerkleBlock from a block, that contains proofs for specific txids.
|
||||||
|
///
|
||||||
|
/// The `block` is a full block containing the header and transactions and `match_txids` is a
|
||||||
|
/// function that returns true for the ids that should be included in the partial merkle tree.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use bitcoin::hash_types::Txid;
|
||||||
|
/// use bitcoin::hashes::hex::FromHex;
|
||||||
|
/// use bitcoin::{Block, MerkleBlock};
|
||||||
|
///
|
||||||
|
/// // Block 80000
|
||||||
|
/// let block_bytes = Vec::from_hex("01000000ba8b9cda965dd8e536670f9ddec10e53aab14b20bacad2\
|
||||||
|
/// 7b9137190000000000190760b278fe7b8565fda3b968b918d5fd997f993b23674c0af3b6fde300b38f33\
|
||||||
|
/// a5914ce6ed5b1b01e32f5702010000000100000000000000000000000000000000000000000000000000\
|
||||||
|
/// 00000000000000ffffffff0704e6ed5b1b014effffffff0100f2052a01000000434104b68a50eaa0287e\
|
||||||
|
/// ff855189f949c1c6e5f58b37c88231373d8a59809cbae83059cc6469d65c665ccfd1cfeb75c6e8e19413\
|
||||||
|
/// bba7fbff9bc762419a76d87b16086eac000000000100000001a6b97044d03da79c005b20ea9c0e1a6d9d\
|
||||||
|
/// c12d9f7b91a5911c9030a439eed8f5000000004948304502206e21798a42fae0e854281abd38bacd1aee\
|
||||||
|
/// d3ee3738d9e1446618c4571d1090db022100e2ac980643b0b82c0e88ffdfec6b64e3e6ba35e7ba5fdd7d\
|
||||||
|
/// 5d6cc8d25c6b241501ffffffff0100f2052a010000001976a914404371705fa9bd789a2fcd52d2c580b6\
|
||||||
|
/// 5d35549d88ac00000000").unwrap();
|
||||||
|
/// let block: Block = bitcoin::consensus::deserialize(&block_bytes).unwrap();
|
||||||
|
///
|
||||||
|
/// // Create a merkle block containing a single transaction
|
||||||
|
/// let txid = "5a4ebf66822b0b2d56bd9dc64ece0bc38ee7844a23ff1d7320a88c5fdb2ad3e2".parse::<Txid>().unwrap();
|
||||||
|
/// let match_txids: Vec<Txid> = vec![txid].into_iter().collect();
|
||||||
|
/// let mb = MerkleBlock::from_block_with_predicate(&block, |t| match_txids.contains(t));
|
||||||
|
///
|
||||||
|
/// // Authenticate and extract matched transaction ids
|
||||||
|
/// let mut matches: Vec<Txid> = vec![];
|
||||||
|
/// let mut index: Vec<u32> = vec![];
|
||||||
|
/// assert!(mb.extract_matches(&mut matches, &mut index).is_ok());
|
||||||
|
/// assert_eq!(txid, matches[0]);
|
||||||
|
/// ```
|
||||||
|
pub fn from_block_with_predicate<F>(block: &Block, match_txids: F) -> Self
|
||||||
|
where
|
||||||
|
F: Fn(&Txid) -> bool,
|
||||||
|
{
|
||||||
|
let block_txids: Vec<_> = block.txdata.iter().map(Transaction::txid).collect();
|
||||||
|
Self::from_header_txids_with_predicate(&block.header, &block_txids, match_txids)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a MerkleBlock from the block's header and txids, that contain proofs for specific txids.
|
||||||
|
///
|
||||||
|
/// The `header` is the block header, `block_txids` is the full list of txids included in the block and
|
||||||
|
/// `match_txids` is a function that returns true for the ids that should be included in the partial merkle tree.
|
||||||
|
pub fn from_header_txids_with_predicate<F>(
|
||||||
|
header: &block::Header,
|
||||||
|
block_txids: &[Txid],
|
||||||
|
match_txids: F,
|
||||||
|
) -> Self
|
||||||
|
where
|
||||||
|
F: Fn(&Txid) -> bool,
|
||||||
|
{
|
||||||
|
let matches: Vec<bool> = block_txids.iter().map(match_txids).collect();
|
||||||
|
|
||||||
|
let pmt = PartialMerkleTree::from_txids(block_txids, &matches);
|
||||||
|
MerkleBlock { header: *header, txn: pmt }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extract the matching txid's represented by this partial merkle tree
|
||||||
|
/// and their respective indices within the partial tree.
|
||||||
|
/// returns Ok(()) on success, or error in case of failure
|
||||||
|
pub fn extract_matches(
|
||||||
|
&self,
|
||||||
|
matches: &mut Vec<Txid>,
|
||||||
|
indexes: &mut Vec<u32>,
|
||||||
|
) -> Result<(), MerkleBlockError> {
|
||||||
|
let merkle_root = self.txn.extract_matches(matches, indexes)?;
|
||||||
|
|
||||||
|
if merkle_root.eq(&self.header.merkle_root) {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(MerkleRootMismatch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Encodable for MerkleBlock {
|
||||||
|
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
|
||||||
|
let len = self.header.consensus_encode(w)? + self.txn.consensus_encode(w)?;
|
||||||
|
Ok(len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Decodable for MerkleBlock {
|
||||||
|
fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
|
||||||
|
Ok(MerkleBlock {
|
||||||
|
header: Decodable::consensus_decode(r)?,
|
||||||
|
txn: Decodable::consensus_decode(r)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Data structure that represents a partial merkle tree.
|
/// Data structure that represents a partial merkle tree.
|
||||||
///
|
///
|
||||||
/// It represents a subset of the txid's of a known block, in a way that
|
/// It represents a subset of the txid's of a known block, in a way that
|
||||||
|
@ -347,115 +456,6 @@ impl Decodable for PartialMerkleTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data structure that represents a block header paired to a partial merkle tree.
|
|
||||||
///
|
|
||||||
/// NOTE: This assumes that the given Block has *at least* 1 transaction. If the Block has 0 txs,
|
|
||||||
/// it will hit an assertion.
|
|
||||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
|
||||||
pub struct MerkleBlock {
|
|
||||||
/// The block header
|
|
||||||
pub header: block::Header,
|
|
||||||
/// Transactions making up a partial merkle tree
|
|
||||||
pub txn: PartialMerkleTree,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MerkleBlock {
|
|
||||||
/// Create a MerkleBlock from a block, that contains proofs for specific txids.
|
|
||||||
///
|
|
||||||
/// The `block` is a full block containing the header and transactions and `match_txids` is a
|
|
||||||
/// function that returns true for the ids that should be included in the partial merkle tree.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// use bitcoin::hash_types::Txid;
|
|
||||||
/// use bitcoin::hashes::hex::FromHex;
|
|
||||||
/// use bitcoin::{Block, MerkleBlock};
|
|
||||||
///
|
|
||||||
/// // Block 80000
|
|
||||||
/// let block_bytes = Vec::from_hex("01000000ba8b9cda965dd8e536670f9ddec10e53aab14b20bacad2\
|
|
||||||
/// 7b9137190000000000190760b278fe7b8565fda3b968b918d5fd997f993b23674c0af3b6fde300b38f33\
|
|
||||||
/// a5914ce6ed5b1b01e32f5702010000000100000000000000000000000000000000000000000000000000\
|
|
||||||
/// 00000000000000ffffffff0704e6ed5b1b014effffffff0100f2052a01000000434104b68a50eaa0287e\
|
|
||||||
/// ff855189f949c1c6e5f58b37c88231373d8a59809cbae83059cc6469d65c665ccfd1cfeb75c6e8e19413\
|
|
||||||
/// bba7fbff9bc762419a76d87b16086eac000000000100000001a6b97044d03da79c005b20ea9c0e1a6d9d\
|
|
||||||
/// c12d9f7b91a5911c9030a439eed8f5000000004948304502206e21798a42fae0e854281abd38bacd1aee\
|
|
||||||
/// d3ee3738d9e1446618c4571d1090db022100e2ac980643b0b82c0e88ffdfec6b64e3e6ba35e7ba5fdd7d\
|
|
||||||
/// 5d6cc8d25c6b241501ffffffff0100f2052a010000001976a914404371705fa9bd789a2fcd52d2c580b6\
|
|
||||||
/// 5d35549d88ac00000000").unwrap();
|
|
||||||
/// let block: Block = bitcoin::consensus::deserialize(&block_bytes).unwrap();
|
|
||||||
///
|
|
||||||
/// // Create a merkle block containing a single transaction
|
|
||||||
/// let txid = "5a4ebf66822b0b2d56bd9dc64ece0bc38ee7844a23ff1d7320a88c5fdb2ad3e2".parse::<Txid>().unwrap();
|
|
||||||
/// let match_txids: Vec<Txid> = vec![txid].into_iter().collect();
|
|
||||||
/// let mb = MerkleBlock::from_block_with_predicate(&block, |t| match_txids.contains(t));
|
|
||||||
///
|
|
||||||
/// // Authenticate and extract matched transaction ids
|
|
||||||
/// let mut matches: Vec<Txid> = vec![];
|
|
||||||
/// let mut index: Vec<u32> = vec![];
|
|
||||||
/// assert!(mb.extract_matches(&mut matches, &mut index).is_ok());
|
|
||||||
/// assert_eq!(txid, matches[0]);
|
|
||||||
/// ```
|
|
||||||
pub fn from_block_with_predicate<F>(block: &Block, match_txids: F) -> Self
|
|
||||||
where
|
|
||||||
F: Fn(&Txid) -> bool,
|
|
||||||
{
|
|
||||||
let block_txids: Vec<_> = block.txdata.iter().map(Transaction::txid).collect();
|
|
||||||
Self::from_header_txids_with_predicate(&block.header, &block_txids, match_txids)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a MerkleBlock from the block's header and txids, that contain proofs for specific txids.
|
|
||||||
///
|
|
||||||
/// The `header` is the block header, `block_txids` is the full list of txids included in the block and
|
|
||||||
/// `match_txids` is a function that returns true for the ids that should be included in the partial merkle tree.
|
|
||||||
pub fn from_header_txids_with_predicate<F>(
|
|
||||||
header: &block::Header,
|
|
||||||
block_txids: &[Txid],
|
|
||||||
match_txids: F,
|
|
||||||
) -> Self
|
|
||||||
where
|
|
||||||
F: Fn(&Txid) -> bool,
|
|
||||||
{
|
|
||||||
let matches: Vec<bool> = block_txids.iter().map(match_txids).collect();
|
|
||||||
|
|
||||||
let pmt = PartialMerkleTree::from_txids(block_txids, &matches);
|
|
||||||
MerkleBlock { header: *header, txn: pmt }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extract the matching txid's represented by this partial merkle tree
|
|
||||||
/// and their respective indices within the partial tree.
|
|
||||||
/// returns Ok(()) on success, or error in case of failure
|
|
||||||
pub fn extract_matches(
|
|
||||||
&self,
|
|
||||||
matches: &mut Vec<Txid>,
|
|
||||||
indexes: &mut Vec<u32>,
|
|
||||||
) -> Result<(), MerkleBlockError> {
|
|
||||||
let merkle_root = self.txn.extract_matches(matches, indexes)?;
|
|
||||||
|
|
||||||
if merkle_root.eq(&self.header.merkle_root) {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(MerkleRootMismatch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Encodable for MerkleBlock {
|
|
||||||
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
|
|
||||||
let len = self.header.consensus_encode(w)? + self.txn.consensus_encode(w)?;
|
|
||||||
Ok(len)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Decodable for MerkleBlock {
|
|
||||||
fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
|
|
||||||
Ok(MerkleBlock {
|
|
||||||
header: Decodable::consensus_decode(r)?,
|
|
||||||
txn: Decodable::consensus_decode(r)?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An error when verifying the merkle block.
|
/// An error when verifying the merkle block.
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
|
|
Loading…
Reference in New Issue