1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
use bitcoin::Transaction;
use sp_core::{Decode, Encode};
use sp_runtime::traits::Block as BlockT;
use subcoin_primitives::BitcoinTransactionAdapter;
/// Responsible for doing the conversion between Bitcoin transaction and Substrate extrinsic.
///
/// ## NOTE
///
/// To convert the bitcoin transactions to substrate extrinsics, the recommended
/// practice in Substrate is to leverage a runtime api for forkless upgrade such that
/// the client (node binary) does not have to be upgraded when the Pallet/Runtime call
/// is changed within the runtime. However, we don't need this convenience as the
/// pallet-bitcoin is designed to be super stable with one and only one call. Hence we
/// choose to pull in the pallet-bitcoin dependency directly for saving the cost of
/// calling a runtime api.
///
/// Using a trait also allows not to introduce the subcoin_runtime and pallet_bitcoin
/// deps when the adapter is needed in other crates, making the compilation faster.
pub struct TransactionAdapter;
impl<Block: BlockT> BitcoinTransactionAdapter<Block> for TransactionAdapter {
fn extrinsic_to_bitcoin_transaction(extrinsic: &Block::Extrinsic) -> Transaction {
let unchecked_extrinsic: subcoin_runtime::UncheckedExtrinsic =
Decode::decode(&mut extrinsic.encode().as_slice()).unwrap();
match unchecked_extrinsic.function {
subcoin_runtime::RuntimeCall::Bitcoin(pallet_bitcoin::Call::<
subcoin_runtime::Runtime,
>::transact {
btc_tx,
}) => btc_tx.into(),
_ => unreachable!("Transactions only exist in pallet-bitcoin; qed"),
}
}
fn bitcoin_transaction_into_extrinsic(btc_tx: bitcoin::Transaction) -> Block::Extrinsic {
Decode::decode(
&mut subcoin_runtime::UncheckedExtrinsic::new_bare(
pallet_bitcoin::Call::<subcoin_runtime::Runtime>::transact {
btc_tx: btc_tx.into(),
}
.into(),
)
.encode()
.as_slice(),
)
.expect("Extrinsic constructed internally must not fail; qed")
}
}