diff --git a/crates/bitcoin/src/formatter.rs b/crates/bitcoin/src/formatter.rs index 1680102117..6dfacef329 100644 --- a/crates/bitcoin/src/formatter.rs +++ b/crates/bitcoin/src/formatter.rs @@ -392,16 +392,15 @@ mod tests { #[test] fn test_format_block_header() { let hex_header = parser::tests::sample_block_header(); - let raw_header = RawBlockHeader::from_hex(&hex_header).unwrap(); - let parsed_header = parser::parse_block_header(&raw_header).unwrap(); - assert_eq!(parsed_header.try_format().unwrap(), raw_header.as_bytes()); + let parsed_header = BlockHeader::from_hex(&hex_header).unwrap(); + assert_eq!(hex::encode(parsed_header.try_format().unwrap()), hex_header); } #[test] fn test_format_block_header_testnet() { let hex_header = "00000020b0b3d77b97015b519553423c96642b33ca534c50ecefd133640000000000000029a0a725684aeca24af83e3ba0a3e3ee56adfdf032d19e5acba6d0a262e1580ca354915fd4c8001ac42a7b3a".to_string(); - let raw_header = RawBlockHeader::from_hex(&hex_header).unwrap(); - let parsed_header = parser::parse_block_header(&raw_header).unwrap(); + let raw_header = hex::decode(&hex_header).unwrap(); + let parsed_header = BlockHeader::from_bytes(&raw_header).unwrap(); assert_eq!( parsed_header, @@ -410,7 +409,7 @@ mod tests { target: U256::from_dec_str("1260618571951953247774709397757627131971305851995253681160192").unwrap(), timestamp: 1603359907, version: 536870912, - hash: raw_header.hash(), + hash: sha256d_le(&raw_header), hash_prev_block: H256Le::from_hex_be( "000000000000006433d1efec504c53ca332b64963c425395515b01977bd7b3b0" ), @@ -418,7 +417,7 @@ mod tests { } ); - assert_eq!(parsed_header.try_format().unwrap(), raw_header.as_bytes()); + assert_eq!(hex::encode(parsed_header.try_format().unwrap()), hex_header); } // taken from https://bitcoin.org/en/developer-reference#block-headers diff --git a/crates/bitcoin/src/merkle.rs b/crates/bitcoin/src/merkle.rs index e289e11c7f..6c76f7489d 100644 --- a/crates/bitcoin/src/merkle.rs +++ b/crates/bitcoin/src/merkle.rs @@ -10,6 +10,8 @@ use crate::{ utils::hash256_merkle_step, Error, }; +use codec::{Decode, Encode}; +use scale_info::TypeInfo; use sp_std::prelude::*; // Values taken from https://github.com/bitcoin/bitcoin/blob/78dae8caccd82cfbfd76557f1fb7d7557c7b5edb/src/consensus/consensus.h @@ -24,7 +26,7 @@ const MAX_TRANSACTIONS_IN_PROOF: u32 = MAX_BLOCK_WEIGHT / MIN_TRANSACTION_WEIGHT pub struct MerkleTree; /// Stores the content of a merkle proof -#[derive(Clone)] +#[derive(Encode, Decode, TypeInfo, PartialEq, Default, Clone)] #[cfg_attr(feature = "std", derive(Debug))] pub struct MerkleProof { pub block_header: BlockHeader, diff --git a/crates/bitcoin/src/parser.rs b/crates/bitcoin/src/parser.rs index 9aa44552ef..e491efc1d4 100644 --- a/crates/bitcoin/src/parser.rs +++ b/crates/bitcoin/src/parser.rs @@ -9,7 +9,7 @@ use sha2::{Digest, Sha256}; #[cfg(test)] use mocktopus::macros::mockable; -use crate::{Error, SetCompact}; +use crate::{utils::sha256d_le, Error, SetCompact}; use sp_core::U256; use sp_std::{prelude::*, vec}; @@ -68,8 +68,7 @@ impl Parsable for CompactUint { impl Parsable for BlockHeader { fn parse(raw_bytes: &[u8], position: usize) -> Result<(BlockHeader, usize), Error> { - let slice = raw_bytes.get(position..position + 80).ok_or(Error::EndOfFile)?; - let header_bytes = RawBlockHeader::from_bytes(slice)?; + let header_bytes = raw_bytes.get(position..position + 80).ok_or(Error::EndOfFile)?; let block_header = parse_block_header(&header_bytes)?; Ok((block_header, 80)) } @@ -224,21 +223,24 @@ pub trait FromLeBytes: Sized { impl FromLeBytes for BlockHeader { fn from_le_bytes(bytes: &[u8]) -> Result { - parse_block_header(&RawBlockHeader::from_bytes(bytes)?) + parse_block_header(bytes) } } -// like parse_block_header, but without the version check. This is needed in testing, to test -// with historical data -pub fn parse_block_header_lenient(raw_header: &RawBlockHeader) -> Result { - let mut parser = BytesParser::new(raw_header.as_bytes()); +/// Parses the raw bitcoin header into a Rust struct +/// +/// # Arguments +/// +/// * `header` - An 80-byte Bitcoin header +pub fn parse_block_header(bytes: &[u8]) -> Result { + let mut parser = BytesParser::new(bytes); let version: i32 = parser.parse()?; let hash_prev_block: H256Le = parser.parse()?; let merkle_root: H256Le = parser.parse()?; let timestamp: u32 = parser.parse()?; let target: U256 = parser.parse()?; let nonce: u32 = parser.parse()?; - let hash: H256Le = raw_header.hash(); + let hash: H256Le = sha256d_le(bytes); let block_header = BlockHeader { merkle_root, @@ -253,26 +255,6 @@ pub fn parse_block_header_lenient(raw_header: &RawBlockHeader) -> Result Result { - let block_header = parse_block_header_lenient(raw_header)?; - - if block_header.version < 4 { - // as per bip65, we reject block versions less than 4. Note that the reason - // we can hardcode this, is that bitcoin switched to version 4 in december - // 2015, and the genesis of the bridge will never be set to a genesis from - // before that date. - // see https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki#spv-clients - return Err(Error::InvalidBlockVersion); - } - - Ok(block_header) -} - /// Returns the value of a compactly encoded uint and the number of bytes consumed /// /// # Arguments @@ -528,8 +510,7 @@ pub(crate) mod tests { #[test] fn test_parse_block_header() { let hex_header = sample_block_header(); - let raw_header = RawBlockHeader::from_hex(&hex_header).unwrap(); - let parsed_header = parse_block_header(&raw_header).unwrap(); + let parsed_header = BlockHeader::from_hex(&hex_header).unwrap(); assert_eq!(parsed_header.version, 4); assert_eq!(parsed_header.timestamp, 1415239972); assert_eq!( @@ -550,11 +531,9 @@ pub(crate) mod tests { let valid_header_hex = "04".to_string() + hex_header_without_version; let invalid_header_hex = "03".to_string() + hex_header_without_version; - assert_ok!(parse_block_header( - &RawBlockHeader::from_hex(&valid_header_hex).unwrap() - )); + assert_ok!(BlockHeader::from_hex(&valid_header_hex)); assert_err!( - parse_block_header(&RawBlockHeader::from_hex(&invalid_header_hex).unwrap()), + BlockHeader::from_hex(&invalid_header_hex).unwrap().ensure_version(), Error::InvalidBlockVersion ); } diff --git a/crates/bitcoin/src/script.rs b/crates/bitcoin/src/script.rs index def1f97940..3b58f1dcc5 100644 --- a/crates/bitcoin/src/script.rs +++ b/crates/bitcoin/src/script.rs @@ -1,11 +1,13 @@ use crate::{formatter::Formattable, parser::extract_op_return_data, types::*, Error}; +use codec::{Decode, Encode}; +use scale_info::TypeInfo; use sp_std::{prelude::*, vec}; #[cfg(feature = "std")] use codec::alloc::string::String; /// Bitcoin script -#[derive(PartialEq, Debug, Clone)] +#[derive(Encode, Decode, TypeInfo, PartialEq, Debug, Clone)] pub struct Script { pub(crate) bytes: Vec, } diff --git a/crates/bitcoin/src/types.rs b/crates/bitcoin/src/types.rs index 52669e30be..7285e37386 100644 --- a/crates/bitcoin/src/types.rs +++ b/crates/bitcoin/src/types.rs @@ -7,14 +7,14 @@ pub use crate::merkle::MerkleProof; use crate::{ formatter::{Formattable, TryFormattable}, merkle::MerkleTree, - parser::{extract_address_hash_scriptsig, extract_address_hash_witness}, + parser::{extract_address_hash_scriptsig, extract_address_hash_witness, parse_block_header}, utils::{log2, reverse_endianness, sha256d_le}, Address, Error, PublicKey, Script, }; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; pub use sp_core::{H160, H256, U256}; -use sp_std::{convert::TryFrom, prelude::*, vec}; +use sp_std::{prelude::*, vec}; #[cfg(feature = "std")] use codec::alloc::string::String; @@ -161,76 +161,6 @@ pub enum OpCode { /// Custom Types -/// Bitcoin raw block header (80 bytes) -#[derive(Encode, Decode, Copy, Clone, TypeInfo, MaxEncodedLen)] -pub struct RawBlockHeader([u8; 80]); - -impl Default for RawBlockHeader { - fn default() -> Self { - Self([0; 80]) - } -} - -impl TryFrom> for RawBlockHeader { - type Error = Error; - - fn try_from(v: Vec) -> Result { - RawBlockHeader::from_bytes(v) - } -} - -impl RawBlockHeader { - /// Returns a raw block header from a bytes slice - /// - /// # Arguments - /// - /// * `bytes` - A slice containing the header - pub fn from_bytes>(bytes: B) -> Result { - let slice = bytes.as_ref(); - if slice.len() != 80 { - return Err(Error::InvalidHeaderSize); - } - let mut result = [0u8; 80]; - result.copy_from_slice(slice); - Ok(RawBlockHeader(result)) - } - - /// Returns a raw block header from a bytes slice - /// - /// # Arguments - /// - /// * `bytes` - A slice containing the header - #[cfg(feature = "std")] - pub fn from_hex>(hex_string: T) -> Result { - let bytes = hex::decode(hex_string).map_err(|_e| Error::MalformedHeader)?; - Self::from_bytes(&bytes) - } - - /// Returns the hash of the block header using Bitcoin's double sha256 - pub fn hash(&self) -> H256Le { - sha256d_le(self.as_bytes()) - } - - /// Returns the block header as a slice - pub fn as_bytes(&self) -> &[u8] { - &self.0 - } -} - -impl PartialEq for RawBlockHeader { - fn eq(&self, other: &Self) -> bool { - let self_bytes = &self.0[..]; - let other_bytes = &other.0[..]; - self_bytes == other_bytes - } -} - -impl sp_std::fmt::Debug for RawBlockHeader { - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - f.debug_list().entries(self.0.iter()).finish() - } -} - // Constants pub const P2PKH_SCRIPT_SIZE: u32 = 25; pub const P2SH_SCRIPT_SIZE: u32 = 23; @@ -250,21 +180,66 @@ pub struct BlockHeader { pub target: U256, pub timestamp: u32, pub version: i32, + // TODO: remove hash pub hash: H256Le, pub hash_prev_block: H256Le, pub nonce: u32, } impl BlockHeader { + /// Returns the hash of the block header using Bitcoin's double sha256 + pub fn hash(&self) -> Result { + Ok(sha256d_le(&self.try_format()?)) + } + + pub fn ensure_version(&self) -> Result<(), Error> { + if self.version < 4 { + // as per bip65, we reject block versions less than 4. Note that the reason + // we can hardcode this, is that bitcoin switched to version 4 in december + // 2015, and the genesis of the bridge will never be set to a genesis from + // before that date. + // see https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki#spv-clients + Err(Error::InvalidBlockVersion) + } else { + Ok(()) + } + } + pub fn update_hash(&mut self) -> Result { - let new_hash = sha256d_le(&self.try_format()?); + let new_hash = self.hash()?; self.hash = new_hash; Ok(self.hash) } + + /// Returns a block header from a bytes slice + /// + /// # Arguments + /// + /// * `bytes` - A slice containing the header + pub fn from_bytes>(bytes: B) -> Result { + let slice = bytes.as_ref(); + if slice.len() != 80 { + return Err(Error::InvalidHeaderSize); + } + let mut result = [0u8; 80]; + result.copy_from_slice(slice); + parse_block_header(&result) + } + + /// Returns a block header from a hex string + /// + /// # Arguments + /// + /// * `data` - A string containing the header + #[cfg(feature = "std")] + pub fn from_hex>(data: T) -> Result { + let bytes = hex::decode(data).map_err(|_e| Error::MalformedHeader)?; + Self::from_bytes(&bytes) + } } -#[derive(PartialEq, Clone, Debug)] +#[derive(Encode, Decode, TypeInfo, PartialEq, Clone, Debug)] pub enum TransactionInputSource { /// Spending from transaction with the given hash, from output with the given index FromOutput(H256Le, u32), @@ -273,7 +248,7 @@ pub enum TransactionInputSource { } /// Bitcoin transaction input -#[derive(PartialEq, Clone, Debug)] +#[derive(Encode, Decode, TypeInfo, PartialEq, Clone, Debug)] pub struct TransactionInput { pub source: TransactionInputSource, pub script: Vec, @@ -302,7 +277,7 @@ impl TransactionInput { pub type Value = i64; /// Bitcoin transaction output -#[derive(PartialEq, Debug, Clone)] +#[derive(Encode, Decode, TypeInfo, PartialEq, Debug, Clone)] pub struct TransactionOutput { pub value: Value, pub script: Script, @@ -330,7 +305,7 @@ impl TransactionOutput { /// Bitcoin transaction // Note: the `default` implementation is used only for testing code -#[derive(PartialEq, Debug, Clone, Default)] +#[derive(Encode, Decode, TypeInfo, Default, PartialEq, Debug, Clone)] pub struct Transaction { pub version: i32, pub inputs: Vec, @@ -350,7 +325,7 @@ impl Transaction { } // https://en.bitcoin.it/wiki/NLockTime -#[derive(PartialEq, Debug, Clone)] +#[derive(Encode, Decode, TypeInfo, PartialEq, Debug, Clone)] pub enum LockTime { /// time as unix timestamp Time(u32), diff --git a/crates/btc-relay/src/benchmarking.rs b/crates/btc-relay/src/benchmarking.rs index 08727f7ef4..e9bbeaf579 100644 --- a/crates/btc-relay/src/benchmarking.rs +++ b/crates/btc-relay/src/benchmarking.rs @@ -1,11 +1,8 @@ use super::*; use crate::Pallet as BtcRelay; -use bitcoin::{ - formatter::{Formattable, TryFormattable}, - types::{ - Block, BlockBuilder, RawBlockHeader, Transaction, TransactionBuilder, TransactionInputBuilder, - TransactionInputSource, TransactionOutput, - }, +use bitcoin::types::{ + Block, BlockBuilder, Transaction, TransactionBuilder, TransactionInputBuilder, TransactionInputSource, + TransactionOutput, }; use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite}; use frame_system::RawOrigin; @@ -21,10 +18,7 @@ fn mine_genesis(account_id: T::AccountId, address: &BtcAddress, heigh .mine(U256::from(2).pow(254.into())) .unwrap(); - let raw_block_header = RawBlockHeader::from_bytes(&block.header.try_format().unwrap()).unwrap(); - let block_header = BtcRelay::::parse_raw_block_header(&raw_block_header).unwrap(); - - BtcRelay::::_initialize(account_id, block_header, height).unwrap(); + BtcRelay::::_initialize(account_id, block.header, height).unwrap(); block } @@ -67,10 +61,7 @@ fn mine_block_with_one_tx( .mine(U256::from(2).pow(254.into())) .unwrap(); - let raw_block_header = RawBlockHeader::from_bytes(&block.header.try_format().unwrap()).unwrap(); - let block_header = BtcRelay::::parse_raw_block_header(&raw_block_header).unwrap(); - - BtcRelay::::_store_block_header(&account_id, block_header).unwrap(); + BtcRelay::::_store_block_header(&account_id, block.header).unwrap(); (block, transaction) } @@ -87,8 +78,8 @@ benchmarks! { .with_coinbase(&address, 50, 3) .with_timestamp(1588813835) .mine(U256::from(2).pow(254.into())).unwrap(); - let block_header = RawBlockHeader::from_bytes(&block.header.try_format().unwrap()).unwrap(); - }: _(RawOrigin::Signed(origin), block_header, height) + + }: _(RawOrigin::Signed(origin), block.header, height) store_block_header { let origin: T::AccountId = account("Origin", 0, 0); @@ -104,11 +95,8 @@ benchmarks! { .mine(U256::from(2).pow(254.into())).unwrap(); let init_block_hash = init_block.header.hash; - let raw_block_header = RawBlockHeader::from_bytes(&init_block.header.try_format().unwrap()) - .expect("could not serialize block header"); - let block_header = BtcRelay::::parse_raw_block_header(&raw_block_header).unwrap(); - BtcRelay::::_initialize(origin.clone(), block_header, height).unwrap(); + BtcRelay::::_initialize(origin.clone(), init_block.header, height).unwrap(); let block = BlockBuilder::new() .with_previous_hash(init_block_hash) @@ -117,10 +105,7 @@ benchmarks! { .with_timestamp(1588814835) .mine(U256::from(2).pow(254.into())).unwrap(); - let raw_block_header = RawBlockHeader::from_bytes(&block.header.try_format().unwrap()) - .expect("could not serialize block header"); - - }: _(RawOrigin::Signed(origin), raw_block_header) + }: _(RawOrigin::Signed(origin), block.header) verify_and_validate_transaction { let origin: T::AccountId = account("Origin", 0, 0); @@ -135,12 +120,11 @@ benchmarks! { let (block, transaction) = mine_block_with_one_tx::(origin.clone(), block, &address, value, &op_return); let tx_id = transaction.tx_id(); - let proof = block.merkle_proof(&[tx_id]).unwrap().try_format().unwrap(); - let raw_tx = transaction.format_with(true); + let merkle_proof = block.merkle_proof(&[tx_id]).unwrap(); Security::::set_active_block_number(100u32.into()); - }: _(RawOrigin::Signed(origin), proof, Some(0), raw_tx, value.into(), address, Some(H256::zero())) + }: _(RawOrigin::Signed(origin), merkle_proof, Some(0), transaction, value.into(), address, Some(H256::zero())) verify_transaction_inclusion { let origin: T::AccountId = account("Origin", 0, 0); @@ -156,11 +140,11 @@ benchmarks! { let tx_id = transaction.tx_id(); let tx_block_height = height; - let proof = block.merkle_proof(&[tx_id]).unwrap().try_format().unwrap(); + let merkle_proof = block.merkle_proof(&[tx_id]).unwrap(); Security::::set_active_block_number(100u32.into()); - }: _(RawOrigin::Signed(origin), tx_id, proof, Some(0)) + }: _(RawOrigin::Signed(origin), tx_id, merkle_proof, Some(0)) validate_transaction { let origin: T::AccountId = account("Origin", 0, 0); @@ -172,9 +156,7 @@ benchmarks! { let block = mine_genesis::(origin.clone(), &address, 0); let (_, transaction) = mine_block_with_one_tx::(origin.clone(), block, &address, value, &op_return); - let raw_tx = transaction.format_with(true); - - }: _(RawOrigin::Signed(origin), raw_tx, value.into(), address, Some(H256::from_slice(&op_return))) + }: _(RawOrigin::Signed(origin), transaction, value.into(), address, Some(H256::from_slice(&op_return))) } diff --git a/crates/btc-relay/src/lib.rs b/crates/btc-relay/src/lib.rs index bafc3fe73c..b869510361 100644 --- a/crates/btc-relay/src/lib.rs +++ b/crates/btc-relay/src/lib.rs @@ -69,8 +69,7 @@ use sp_std::{ pub use bitcoin::{self, Address as BtcAddress, PublicKey as BtcPublicKey}; use bitcoin::{ merkle::{MerkleProof, ProofResult}, - parser::{parse_block_header, parse_transaction}, - types::{BlockChain, BlockHeader, H256Le, RawBlockHeader, Transaction, Value}, + types::{BlockChain, BlockHeader, H256Le, Transaction, Value}, Error as BitcoinError, SetCompact, }; pub use types::{OpReturnPaymentData, RichBlockHeader}; @@ -110,7 +109,7 @@ pub mod pallet { /// /// # Arguments /// - /// * `block_header_bytes` - 80 byte raw Bitcoin block header. + /// * `block_header` - Bitcoin block header. /// * `block_height` - starting Bitcoin block height of the submitted block header. /// /// # @@ -134,12 +133,12 @@ pub mod pallet { #[transactional] pub fn initialize( origin: OriginFor, - raw_block_header: RawBlockHeader, + mut block_header: BlockHeader, block_height: u32, ) -> DispatchResultWithPostInfo { let relayer = ensure_signed(origin)?; - let block_header = Self::parse_raw_block_header(&raw_block_header)?; + Self::_validate_block_header(&mut block_header)?; Self::_initialize(relayer, block_header, block_height)?; // don't take tx fees on success @@ -150,7 +149,7 @@ pub mod pallet { /// /// # Arguments /// - /// * `raw_block_header` - 80 byte raw Bitcoin block header. + /// * `block_header` - Bitcoin block header. /// /// # /// Key: C (len of chains), P (len of positions) @@ -179,28 +178,25 @@ pub mod pallet { #[pallet::call_index(1)] #[pallet::weight(::WeightInfo::store_block_header())] #[transactional] - pub fn store_block_header( - origin: OriginFor, - raw_block_header: RawBlockHeader, - ) -> DispatchResultWithPostInfo { + pub fn store_block_header(origin: OriginFor, mut block_header: BlockHeader) -> DispatchResultWithPostInfo { let relayer = ensure_signed(origin)?; - let block_header = Self::parse_raw_block_header(&raw_block_header)?; + Self::_validate_block_header(&mut block_header)?; Self::_store_block_header(&relayer, block_header)?; // don't take tx fees on success Ok(Pays::No.into()) } - /// Verifies the inclusion of `tx_id` into the relay, and validates the given raw Bitcoin transaction, according + /// Verifies the inclusion of `tx_id` into the relay, and validates the given Bitcoin transaction, according /// to the supported transaction format (see ) /// /// # Arguments /// - /// * `raw_merkle_proof` - The raw merkle proof as returned by bitcoin `gettxoutproof` + /// * `merkle_proof` - The merkle proof as returned by bitcoin `gettxoutproof` /// * `confirmations` - The number of confirmations needed to accept the proof. If `none`, the value stored in /// the StableBitcoinConfirmations storage item is used. - /// * `raw_tx` - raw Bitcoin transaction + /// * `transaction` - The Bitcoin transaction /// * `expected_btc` - expected amount of BTC (satoshis) sent to the recipient /// * `recipient_btc_address` - 20 byte Bitcoin address of recipient of the BTC in the 1st / payment UTXO /// * `op_return_id` - 32 byte hash identifier expected in OP_RETURN (replay protection) @@ -209,17 +205,14 @@ pub mod pallet { #[transactional] pub fn verify_and_validate_transaction( origin: OriginFor, - raw_merkle_proof: Vec, + merkle_proof: MerkleProof, confirmations: Option, - raw_tx: Vec, + transaction: Transaction, expected_btc: Value, recipient_btc_address: BtcAddress, op_return_id: Option, ) -> DispatchResultWithPostInfo { let _ = ensure_signed(origin)?; - - let transaction = Self::parse_transaction(&raw_tx)?; - let merkle_proof = Self::parse_merkle_proof(&raw_merkle_proof)?; Self::_verify_transaction_inclusion(transaction.tx_id(), merkle_proof, confirmations)?; Self::_validate_transaction(transaction, expected_btc, recipient_btc_address, op_return_id)?; Ok(().into()) @@ -230,7 +223,7 @@ pub mod pallet { /// # Arguments /// /// * `tx_id` - The hash of the transaction to check for - /// * `raw_merkle_proof` - The raw merkle proof as returned by bitcoin `gettxoutproof` + /// * `merkle_proof` - The merkle proof as returned by bitcoin `gettxoutproof` /// * `confirmations` - The number of confirmations needed to accept the proof. If `none`, the value stored in /// the `StableBitcoinConfirmations` storage item is used. /// @@ -251,23 +244,21 @@ pub mod pallet { pub fn verify_transaction_inclusion( origin: OriginFor, tx_id: H256Le, - raw_merkle_proof: Vec, + merkle_proof: MerkleProof, confirmations: Option, ) -> DispatchResultWithPostInfo { let _ = ensure_signed(origin)?; - - let merkle_proof = Self::parse_merkle_proof(&raw_merkle_proof)?; Self::_verify_transaction_inclusion(tx_id, merkle_proof, confirmations)?; Ok(().into()) } - /// Validates a given raw Bitcoin transaction, according to the supported transaction + /// Validates a given Bitcoin transaction, according to the supported transaction /// format (see ) /// This DOES NOT check if the transaction is included in a block, nor does it guarantee that the /// transaction is fully valid according to the consensus (needs full node). /// /// # Arguments - /// * `raw_tx` - raw Bitcoin transaction + /// * `transaction` - Bitcoin transaction /// * `expected_btc` - expected amount of BTC (satoshis) sent to the recipient /// * `recipient_btc_address` - expected Bitcoin address of recipient (p2sh, p2pkh, p2wpkh) /// * `op_return_id` - 32 byte hash identifier expected in OP_RETURN (replay protection) @@ -276,15 +267,12 @@ pub mod pallet { #[transactional] pub fn validate_transaction( origin: OriginFor, - raw_tx: Vec, + transaction: Transaction, expected_btc: Value, recipient_btc_address: BtcAddress, op_return_id: Option, ) -> DispatchResultWithPostInfo { let _ = ensure_signed(origin)?; - - let transaction = Self::parse_transaction(&raw_tx)?; - Self::_validate_transaction(transaction, expected_btc, recipient_btc_address, op_return_id)?; Ok(().into()) } @@ -522,7 +510,7 @@ pub const DIFFICULTY_ADJUSTMENT_INTERVAL: u32 = 2016; // https://github.com/bitcoin/bitcoin/blob/5ba5becbb5d8c794efe579caeea7eea64f895a13/src/chainparams.cpp#L78 pub const TARGET_SPACING: u32 = 10 * 60; -/// Accepted maximum number of transaction outputs for validation of redeem & replace requests +/// Accepted maximum number of transaction outputs for validation of redeem/replace/refund /// See: pub const ACCEPTED_MAX_TRANSACTION_OUTPUTS: usize = 3; @@ -635,8 +623,10 @@ impl Pallet { Ok(()) } - pub fn parse_raw_block_header(raw_block_header: &RawBlockHeader) -> Result { - Ok(parse_block_header(raw_block_header).map_err(Error::::from)?) + pub fn _validate_block_header(block_header: &mut BlockHeader) -> Result<(), DispatchError> { + block_header.ensure_version().map_err(Error::::from)?; + block_header.update_hash().map_err(Error::::from)?; + Ok(()) } // helper for the dispatchable @@ -701,7 +691,7 @@ impl Pallet { // Verify that the transaction is indeed included in the main chain Self::_verify_transaction_inclusion(transaction.tx_id(), merkle_proof, None)?; - // Parse transaction and check that it matches the given parameters + // Check that the transaction matches the given parameters Self::validate_op_return_transaction(transaction, recipient_btc_address, expected_btc, op_return_id)?; Ok(()) } @@ -1007,19 +997,11 @@ impl Pallet { // ********************************* // Wrapper functions around bitcoin lib for testing purposes - pub fn parse_transaction(raw_tx: &[u8]) -> Result { - Ok(parse_transaction(&raw_tx).map_err(Error::::from)?) - } - - pub fn parse_merkle_proof(raw_merkle_proof: &[u8]) -> Result { - MerkleProof::parse(&raw_merkle_proof).map_err(|err| Error::::from(err).into()) - } - fn verify_merkle_proof(merkle_proof: &MerkleProof) -> Result { merkle_proof.verify_proof().map_err(|err| Error::::from(err).into()) } - /// Parses and verifies a raw Bitcoin block header. + /// Verifies a Bitcoin block header. /// /// # Arguments /// diff --git a/crates/btc-relay/src/tests.rs b/crates/btc-relay/src/tests.rs index 923a511950..79709c1636 100644 --- a/crates/btc-relay/src/tests.rs +++ b/crates/btc-relay/src/tests.rs @@ -6,7 +6,7 @@ use crate::{ext, mock::*, types::*, BtcAddress, Error, DIFFICULTY_ADJUSTMENT_INT type Event = crate::Event; use crate::{Chains, ChainsIndex}; -use bitcoin::{formatter::TryFormattable, merkle::*, parser::*, types::*}; +use bitcoin::{merkle::*, parser::*, types::*}; use frame_support::{assert_err, assert_ok}; use mocktopus::mocking::*; use sp_std::{ @@ -493,8 +493,7 @@ mod store_block_header_tests { } fn parse_from_hex(hex_string: &str) -> BlockHeader { - let raw = RawBlockHeader::from_hex(hex_string).unwrap(); - parse_block_header_lenient(&raw).unwrap() + BlockHeader::from_hex(hex_string).unwrap() } #[test] @@ -795,13 +794,11 @@ fn test_verify_block_header_no_retarget_succeeds() { let block_height: u32 = 100; let genesis_header = sample_parsed_genesis_header(chain_id, block_height); - let raw_first_header = RawBlockHeader::from_hex(sample_raw_first_header()).unwrap(); + let block_header = BlockHeader::from_hex(sample_raw_first_header()).unwrap(); // Not duplicate block BTCRelay::block_header_exists.mock_safe(move |_| MockResult::Return(false)); - let block_header = parse_block_header_lenient(&raw_first_header).unwrap(); - assert_ok!(BTCRelay::verify_block_header( &block_header, genesis_header.block_height + 1, @@ -819,14 +816,10 @@ fn test_verify_block_header_correct_retarget_increase_succeeds() { // Sample interval with INCREASING target let retarget_headers = sample_retarget_interval_increase(); - let prev_block_header_rich = RichBlockHeader::::new( - parse_block_header_lenient(&retarget_headers[1]).unwrap(), - chain_id, - block_height, - Default::default(), - ); + let prev_block_header_rich = + RichBlockHeader::::new(retarget_headers[1], chain_id, block_height, Default::default()); - let curr_block_header = parse_block_header_lenient(&retarget_headers[2]).unwrap(); + let curr_block_header = retarget_headers[2]; // Prev block exists BTCRelay::get_block_header_from_hash.mock_safe(move |_| MockResult::Return(Ok(prev_block_header_rich))); // Not duplicate block @@ -834,7 +827,7 @@ fn test_verify_block_header_correct_retarget_increase_succeeds() { // Compute new target returns target of submitted header (i.e., correct) BTCRelay::compute_new_target.mock_safe(move |_, _| MockResult::Return(Ok(curr_block_header.target))); - let block_header = parse_block_header_lenient(&retarget_headers[2]).unwrap(); + let block_header = retarget_headers[2]; assert_ok!(BTCRelay::verify_block_header( &block_header, prev_block_header_rich.block_height + 1, @@ -852,20 +845,16 @@ fn test_verify_block_header_correct_retarget_decrease_succeeds() { // Sample interval with DECREASING target let retarget_headers = sample_retarget_interval_decrease(); - let prev_block_header_rich = RichBlockHeader::::new( - parse_block_header(&retarget_headers[1]).unwrap(), - chain_id, - block_height, - Default::default(), - ); + let prev_block_header_rich = + RichBlockHeader::::new(retarget_headers[1], chain_id, block_height, Default::default()); - let curr_block_header = parse_block_header(&retarget_headers[2]).unwrap(); + let curr_block_header = retarget_headers[2]; // Not duplicate block BTCRelay::block_header_exists.mock_safe(move |_| MockResult::Return(false)); // Compute new target returns target of submitted header (i.e., correct) BTCRelay::compute_new_target.mock_safe(move |_, _| MockResult::Return(Ok(curr_block_header.target))); - let block_header = BTCRelay::parse_raw_block_header(&retarget_headers[2]).unwrap(); + let block_header = &retarget_headers[2]; assert_ok!(BTCRelay::verify_block_header( &block_header, prev_block_header_rich.block_height + 1, @@ -882,20 +871,16 @@ fn test_verify_block_header_missing_retarget_succeeds() { let block_height: u32 = 2015; let retarget_headers = sample_retarget_interval_increase(); - let prev_block_header_rich = RichBlockHeader::::new( - parse_block_header_lenient(&retarget_headers[1]).unwrap(), - chain_id, - block_height, - Default::default(), - ); + let prev_block_header_rich = + RichBlockHeader::::new(retarget_headers[1], chain_id, block_height, Default::default()); - let curr_block_header = parse_block_header_lenient(&retarget_headers[2]).unwrap(); + let curr_block_header = retarget_headers[2]; // Not duplicate block BTCRelay::block_header_exists.mock_safe(move |_| MockResult::Return(false)); // Compute new target returns HIGHER target BTCRelay::compute_new_target.mock_safe(move |_, _| MockResult::Return(Ok(curr_block_header.target + 1))); - let block_header = parse_block_header_lenient(&retarget_headers[2]).unwrap(); + let block_header = retarget_headers[2]; assert_err!( BTCRelay::verify_block_header( &block_header, @@ -914,15 +899,11 @@ fn test_compute_new_target() { let block_height: u32 = 2016; let retarget_headers = sample_retarget_interval_increase(); - let last_retarget_time = parse_block_header_lenient(&retarget_headers[0]).unwrap().timestamp as u64; - let prev_block_header = RichBlockHeader::::new( - parse_block_header_lenient(&retarget_headers[1]).unwrap(), - chain_id, - block_height, - Default::default(), - ); + let last_retarget_time = retarget_headers[0].timestamp as u64; + let prev_block_header = + RichBlockHeader::::new(retarget_headers[1], chain_id, block_height, Default::default()); - let curr_block_header = parse_block_header_lenient(&retarget_headers[2]).unwrap(); + let curr_block_header = retarget_headers[2]; BTCRelay::get_last_retarget_time.mock_safe(move |_, _| MockResult::Return(Ok(last_retarget_time))); @@ -949,8 +930,7 @@ fn test_verify_block_header_duplicate_fails() { MockResult::Return(true) }); - let raw_first_header = RawBlockHeader::from_hex(sample_raw_first_header()).unwrap(); - let first_header = parse_block_header_lenient(&raw_first_header).unwrap(); + let first_header = BlockHeader::from_hex(sample_raw_first_header()).unwrap(); assert_err!( BTCRelay::verify_block_header(&first_header, genesis_header.block_height + 1, genesis_header), TestError::DuplicateBlock @@ -967,12 +947,11 @@ fn test_verify_block_header_low_diff_fails() { let genesis_header = sample_parsed_genesis_header(chain_id, block_height); // block header with high target but weak hash - let raw_first_header_weak = RawBlockHeader::from_hex(sample_raw_first_header_low_diff()).unwrap(); + let first_header_weak = BlockHeader::from_hex(sample_raw_first_header_low_diff()).unwrap(); // submitted block does not yet exist BTCRelay::block_header_exists.mock_safe(move |_| MockResult::Return(false)); - let first_header_weak = parse_block_header_lenient(&raw_first_header_weak).unwrap(); assert_err!( BTCRelay::verify_block_header(&first_header_weak, genesis_header.block_height + 1, genesis_header), TestError::LowDiff @@ -983,18 +962,17 @@ fn test_verify_block_header_low_diff_fails() { #[test] fn test_validate_transaction_succeeds_with_payment() { run_test(|| { - let raw_tx = hex::decode(sample_accepted_transaction()).unwrap(); let minimum_btc: i64 = 2500200000; let recipient_btc_address = BtcAddress::P2SH(H160::from_str(&"66c7060feb882664ae62ffad0051fe843e318e85").unwrap()); let outputs = vec![sample_valid_payment_output()]; - BTCRelay::parse_transaction.mock_safe(move |_| MockResult::Return(Ok(sample_transaction_parsed(&outputs)))); + let transaction = sample_transaction_parsed(&outputs); assert_ok!(BTCRelay::validate_transaction( RuntimeOrigin::signed(3), - raw_tx, + transaction, minimum_btc, recipient_btc_address, None, @@ -1005,7 +983,6 @@ fn test_validate_transaction_succeeds_with_payment() { #[test] fn test_validate_transaction_succeeds_with_payment_and_op_return() { run_test(|| { - let raw_tx = hex::decode(sample_accepted_transaction()).unwrap(); let minimum_btc: i64 = 2500200000; let recipient_btc_address = BtcAddress::P2SH(H160::from_str(&"66c7060feb882664ae62ffad0051fe843e318e85").unwrap()); @@ -1014,11 +991,11 @@ fn test_validate_transaction_succeeds_with_payment_and_op_return() { let outputs = vec![sample_valid_payment_output(), sample_valid_data_output()]; - BTCRelay::parse_transaction.mock_safe(move |_| MockResult::Return(Ok(sample_transaction_parsed(&outputs)))); + let transaction = sample_transaction_parsed(&outputs); assert_ok!(BTCRelay::validate_transaction( RuntimeOrigin::signed(3), - raw_tx, + transaction, minimum_btc, recipient_btc_address, Some(H256::from_slice(&op_return_id)) @@ -1029,7 +1006,6 @@ fn test_validate_transaction_succeeds_with_payment_and_op_return() { #[test] fn test_validate_transaction_succeeds_with_op_return_and_payment() { run_test(|| { - let raw_tx = hex::decode(sample_accepted_transaction()).unwrap(); let minimum_btc: i64 = 2500200000; let recipient_btc_address = BtcAddress::P2SH(H160::from_str(&"66c7060feb882664ae62ffad0051fe843e318e85").unwrap()); @@ -1038,11 +1014,11 @@ fn test_validate_transaction_succeeds_with_op_return_and_payment() { let outputs = vec![sample_valid_data_output(), sample_valid_payment_output()]; - BTCRelay::parse_transaction.mock_safe(move |_| MockResult::Return(Ok(sample_transaction_parsed(&outputs)))); + let transaction = sample_transaction_parsed(&outputs); assert_ok!(BTCRelay::validate_transaction( RuntimeOrigin::signed(3), - raw_tx, + transaction, minimum_btc, recipient_btc_address, Some(H256::from_slice(&op_return_id)) @@ -1053,7 +1029,6 @@ fn test_validate_transaction_succeeds_with_op_return_and_payment() { #[test] fn test_validate_transaction_succeeds_with_payment_and_refund_and_op_return() { run_test(|| { - let raw_tx = hex::decode(sample_accepted_transaction()).unwrap(); let minimum_btc: i64 = 2500200000; let recipient_btc_address = BtcAddress::P2SH(H160::from_str(&"66c7060feb882664ae62ffad0051fe843e318e85").unwrap()); @@ -1066,11 +1041,11 @@ fn test_validate_transaction_succeeds_with_payment_and_refund_and_op_return() { sample_valid_data_output(), ]; - BTCRelay::parse_transaction.mock_safe(move |_| MockResult::Return(Ok(sample_transaction_parsed(&outputs)))); + let transaction = sample_transaction_parsed(&outputs); assert_ok!(BTCRelay::validate_transaction( RuntimeOrigin::signed(3), - raw_tx, + transaction, minimum_btc, recipient_btc_address, Some(H256::from_slice(&op_return_id)) @@ -1081,9 +1056,6 @@ fn test_validate_transaction_succeeds_with_payment_and_refund_and_op_return() { #[test] fn test_validate_transaction_invalid_no_outputs_fails() { run_test(|| { - // Simulate input (we mock the parsed transaction) - let raw_tx = hex::decode(sample_accepted_transaction()).unwrap(); - let minimum_btc: i64 = 2500200000; let recipient_btc_address = BtcAddress::P2SH(H160::from_str(&"66c7060feb882664ae62ffad0051fe843e318e85").unwrap()); @@ -1092,12 +1064,12 @@ fn test_validate_transaction_invalid_no_outputs_fails() { // missing required data output let outputs = vec![sample_valid_payment_output()]; - BTCRelay::parse_transaction.mock_safe(move |_| MockResult::Return(Ok(sample_transaction_parsed(&outputs)))); + let transaction = sample_transaction_parsed(&outputs); assert_err!( BTCRelay::validate_transaction( RuntimeOrigin::signed(3), - raw_tx, + transaction, minimum_btc, recipient_btc_address, Some(H256::from_slice(&op_return_id)) @@ -1110,9 +1082,6 @@ fn test_validate_transaction_invalid_no_outputs_fails() { #[test] fn test_validate_transaction_insufficient_payment_value_fails() { run_test(|| { - // Simulate input (we mock the parsed transaction) - let raw_tx = vec![0u8; 342]; - let minimum_btc: i64 = 2500200000; let recipient_btc_address = BtcAddress::P2SH(H160::from_str(&"66c7060feb882664ae62ffad0051fe843e318e85").unwrap()); @@ -1121,12 +1090,12 @@ fn test_validate_transaction_insufficient_payment_value_fails() { let outputs = vec![sample_insufficient_value_payment_output(), sample_valid_data_output()]; - BTCRelay::parse_transaction.mock_safe(move |_| MockResult::Return(Ok(sample_transaction_parsed(&outputs)))); + let transaction = sample_transaction_parsed(&outputs); assert_err!( BTCRelay::validate_transaction( RuntimeOrigin::signed(3), - raw_tx, + transaction, minimum_btc, recipient_btc_address, Some(H256::from_slice(&op_return_id)) @@ -1139,9 +1108,6 @@ fn test_validate_transaction_insufficient_payment_value_fails() { #[test] fn test_validate_transaction_wrong_recipient_fails() { run_test(|| { - // Simulate input (we mock the parsed transaction) - let raw_tx = vec![0u8; 342]; - let minimum_btc: i64 = 2500200000; let recipient_btc_address = BtcAddress::P2SH(H160::from_str(&"66c7060feb882664ae62ffad0051fe843e318e85").unwrap()); @@ -1154,12 +1120,12 @@ fn test_validate_transaction_wrong_recipient_fails() { sample_valid_data_output(), ]; - BTCRelay::parse_transaction.mock_safe(move |_| MockResult::Return(Ok(sample_transaction_parsed(&outputs)))); + let transaction = sample_transaction_parsed(&outputs); assert_err!( BTCRelay::validate_transaction( RuntimeOrigin::signed(3), - raw_tx, + transaction, minimum_btc, recipient_btc_address, Some(H256::from_slice(&op_return_id)) @@ -1172,9 +1138,6 @@ fn test_validate_transaction_wrong_recipient_fails() { #[test] fn test_validate_transaction_incorrect_opreturn_fails() { run_test(|| { - // Simulate input (we mock the parsed transaction) - let raw_tx = vec![0u8; 342]; - let minimum_btc: i64 = 2500200000; let recipient_btc_address = BtcAddress::P2SH(H160::from_str(&"66c7060feb882664ae62ffad0051fe843e318e85").unwrap()); @@ -1183,12 +1146,12 @@ fn test_validate_transaction_incorrect_opreturn_fails() { let outputs = vec![sample_valid_payment_output(), sample_incorrect_data_output()]; - BTCRelay::parse_transaction.mock_safe(move |_| MockResult::Return(Ok(sample_transaction_parsed(&outputs)))); + let transaction = sample_transaction_parsed(&outputs); assert_err!( BTCRelay::validate_transaction( RuntimeOrigin::signed(3), - raw_tx, + transaction, minimum_btc, recipient_btc_address, Some(H256::from_slice(&op_return_id)) @@ -1215,22 +1178,21 @@ fn test_verify_and_validate_transaction_succeeds() { // rest are example values -- not checked in this test. // let block_height = 0; - let raw_merkle_proof = vec![0u8; 100]; + let merkle_proof = sample_merkle_proof(); let confirmations = None; let minimum_btc: i64 = 0; let recipient_btc_address = BtcAddress::P2SH(H160::from_str(&"66c7060feb882664ae62ffad0051fe843e318e85").unwrap()); let op_return_id = hex::decode("e5c17d15b8b1fa2811b7e6da66ffa5e1aaa05922c69068bf90cd585b95bb4675".to_owned()).unwrap(); - BTCRelay::parse_merkle_proof.mock_safe(|_| MockResult::Return(Ok(sample_merkle_proof()))); BTCRelay::_validate_transaction.mock_safe(move |_, _, _, _| MockResult::Return(Ok(()))); BTCRelay::_verify_transaction_inclusion.mock_safe(move |_, _, _| MockResult::Return(Ok(()))); assert_ok!(BTCRelay::verify_and_validate_transaction( RuntimeOrigin::signed(3), - raw_merkle_proof, + merkle_proof, confirmations, - raw_tx, + transaction, minimum_btc, recipient_btc_address, Some(H256::from_slice(&op_return_id)) @@ -1246,12 +1208,10 @@ fn test_verify_transaction_inclusion_succeeds() { let start = 10; let main_chain_height = 300; let fork_chain_height = 280; - // Random init since we mock this - let raw_merkle_proof = vec![0u8; 100]; let confirmations = None; let rich_block_header = sample_rich_tx_block_header(chain_id, main_chain_height); - let proof = sample_merkle_proof(); + let merkle_proof = sample_merkle_proof(); let proof_result = sample_valid_proof_result(); let main = get_empty_block_chain_from_chain_id_and_height(chain_id, start, main_chain_height); @@ -1269,7 +1229,6 @@ fn test_verify_transaction_inclusion_succeeds() { BTCRelay::get_best_block_height.mock_safe(move || MockResult::Return(main_chain_height)); - BTCRelay::parse_merkle_proof.mock_safe(move |_| MockResult::Return(Ok(proof.clone()))); BTCRelay::verify_merkle_proof.mock_safe(move |_| MockResult::Return(Ok(proof_result))); BTCRelay::get_block_header_from_hash.mock_safe(move |_| MockResult::Return(Ok(rich_block_header))); @@ -1281,7 +1240,7 @@ fn test_verify_transaction_inclusion_succeeds() { assert_ok!(BTCRelay::verify_transaction_inclusion( RuntimeOrigin::signed(3), proof_result.transaction_hash, - raw_merkle_proof, + merkle_proof, confirmations )); }); @@ -1293,12 +1252,10 @@ fn test_verify_transaction_inclusion_empty_fork_succeeds() { let chain_id = 0; let start = 10; let main_chain_height = 300; - // Random init since we mock this - let raw_merkle_proof = vec![0u8; 100]; let confirmations = None; let rich_block_header = sample_rich_tx_block_header(chain_id, main_chain_height); - let proof = sample_merkle_proof(); + let merkle_proof = sample_merkle_proof(); let proof_result = sample_valid_proof_result(); let main = get_empty_block_chain_from_chain_id_and_height(chain_id, start, main_chain_height); @@ -1313,7 +1270,6 @@ fn test_verify_transaction_inclusion_empty_fork_succeeds() { BTCRelay::get_best_block_height.mock_safe(move || MockResult::Return(main_chain_height)); - BTCRelay::parse_merkle_proof.mock_safe(move |_| MockResult::Return(Ok(proof.clone()))); BTCRelay::verify_merkle_proof.mock_safe(move |_| MockResult::Return(Ok(proof_result))); BTCRelay::get_block_header_from_hash.mock_safe(move |_| MockResult::Return(Ok(rich_block_header))); @@ -1325,7 +1281,7 @@ fn test_verify_transaction_inclusion_empty_fork_succeeds() { assert_ok!(BTCRelay::verify_transaction_inclusion( RuntimeOrigin::signed(3), proof_result.transaction_hash, - raw_merkle_proof, + merkle_proof, confirmations, )); }); @@ -1339,8 +1295,6 @@ fn test_verify_transaction_inclusion_invalid_tx_id_fails() { let start = 10; let main_chain_height = 300; let fork_chain_height = 280; - // Random init since we mock this - let raw_merkle_proof = vec![0u8; 100]; let confirmations = None; let rich_block_header = sample_rich_tx_block_header(chain_id, main_chain_height); @@ -1349,7 +1303,7 @@ fn test_verify_transaction_inclusion_invalid_tx_id_fails() { &hex::decode("0000000000000000000000000000000000000000000000000000000000000000".to_owned()).unwrap(), ); - let proof = sample_merkle_proof(); + let merkle_proof = sample_merkle_proof(); let proof_result = sample_valid_proof_result(); let main = get_empty_block_chain_from_chain_id_and_height(chain_id, start, main_chain_height); @@ -1367,7 +1321,6 @@ fn test_verify_transaction_inclusion_invalid_tx_id_fails() { BTCRelay::get_best_block_height.mock_safe(move || MockResult::Return(main_chain_height)); - BTCRelay::parse_merkle_proof.mock_safe(move |_| MockResult::Return(Ok(proof.clone()))); BTCRelay::verify_merkle_proof.mock_safe(move |_| MockResult::Return(Ok(proof_result))); BTCRelay::get_block_header_from_hash.mock_safe(move |_| MockResult::Return(Ok(rich_block_header))); @@ -1380,7 +1333,7 @@ fn test_verify_transaction_inclusion_invalid_tx_id_fails() { BTCRelay::verify_transaction_inclusion( RuntimeOrigin::signed(3), invalid_tx_id, - raw_merkle_proof, + merkle_proof, confirmations, ), TestError::InvalidTxid @@ -1396,8 +1349,6 @@ fn test_verify_transaction_inclusion_invalid_merkle_root_fails() { let start = 10; let main_chain_height = 300; let fork_chain_height = 280; - // Random init since we mock this - let raw_merkle_proof = vec![0u8; 100]; let confirmations = None; let mut rich_block_header = sample_rich_tx_block_header(chain_id, main_chain_height); @@ -1407,7 +1358,7 @@ fn test_verify_transaction_inclusion_invalid_merkle_root_fails() { ); rich_block_header.block_header.merkle_root = invalid_merkle_root; - let proof = sample_merkle_proof(); + let merkle_proof = sample_merkle_proof(); let proof_result = sample_valid_proof_result(); let main = get_empty_block_chain_from_chain_id_and_height(chain_id, start, main_chain_height); @@ -1425,8 +1376,6 @@ fn test_verify_transaction_inclusion_invalid_merkle_root_fails() { BTCRelay::get_best_block_height.mock_safe(move || MockResult::Return(main_chain_height)); - BTCRelay::parse_merkle_proof.mock_safe(move |_| MockResult::Return(Ok(proof.clone()))); - BTCRelay::get_block_header_from_hash.mock_safe(move |_| MockResult::Return(Ok(rich_block_header))); BTCRelay::check_bitcoin_confirmations.mock_safe(|_, _, _| MockResult::Return(Ok(()))); @@ -1437,7 +1386,7 @@ fn test_verify_transaction_inclusion_invalid_merkle_root_fails() { BTCRelay::verify_transaction_inclusion( RuntimeOrigin::signed(3), proof_result.transaction_hash, - raw_merkle_proof, + merkle_proof, confirmations, ), TestError::InvalidMerkleProof @@ -1450,15 +1399,14 @@ fn test_verify_transaction_inclusion_fails_with_ongoing_fork() { run_test(|| { BTCRelay::get_chain_id_from_position.mock_safe(|_| MockResult::Return(Ok(1))); BTCRelay::get_block_chain_from_id.mock_safe(|_| MockResult::Return(Ok(BlockChain::default()))); - BTCRelay::parse_merkle_proof.mock_safe(|_| MockResult::Return(Ok(sample_merkle_proof()))); BTCRelay::verify_merkle_proof.mock_safe(|_| MockResult::Return(Ok(sample_valid_proof_result()))); let tx_id = sample_valid_proof_result().transaction_hash; - let raw_merkle_proof = vec![0u8; 100]; + let merkle_proof = sample_merkle_proof(); let confirmations = None; assert_err!( - BTCRelay::verify_transaction_inclusion(RuntimeOrigin::signed(3), tx_id, raw_merkle_proof, confirmations,), + BTCRelay::verify_transaction_inclusion(RuntimeOrigin::signed(3), tx_id, merkle_proof, confirmations,), TestError::OngoingFork ); }); @@ -1469,11 +1417,11 @@ fn test_get_and_verify_issue_payment_with_tx_containing_taproot() { run_test(|| { let raw_tx = "010000000001013413e41f47eecad702082578c35a2925217056fd0a837b22f1a205fe178a010d0500000000ffffffff19771000000000000017a91415f691c1905082c300362d48540846c30855162d877a1000000000000022512038234fa3e3ca718dfadfb540c320180e68798e67e0a9d4f10d98ea33d37caf047a100000000000001976a914d73838271ee26471aa3640915ed7274b49435b6688acee2000000000000016001470eab26ae0074a58802acc7c38cd9941619c408d14250000000000001976a91479ef95650e8284c3be439d888cf2ee2d1d8ef63088ac3129000000000000160014a558dd2db8167e069f580da2482a9b73dc4f5960217f0000000000001976a91409f3607112083fb1ffe3718214a8e5d5eb0da46188ac04a50000000000001600149215c14609d581aacaa54f629e823cc8abd17ee6c7cd00000000000017a9146da59c9a54a5465402884712bbbe140bc68a4f218728f700000000000017a914ed99cbd06b43b4e3741d1457f7af7b24c2e8d12487ae380100000000001976a91448296f6f29c497f59193ab4e7def5f2e03ef2f9988ac654901000000000017a914ba997376b5daaa3707aefdf30cc09745b579df2187a6a301000000000017a914ffed3c6e71adc2b73939d6951f4655ed1432909b87ec9202000000000017a9147759a1bffe2acca168afdb5b106250b02a703b2887d63603000000000016001439fef3095e8a3bce11ce471aa602bf3e3609d8ddae3703000000000017a914ea0d18bbd804d17a1f2f07ed9aa1670721777d2287cd370300000000001976a914bcc6bcffe584761176d8f510896e882f838208d988ac1d3803000000000016001470eb59ad925fdec71ca0ec50cf7c6b9bbe8dc7592f380300000000001976a91447eb6c94d7b2ac0c11eb3957c0844d333e21d02e88ac724803000000000016001470eb59ad925fdec71ca0ec50cf7c6b9bbe8dc759692e050000000000160014ae26178c1a9b4adb6f24f047fa119e034205900c381b10000000000017a914c9e20b0d7e46d07a878585955ca377db833d181587d32b20000000000017a914bbfcd0b601046e1656ba9b74a98ee8d362d5b63687402f200000000000160014ca146a720a30ca404e979df59d3ddca039e8fd58f22fea0000000000220020935f3eb059cd94bd307e6378bd590724f361f0316fd0964eb5952f274dfb7b4f0400483045022100c9fc44a423e31fc792f5d255ae09ffdc0b224cb70fcebacd52183ce2813ba11d022046c8530230f644be4a05f25bd6a2264b99afc7e3e38531d4bde12d477d03f18001473044022027f50b14154123b173286db76e189a32973a13b0b4ca425329533229cf7f8d9a02202cea81a657ee654c63ab4a01a741931378abae036435a1d695622216596d9e27016952210257bf4070df9735de32305f3bc25320d331edb10c662423e06cd1e50bc58d8fa7210246454540c4e36ba6a481347d0194ffe476640289aecfd2d3f3db1328415b9a5c210248e0a3385d6f744ae81779e10f8ccafbbed7d44debf08a2b0d5250e2f0a0e84853aef0210b00"; let tx_bytes = hex::decode(&raw_tx).unwrap(); - let transaction = BTCRelay::parse_transaction(&tx_bytes).unwrap(); + let transaction = parse_transaction(&tx_bytes).unwrap(); let raw_proof = "0000402007abe6919ca547e5a9ffe0a11936feef61cb59e7b1f703000000000000000000a53fd3336aa8a18ea00d4127ddb4f4c8d602eee44e271191ee957c257d6b28fc104c4362c0400a17783168d59f0a00000d20a74fa5c909996400a1eaf8ccb08a1fe93f125d260bdbe85f6c46a8ceb0135825c9767aea6bd8d7534a4dcb550332a174a3532aca52665e621c23504d020547dbaa46c7c8fd72b89d3b7dbe1f4f7ca977f3227ad9ce47fc725eb166324662ffdf6b1c856c7a4ec042017fd6c4b10b7b7405d35d2334389b1ea7455f3d94153b3ecfcbaea201e40fdfde250f6a810857bf3ce25af03521a417f44f038e48d7443c46d8574331f1e393ac0c47700544235de90786fca8b6f6d6ce4dce28eabfe82afdf11f4b31ae5209384e56cfc2e103a28f62cd5a269323966a3e29210276fd3fad24c0a2a832ba276dd036b0f50d1d24b12ad239812ffd64cc318f6c28a1a98295da3e28cc22959235808a432225dc101b3c5d545067c8c6553ea89675c7652d914146f9851d78c52802e5dffcbb77ae2f90478f507811c2cece1c2e7b08e5978b8384e6bdf73573b0033a6c2da1494abb5e0b760a00583c106cfdb9b658cecd0d11f35385dbbeb5546bda1144978c674a589e1991e8610aa5ef7480abff3e82bd5bcb91174fd1e896bab2746c9f5fed3faad55d043c1822e7a98f8b8862a104d7ae0500"; let proof_bytes = hex::decode(&raw_proof).unwrap(); - let merkle_proof = BTCRelay::parse_merkle_proof(&proof_bytes).unwrap(); + let merkle_proof = MerkleProof::parse(&proof_bytes).unwrap(); // check the last output address let raw_address = "935f3eb059cd94bd307e6378bd590724f361f0316fd0964eb5952f274dfb7b4f"; @@ -1622,21 +1570,17 @@ fn get_chain_from_id_ok() { fn store_generated_block_headers() { let target = U256::from(2).pow(254.into()); let miner = BtcAddress::P2PKH(H160::from_str(&"66c7060feb882664ae62ffad0051fe843e318e85").unwrap()); - let get_header = |block: &Block| RawBlockHeader::from_bytes(&block.header.try_format().unwrap()).unwrap(); run_test(|| { let mut last_block = BlockBuilder::new().with_coinbase(&miner, 50, 0).mine(target).unwrap(); - let last_block_header = BTCRelay::parse_raw_block_header(&get_header(&last_block)).unwrap(); - assert_ok!(BTCRelay::_initialize(3, last_block_header, 0)); + assert_ok!(BTCRelay::_initialize(3, last_block.header, 0)); for i in 1..20 { last_block = BlockBuilder::new() .with_coinbase(&miner, 50, i) .with_previous_hash(last_block.header.hash) .mine(target) .unwrap(); - let raw_header = get_header(&last_block); - let block_header = parse_block_header(&raw_header).unwrap(); - assert_ok!(BTCRelay::_store_block_header(&3, block_header)); + assert_ok!(BTCRelay::_store_block_header(&3, last_block.header)); } let main_chain: BlockChain = BTCRelay::get_block_chain_from_id(crate::MAIN_CHAIN_ID).unwrap(); assert_eq!(main_chain.start_height, 0); @@ -2091,9 +2035,9 @@ fn sample_raw_genesis_header() -> String { } fn sample_parsed_genesis_header(chain_id: u32, block_height: u32) -> RichBlockHeader { - let genesis_header = RawBlockHeader::from_hex(sample_raw_genesis_header()).unwrap(); + let genesis_header = BlockHeader::from_hex(sample_raw_genesis_header()).unwrap(); RichBlockHeader:: { - block_header: parse_block_header_lenient(&genesis_header).unwrap(), + block_header: genesis_header, block_height, chain_id, para_height: Default::default(), @@ -2114,45 +2058,41 @@ fn sample_raw_first_header() -> String { } fn sample_parsed_first_block(chain_id: u32, block_height: u32) -> RichBlockHeader { - let block_header = RawBlockHeader::from_hex(sample_raw_first_header()).unwrap(); + let block_header = BlockHeader::from_hex(sample_raw_first_header()).unwrap(); RichBlockHeader:: { - block_header: parse_block_header_lenient(&block_header).unwrap(), + block_header, block_height, chain_id, para_height: Default::default(), } } -fn sample_retarget_interval_increase() -> [RawBlockHeader; 3] { +fn sample_retarget_interval_increase() -> [BlockHeader; 3] { // block height 66528 - let last_retarget_header = RawBlockHeader::from_hex("01000000".to_owned() + "4e8e5cf3c4e4b8f63a9cf88beb2dbaba1949182101ae4e5cf54ad100000000009f2a2344e8112b0d7bd8089414106ee5f17bb6cd64078883e1b661fa251aac6bed1d3c4cf4a3051c4dcd2b02").unwrap(); + let last_retarget_header = BlockHeader::from_hex("01000000".to_owned() + "4e8e5cf3c4e4b8f63a9cf88beb2dbaba1949182101ae4e5cf54ad100000000009f2a2344e8112b0d7bd8089414106ee5f17bb6cd64078883e1b661fa251aac6bed1d3c4cf4a3051c4dcd2b02").unwrap(); // block height 66543 - let prev_block_header = RawBlockHeader::from_hex("01000000".to_owned() + "1e321d88cb25946c4ca521eece3752803c021f9403fc4e0171203a0500000000317057f8b50414848a5a3a26d9eb8ace3d6f5495df456d0104dd1421159faf5029293c4cf4a3051c73199005").unwrap(); + let prev_block_header = BlockHeader::from_hex("01000000".to_owned() + "1e321d88cb25946c4ca521eece3752803c021f9403fc4e0171203a0500000000317057f8b50414848a5a3a26d9eb8ace3d6f5495df456d0104dd1421159faf5029293c4cf4a3051c73199005").unwrap(); // block height 68544 - let curr_header = RawBlockHeader::from_hex("01000000".to_owned() + "fb57c71ccd211b3de4ccc2e23b50a7cdb72aab91e60737b3a2bfdf030000000088a88ad9df68925e880e5d52b7e50cef225871c68b40a2cd0bca1084cd436037f388404cfd68011caeb1f801").unwrap(); + let curr_header = BlockHeader::from_hex("01000000".to_owned() + "fb57c71ccd211b3de4ccc2e23b50a7cdb72aab91e60737b3a2bfdf030000000088a88ad9df68925e880e5d52b7e50cef225871c68b40a2cd0bca1084cd436037f388404cfd68011caeb1f801").unwrap(); [last_retarget_header, prev_block_header, curr_header] } -fn sample_retarget_interval_decrease() -> [RawBlockHeader; 3] { +fn sample_retarget_interval_decrease() -> [BlockHeader; 3] { // block height 558432 - let last_retarget_header = RawBlockHeader::from_hex("00c0ff2f".to_owned() + "6550b5dae76559589e3e3e135237072b6bc498949da6280000000000000000005988783435f506d2ccfbadb484e56d6f1d5dfdd480650acae1e3b43d3464ea73caf13b5c33d62f171d508fdb").unwrap(); + let last_retarget_header = BlockHeader::from_hex("00c0ff2f".to_owned() + "6550b5dae76559589e3e3e135237072b6bc498949da6280000000000000000005988783435f506d2ccfbadb484e56d6f1d5dfdd480650acae1e3b43d3464ea73caf13b5c33d62f171d508fdb").unwrap(); // block height 560447 - let prev_block_header = RawBlockHeader::from_hex("00000020".to_owned() + "d8e8e54ca5e33522b94fbba5de736efc55ff75e832cf2300000000000000000007b395f80858ee022c9c3c2f0f5cee4bd807039f0729b0559ae4326c3ba77d6b209f4e5c33d62f1746ee356d").unwrap(); + let prev_block_header = BlockHeader::from_hex("00000020".to_owned() + "d8e8e54ca5e33522b94fbba5de736efc55ff75e832cf2300000000000000000007b395f80858ee022c9c3c2f0f5cee4bd807039f0729b0559ae4326c3ba77d6b209f4e5c33d62f1746ee356d").unwrap(); // block height 560448 - let curr_header = RawBlockHeader::from_hex("00000020".to_owned() + "6b05bd2c4a06b3d8503a033c2593396a25a79e1dcadb140000000000000000001b08df3d42cd9a38d8b66adf9dc5eb464f503633bd861085ffff723634531596a1a24e5c35683017bf67b72a").unwrap(); + let curr_header = BlockHeader::from_hex("00000020".to_owned() + "6b05bd2c4a06b3d8503a033c2593396a25a79e1dcadb140000000000000000001b08df3d42cd9a38d8b66adf9dc5eb464f503633bd861085ffff723634531596a1a24e5c35683017bf67b72a").unwrap(); [last_retarget_header, prev_block_header, curr_header] } -fn sample_accepted_transaction() -> String { - "020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0502cb000101ffffffff02400606950000000017a91466c7060feb882664ae62ffad0051fe843e318e85870000000000000000266a24aa21a9ede5c17d15b8b1fa2811b7e6da66ffa5e1aaa05922c69068bf90cd585b95bb46750120000000000000000000000000000000000000000000000000000000000000000000000000".to_owned() -} - fn sample_rich_tx_block_header(chain_id: u32, block_height: u32) -> RichBlockHeader { - let raw_header = RawBlockHeader::from_hex("0000003096cb3d93696c4f56c10da153963d35abf4692c07b2b3bf0702fb4cb32a8682211ee1fb90996ca1d5dcd12866ba9066458bf768641215933d7d8b3a10ef79d090e8a13a5effff7f2005000000".to_owned()).unwrap(); + let block_header = BlockHeader::from_hex("0000003096cb3d93696c4f56c10da153963d35abf4692c07b2b3bf0702fb4cb32a8682211ee1fb90996ca1d5dcd12866ba9066458bf768641215933d7d8b3a10ef79d090e8a13a5effff7f2005000000".to_owned()).unwrap(); RichBlockHeader:: { - block_header: parse_block_header(&raw_header).unwrap(), + block_header, block_height, chain_id, para_height: Default::default(), diff --git a/crates/issue/src/benchmarking.rs b/crates/issue/src/benchmarking.rs index 748398637b..f21df1e36d 100644 --- a/crates/issue/src/benchmarking.rs +++ b/crates/issue/src/benchmarking.rs @@ -1,10 +1,6 @@ use super::*; -use bitcoin::{ - formatter::{Formattable, TryFormattable}, - types::{ - BlockBuilder, RawBlockHeader, TransactionBuilder, TransactionInputBuilder, TransactionInputSource, - TransactionOutput, - }, +use bitcoin::types::{ + BlockBuilder, TransactionBuilder, TransactionInputBuilder, TransactionInputSource, TransactionOutput, }; use btc_relay::{BtcAddress, BtcPublicKey}; use currency::getters::{get_relay_chain_currency_id as get_collateral_currency_id, *}; @@ -82,11 +78,8 @@ fn mine_blocks(end_height: u32) { .mine(U256::from(2).pow(254.into())) .unwrap(); - let raw_block_header = RawBlockHeader::from_bytes(&block.header.try_format().unwrap()).unwrap(); - let block_header = BtcRelay::::parse_raw_block_header(&raw_block_header).unwrap(); - Security::::set_active_block_number(1u32.into()); - BtcRelay::::_initialize(relayer_id.clone(), block_header, height).unwrap(); + BtcRelay::::_initialize(relayer_id.clone(), block.header, height).unwrap(); let transaction = TransactionBuilder::new() .with_version(2) @@ -118,10 +111,7 @@ fn mine_blocks(end_height: u32) { .unwrap(); prev_hash = block.header.hash; - let raw_block_header = RawBlockHeader::from_bytes(&block.header.try_format().unwrap()).unwrap(); - let block_header = BtcRelay::::parse_raw_block_header(&raw_block_header).unwrap(); - - BtcRelay::::_store_block_header(&relayer_id, block_header).unwrap(); + BtcRelay::::_store_block_header(&relayer_id, block.header).unwrap(); } } @@ -150,11 +140,9 @@ benchmarks! { .with_timestamp(1588813835) .mine(U256::from(2).pow(254.into())).unwrap(); let block_hash = block.header.hash; - let raw_block_header = RawBlockHeader::from_bytes(&block.header.try_format().unwrap()).unwrap(); - let block_header = BtcRelay::::parse_raw_block_header(&raw_block_header).unwrap(); Security::::set_active_block_number(1u32.into()); - BtcRelay::::_initialize(relayer_id.clone(), block_header, height).unwrap(); + BtcRelay::::_initialize(relayer_id.clone(), block.header, height).unwrap(); let vault_btc_address = BtcAddress::dummy(); @@ -187,9 +175,7 @@ benchmarks! { .add_transaction(transaction) .mine(U256::from(2).pow(254.into())).unwrap(); - let raw_block_header = RawBlockHeader::from_bytes(&block.header.try_format().unwrap()).unwrap(); - let block_header = BtcRelay::::parse_raw_block_header(&raw_block_header).unwrap(); - BtcRelay::::_store_block_header(&relayer_id, block_header).unwrap(); + BtcRelay::::_store_block_header(&relayer_id, block.header).unwrap(); Security::::set_active_block_number(Security::::active_block_number() + BtcRelay::::parachain_confirmations()); }: _(RawOrigin::Signed(origin), amount, vault_id) @@ -230,11 +216,9 @@ benchmarks! { .mine(U256::from(2).pow(254.into())).unwrap(); let block_hash = block.header.hash; - let raw_block_header = RawBlockHeader::from_bytes(&block.header.try_format().unwrap()).unwrap(); - let block_header = BtcRelay::::parse_raw_block_header(&raw_block_header).unwrap(); Security::::set_active_block_number(1u32.into()); - BtcRelay::::_initialize(relayer_id.clone(), block_header, height).unwrap(); + BtcRelay::::_initialize(relayer_id.clone(), block.header, height).unwrap(); let transaction = TransactionBuilder::new() .with_version(2) @@ -267,13 +251,9 @@ benchmarks! { .mine(U256::from(2).pow(254.into())).unwrap(); let tx_id = transaction.tx_id(); - let proof = block.merkle_proof(&[tx_id]).unwrap().try_format().unwrap(); - let raw_tx = transaction.format_with(true); - - let raw_block_header = RawBlockHeader::from_bytes(&block.header.try_format().unwrap()).unwrap(); - let block_header = BtcRelay::::parse_raw_block_header(&raw_block_header).unwrap(); + let merkle_proof = block.merkle_proof(&[tx_id]).unwrap(); - BtcRelay::::_store_block_header(&relayer_id, block_header).unwrap(); + BtcRelay::::_store_block_header(&relayer_id, block.header).unwrap(); Security::::set_active_block_number(Security::::active_block_number() + BtcRelay::::parachain_confirmations()); VaultRegistry::::_set_system_collateral_ceiling(get_currency_pair::(), 1_000_000_000u32.into()); @@ -284,7 +264,7 @@ benchmarks! { VaultRegistry::::try_increase_to_be_issued_tokens(&vault_id, &value).unwrap(); let secure_id = Security::::get_secure_id(&vault_id.account_id); VaultRegistry::::register_deposit_address(&vault_id, secure_id).unwrap(); - }: _(RawOrigin::Signed(origin), issue_id, proof, raw_tx) + }: _(RawOrigin::Signed(origin), issue_id, merkle_proof, transaction) cancel_issue { let origin: T::AccountId = account("Origin", 0, 0); diff --git a/crates/issue/src/ext.rs b/crates/issue/src/ext.rs index 7bfb27abd3..fb82af9b07 100644 --- a/crates/issue/src/ext.rs +++ b/crates/issue/src/ext.rs @@ -24,14 +24,6 @@ pub(crate) mod btc_relay { >::is_fully_initialized() } - pub fn parse_transaction(raw_tx: &[u8]) -> Result { - >::parse_transaction(raw_tx) - } - - pub fn parse_merkle_proof(raw_merkle_proof: &[u8]) -> Result { - >::parse_merkle_proof(raw_merkle_proof) - } - pub fn has_request_expired( opentime: T::BlockNumber, btc_open_height: u32, diff --git a/crates/issue/src/lib.rs b/crates/issue/src/lib.rs index 5f32fed8cb..548482f187 100644 --- a/crates/issue/src/lib.rs +++ b/crates/issue/src/lib.rs @@ -30,6 +30,7 @@ pub mod types; pub use crate::types::{DefaultIssueRequest, IssueRequest, IssueRequestStatus}; use crate::types::{BalanceOf, DefaultVaultId, Version}; +use bitcoin::types::{MerkleProof, Transaction}; use btc_relay::{BtcAddress, BtcPublicKey}; use currency::Amount; use frame_support::{dispatch::DispatchError, ensure, traits::Get, transactional, PalletId}; @@ -225,11 +226,11 @@ pub mod pallet { pub fn execute_issue( origin: OriginFor, issue_id: H256, - merkle_proof: Vec, - raw_tx: Vec, + merkle_proof: MerkleProof, + transaction: Transaction, ) -> DispatchResultWithPostInfo { let executor = ensure_signed(origin)?; - Self::_execute_issue(executor, issue_id, merkle_proof, raw_tx)?; + Self::_execute_issue(executor, issue_id, merkle_proof, transaction)?; Ok(().into()) } @@ -355,15 +356,13 @@ impl Pallet { fn _execute_issue( executor: T::AccountId, issue_id: H256, - raw_merkle_proof: Vec, - raw_tx: Vec, + merkle_proof: MerkleProof, + transaction: Transaction, ) -> Result<(), DispatchError> { let mut issue = Self::get_issue_request_from_id(&issue_id)?; // allow anyone to complete issue request let requester = issue.requester.clone(); - let transaction = ext::btc_relay::parse_transaction::(&raw_tx)?; - let merkle_proof = ext::btc_relay::parse_merkle_proof::(&raw_merkle_proof)?; let amount_transferred = ext::btc_relay::get_and_verify_issue_payment::>( merkle_proof, transaction, diff --git a/crates/issue/src/tests.rs b/crates/issue/src/tests.rs index 77b0fdd0eb..fc4eb9c6ff 100644 --- a/crates/issue/src/tests.rs +++ b/crates/issue/src/tests.rs @@ -1,6 +1,5 @@ use crate::{ext, mock::*, Event, IssueRequest}; -use bitcoin::types::{MerkleProof, Transaction}; use btc_relay::{BtcAddress, BtcPublicKey}; use currency::Amount; use frame_support::{assert_noop, assert_ok, dispatch::DispatchError}; @@ -12,15 +11,6 @@ use sp_core::H256; use sp_runtime::traits::One; use vault_registry::{DefaultVault, DefaultVaultId, Vault, VaultStatus}; -fn dummy_merkle_proof() -> MerkleProof { - MerkleProof { - block_header: Default::default(), - transactions_count: 0, - flag_bits: vec![], - hashes: vec![], - } -} - fn griefing(amount: u128) -> Amount { Amount::new(amount, DEFAULT_NATIVE_CURRENCY) } @@ -64,7 +54,7 @@ fn request_issue_ok_with_address( } fn execute_issue(origin: AccountId, issue_id: &H256) -> Result<(), DispatchError> { - Issue::_execute_issue(origin, *issue_id, vec![0u8; 100], vec![0u8; 100]) + Issue::_execute_issue(origin, *issue_id, Default::default(), Default::default()) } fn cancel_issue(origin: AccountId, issue_id: &H256) -> Result<(), DispatchError> { @@ -166,8 +156,6 @@ fn setup_execute( let issue_id = request_issue_ok(USER, issue_amount, VAULT); >::set_active_block_number(5); - ext::btc_relay::parse_merkle_proof::.mock_safe(|_| MockResult::Return(Ok(dummy_merkle_proof()))); - ext::btc_relay::parse_transaction::.mock_safe(|_| MockResult::Return(Ok(Transaction::default()))); ext::btc_relay::get_and_verify_issue_payment:: .mock_safe(move |_, _, _| MockResult::Return(Ok(btc_transferred))); diff --git a/crates/redeem/src/benchmarking.rs b/crates/redeem/src/benchmarking.rs index 96490a2f7b..6c7d6740f7 100644 --- a/crates/redeem/src/benchmarking.rs +++ b/crates/redeem/src/benchmarking.rs @@ -1,10 +1,6 @@ use super::*; -use bitcoin::{ - formatter::{Formattable, TryFormattable}, - types::{ - BlockBuilder, RawBlockHeader, TransactionBuilder, TransactionInputBuilder, TransactionInputSource, - TransactionOutput, - }, +use bitcoin::types::{ + BlockBuilder, TransactionBuilder, TransactionInputBuilder, TransactionInputSource, TransactionOutput, }; use btc_relay::{BtcAddress, BtcPublicKey}; use currency::getters::{get_relay_chain_currency_id as get_collateral_currency_id, *}; @@ -94,11 +90,8 @@ fn mine_blocks(end_height: u32) { .mine(U256::from(2).pow(254.into())) .unwrap(); - let raw_block_header = RawBlockHeader::from_bytes(&block.header.try_format().unwrap()).unwrap(); - let block_header = BtcRelay::::parse_raw_block_header(&raw_block_header).unwrap(); - Security::::set_active_block_number(1u32.into()); - BtcRelay::::_initialize(relayer_id.clone(), block_header, height).unwrap(); + BtcRelay::::_initialize(relayer_id.clone(), block.header, height).unwrap(); let transaction = TransactionBuilder::new() .with_version(2) @@ -130,10 +123,7 @@ fn mine_blocks(end_height: u32) { .unwrap(); prev_hash = block.header.hash; - let raw_block_header = RawBlockHeader::from_bytes(&block.header.try_format().unwrap()).unwrap(); - let block_header = BtcRelay::::parse_raw_block_header(&raw_block_header).unwrap(); - - BtcRelay::::_store_block_header(&relayer_id, block_header).unwrap(); + BtcRelay::::_store_block_header(&relayer_id, block.header).unwrap(); } } @@ -255,11 +245,9 @@ benchmarks! { .mine(U256::from(2).pow(254.into())).unwrap(); let block_hash = block.header.hash; - let raw_block_header = RawBlockHeader::from_bytes(&block.header.try_format().unwrap()).unwrap(); - let block_header = BtcRelay::::parse_raw_block_header(&raw_block_header).unwrap(); Security::::set_active_block_number(1u32.into()); - BtcRelay::::_initialize(relayer_id.clone(), block_header, height).unwrap(); + BtcRelay::::_initialize(relayer_id.clone(), block.header, height).unwrap(); let value = 0; let transaction = TransactionBuilder::new() @@ -293,20 +281,19 @@ benchmarks! { .mine(U256::from(2).pow(254.into())).unwrap(); let tx_id = transaction.tx_id(); - let proof = block.merkle_proof(&[tx_id]).unwrap().try_format().unwrap(); - let raw_tx = transaction.format_with(true); + let merkle_proof = block.merkle_proof(&[tx_id]).unwrap(); - let raw_block_header = RawBlockHeader::from_bytes(&block.header.try_format().unwrap()).unwrap(); - let block_header = BtcRelay::::parse_raw_block_header(&raw_block_header).unwrap(); - - BtcRelay::::_store_block_header(&relayer_id, block_header).unwrap(); - Security::::set_active_block_number(Security::::active_block_number() + -BtcRelay::::parachain_confirmations() + 1u32.into()); + BtcRelay::::_store_block_header(&relayer_id, block.header).unwrap(); + Security::::set_active_block_number( + Security::::active_block_number() + + BtcRelay::::parachain_confirmations() + + 1u32.into() + ); assert_ok!(Oracle::::_set_exchange_rate(get_collateral_currency_id::(), UnsignedFixedPoint::::one() )); - }: _(RawOrigin::Signed(vault_id.account_id.clone()), redeem_id, proof, raw_tx) + }: _(RawOrigin::Signed(vault_id.account_id.clone()), redeem_id, merkle_proof, transaction) cancel_redeem_reimburse { let origin: T::AccountId = account("Origin", 0, 0); diff --git a/crates/redeem/src/ext.rs b/crates/redeem/src/ext.rs index 96ebe2874e..f81267fb4f 100644 --- a/crates/redeem/src/ext.rs +++ b/crates/redeem/src/ext.rs @@ -29,14 +29,6 @@ pub(crate) mod btc_relay { >::get_best_block_height() } - pub fn parse_transaction(raw_tx: &[u8]) -> Result { - >::parse_transaction(raw_tx) - } - - pub fn parse_merkle_proof(raw_merkle_proof: &[u8]) -> Result { - >::parse_merkle_proof(raw_merkle_proof) - } - pub fn has_request_expired( opentime: T::BlockNumber, btc_open_height: u32, diff --git a/crates/redeem/src/lib.rs b/crates/redeem/src/lib.rs index 4679e0f133..5047223dd7 100644 --- a/crates/redeem/src/lib.rs +++ b/crates/redeem/src/lib.rs @@ -30,6 +30,7 @@ pub mod types; pub use crate::types::{DefaultRedeemRequest, RedeemRequest, RedeemRequestStatus}; use crate::types::{BalanceOf, RedeemRequestExt, Version}; +use bitcoin::types::{MerkleProof, Transaction}; use btc_relay::BtcAddress; use currency::Amount; use frame_support::{ @@ -274,11 +275,11 @@ pub mod pallet { pub fn execute_redeem( origin: OriginFor, redeem_id: H256, - merkle_proof: Vec, - raw_tx: Vec, + merkle_proof: MerkleProof, + transaction: Transaction, ) -> DispatchResultWithPostInfo { let _ = ensure_signed(origin)?; - Self::_execute_redeem(redeem_id, merkle_proof, raw_tx)?; + Self::_execute_redeem(redeem_id, merkle_proof, transaction)?; // Don't take tx fees on success. If the vault had to pay for this function, it would // have been vulnerable to a griefing attack where users would redeem amounts just @@ -568,12 +569,14 @@ impl Pallet { Ok(()) } - fn _execute_redeem(redeem_id: H256, raw_merkle_proof: Vec, raw_tx: Vec) -> Result<(), DispatchError> { + fn _execute_redeem( + redeem_id: H256, + merkle_proof: MerkleProof, + transaction: Transaction, + ) -> Result<(), DispatchError> { let redeem = Self::get_open_redeem_request_from_id(&redeem_id)?; // check the transaction inclusion and validity - let transaction = ext::btc_relay::parse_transaction::(&raw_tx)?; - let merkle_proof = ext::btc_relay::parse_merkle_proof::(&raw_merkle_proof)?; ext::btc_relay::verify_and_validate_op_return_transaction::( merkle_proof, transaction, diff --git a/crates/redeem/src/tests.rs b/crates/redeem/src/tests.rs index 9f66cc1b48..a81b2f4fd2 100644 --- a/crates/redeem/src/tests.rs +++ b/crates/redeem/src/tests.rs @@ -1,7 +1,6 @@ use crate::{ext, mock::*}; use crate::types::{RedeemRequest, RedeemRequestStatus}; -use bitcoin::types::{MerkleProof, Transaction}; use btc_relay::BtcAddress; use currency::Amount; use frame_support::{assert_err, assert_noop, assert_ok, dispatch::DispatchError}; @@ -36,15 +35,6 @@ macro_rules! assert_emitted { }; } -fn dummy_merkle_proof() -> MerkleProof { - MerkleProof { - block_header: Default::default(), - transactions_count: 0, - flag_bits: vec![], - hashes: vec![], - } -} - fn inject_redeem_request(key: H256, value: RedeemRequest) { Redeem::insert_redeem_request(&key, &value) } @@ -376,8 +366,8 @@ fn test_execute_redeem_fails_with_redeem_id_not_found() { Redeem::execute_redeem( RuntimeOrigin::signed(VAULT.account_id), H256([0u8; 32]), - Vec::default(), - Vec::default() + Default::default(), + Default::default() ), TestError::RedeemIdNotFound ); @@ -405,8 +395,6 @@ fn test_execute_redeem_succeeds_with_another_account() { liquidated_collateral: 0, }, ); - ext::btc_relay::parse_merkle_proof::.mock_safe(|_| MockResult::Return(Ok(dummy_merkle_proof()))); - ext::btc_relay::parse_transaction::.mock_safe(|_| MockResult::Return(Ok(Transaction::default()))); ext::btc_relay::verify_and_validate_op_return_transaction:: .mock_safe(|_, _, _, _, _| MockResult::Return(Ok(()))); @@ -447,8 +435,8 @@ fn test_execute_redeem_succeeds_with_another_account() { assert_ok!(Redeem::execute_redeem( RuntimeOrigin::signed(USER), H256([0u8; 32]), - Vec::default(), - Vec::default() + Default::default(), + Default::default() )); assert_emitted!(Event::ExecuteRedeem { redeem_id: H256([0; 32]), @@ -486,8 +474,6 @@ fn test_execute_redeem_succeeds() { liquidated_collateral: 0, }, ); - ext::btc_relay::parse_merkle_proof::.mock_safe(|_| MockResult::Return(Ok(dummy_merkle_proof()))); - ext::btc_relay::parse_transaction::.mock_safe(|_| MockResult::Return(Ok(Transaction::default()))); ext::btc_relay::verify_and_validate_op_return_transaction:: .mock_safe(|_, _, _, _, _| MockResult::Return(Ok(()))); @@ -528,8 +514,8 @@ fn test_execute_redeem_succeeds() { assert_ok!(Redeem::execute_redeem( RuntimeOrigin::signed(VAULT.account_id), H256([0u8; 32]), - Vec::default(), - Vec::default() + Default::default(), + Default::default() )); assert_emitted!(Event::ExecuteRedeem { redeem_id: H256([0; 32]), @@ -847,8 +833,6 @@ mod spec_based_tests { ..default_vault() }, ); - ext::btc_relay::parse_merkle_proof::.mock_safe(|_| MockResult::Return(Ok(dummy_merkle_proof()))); - ext::btc_relay::parse_transaction::.mock_safe(|_| MockResult::Return(Ok(Transaction::default()))); ext::btc_relay::verify_and_validate_op_return_transaction:: .mock_safe(|_, _, _, _, _| MockResult::Return(Ok(()))); @@ -885,8 +869,8 @@ mod spec_based_tests { assert_ok!(Redeem::execute_redeem( RuntimeOrigin::signed(USER), H256([0u8; 32]), - Vec::default(), - Vec::default() + Default::default(), + Default::default() )); assert_emitted!(Event::ExecuteRedeem { redeem_id: H256([0; 32]), diff --git a/crates/replace/src/benchmarking.rs b/crates/replace/src/benchmarking.rs index 5a60403368..302fb4c3da 100644 --- a/crates/replace/src/benchmarking.rs +++ b/crates/replace/src/benchmarking.rs @@ -1,10 +1,6 @@ use super::*; -use bitcoin::{ - formatter::{Formattable, TryFormattable}, - types::{ - BlockBuilder, RawBlockHeader, TransactionBuilder, TransactionInputBuilder, TransactionInputSource, - TransactionOutput, - }, +use bitcoin::types::{ + BlockBuilder, TransactionBuilder, TransactionInputBuilder, TransactionInputSource, TransactionOutput, }; use btc_relay::{BtcAddress, BtcPublicKey}; use currency::getters::{get_relay_chain_currency_id as get_collateral_currency_id, *}; @@ -65,11 +61,8 @@ fn mine_blocks(end_height: u32) { .mine(U256::from(2).pow(254.into())) .unwrap(); - let raw_block_header = RawBlockHeader::from_bytes(&block.header.try_format().unwrap()).unwrap(); - let block_header = BtcRelay::::parse_raw_block_header(&raw_block_header).unwrap(); - Security::::set_active_block_number(1u32.into()); - BtcRelay::::_initialize(relayer_id.clone(), block_header, height).unwrap(); + BtcRelay::::_initialize(relayer_id.clone(), block.header, height).unwrap(); let transaction = TransactionBuilder::new() .with_version(2) @@ -101,10 +94,7 @@ fn mine_blocks(end_height: u32) { .unwrap(); prev_hash = block.header.hash; - let raw_block_header = RawBlockHeader::from_bytes(&block.header.try_format().unwrap()).unwrap(); - let block_header = BtcRelay::::parse_raw_block_header(&raw_block_header).unwrap(); - - BtcRelay::::_store_block_header(&relayer_id, block_header).unwrap(); + BtcRelay::::_store_block_header(&relayer_id, block.header).unwrap(); } } @@ -263,12 +253,10 @@ benchmarks! { .mine(U256::from(2).pow(254.into())).unwrap(); let block_hash = block.header.hash; - let raw_block_header = RawBlockHeader::from_bytes(&block.header.try_format().unwrap()).unwrap(); - let block_header = BtcRelay::::parse_raw_block_header(&raw_block_header).unwrap(); Security::::set_active_block_number(1u32.into()); VaultRegistry::::_set_system_collateral_ceiling(get_currency_pair::(), 1_000_000_000u32.into()); - BtcRelay::::_initialize(relayer_id.clone(), block_header, height).unwrap(); + BtcRelay::::_initialize(relayer_id.clone(), block.header, height).unwrap(); let value = 0; let transaction = TransactionBuilder::new() @@ -302,16 +290,12 @@ benchmarks! { .mine(U256::from(2).pow(254.into())).unwrap(); let tx_id = transaction.tx_id(); - let proof = block.merkle_proof(&[tx_id]).unwrap().try_format().unwrap(); - let raw_tx = transaction.format_with(true); - - let raw_block_header = RawBlockHeader::from_bytes(&block.header.try_format().unwrap()).unwrap(); - let block_header = BtcRelay::::parse_raw_block_header(&raw_block_header).unwrap(); + let merkle_proof = block.merkle_proof(&[tx_id]).unwrap(); - BtcRelay::::_store_block_header(&relayer_id, block_header).unwrap(); + BtcRelay::::_store_block_header(&relayer_id, block.header).unwrap(); Security::::set_active_block_number(Security::::active_block_number() + BtcRelay::::parachain_confirmations() + 1u32.into()); - }: _(RawOrigin::Signed(old_vault_id.account_id), replace_id, proof, raw_tx) + }: _(RawOrigin::Signed(old_vault_id.account_id), replace_id, merkle_proof, transaction) cancel_replace { let new_vault_id = get_vault_id::("NewVault"); diff --git a/crates/replace/src/ext.rs b/crates/replace/src/ext.rs index e461735fd1..8bde47783a 100644 --- a/crates/replace/src/ext.rs +++ b/crates/replace/src/ext.rs @@ -29,14 +29,6 @@ pub(crate) mod btc_relay { >::get_best_block_height() } - pub fn parse_transaction(raw_tx: &[u8]) -> Result { - >::parse_transaction(raw_tx) - } - - pub fn parse_merkle_proof(raw_merkle_proof: &[u8]) -> Result { - >::parse_merkle_proof(raw_merkle_proof) - } - pub fn has_request_expired( opentime: T::BlockNumber, btc_open_height: u32, diff --git a/crates/replace/src/lib.rs b/crates/replace/src/lib.rs index 3b2da48f41..51e599e26c 100644 --- a/crates/replace/src/lib.rs +++ b/crates/replace/src/lib.rs @@ -27,6 +27,7 @@ use mocktopus::macros::mockable; use crate::types::{BalanceOf, ReplaceRequestExt, Version}; pub use crate::types::{DefaultReplaceRequest, ReplaceRequest, ReplaceRequestStatus}; +use bitcoin::types::{MerkleProof, Transaction}; use btc_relay::BtcAddress; use currency::Amount; pub use default_weights::WeightInfo; @@ -271,11 +272,11 @@ pub mod pallet { pub fn execute_replace( origin: OriginFor, replace_id: H256, - merkle_proof: Vec, - raw_tx: Vec, + merkle_proof: MerkleProof, + transaction: Transaction, ) -> DispatchResultWithPostInfo { let _ = ensure_signed(origin)?; - Self::_execute_replace(replace_id, merkle_proof, raw_tx)?; + Self::_execute_replace(replace_id, merkle_proof, transaction)?; Ok(().into()) } @@ -475,7 +476,7 @@ impl Pallet { Ok(()) } - fn _execute_replace(replace_id: H256, raw_merkle_proof: Vec, raw_tx: Vec) -> DispatchResult { + fn _execute_replace(replace_id: H256, merkle_proof: MerkleProof, transaction: Transaction) -> DispatchResult { // retrieve the replace request using the id parameter // we can still execute cancelled requests let replace = Self::get_open_or_cancelled_replace_request(&replace_id)?; @@ -489,8 +490,6 @@ impl Pallet { let old_vault_id = replace.old_vault; // check the transaction inclusion and validity - let transaction = ext::btc_relay::parse_transaction::(&raw_tx)?; - let merkle_proof = ext::btc_relay::parse_merkle_proof::(&raw_merkle_proof)?; ext::btc_relay::verify_and_validate_op_return_transaction::( merkle_proof, transaction, diff --git a/crates/replace/src/tests.rs b/crates/replace/src/tests.rs index f6326cf2c6..ca826e297c 100644 --- a/crates/replace/src/tests.rs +++ b/crates/replace/src/tests.rs @@ -3,7 +3,6 @@ use crate::{ *, }; -use bitcoin::types::{MerkleProof, Transaction}; use btc_relay::BtcAddress; use currency::Amount; use frame_support::{assert_err, assert_ok}; @@ -12,15 +11,6 @@ use sp_core::H256; type Event = crate::Event; -fn dummy_merkle_proof() -> MerkleProof { - MerkleProof { - block_header: Default::default(), - transactions_count: 0, - flag_bits: vec![], - hashes: vec![], - } -} - macro_rules! assert_event_matches { ($( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => { @@ -198,8 +188,6 @@ mod execute_replace_test { Replace::replace_period.mock_safe(|| MockResult::Return(20)); ext::btc_relay::has_request_expired::.mock_safe(|_, _, _| MockResult::Return(Ok(false))); - ext::btc_relay::parse_merkle_proof::.mock_safe(|_| MockResult::Return(Ok(dummy_merkle_proof()))); - ext::btc_relay::parse_transaction::.mock_safe(|_| MockResult::Return(Ok(Transaction::default()))); ext::btc_relay::verify_and_validate_op_return_transaction:: .mock_safe(|_, _, _, _, _| MockResult::Return(Ok(()))); ext::vault_registry::replace_tokens::.mock_safe(|_, _, _, _| MockResult::Return(Ok(()))); @@ -214,7 +202,11 @@ mod execute_replace_test { fn test_execute_replace_succeeds() { run_test(|| { setup_mocks(); - assert_ok!(Replace::_execute_replace(H256::zero(), Vec::new(), Vec::new())); + assert_ok!(Replace::_execute_replace( + H256::zero(), + Default::default(), + Default::default() + )); assert_event_matches!(Event::ExecuteReplace { replace_id: _, old_vault_id: OLD_VAULT, @@ -236,7 +228,11 @@ mod execute_replace_test { replace }); - assert_ok!(Replace::_execute_replace(H256::zero(), Vec::new(), Vec::new())); + assert_ok!(Replace::_execute_replace( + H256::zero(), + Default::default(), + Default::default() + )); assert_event_matches!(Event::ExecuteReplace { replace_id: _, old_vault_id: OLD_VAULT, diff --git a/standalone/runtime/tests/bitcoin_data.rs b/standalone/runtime/tests/bitcoin_data.rs index 4a8e0c58c0..8479f974bd 100644 --- a/standalone/runtime/tests/bitcoin_data.rs +++ b/standalone/runtime/tests/bitcoin_data.rs @@ -1,4 +1,4 @@ -use bitcoin::types::{H256Le, RawBlockHeader}; +use bitcoin::types::{BlockHeader, H256Le, MerkleProof}; use flate2::read::GzDecoder; use serde::Deserialize; use std::{ @@ -35,8 +35,8 @@ impl Block { H256Le::from_hex_be(&self.hash) } - pub fn get_raw_header(&self) -> RawBlockHeader { - RawBlockHeader::from_hex(&self.raw_header).expect(ERR_INVALID_HEADER) + pub fn get_block_header(&self) -> BlockHeader { + BlockHeader::from_hex(&self.raw_header).expect(ERR_INVALID_HEADER) } } @@ -51,8 +51,8 @@ impl Transaction { H256Le::from_hex_be(&self.txid) } - pub fn get_raw_merkle_proof(&self) -> Vec { - hex::decode(&self.raw_merkle_proof).expect(ERR_INVALID_PROOF) + pub fn get_merkle_proof(&self) -> MerkleProof { + MerkleProof::parse(&hex::decode(&self.raw_merkle_proof).expect(ERR_INVALID_PROOF)).expect(ERR_INVALID_PROOF) } } @@ -87,12 +87,12 @@ pub fn get_bitcoin_testdata() -> Vec { test_data } -pub fn get_fork_testdata() -> Vec { +pub fn get_fork_testdata() -> Vec { let data = read_data(PATH_TESTNET_FORKS); - let test_data: Vec = data + let test_data: Vec = data .lines() - .filter_map(|s| RawBlockHeader::from_hex(s.strip_prefix(FORK_PREFIX).unwrap_or(s)).ok()) + .filter_map(|s| BlockHeader::from_hex(s.strip_prefix(FORK_PREFIX).unwrap_or(s)).ok()) .collect(); assert!(test_data.len() == NUM_FORK_HEADERS as usize); diff --git a/standalone/runtime/tests/mock/issue_testing_utils.rs b/standalone/runtime/tests/mock/issue_testing_utils.rs index ba86b84f1d..f5981e7121 100644 --- a/standalone/runtime/tests/mock/issue_testing_utils.rs +++ b/standalone/runtime/tests/mock/issue_testing_utils.rs @@ -66,7 +66,7 @@ pub struct ExecuteIssueBuilder { submitter: AccountId, register_vault_with_currency_id: Option, relayer: Option<[u8; 32]>, - execution_tx: Option<(Vec, Vec)>, + execution_tx: Option<(MerkleProof, Transaction)>, } impl ExecuteIssueBuilder { @@ -116,12 +116,12 @@ impl ExecuteIssueBuilder { pub fn execute_prepared(&self) -> DispatchResultWithPostInfo { VaultRegistryPallet::collateral_integrity_check(); - if let Some((proof, raw_tx)) = &self.execution_tx { + if let Some((merkle_proof, transaction)) = &self.execution_tx { // alice executes the issuerequest by confirming the btc transaction let ret = RuntimeCall::Issue(IssueCall::execute_issue { issue_id: self.issue_id, - merkle_proof: proof.to_vec(), - raw_tx: raw_tx.to_vec(), + merkle_proof: merkle_proof.clone(), + transaction: transaction.clone(), }) .dispatch(origin_of(self.submitter.clone())); VaultRegistryPallet::collateral_integrity_check(); @@ -133,7 +133,7 @@ impl ExecuteIssueBuilder { pub fn prepare_for_execution(&mut self) -> &mut Self { // send the btc from the user to the vault - let (_tx_id, _height, proof, raw_tx, _) = TransactionGenerator::new() + let (_tx_id, _height, merkle_proof, transaction) = TransactionGenerator::new() .with_outputs(vec![(self.issue.btc_address, self.amount)]) .with_relayer(self.relayer) .mine(); @@ -147,7 +147,7 @@ impl ExecuteIssueBuilder { ); } - self.execution_tx = Some((proof, raw_tx)); + self.execution_tx = Some((merkle_proof, transaction)); self } diff --git a/standalone/runtime/tests/mock/mod.rs b/standalone/runtime/tests/mock/mod.rs index 76214ad3b2..c6791e4dfd 100644 --- a/standalone/runtime/tests/mock/mod.rs +++ b/standalone/runtime/tests/mock/mod.rs @@ -1235,7 +1235,7 @@ impl TransactionGenerator { self.relayer = relayer; self } - pub fn mine(&self) -> (H256Le, u32, Vec, Vec, Transaction) { + pub fn mine(&self) -> (H256Le, u32, MerkleProof, Transaction) { let mut height = BTCRelayPallet::get_best_block_height() + 1; let extra_confirmations = self.confirmations - 1; @@ -1251,11 +1251,7 @@ impl TransactionGenerator { .mine(U256::from(2).pow(254.into())) .unwrap(); - let raw_init_block_header = RawBlockHeader::from_bytes(&init_block.header.try_format().unwrap()) - .expect("could not serialize block header"); - let init_block_header = BTCRelayPallet::parse_raw_block_header(&raw_init_block_header).unwrap(); - - match BTCRelayPallet::_initialize(account_of(ALICE), init_block_header, height) { + match BTCRelayPallet::_initialize(account_of(ALICE), init_block.header, height) { Ok(_) => {} Err(e) if e == BTCRelayError::AlreadyInitialized.into() => {} _ => panic!("Failed to initialize btc relay"), @@ -1313,16 +1309,11 @@ impl TransactionGenerator { .mine(U256::from(2).pow(254.into())) .unwrap(); - let raw_block_header = - RawBlockHeader::from_bytes(&block.header.try_format().unwrap()).expect("could not serialize block header"); - let tx_id = transaction.tx_id(); let tx_block_height = height; - let proof = block.merkle_proof(&[tx_id]).unwrap(); - let bytes_proof = proof.try_format().unwrap(); - let raw_tx = transaction.format_with(true); + let merkle_proof = block.merkle_proof(&[tx_id]).unwrap(); - self.relay(height, &block, raw_block_header); + self.relay(height, &block, block.header); // Mine six new blocks to get over required confirmations let mut prev_block_hash = block.header.hash; @@ -1338,26 +1329,22 @@ impl TransactionGenerator { .mine(U256::from(2).pow(254.into())) .unwrap(); - let raw_conf_block_header = RawBlockHeader::from_bytes(&conf_block.header.try_format().unwrap()) - .expect("could not serialize block header"); - self.relay(height, &conf_block, raw_conf_block_header); + self.relay(height, &conf_block, conf_block.header); prev_block_hash = conf_block.header.hash; } - (tx_id, tx_block_height, bytes_proof, raw_tx, transaction) + (tx_id, tx_block_height, merkle_proof, transaction) } - fn relay(&self, height: u32, block: &Block, raw_block_header: RawBlockHeader) { + fn relay(&self, height: u32, block: &Block, block_header: BlockHeader) { if let Some(relayer) = self.relayer { assert_ok!(RuntimeCall::BTCRelay(BTCRelayCall::store_block_header { - raw_block_header: raw_block_header + block_header: block_header }) .dispatch(origin_of(account_of(relayer)))); - assert_store_main_chain_header_event(height, raw_block_header.hash(), account_of(relayer)); + assert_store_main_chain_header_event(height, block_header.hash, account_of(relayer)); } else { - // bypass staked relayer module - let block_header = BTCRelayPallet::parse_raw_block_header(&raw_block_header).unwrap(); assert_ok!(BTCRelayPallet::_store_block_header(&account_of(ALICE), block_header)); assert_store_main_chain_header_event(height, block.header.hash, account_of(ALICE)); } @@ -1369,14 +1356,13 @@ pub fn generate_transaction_and_mine( inputs: Vec<(Transaction, u32, Option)>, outputs: Vec<(BtcAddress, Amount)>, return_data: Vec, -) -> (H256Le, u32, Vec, Vec, Transaction) { - let (tx_id, height, proof, raw_tx, tx) = TransactionGenerator::new() +) -> (H256Le, u32, MerkleProof, Transaction) { + TransactionGenerator::new() .with_script(signer.to_p2pkh_script_sig(vec![1; 32]).as_bytes()) .with_inputs(inputs) .with_outputs(outputs) .with_op_return(return_data) - .mine(); - (tx_id, height, proof, raw_tx, tx) + .mine() } pub struct ExtBuilder { diff --git a/standalone/runtime/tests/mock/redeem_testing_utils.rs b/standalone/runtime/tests/mock/redeem_testing_utils.rs index cd2ef290b3..c383ad6626 100644 --- a/standalone/runtime/tests/mock/redeem_testing_utils.rs +++ b/standalone/runtime/tests/mock/redeem_testing_utils.rs @@ -56,7 +56,7 @@ impl ExecuteRedeemBuilder { #[transactional] pub fn execute(&self) -> DispatchResultWithPostInfo { // send the btc from the user to the vault - let (_tx_id, _height, proof, raw_tx, _) = TransactionGenerator::new() + let (_tx_id, _height, merkle_proof, transaction) = TransactionGenerator::new() .with_outputs(vec![(self.redeem.btc_address, self.amount)]) .with_op_return(vec![self.redeem_id]) .mine(); @@ -68,8 +68,8 @@ impl ExecuteRedeemBuilder { // alice executes the redeemrequest by confirming the btc transaction let ret = RuntimeCall::Redeem(RedeemCall::execute_redeem { redeem_id: self.redeem_id, - merkle_proof: proof, - raw_tx: raw_tx, + merkle_proof, + transaction, }) .dispatch(origin_of(self.submitter.clone())); VaultRegistryPallet::collateral_integrity_check(); @@ -198,7 +198,7 @@ pub fn assert_redeem_error( error: BTCRelayError, ) -> u32 { // send the btc from the vault to the user - let (_tx_id, _tx_block_height, merkle_proof, raw_tx, _) = generate_transaction_and_mine( + let (_tx_id, _tx_block_height, merkle_proof, transaction) = generate_transaction_and_mine( Default::default(), vec![], vec![(user_btc_address, amount)], @@ -210,8 +210,8 @@ pub fn assert_redeem_error( assert_noop!( RuntimeCall::Redeem(RedeemCall::execute_redeem { redeem_id: redeem_id, - merkle_proof: merkle_proof.clone(), - raw_tx: raw_tx + merkle_proof, + transaction, }) .dispatch(origin_of(account_of(VAULT))), error diff --git a/standalone/runtime/tests/test_btc_relay.rs b/standalone/runtime/tests/test_btc_relay.rs index 284dffb135..99e1095117 100644 --- a/standalone/runtime/tests/test_btc_relay.rs +++ b/standalone/runtime/tests/test_btc_relay.rs @@ -32,20 +32,19 @@ fn integration_test_submit_block_headers_and_verify_transaction_inclusion() { .iter() .position(|d| d.height % DIFFICULTY_ADJUSTMENT_INTERVAL == 0) .unwrap(); - let parachain_genesis_header = test_data[skip_blocks].get_raw_header(); + let parachain_genesis_header = test_data[skip_blocks].get_block_header(); let parachain_genesis_height = test_data[skip_blocks].height; assert_eq!(parachain_genesis_height % DIFFICULTY_ADJUSTMENT_INTERVAL, 0); assert_ok!(RuntimeCall::BTCRelay(BTCRelayCall::initialize { - raw_block_header: parachain_genesis_header, + block_header: parachain_genesis_header, block_height: parachain_genesis_height }) .dispatch(origin_of(account_of(ALICE)))); for block in test_data.iter().skip(skip_blocks + 1).take(BLOCKS_TO_TEST) { - let raw_header = block.get_raw_header(); - let parsed_block = bitcoin::parser::parse_block_header_lenient(&raw_header).unwrap(); - let prev_header_hash = parsed_block.hash_prev_block; + let block_header = block.get_block_header(); + let prev_header_hash = block_header.hash_prev_block; // check that the previously submitted header and the current header are matching let best_block_hash = BTCRelayPallet::get_best_block(); @@ -56,7 +55,7 @@ fn integration_test_submit_block_headers_and_verify_transaction_inclusion() { // submit block hashes assert_ok!(RuntimeCall::BTCRelay(BTCRelayCall::store_block_header { - raw_block_header: block.get_raw_header() + block_header: block.get_block_header() }) .dispatch(origin_of(account_of(ALICE)))); @@ -69,11 +68,11 @@ fn integration_test_submit_block_headers_and_verify_transaction_inclusion() { for block in test_data.iter().skip(skip_blocks).take(BLOCKS_TO_TEST) { for tx in &block.test_txs { let txid = tx.get_txid(); - let raw_merkle_proof = tx.get_raw_merkle_proof(); + let merkle_proof = tx.get_merkle_proof(); if block.height <= current_height - CONFIRMATIONS + 1 { assert_ok!(RuntimeCall::BTCRelay(BTCRelayCall::verify_transaction_inclusion { tx_id: txid, - raw_merkle_proof: raw_merkle_proof, + merkle_proof, confirmations: None, }) .dispatch(origin_of(account_of(ALICE)))); @@ -82,7 +81,7 @@ fn integration_test_submit_block_headers_and_verify_transaction_inclusion() { assert_noop!( RuntimeCall::BTCRelay(BTCRelayCall::verify_transaction_inclusion { tx_id: txid, - raw_merkle_proof: raw_merkle_proof, + merkle_proof, confirmations: None, }) .dispatch(origin_of(account_of(ALICE))), @@ -113,12 +112,10 @@ fn integration_test_submit_fork_headers() { SecurityPallet::set_active_block_number(1); let genesis_height = 0; - let raw_genesis_header = test_data[0]; - // Note: the testdata set is old and hence this is a block version below 4 // Therefore, this is stored directly from the parsed block in the `btc-relay` pallet // without going through the `relay` pallet, which checks for the block version when parsing - let genesis_header = bitcoin::parser::parse_block_header_lenient(&raw_genesis_header).unwrap(); + let genesis_header = test_data[0]; assert_ok!(BTCRelayPallet::_initialize( account_of(ALICE), @@ -128,21 +125,19 @@ fn integration_test_submit_fork_headers() { // submit the two fork headers first so that they become the main chain // chains_index[0]: [0] -> [f1] -> [f2] - for (index, raw_header) in test_data.iter().enumerate().skip(1).take(NUM_FORK_HEADERS as usize) { + for (index, header) in test_data.iter().enumerate().skip(1).take(NUM_FORK_HEADERS as usize) { SecurityPallet::set_active_block_number(index as u32); - let header = bitcoin::parser::parse_block_header_lenient(raw_header).unwrap(); - assert_ok!(BTCRelayPallet::_store_block_header(&account_of(ALICE), header)); + assert_ok!(BTCRelayPallet::_store_block_header(&account_of(ALICE), header.clone())); assert_store_main_chain_header_event(index as u32, header.hash, account_of(ALICE)); } // submit future main chain without genesis - for (index, raw_header) in test_data.iter().enumerate().skip(1 + NUM_FORK_HEADERS as usize) { + for (index, header) in test_data.iter().enumerate().skip(1 + NUM_FORK_HEADERS as usize) { SecurityPallet::set_active_block_number(index as u32); - let header = bitcoin::parser::parse_block_header_lenient(raw_header).unwrap(); let height: u32 = index as u32 - NUM_FORK_HEADERS; - assert_ok!(BTCRelayPallet::_store_block_header(&account_of(ALICE), header)); + assert_ok!(BTCRelayPallet::_store_block_header(&account_of(ALICE), header.clone())); // depending on the height and header, we expect different events and chain state match height { diff --git a/standalone/runtime/tests/test_issue.rs b/standalone/runtime/tests/test_issue.rs index 2a346a7498..cda0e6085c 100644 --- a/standalone/runtime/tests/test_issue.rs +++ b/standalone/runtime/tests/test_issue.rs @@ -475,7 +475,7 @@ fn integration_test_issue_wrapped_execute_succeeds() { let total_amount_btc = amount_btc + fee_amount_btc; // send the btc from the user to the vault - let (_tx_id, _height, proof, raw_tx, _) = generate_transaction_and_mine( + let (_tx_id, _height, merkle_proof, transaction) = generate_transaction_and_mine( Default::default(), vec![], vec![(vault_btc_address, total_amount_btc)], @@ -487,8 +487,8 @@ fn integration_test_issue_wrapped_execute_succeeds() { // alice executes the issue by confirming the btc transaction assert_ok!(RuntimeCall::Issue(IssueCall::execute_issue { issue_id: issue_id, - merkle_proof: proof, - raw_tx: raw_tx + merkle_proof, + transaction, }) .dispatch(origin_of(account_of(vault_proof_submitter)))); }); @@ -597,7 +597,7 @@ mod execute_pending_issue_tests { fn integration_test_issue_execute_precond_rawtx_valid() { test_with_initialized_vault(|vault_id| { let (issue_id, issue) = request_issue(&vault_id, vault_id.wrapped(1000)); - let (_tx_id, _height, proof, _raw_tx, mut transaction) = TransactionGenerator::new() + let (_tx_id, _height, merkle_proof, mut transaction) = TransactionGenerator::new() .with_outputs(vec![(issue.btc_address, wrapped(1000))]) .mine(); @@ -609,8 +609,8 @@ mod execute_pending_issue_tests { assert_noop!( RuntimeCall::Issue(IssueCall::execute_issue { issue_id: issue_id, - merkle_proof: proof, - raw_tx: transaction.format_with(true) + merkle_proof, + transaction, }) .dispatch(origin_of(account_of(CAROL))), BTCRelayError::InvalidTxid @@ -623,19 +623,19 @@ mod execute_pending_issue_tests { fn integration_test_issue_execute_precond_proof_valid() { test_with_initialized_vault(|vault_id| { let (issue_id, issue) = request_issue(&vault_id, vault_id.wrapped(1000)); - let (_tx_id, _height, mut proof, _raw_tx, transaction) = TransactionGenerator::new() + let (_tx_id, _height, mut merkle_proof, transaction) = TransactionGenerator::new() .with_outputs(vec![(issue.btc_address, wrapped(1))]) .mine(); SecurityPallet::set_active_block_number(SecurityPallet::active_block_number() + CONFIRMATIONS); // mangle block header in merkle proof - proof[0] += 1; + merkle_proof.block_header = Default::default(); assert_noop!( RuntimeCall::Issue(IssueCall::execute_issue { issue_id: issue_id, - merkle_proof: proof, - raw_tx: transaction.format_with(true) + merkle_proof, + transaction, }) .dispatch(origin_of(account_of(CAROL))), BTCRelayError::BlockNotFound diff --git a/standalone/runtime/tests/test_redeem.rs b/standalone/runtime/tests/test_redeem.rs index 623dd3b4c9..3bee478957 100644 --- a/standalone/runtime/tests/test_redeem.rs +++ b/standalone/runtime/tests/test_redeem.rs @@ -455,8 +455,8 @@ mod spec_based_tests { assert_noop!( RuntimeCall::Redeem(RedeemCall::execute_redeem { redeem_id: H256::random(), - merkle_proof: vec![0; 240], - raw_tx: vec![0; 240] + merkle_proof: Default::default(), + transaction: Default::default(), }) .dispatch(origin_of(account_of(VAULT))), RedeemError::RedeemIdNotFound @@ -516,7 +516,7 @@ mod spec_based_tests { ); // The `merkleProof` MUST contain a valid proof of of `rawTX` - let (_tx_id, _tx_block_height, _merkle_proof, raw_tx, _) = generate_transaction_and_mine( + let (_tx_id, _tx_block_height, _merkle_proof, transaction) = generate_transaction_and_mine( Default::default(), vec![], vec![(user_btc_address, redeem.amount_btc())], @@ -526,8 +526,8 @@ mod spec_based_tests { assert_noop!( RuntimeCall::Redeem(RedeemCall::execute_redeem { redeem_id: redeem_id, - merkle_proof: invalid_merkle_proof, - raw_tx: raw_tx.clone() + merkle_proof: MerkleProof::parse(&invalid_merkle_proof).unwrap(), + transaction, }) .dispatch(origin_of(account_of(VAULT))), BTCRelayError::BlockNotFound @@ -1268,7 +1268,7 @@ fn integration_test_premium_redeem_wrapped_execute() { let redeem = RedeemPallet::get_open_redeem_request_from_id(&redeem_id).unwrap(); // send the btc from the vault to the user - let (_tx_id, _tx_block_height, merkle_proof, raw_tx, _) = generate_transaction_and_mine( + let (_tx_id, _tx_block_height, merkle_proof, transaction) = generate_transaction_and_mine( Default::default(), vec![], vec![(user_btc_address, redeem.amount_btc())], @@ -1278,9 +1278,9 @@ fn integration_test_premium_redeem_wrapped_execute() { SecurityPallet::set_active_block_number(1 + CONFIRMATIONS); assert_ok!(RuntimeCall::Redeem(RedeemCall::execute_redeem { - redeem_id: redeem_id, - merkle_proof: merkle_proof, - raw_tx: raw_tx + redeem_id, + merkle_proof, + transaction }) .dispatch(origin_of(account_of(VAULT)))); @@ -1336,7 +1336,7 @@ fn integration_test_multiple_redeems_multiple_op_returns() { let redeem_2 = RedeemPallet::get_open_redeem_request_from_id(&redeem_2_id).unwrap(); // try to fulfill both redeem requests in a single transaction - let (_tx_id, _tx_block_height, merkle_proof, raw_tx, _) = generate_transaction_and_mine( + let (_tx_id, _tx_block_height, merkle_proof, transaction) = generate_transaction_and_mine( Default::default(), vec![], vec![ @@ -1352,7 +1352,7 @@ fn integration_test_multiple_redeems_multiple_op_returns() { RuntimeCall::Redeem(RedeemCall::execute_redeem { redeem_id: redeem_1_id, merkle_proof: merkle_proof.clone(), - raw_tx: raw_tx.clone() + transaction: transaction.clone(), }) .dispatch(origin_of(account_of(VAULT))), BTCRelayError::InvalidOpReturnTransaction @@ -1362,7 +1362,7 @@ fn integration_test_multiple_redeems_multiple_op_returns() { RuntimeCall::Redeem(RedeemCall::execute_redeem { redeem_id: redeem_2_id, merkle_proof: merkle_proof.clone(), - raw_tx: raw_tx.clone() + transaction: transaction.clone(), }) .dispatch(origin_of(account_of(VAULT))), BTCRelayError::InvalidOpReturnTransaction @@ -1387,7 +1387,7 @@ fn integration_test_single_redeem_multiple_op_returns() { let redeem_id = assert_redeem_request_event(); let redeem = RedeemPallet::get_open_redeem_request_from_id(&redeem_id).unwrap(); - let (_tx_id, _tx_block_height, merkle_proof, raw_tx, _) = generate_transaction_and_mine( + let (_tx_id, _tx_block_height, merkle_proof, transaction) = generate_transaction_and_mine( Default::default(), vec![], vec![(user_btc_address, redeem.amount_btc())], @@ -1401,9 +1401,9 @@ fn integration_test_single_redeem_multiple_op_returns() { assert_err!( RuntimeCall::Redeem(RedeemCall::execute_redeem { - redeem_id: redeem_id, - merkle_proof: merkle_proof.clone(), - raw_tx: raw_tx.clone() + redeem_id, + merkle_proof, + transaction }) .dispatch(origin_of(account_of(VAULT))), BTCRelayError::InvalidOpReturnTransaction diff --git a/standalone/runtime/tests/test_replace.rs b/standalone/runtime/tests/test_replace.rs index c887acacff..99c26142ea 100644 --- a/standalone/runtime/tests/test_replace.rs +++ b/standalone/runtime/tests/test_replace.rs @@ -705,7 +705,7 @@ fn execute_replace_with_amount(replace_id: H256, amount: Amount) -> Dis let replace = ReplacePallet::get_open_or_cancelled_replace_request(&replace_id).unwrap(); // send the btc from the old_vault to the new_vault - let (_tx_id, _tx_block_height, merkle_proof, raw_tx, _) = generate_transaction_and_mine( + let (_tx_id, _tx_block_height, merkle_proof, transaction) = generate_transaction_and_mine( Default::default(), vec![], vec![(replace.btc_address, amount)], @@ -715,9 +715,9 @@ fn execute_replace_with_amount(replace_id: H256, amount: Amount) -> Dis SecurityPallet::set_active_block_number(SecurityPallet::active_block_number() + CONFIRMATIONS); RuntimeCall::Replace(ReplaceCall::execute_replace { - replace_id: replace_id, - merkle_proof: merkle_proof, - raw_tx: raw_tx, + replace_id, + merkle_proof, + transaction, }) .dispatch(origin_of(account_of(OLD_VAULT))) }