diff --git a/.github/workflows/create_release-and-upload.yml b/.github/workflows/create_release-and-upload.yml index a462f91..df8c76f 100644 --- a/.github/workflows/create_release-and-upload.yml +++ b/.github/workflows/create_release-and-upload.yml @@ -118,8 +118,8 @@ jobs: strategy: fail-fast: false matrix: -# os: [ubuntu-20.04, ubuntu-18.04, ubuntu-16.04] - os_ver: [20, 18, 16] +# os: [ubuntu-20.04, ubuntu-18.04] + os_ver: [20, 18] bin: [gcc, gcc-static] include: - bin: gcc diff --git a/Cargo.toml b/Cargo.toml index 9e53f40..24000d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cfd-rust" -version = "0.3.1" +version = "0.3.2" license = "MIT" readme = "README.md" keywords = ["build-dependencies"] diff --git a/README.md b/README.md index c72848a..5e9e021 100644 --- a/README.md +++ b/README.md @@ -105,10 +105,10 @@ Using pkg-config, build is quickly. ```Shell # The described version is an example. If you use it, please rewrite it to an appropriate version. -wget https://github.com/p2pderivatives/cfd-rust/releases/download/v0.3.0/cfd-sys-v0.3.0-osx-xcode12.4-static-x86_64.zip +wget https://github.com/p2pderivatives/cfd-rust/releases/download/v0.3.2/cfd-sys-v0.3.2-osx-xcode12.4-static-x86_64.zip # decompress -sudo unzip -d / cfd-sys-v0.3.0-osx-xcode12.4-static-x86_64.zip +sudo unzip -d / cfd-sys-v0.3.2-osx-xcode12.4-static-x86_64.zip # build cargo build ``` @@ -117,7 +117,7 @@ cargo build Using cmake find_package. -1. get releases asset. (ex. [https://github.com/p2pderivatives/cfd-rust/releases/download/v0.3.0/cfd-sys-v0.3.0-win-vs2019-x86_64.zip](https://github.com/p2pderivatives/cfd-rust/releases/download/v0.3.0/cfd-sys-v0.3.0-win-vs2019-x86_64.zip) ) +1. get releases asset. (ex. [https://github.com/p2pderivatives/cfd-rust/releases/download/v0.3.2/cfd-sys-v0.3.2-win-vs2019-x86_64.zip](https://github.com/p2pderivatives/cfd-rust/releases/download/v0.3.2/cfd-sys-v0.3.2-win-vs2019-x86_64.zip) ) 2. Expand to PATH --- diff --git a/cfd-sys/Cargo.toml b/cfd-sys/Cargo.toml index e7a5257..e694411 100644 --- a/cfd-sys/Cargo.toml +++ b/cfd-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cfd_sys" -version = "0.3.1" +version = "0.3.2" license = "MIT" readme = "../README.md" keywords = ["build-dependencies"] diff --git a/cfd-sys/cfd-cmake/external/CMakeLists.txt b/cfd-sys/cfd-cmake/external/CMakeLists.txt index d239ebd..3e9169f 100644 --- a/cfd-sys/cfd-cmake/external/CMakeLists.txt +++ b/cfd-sys/cfd-cmake/external/CMakeLists.txt @@ -43,7 +43,7 @@ if(CFD_TARGET_VERSION) set(CFD_TARGET_TAG ${CFD_TARGET_VERSION}) message(STATUS "[external project local] cfd target=${CFD_TARGET_VERSION}") else() -set(CFD_TARGET_TAG v0.3.1) +set(CFD_TARGET_TAG v0.3.2) endif() if(CFD_TARGET_URL) set(CFD_TARGET_REP ${CFD_TARGET_URL}) diff --git a/cfd-sys/src/lib.rs b/cfd-sys/src/lib.rs index 7baa79d..3e2c3bc 100644 --- a/cfd-sys/src/lib.rs +++ b/cfd-sys/src/lib.rs @@ -124,6 +124,16 @@ fns! { claim_script: *mut *mut c_char, tweaked_fedpeg_script: *mut *mut c_char, ) -> c_int; + pub fn CfdGetPegoutAddress( + handle: *const c_void, + mainchain_network: c_int, + elements_network: c_int, + descriptor: *const c_char, + bip32_counter: c_uint, + address_type: c_int, + mainchain_address: *mut *mut c_char, + base_descriptor: *mut *mut c_char, + ) -> c_int; pub fn CfdParseDescriptor( handle: *const c_void, descriptor: *const i8, @@ -185,6 +195,61 @@ fns! { descriptor: *const c_char, descriptor_added_checksum: *mut *mut c_char, ) -> c_int; + + pub fn CfdInitializeBlockHandle( + handle: *const c_void, + network_type: c_int, + block_hex: *const c_char, + block_handle: *mut *mut c_void, + ) -> c_int; + pub fn CfdFreeBlockHandle( + handle: *const c_void, + block_handle: *const c_void, + ) -> c_int; + pub fn CfdGetBlockHash( + handle: *const c_void, + block_handle: *const c_void, + block_hash: *mut *mut c_char, + ) -> c_int; + pub fn CfdGetBlockHeaderData( + handle: *const c_void, + block_handle: *const c_void, + version: *mut c_uint, + prev_block_hash: *mut *mut c_char, + merkle_root_hash: *mut *mut c_char, + time: *mut c_uint, + bits: *mut c_uint, + nonce: *mut c_uint, + ) -> c_int; + pub fn CfdGetTransactionFromBlock( + handle: *const c_void, + block_handle: *const c_void, + txid: *const c_char, + tx_hex: *mut *mut c_char, + ) -> c_int; + pub fn CfdGetTxOutProof( + handle: *const c_void, + block_handle: *const c_void, + txid: *const c_char, + txout_proof: *mut *mut c_char, + ) -> c_int; + pub fn CfdExistTxidInBlock( + handle: *const c_void, + block_handle: *const c_void, + txid: *const c_char, + ) -> c_int; + pub fn CfdGetTxCountInBlock( + handle: *const c_void, + block_handle: *const c_void, + tx_count: *mut c_uint, + ) -> c_int; + pub fn CfdGetTxidFromBlock( + handle: *const c_void, + block_handle: *const c_void, + index: c_uint, + txid: *mut *mut c_char, + ) -> c_int; + pub fn CfdCreateExtkeyFromSeed( handle: *const c_void, seed_hex: *const i8, @@ -242,7 +307,7 @@ fns! { network_type: c_int, pubkey: *mut *mut c_char, ) -> c_int; - pub fn CfdGetExtkeyInformation( + pub fn CfdGetExtkeyInfo( handle: *const c_void, extkey: *const i8, version: *mut *mut c_char, @@ -250,6 +315,8 @@ fns! { chain_code: *mut *mut c_char, depth: *mut c_uint, child_number: *mut c_uint, + key_type: *mut c_int, + network_type: *mut c_int, ) -> c_int; pub fn CfdInitializeMnemonicWordList( @@ -753,6 +820,13 @@ fns! { vout: c_uint, script_sig: *const i8, ) -> c_int; + pub fn CfdUpdateTxInSequence( + handle: *const c_void, + create_handle: *const c_void, + txid: *const i8, + vout: c_uint, + sequence: c_uint, + ) -> c_int; pub fn CfdSetTransactionUtxoData( handle: *const c_void, create_handle: *const c_void, @@ -1082,7 +1156,7 @@ fns! { is_blind_issuance: bool, is_pegin: bool, pegin_btc_tx_size: c_uint, - fedpeg_script: *const i8, + claim_script: *const i8, ) -> c_int; pub fn CfdAddTxInTemplateForEstimateFee( handle: *const c_void, @@ -1095,7 +1169,22 @@ fns! { is_blind_issuance: bool, is_pegin: bool, pegin_btc_tx_size: c_uint, - fedpeg_script: *const i8, + claim_script: *const i8, + scriptsig_template: *const i8, + ) -> c_int; + pub fn CfdAddTxInputForEstimateFee( + handle: *const c_void, + fee_handle: *const c_void, + txid: *const i8, + vout: c_uint, + descriptor: *const i8, + asset: *const i8, + is_issuance: bool, + is_blind_issuance: bool, + is_pegin: bool, + claim_script: *const i8, + pegin_btc_tx_size: c_uint, + pegin_txoutproof_size: c_uint, scriptsig_template: *const i8, ) -> c_int; pub fn CfdSetOptionEstimateFee( @@ -1136,7 +1225,7 @@ fns! { is_blind_issuance: bool, is_pegin: bool, pegin_btc_tx_size: c_uint, - fedpeg_script: *const i8, + claim_script: *const i8, ) -> c_int; pub fn CfdAddTxInTemplateForFundRawTx( handle: *const c_void, @@ -1150,7 +1239,23 @@ fns! { is_blind_issuance: bool, is_pegin: bool, pegin_btc_tx_size: c_uint, - fedpeg_script: *const i8, + claim_script: *const i8, + scriptsig_template: *const i8, + ) -> c_int; + pub fn CfdAddTxInputForFundRawTx( + handle: *const c_void, + fund_handle: *const c_void, + txid: *const i8, + vout: c_uint, + amount: c_longlong, + descriptor: *const i8, + asset: *const i8, + is_issuance: bool, + is_blind_issuance: bool, + is_pegin: bool, + claim_script: *const i8, + pegin_btc_tx_size: c_uint, + pegin_txoutproof_size: c_uint, scriptsig_template: *const i8, ) -> c_int; pub fn CfdAddUtxoForFundRawTx( @@ -1323,6 +1428,11 @@ fns! { handle: *const c_void, tx_data_handle: *const c_void, txid: *mut *mut c_char, wtxid: *mut *mut c_char, wit_hash: *mut *mut c_char, size: *mut c_uint, vsize: *mut c_uint, weight: *mut c_uint, version: *mut c_uint, locktime: *mut c_uint) -> c_int; + pub fn CfdHasPegoutConfidentialTxOut( + handle: *const c_void, tx_data_handle: *const c_void, index: c_uint) -> c_int; + pub fn CfdGetPegoutMainchainAddress( + handle: *const c_void, tx_data_handle: *const c_void, index: c_uint, + mainchain_network: c_int, mainchain_address: *mut *mut c_char) -> c_int; pub fn CfdGetTxInIssuanceInfoByHandle( handle: *const c_void, tx_data_handle: *const c_void, index: c_uint, entropy: *mut *mut c_char, nonce: *mut *mut c_char, asset_amount: *mut c_longlong, asset_value: *mut *mut c_char, @@ -1436,6 +1546,19 @@ fns! { master_online_key: *const c_char, mainchain_output_descriptor: *const c_char, bip32_counter: c_uint, whitelist: *const c_char, mainchain_address: *mut *mut c_char) -> c_int; + pub fn CfdUnblindTxOutData( + handle: *const c_void, + blinding_key: *const c_char, + locking_script: *const c_char, + asset_commitment: *const c_char, + value_commitment: *const c_char, + commitment_nonce: *const c_char, + rangeproof: *const c_char, + asset: *mut *mut c_char, + amount: *mut c_longlong, + asset_blind_factor: *mut *mut c_char, + value_blind_factor: *mut *mut c_char, + ) -> c_int; pub fn CfdCreatePsbtHandle( handle: *const c_void, net_type: c_int, psbt_string: *const c_char, tx_hex_string: *const c_char, version: c_uint, locktime: c_uint, diff --git a/src/address.rs b/src/address.rs index a5ad4ce..bc22d9f 100644 --- a/src/address.rs +++ b/src/address.rs @@ -6,6 +6,7 @@ use crate::common::{ alloc_c_string, collect_cstring_and_free, collect_multi_cstring_and_free, ByteData, CfdError, ErrorHandle, Network, }; +use crate::descriptor::Descriptor; use crate::{key::Pubkey, schnorr::SchnorrPubkey, script::Script}; use std::fmt; use std::ptr; @@ -15,6 +16,7 @@ use std::str::FromStr; use self::cfd_sys::{ CfdCreateAddress, CfdFreeAddressesMultisigHandle, CfdGetAddressFromLockingScript, CfdGetAddressFromMultisigKey, CfdGetAddressInfo, CfdGetAddressesFromMultisig, CfdGetPeginAddress, + CfdGetPegoutAddress, }; /// Hash type of locking script. @@ -52,7 +54,7 @@ impl HashType { } } - pub(in crate) fn to_c_value(&self) -> c_int { + pub(in crate) fn to_c_value(self) -> c_int { match self { HashType::P2sh => 1, HashType::P2pkh => 2, @@ -140,7 +142,7 @@ pub enum AddressType { } impl AddressType { - pub(in crate) fn to_c_value(&self) -> c_int { + pub(in crate) fn to_c_value(self) -> c_int { match self { AddressType::P2shAddress => 1, AddressType::P2pkhAddress => 2, @@ -153,7 +155,7 @@ impl AddressType { } } - pub(in crate) fn to_c_hash_type(&self) -> c_int { + pub(in crate) fn to_c_hash_type(self) -> c_int { self.to_c_value() } @@ -709,6 +711,80 @@ impl Address { }) } + /// Create pegout address. + /// + /// # Arguments + /// * `network_type` - A network type. + /// * `descriptor` - An output descriptor for pegout. + /// * `bip32_counter` - A bip32 counter for output descriptor. + /// + /// # Example + /// + /// ``` + /// use cfd_rust::{Address, Network}; + /// let descriptor = "wpkh(tpubDASgDECJvTMzUgS7GkSCxQAAWPveW7BeTPSvbi1wpUe1Mq1v743FRw1i7vTavjAb3D3Y8geCTYw2ezgiVS7SFXDXS6NpZmvr6XPjPvg632y)"; + /// let bip32_counter: u32 = 0; + /// let network = Network::Regtest; + /// let pegout_data = Address::pegout(network, &descriptor, bip32_counter).expect("Fail"); + /// ``` + pub fn pegout( + network_type: Network, + descriptor: &str, + bip32_counter: u32, + ) -> Result<(Address, String), CfdError> { + let mut addr_type: AddressType = AddressType::P2pkhAddress; + let desc_ret = Descriptor::with_derive_bip32path(descriptor, "0", &network_type); + if let Ok(desc_data) = desc_ret { + if !desc_data.has_key_hash() { + return Err(CfdError::IllegalArgument( + "support descriptor is pubkey hash only.".to_string(), + )); + } + addr_type = desc_data.get_address().address_type; + } + let mut elements_net_type: Network = Network::LiquidV1; + let mut mainchain_net_type: Network = Network::Mainnet; + if network_type.is_elements() { + elements_net_type = network_type; + if !network_type.is_mainnet() { + mainchain_net_type = Network::Regtest; + } + } else { + mainchain_net_type = network_type; + if !network_type.is_mainnet() { + elements_net_type = Network::ElementsRegtest; + } + } + + let descriptor_str = alloc_c_string(descriptor)?; + let mut handle = ErrorHandle::new()?; + let mut address: *mut c_char = ptr::null_mut(); + let mut base_descriptor: *mut c_char = ptr::null_mut(); + let error_code = unsafe { + CfdGetPegoutAddress( + handle.as_handle(), + mainchain_net_type.to_c_value(), + elements_net_type.to_c_value(), + descriptor_str.as_ptr(), + bip32_counter, + addr_type.to_c_hash_type(), + &mut address, + &mut base_descriptor, + ) + }; + let result = match error_code { + 0 => { + let str_list = unsafe { collect_multi_cstring_and_free(&[address, base_descriptor]) }?; + let addr_str = &str_list[0]; + let base_descriptor_str = &str_list[1]; + Ok((Address::from_string(addr_str)?, base_descriptor_str.clone())) + } + _ => Err(handle.get_error(error_code)), + }; + handle.free_handle(); + result + } + #[inline] pub fn is_valid(&self) -> bool { !self.address.is_empty() @@ -882,8 +958,8 @@ impl Address { let str_list = unsafe { collect_multi_cstring_and_free(&[address, pubkey]) }?; let addr_obj = &str_list[0]; let pubkey_obj = &str_list[1]; - let address = Address::from_string(&addr_obj)?; - let pubkey = Pubkey::from_str(&pubkey_obj)?; + let address = Address::from_string(addr_obj)?; + let pubkey = Pubkey::from_str(pubkey_obj)?; Ok(MultisigItem { address, pubkey }) } _ => Err(handle.get_error(error_code)), @@ -1025,9 +1101,9 @@ impl Address { let claim_script_obj = &str_list[1]; let fedpeg_script_obj = &str_list[2]; Ok(( - Address::from_string(&addr_str)?, - Script::from_hex(&claim_script_obj)?, - Script::from_hex(&fedpeg_script_obj)?, + Address::from_string(addr_str)?, + Script::from_hex(claim_script_obj)?, + Script::from_hex(fedpeg_script_obj)?, )) } _ => Err(handle.get_error(error_code)), diff --git a/src/block.rs b/src/block.rs new file mode 100644 index 0000000..f358e71 --- /dev/null +++ b/src/block.rs @@ -0,0 +1,415 @@ +extern crate cfd_sys; +extern crate libc; + +use self::libc::{c_char, c_uint, c_void}; +use crate::common::{ + alloc_c_string, byte_from_hex, collect_cstring_and_free, collect_multi_cstring_and_free, + hex_from_bytes, ErrorHandle, +}; +use crate::{ + common::{ByteData, CfdError, Network}, + transaction::{BlockHash, Transaction, Txid}, +}; +use std::fmt; +use std::ptr; +use std::result::Result::{Err, Ok}; +use std::str::FromStr; + +use self::cfd_sys::{ + CfdFreeBlockHandle, CfdGetBlockHash, CfdGetBlockHeaderData, CfdGetTransactionFromBlock, + CfdGetTxCountInBlock, CfdGetTxOutProof, CfdGetTxidFromBlock, CfdInitializeBlockHandle, +}; + +/// A container that stores a bitcoin block header. +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct BlockHeader { + pub version: u32, + pub prev_block_hash: BlockHash, + pub merkle_root: BlockHash, + pub time: u32, + pub bits: u32, + pub nonce: u32, +} + +impl Default for BlockHeader { + fn default() -> BlockHeader { + BlockHeader { + version: 0, + prev_block_hash: BlockHash::default(), + merkle_root: BlockHash::default(), + time: 0, + bits: 0, + nonce: 0, + } + } +} +/// A container that stores a bitcoin block. +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct Block { + buffer: Vec, + hash: BlockHash, + header: BlockHeader, + txid_list: Vec, +} + +impl Block { + /// Generate from slice. + /// + /// # Arguments + /// * `data` - An unsigned 8bit slice that holds the byte data. + #[inline] + pub fn from_slice(data: &[u8]) -> Result { + Block::parse(data, &Network::Mainnet) + } + + /// Generate from ByteData. + /// + /// # Arguments + /// * `data` - An unsigned 8bit slice that holds the byte data. + #[inline] + pub fn from_data(data: &ByteData) -> Result { + Block::from_slice(data.to_slice()) + } + + #[inline] + pub fn to_slice(&self) -> &Vec { + &self.buffer + } + + #[inline] + pub fn to_data(&self) -> ByteData { + ByteData::from_slice(&self.buffer) + } + + #[inline] + pub fn to_hex(&self) -> String { + hex_from_bytes(&self.buffer) + } + + /// Get the block hash + pub fn get_hash(&self) -> &BlockHash { + &self.hash + } + + /// Get the block header. + pub fn get_header(&self) -> &BlockHeader { + &self.header + } + + /// Get txid list from block. + pub fn get_txid_list(&self) -> &Vec { + &self.txid_list + } + + /// Get tx count in block. + pub fn get_tx_count(&self) -> usize { + self.txid_list.len() + } + + /// Exist txid in block + /// + /// # Arguments + /// * `txid` - A transaction id. + pub fn exist_txid(&self, txid: &Txid) -> bool { + for temp_txid in &self.txid_list { + if temp_txid == txid { + return true; + } + } + false + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.buffer.is_empty() + } + + /// Get a transaction from block. + /// + /// # Arguments + /// * `txid` - A transaction id. + pub fn get_transaction(&self, txid: &Txid) -> Result { + let mut handle = ErrorHandle::new()?; + let result = { + let hex_str = hex_from_bytes(&self.buffer); + let block_handle = BlockHandle::new(&handle, &Network::Mainnet, &hex_str)?; + let block_result = Block::get_transaction_internal(&handle, &block_handle, txid)?; + block_handle.free_handle(&handle); + block_result + }; + handle.free_handle(); + Ok(result) + } + + /// Get a txoutproof. + /// + /// # Arguments + /// * `txid` - A transaction id. + pub fn get_txoutproof(&self, txid: &Txid) -> Result { + let mut handle = ErrorHandle::new()?; + let result = { + let hex_str = hex_from_bytes(&self.buffer); + let block_handle = BlockHandle::new(&handle, &Network::Mainnet, &hex_str)?; + let block_result = Block::get_txoutproof_internal(&handle, &block_handle, txid)?; + block_handle.free_handle(&handle); + block_result + }; + handle.free_handle(); + Ok(result) + } + + /// Get transaction and txoutproof. + /// + /// # Arguments + /// * `txid` - A transaction id. + pub fn get_tx_data(&self, txid: &Txid) -> Result<(Transaction, ByteData), CfdError> { + let mut handle = ErrorHandle::new()?; + let result = { + let hex_str = hex_from_bytes(&self.buffer); + let block_handle = BlockHandle::new(&handle, &Network::Mainnet, &hex_str)?; + let block_result = { + let tx = Block::get_transaction_internal(&handle, &block_handle, txid)?; + let txoutproof = Block::get_txoutproof_internal(&handle, &block_handle, txid)?; + Ok((tx, txoutproof)) + }?; + block_handle.free_handle(&handle); + block_result + }; + handle.free_handle(); + Ok(result) + } + + #[inline] + pub(in crate) fn parse(data: &[u8], network: &Network) -> Result { + let mut handle = ErrorHandle::new()?; + let result = { + let hex_str = hex_from_bytes(data); + let block_handle = BlockHandle::new(&handle, network, &hex_str)?; + let block_result = { + let hash = Block::get_hash_internal(&handle, &block_handle)?; + let header = Block::get_header_internal(&handle, &block_handle)?; + let txid_list = Block::get_txid_list_internal(&handle, &block_handle)?; + Ok(Block { + buffer: data.to_vec(), + hash, + header, + txid_list, + }) + }?; + block_handle.free_handle(&handle); + block_result + }; + handle.free_handle(); + Ok(result) + } + + pub(in crate) fn get_hash_internal( + handle: &ErrorHandle, + block_handle: &BlockHandle, + ) -> Result { + let mut hash: *mut c_char = ptr::null_mut(); + let error_code = + unsafe { CfdGetBlockHash(handle.as_handle(), block_handle.as_handle(), &mut hash) }; + match error_code { + 0 => { + let block_hash = unsafe { collect_cstring_and_free(hash) }?; + Ok(BlockHash::from_str(&block_hash)?) + } + _ => Err(handle.get_error(error_code)), + } + } + + pub(in crate) fn get_header_internal( + handle: &ErrorHandle, + block_handle: &BlockHandle, + ) -> Result { + let mut version = 0; + let mut time = 0; + let mut bits = 0; + let mut nonce = 0; + let mut prev_block_hash: *mut c_char = ptr::null_mut(); + let mut merkle_root: *mut c_char = ptr::null_mut(); + let error_code = unsafe { + CfdGetBlockHeaderData( + handle.as_handle(), + block_handle.as_handle(), + &mut version, + &mut prev_block_hash, + &mut merkle_root, + &mut time, + &mut bits, + &mut nonce, + ) + }; + match error_code { + 0 => { + let str_list = unsafe { collect_multi_cstring_and_free(&[prev_block_hash, merkle_root]) }?; + let prev_hash = BlockHash::from_str(&str_list[0])?; + let merkle_root_obj = BlockHash::from_str(&str_list[1])?; + Ok(BlockHeader { + version, + prev_block_hash: prev_hash, + merkle_root: merkle_root_obj, + time, + bits, + nonce, + }) + } + _ => Err(handle.get_error(error_code)), + } + } + + pub(in crate) fn get_txid_list_internal( + handle: &ErrorHandle, + block_handle: &BlockHandle, + ) -> Result, CfdError> { + let tx_count = { + let mut count = 0; + let error_code = + unsafe { CfdGetTxCountInBlock(handle.as_handle(), block_handle.as_handle(), &mut count) }; + match error_code { + 0 => Ok(count), + _ => Err(handle.get_error(error_code)), + } + }?; + + let mut list: Vec = vec![]; + let mut index = 0; + while index < tx_count { + let txid = { + let mut txid_str: *mut c_char = ptr::null_mut(); + let error_code = unsafe { + CfdGetTxidFromBlock( + handle.as_handle(), + block_handle.as_handle(), + index as c_uint, + &mut txid_str, + ) + }; + match error_code { + 0 => { + let txid_hex = unsafe { collect_cstring_and_free(txid_str) }?; + Ok(Txid::from_str(&txid_hex)?) + } + _ => Err(handle.get_error(error_code)), + } + }?; + list.push(txid); + index += 1; + } + Ok(list) + } + + pub(in crate) fn get_transaction_internal( + handle: &ErrorHandle, + block_handle: &BlockHandle, + txid: &Txid, + ) -> Result { + let txid_hex = alloc_c_string(&txid.to_hex())?; + let mut tx_hex: *mut c_char = ptr::null_mut(); + let error_code: i32 = unsafe { + CfdGetTransactionFromBlock( + handle.as_handle(), + block_handle.as_handle(), + txid_hex.as_ptr(), + &mut tx_hex, + ) + }; + match error_code { + 0 => { + let tx = unsafe { collect_cstring_and_free(tx_hex) }?; + Ok(Transaction::from_str(&tx)?) + } + _ => Err(handle.get_error(error_code)), + } + } + + pub(in crate) fn get_txoutproof_internal( + handle: &ErrorHandle, + block_handle: &BlockHandle, + txid: &Txid, + ) -> Result { + let txid_hex = alloc_c_string(&txid.to_hex())?; + let mut proof: *mut c_char = ptr::null_mut(); + let error_code: i32 = unsafe { + CfdGetTxOutProof( + handle.as_handle(), + block_handle.as_handle(), + txid_hex.as_ptr(), + &mut proof, + ) + }; + match error_code { + 0 => { + let txoutproof = unsafe { collect_cstring_and_free(proof) }?; + Ok(ByteData::from_str(&txoutproof)?) + } + _ => Err(handle.get_error(error_code)), + } + } +} + +impl FromStr for Block { + type Err = CfdError; + fn from_str(text: &str) -> Result { + let buf = byte_from_hex(text)?; + Block::from_slice(&buf) + } +} + +impl Default for Block { + fn default() -> Block { + Block { + buffer: vec![], + hash: BlockHash::default(), + header: BlockHeader::default(), + txid_list: vec![], + } + } +} + +impl fmt::Display for Block { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Block[{}]", &self.hash.to_hex()) + } +} + +/// A container that tx data handler. +#[derive(Debug, Clone)] +pub(in crate) struct BlockHandle { + block_handle: *mut c_void, +} + +impl BlockHandle { + pub fn new( + handle: &ErrorHandle, + network: &Network, + block: &str, + ) -> Result { + let block_str = alloc_c_string(block)?; + let mut block_handle: *mut c_void = ptr::null_mut(); + let error_code = unsafe { + CfdInitializeBlockHandle( + handle.as_handle(), + network.to_c_value(), + block_str.as_ptr(), + &mut block_handle, + ) + }; + match error_code { + 0 => Ok(BlockHandle { block_handle }), + _ => Err(handle.get_error(error_code)), + } + } + + #[inline] + pub fn as_handle(&self) -> *const c_void { + self.block_handle + } + + pub fn free_handle(&self, handle: &ErrorHandle) { + unsafe { + CfdFreeBlockHandle(handle.as_handle(), self.block_handle); + } + } +} diff --git a/src/common.rs b/src/common.rs index bfd6c89..d495d77 100644 --- a/src/common.rs +++ b/src/common.rs @@ -97,7 +97,7 @@ pub enum Network { } impl Network { - pub(in crate) fn to_c_value(&self) -> c_int { + pub(in crate) fn to_c_value(self) -> c_int { match self { Network::Mainnet => 0, Network::Testnet => 1, @@ -127,6 +127,10 @@ impl Network { } } + pub fn is_mainnet(&self) -> bool { + matches!(self, Network::LiquidV1 | Network::Mainnet) + } + pub fn to_str(&self) -> &str { match self { Network::Mainnet => "mainnet", @@ -541,7 +545,7 @@ impl FromStr for ReverseContainer { let byte_data = ByteData::from_slice_reverse(&bytes); let reverse_bytes = byte_data.to_slice(); let data = ReverseContainer { - data: copy_array_32byte(&reverse_bytes), + data: copy_array_32byte(reverse_bytes), }; Ok(data) } diff --git a/src/confidential_address.rs b/src/confidential_address.rs index dbde83f..0d4ee31 100644 --- a/src/confidential_address.rs +++ b/src/confidential_address.rs @@ -106,8 +106,8 @@ impl ConfidentialAddress { let str_list = unsafe { collect_multi_cstring_and_free(&[address, confidential_key]) }?; let addr_obj = &str_list[0]; let ct_key_obj = &str_list[1]; - let addr = Address::from_string(&addr_obj)?; - let ct_key = Pubkey::from_str(&ct_key_obj)?; + let addr = Address::from_string(addr_obj)?; + let ct_key = Pubkey::from_str(ct_key_obj)?; Ok(ConfidentialAddress { confidential_address: confidential_address.to_string(), address: addr, diff --git a/src/confidential_transaction.rs b/src/confidential_transaction.rs index dd04e19..6e26ab3 100644 --- a/src/confidential_transaction.rs +++ b/src/confidential_transaction.rs @@ -30,7 +30,7 @@ use self::cfd_sys::{ CfdAddBlindTxInData, CfdAddBlindTxOutByAddress, CfdAddBlindTxOutData, CfdAddCoinSelectionAmount, CfdAddCoinSelectionUtxoTemplate, CfdAddConfidentialTxOutput, CfdAddConfidentialTxSignWithPrivkeySimple, CfdAddTargetAmountForFundRawTx, - CfdAddTransactionInput, CfdAddTxInTemplateForEstimateFee, CfdAddTxInTemplateForFundRawTx, + CfdAddTransactionInput, CfdAddTxInputForEstimateFee, CfdAddTxInputForFundRawTx, CfdAddTxPeginInput, CfdAddTxPegoutOutput, CfdAddUtxoTemplateForFundRawTx, CfdCreateConfidentialSighash, CfdFinalizeBlindTx, CfdFinalizeCoinSelection, CfdFinalizeEstimateFee, CfdFinalizeFundRawTx, CfdFinalizeTransaction, CfdFreeBlindHandle, @@ -38,12 +38,13 @@ use self::cfd_sys::{ CfdFreeTransactionHandle, CfdGetAppendTxOutFundRawTx, CfdGetAssetCommitment, CfdGetBlindTxBlindData, CfdGetConfidentialTxInfoByHandle, CfdGetConfidentialTxOutSimpleByHandle, CfdGetConfidentialValueHex, CfdGetDefaultBlindingKey, CfdGetIssuanceBlindingKey, - CfdGetSelectedCoinIndex, CfdGetTxInByHandle, CfdGetTxInIndexByHandle, - CfdGetTxInIssuanceInfoByHandle, CfdGetTxOutIndex, CfdGetValueCommitment, CfdInitializeBlindTx, - CfdInitializeCoinSelection, CfdInitializeEstimateFee, CfdInitializeFundRawTx, - CfdInitializeTransaction, CfdSetBlindTxOption, CfdSetIssueAsset, CfdSetOptionCoinSelection, - CfdSetOptionEstimateFee, CfdSetReissueAsset, CfdUnblindIssuance, CfdUnblindTxOut, - CfdUpdateTxOutAmount, BLIND_OPT_COLLECT_BLINDER, BLIND_OPT_EXPONENT, BLIND_OPT_MINIMUM_BITS, + CfdGetPegoutMainchainAddress, CfdGetSelectedCoinIndex, CfdGetTxInByHandle, + CfdGetTxInIndexByHandle, CfdGetTxInIssuanceInfoByHandle, CfdGetTxOutIndex, CfdGetValueCommitment, + CfdHasPegoutConfidentialTxOut, CfdInitializeBlindTx, CfdInitializeCoinSelection, + CfdInitializeEstimateFee, CfdInitializeFundRawTx, CfdInitializeTransaction, CfdSetBlindTxOption, + CfdSetIssueAsset, CfdSetOptionCoinSelection, CfdSetOptionEstimateFee, CfdSetReissueAsset, + CfdUnblindIssuance, CfdUnblindTxOut, CfdUnblindTxOutData, CfdUpdateTxOutAmount, + BLIND_OPT_COLLECT_BLINDER, BLIND_OPT_EXPONENT, BLIND_OPT_MINIMUM_BITS, BLIND_OPT_MINIMUM_RANGE_VALUE, COIN_OPT_BLIND_EXPONENT, COIN_OPT_BLIND_MINIMUM_BITS, DEFAULT_BLIND_MINIMUM_BITS, FEE_OPT_BLIND_EXPONENT, FEE_OPT_BLIND_MINIMUM_BITS, FUND_OPT_BLIND_EXPONENT, FUND_OPT_BLIND_MINIMUM_BITS, FUND_OPT_DUST_FEE_RATE, FUND_OPT_IS_BLIND, @@ -870,7 +871,7 @@ impl IssuanceKeyMap { } pub fn get_value(&self, outpoint: &OutPoint) -> Option<&IssuanceKeyItem> { - self.map.get(&outpoint) + self.map.get(outpoint) } } @@ -946,8 +947,9 @@ pub struct ElementsUtxoOptionData { pub is_issuance: bool, pub is_blind_issuance: bool, pub is_pegin: bool, + pub claim_script: Script, pub pegin_btc_tx_size: u32, - pub fedpeg_script: Script, + pub pegin_txoutproof_size: u32, } impl fmt::Display for ElementsUtxoOptionData { @@ -962,8 +964,9 @@ impl Default for ElementsUtxoOptionData { is_issuance: false, is_blind_issuance: true, is_pegin: false, + claim_script: Script::default(), pegin_btc_tx_size: 0, - fedpeg_script: Script::default(), + pegin_txoutproof_size: 0, } } } @@ -1133,11 +1136,11 @@ impl ElementsUtxoData { self.asset_blind_factor = asset_blind_factor.clone(); self.amount_blind_factor = amount_blind_factor.clone(); if !asset_blind_factor.is_empty() || !amount_blind_factor.is_empty() { - let asset_commitment = self.asset.get_commitment(&asset_blind_factor)?; + let asset_commitment = self.asset.get_commitment(asset_blind_factor)?; let commitment = ConfidentialValue::get_commitment( self.utxo.amount, &asset_commitment, - &amount_blind_factor, + amount_blind_factor, )?; if !value_commitment.eq(&commitment) { return Err(CfdError::IllegalArgument( @@ -1153,15 +1156,17 @@ impl ElementsUtxoData { is_issuance: bool, is_blind_issuance: bool, is_pegin: bool, + claim_script: &Script, pegin_btc_tx_size: u32, - fedpeg_script: &Script, + pegin_txoutproof_size: u32, ) -> ElementsUtxoData { let option = ElementsUtxoOptionData { is_issuance, is_blind_issuance, is_pegin, + claim_script: claim_script.clone(), pegin_btc_tx_size, - fedpeg_script: fedpeg_script.clone(), + pegin_txoutproof_size, }; self.option = option; self @@ -1633,6 +1638,58 @@ pub struct ConfidentialTxOut { } impl ConfidentialTxOut { + pub fn unblind( + blinding_key: &Privkey, + locking_script: &Script, + asset_commitment: &ConfidentialAsset, + value_commitment: &ConfidentialValue, + nonce: &ConfidentialNonce, + rangeproof: &ByteData, + ) -> Result { + let mut handle = ErrorHandle::new()?; + let key_hex = alloc_c_string(&blinding_key.to_hex())?; + let script_hex = alloc_c_string(&locking_script.to_hex())?; + let asset_hex = alloc_c_string(&asset_commitment.to_hex())?; + let value_hex = alloc_c_string(&value_commitment.as_str())?; + let nonce_hex = alloc_c_string(&nonce.to_hex())?; + let rangeproof_hex = alloc_c_string(&rangeproof.to_hex())?; + let mut amount: c_longlong = 0; + let mut asset: *mut c_char = ptr::null_mut(); + let mut asset_blind_factor: *mut c_char = ptr::null_mut(); + let mut value_blind_factor: *mut c_char = ptr::null_mut(); + let error_code = unsafe { + CfdUnblindTxOutData( + handle.as_handle(), + key_hex.as_ptr(), + script_hex.as_ptr(), + asset_hex.as_ptr(), + value_hex.as_ptr(), + nonce_hex.as_ptr(), + rangeproof_hex.as_ptr(), + &mut asset, + &mut amount, + &mut asset_blind_factor, + &mut value_blind_factor, + ) + }; + let result = match error_code { + 0 => { + let str_list = unsafe { + collect_multi_cstring_and_free(&[asset, asset_blind_factor, value_blind_factor]) + }?; + Ok(UnblindData { + asset: ConfidentialAsset::from_str(&str_list[0])?, + amount: ConfidentialValue::from_amount(amount)?, + asset_blind_factor: BlindFactor::from_str(&str_list[1])?, + amount_blind_factor: BlindFactor::from_str(&str_list[2])?, + }) + } + _ => Err(handle.get_error(error_code)), + }; + handle.free_handle(); + result + } + pub fn from_data_list(list: &[ConfidentialTxOutData]) -> Vec { let mut output: Vec = vec![]; output.reserve(list.len()); @@ -1819,6 +1876,27 @@ impl ConfidentialTransaction { }) } + /// Update txin sequence. + /// + /// # Arguments + /// * `outpoint` - An outpoint. + /// * `sequence` - A sequence number. + pub fn update_txin_sequence( + &self, + outpoint: &OutPoint, + sequence: u32, + ) -> Result { + let mut ope = ConfidentialTxOperation::new(&Network::LiquidV1); + let tx = ope.update_txin_sequence(&hex_from_bytes(&self.tx), outpoint, sequence)?; + Ok(ConfidentialTransaction { + tx, + data: ope.get_last_tx_data().clone(), + txin_list: ope.get_txin_list_cache().to_vec(), + txout_list: self.txout_list.clone(), + // txin_utxo_list: self.txin_utxo_list.clone(), + }) + } + /// Update witness stack. /// /// # Arguments @@ -2229,6 +2307,29 @@ impl ConfidentialTransaction { }) } + /// Has pegout into the transaction output. + /// + /// # Arguments + /// * `index` - A transaction output index. + pub fn has_pegout_txout(&self, index: u32) -> Result { + let ope = ConfidentialTxOperation::new(&Network::LiquidV1); + ope.has_pegout_txout(&hex_from_bytes(&self.tx), index) + } + + /// Get pegout address. + /// + /// # Arguments + /// * `index` - A transaction output index. + /// * `mainchain_network_type` - A mainchain network type. + pub fn get_pegout_address( + &self, + index: u32, + mainchain_network_type: Network, + ) -> Result { + let ope = ConfidentialTxOperation::new(&Network::LiquidV1); + ope.get_pegout_address(&hex_from_bytes(&self.tx), index, mainchain_network_type) + } + pub fn get_txin_index(&self, outpoint: &OutPoint) -> Result { let ope = TransactionOperation::new(&Network::LiquidV1); ope.get_txin_index_by_outpoint(&hex_from_bytes(&self.tx), outpoint) @@ -2417,7 +2518,7 @@ impl ConfidentialTransaction { let tx = ope.add_pubkey_hash_sign(&tx_hex, outpoint, hash_type, pubkey, signature)?; let new_tx_hex = ope.get_last_tx(); let mut ope2 = ConfidentialTxOperation::new(&Network::LiquidV1); - let new_txin = ope2.get_txin_by_outpoint(&new_tx_hex, outpoint)?; + let new_txin = ope2.get_txin_by_outpoint(new_tx_hex, outpoint)?; let index = ope2.get_last_txin_index(); let data = ope2.get_last_tx_data().clone(); let mut tx_obj = ConfidentialTransaction { @@ -2482,7 +2583,7 @@ impl ConfidentialTransaction { let tx = ope.sign_with_privkey(&tx_hex, outpoint, hash_type, &key, &option, true)?; let new_tx_hex = ope.get_last_tx(); let mut ope2 = ope.clone(); - let new_txin = ope2.get_txin_by_outpoint(&new_tx_hex, outpoint)?; + let new_txin = ope2.get_txin_by_outpoint(new_tx_hex, outpoint)?; let index = ope2.get_last_txin_index(); let data = ope2.get_last_tx_data().clone(); let mut tx_obj = ConfidentialTransaction { @@ -2551,7 +2652,7 @@ impl ConfidentialTransaction { let tx = ope.add_multisig_sign(&tx_hex, outpoint, hash_type, redeem_script, signature_list)?; let new_tx_hex = ope.get_last_tx(); let mut ope2 = ConfidentialTxOperation::new(&Network::LiquidV1); - let new_txin = ope2.get_txin_by_outpoint(&new_tx_hex, outpoint)?; + let new_txin = ope2.get_txin_by_outpoint(new_tx_hex, outpoint)?; let index = ope2.get_last_txin_index(); let data = ope2.get_last_tx_data().clone(); let mut tx_obj = ConfidentialTransaction { @@ -2609,7 +2710,7 @@ impl ConfidentialTransaction { let tx = ope.add_sign(&tx_hex, outpoint, hash_type, sign_data, clear_stack)?; let new_tx_hex = ope.get_last_tx(); let mut ope2 = ConfidentialTxOperation::new(&Network::LiquidV1); - let new_txin = ope2.get_txin_by_outpoint(&new_tx_hex, outpoint)?; + let new_txin = ope2.get_txin_by_outpoint(new_tx_hex, outpoint)?; let index = ope2.get_last_txin_index(); let data = ope2.get_last_tx_data().clone(); let mut tx_obj = ConfidentialTransaction { @@ -2679,7 +2780,7 @@ impl ConfidentialTransaction { )?; let new_tx_hex = ope.get_last_tx(); let mut ope2 = ConfidentialTxOperation::new(&Network::LiquidV1); - let new_txin = ope2.get_txin_by_outpoint(&new_tx_hex, outpoint)?; + let new_txin = ope2.get_txin_by_outpoint(new_tx_hex, outpoint)?; let index = ope2.get_last_txin_index(); let data = ope2.get_last_tx_data().clone(); let mut tx_obj = ConfidentialTransaction { @@ -3139,7 +3240,7 @@ impl ConfidentialTxOperation { } for ct_addr in confidential_addresses.iter() { let _ret = { - let addr = alloc_c_string(&ct_addr.to_str())?; + let addr = alloc_c_string(ct_addr.to_str())?; let error_code = unsafe { CfdAddBlindTxOutByAddress(handle.as_handle(), blind_handle, addr.as_ptr()) }; @@ -3659,6 +3760,62 @@ impl ConfidentialTxOperation { } } + pub fn has_pegout_txout(&self, tx: &str, index: u32) -> Result { + let mut handle = ErrorHandle::new()?; + let result = { + let tx_handle = TxDataHandle::new(&handle, &self.network, tx)?; + let tx_result = { + let error_code = unsafe { + CfdHasPegoutConfidentialTxOut(handle.as_handle(), tx_handle.as_handle(), index) + }; + match error_code { + 0 => Ok(true), + 7 => Ok(false), + _ => Err(handle.get_error(error_code)), + } + }; + tx_handle.free_handle(&handle); + tx_result + }; + handle.free_handle(); + result + } + + pub fn get_pegout_address( + &self, + tx: &str, + index: u32, + mainchain_network_type: Network, + ) -> Result { + let mut handle = ErrorHandle::new()?; + let result = { + let tx_handle = TxDataHandle::new(&handle, &self.network, tx)?; + let tx_result = { + let mut address: *mut c_char = ptr::null_mut(); + let error_code = unsafe { + CfdGetPegoutMainchainAddress( + handle.as_handle(), + tx_handle.as_handle(), + index, + mainchain_network_type.to_c_value(), + &mut address, + ) + }; + match error_code { + 0 => { + let addr_str = unsafe { collect_cstring_and_free(address) }?; + Address::from_str(&addr_str) + } + _ => Err(handle.get_error(error_code)), + } + }; + tx_handle.free_handle(&handle); + tx_result + }; + handle.free_handle(); + result + } + pub fn create( &mut self, version: u32, @@ -3678,6 +3835,33 @@ impl ConfidentialTxOperation { self.create_tx(0, 0, tx, txin_list, txout_list) } + pub fn update_txin_sequence( + &mut self, + tx: &str, + outpoint: &OutPoint, + sequence: u32, + ) -> Result, CfdError> { + let mut handle = ErrorHandle::new()?; + let result = { + let tx_handle = TxDataHandle::new(&handle, &self.network, tx)?; + let tx_result = { + TransactionOperation::update_txin_sequence_internal( + &CreateTxData::new(&self.network), + &handle, + &tx_handle, + outpoint, + sequence, + )?; + self.get_txin_by_outpoint_internal(&handle, &tx_handle, &String::default(), outpoint)?; + self.get_tx_internal(&handle, &tx_handle, &String::default()) + }?; + tx_handle.free_handle(&handle); + tx_result + }; + handle.free_handle(); + Ok(result) + } + pub fn update_witness_stack( &mut self, tx: &str, @@ -3832,7 +4016,7 @@ impl ConfidentialTxOperation { &tx_handle, &String::default(), index, - &txout_list, + txout_list, )?; self.tx_data = self.get_all_data_internal(&handle, &tx_handle, &String::default())?; self.get_tx_internal(&handle, &tx_handle, &String::default()) @@ -3864,24 +4048,24 @@ impl ConfidentialTxOperation { ) -> Result { let tx_data_handle = match tx_handle.is_null() { false => tx_handle.clone(), - _ => TxDataHandle::new(&handle, &self.network, tx)?, + _ => TxDataHandle::new(handle, &self.network, tx)?, }; let result = { - let data = self.get_tx_data_internal(&handle, &tx_handle, tx)?; + let data = self.get_tx_data_internal(handle, tx_handle, tx)?; let in_count = - TransactionOperation::get_count_internal(&self.network, &handle, &tx_handle, tx, true)?; + TransactionOperation::get_count_internal(&self.network, handle, tx_handle, tx, true)?; let out_count = - TransactionOperation::get_count_internal(&self.network, &handle, &tx_handle, tx, false)?; + TransactionOperation::get_count_internal(&self.network, handle, tx_handle, tx, false)?; let in_indexes = ConfidentialTxOperation::create_index_list(in_count); let out_indexes = ConfidentialTxOperation::create_index_list(out_count); - let in_data = self.get_tx_input_list_internal(&handle, &tx_handle, tx, &in_indexes)?; - let out_data = self.get_tx_output_list_internal(&handle, &tx_handle, tx, &out_indexes)?; + let in_data = self.get_tx_input_list_internal(handle, tx_handle, tx, &in_indexes)?; + let out_data = self.get_tx_output_list_internal(handle, tx_handle, tx, &out_indexes)?; self.txin_list = in_data; self.txout_list = out_data; Ok(data) }; if tx_handle.is_null() { - tx_data_handle.free_handle(&handle); + tx_data_handle.free_handle(handle); } result } @@ -3915,7 +4099,7 @@ impl ConfidentialTxOperation { ) -> Result, CfdError> { let tx_data_handle = match tx_handle.is_null() { false => tx_handle.clone(), - _ => TxDataHandle::new(&handle, &self.network, tx)?, + _ => TxDataHandle::new(handle, &self.network, tx)?, }; let mut output: *mut c_char = ptr::null_mut(); let result = { @@ -3932,7 +4116,7 @@ impl ConfidentialTxOperation { } }; if tx_handle.is_null() { - tx_data_handle.free_handle(&handle); + tx_data_handle.free_handle(handle); } result } @@ -3952,7 +4136,7 @@ impl ConfidentialTxOperation { ) -> Result { let tx_data_handle = match tx_handle.is_null() { false => tx_handle.clone(), - _ => TxDataHandle::new(&handle, &self.network, tx)?, + _ => TxDataHandle::new(handle, &self.network, tx)?, }; let mut data = ConfidentialTxData::default(); let mut txid: *mut c_char = ptr::null_mut(); @@ -3986,7 +4170,7 @@ impl ConfidentialTxOperation { _ => Err(handle.get_error(error_code)), }; if tx_handle.is_null() { - tx_data_handle.free_handle(&handle); + tx_data_handle.free_handle(handle); } result } @@ -4046,7 +4230,7 @@ impl ConfidentialTxOperation { ) -> Result { let tx_data_handle = match tx_handle.is_null() { false => tx_handle.clone(), - _ => TxDataHandle::new(&handle, &self.network, tx)?, + _ => TxDataHandle::new(handle, &self.network, tx)?, }; let list_result = { let index = { @@ -4068,8 +4252,8 @@ impl ConfidentialTxOperation { }?; let indexes = vec![index]; - let list_result = self.get_tx_input_list_internal(&handle, &tx_data_handle, tx, &indexes)?; - let data_result = self.get_tx_data_internal(&handle, &tx_data_handle, tx)?; + let list_result = self.get_tx_input_list_internal(handle, &tx_data_handle, tx, &indexes)?; + let data_result = self.get_tx_data_internal(handle, &tx_data_handle, tx)?; self.tx_data = data_result; if list_result.is_empty() { Err(CfdError::Internal("Failed to empty list.".to_string())) @@ -4080,7 +4264,7 @@ impl ConfidentialTxOperation { } }; if tx_handle.is_null() { - tx_data_handle.free_handle(&handle); + tx_data_handle.free_handle(handle); } list_result } @@ -4094,7 +4278,7 @@ impl ConfidentialTxOperation { ) -> Result, CfdError> { let tx_data_handle = match tx_handle.is_null() { false => tx_handle.clone(), - _ => TxDataHandle::new(&handle, &self.network, tx)?, + _ => TxDataHandle::new(handle, &self.network, tx)?, }; let mut list: Vec = vec![]; list.reserve(indexes.len()); @@ -4122,18 +4306,18 @@ impl ConfidentialTxOperation { let txid_ret = Txid::from_str(&str_list[0])?; let script_ret = Script::from_hex(&str_list[1])?; let script_witness = TransactionOperation::get_tx_input_witness( - &handle, + handle, &tx_data_handle, *index, WITNESS_STACK_TYPE_NORMAL, )?; let pegin_witness = TransactionOperation::get_tx_input_witness( - &handle, + handle, &tx_data_handle, *index, WITNESS_STACK_TYPE_PEGIN, )?; - let issuance = self.get_tx_input_issuance(&handle, &tx_data_handle, *index)?; + let issuance = self.get_tx_input_issuance(handle, &tx_data_handle, *index)?; data.outpoint = OutPoint::new(&txid_ret, data.outpoint.get_vout()); data.script_sig = script_ret; data.script_witness = script_witness; @@ -4155,7 +4339,7 @@ impl ConfidentialTxOperation { } }; if tx_handle.is_null() { - tx_data_handle.free_handle(&handle); + tx_data_handle.free_handle(handle); } result } @@ -4169,7 +4353,7 @@ impl ConfidentialTxOperation { ) -> Result, CfdError> { let tx_data_handle = match tx_handle.is_null() { false => tx_handle.clone(), - _ => TxDataHandle::new(&handle, &self.network, tx)?, + _ => TxDataHandle::new(handle, &self.network, tx)?, }; let mut list: Vec = vec![]; list.reserve(indexes.len()); @@ -4226,7 +4410,7 @@ impl ConfidentialTxOperation { } }; if tx_handle.is_null() { - tx_data_handle.free_handle(&handle); + tx_data_handle.free_handle(handle); } result } @@ -4346,12 +4530,12 @@ impl ConfidentialTxOperation { for txin_data in txin_list { let _err = { let txid = alloc_c_string(&txin_data.utxo.outpoint.get_txid().to_hex())?; - let descriptor = alloc_c_string(&txin_data.utxo.descriptor.to_str())?; + let descriptor = alloc_c_string(txin_data.utxo.descriptor.to_str())?; let sig_tmpl = alloc_c_string(&txin_data.utxo.scriptsig_template.to_hex())?; let asset = alloc_c_string(&txin_data.asset.get_unblind_asset()?)?; - let fedpeg_script = alloc_c_string(&txin_data.option.fedpeg_script.to_hex())?; + let claim_script = alloc_c_string(&txin_data.option.claim_script.to_hex())?; let error_code = unsafe { - CfdAddTxInTemplateForEstimateFee( + CfdAddTxInputForEstimateFee( handle.as_handle(), fee_handle, txid.as_ptr(), @@ -4361,8 +4545,9 @@ impl ConfidentialTxOperation { txin_data.option.is_issuance, txin_data.option.is_blind_issuance, txin_data.option.is_pegin, + claim_script.as_ptr(), + txin_data.option.pegin_btc_tx_size, txin_data.option.pegin_btc_tx_size, - fedpeg_script.as_ptr(), sig_tmpl.as_ptr(), ) }; @@ -4444,7 +4629,7 @@ impl ConfidentialTxOperation { for (index, utxo_data) in utxo_list.iter().enumerate() { let _err = { let txid = alloc_c_string(&utxo_data.utxo.outpoint.get_txid().to_hex())?; - let descriptor = alloc_c_string(&utxo_data.utxo.descriptor.to_str())?; + let descriptor = alloc_c_string(utxo_data.utxo.descriptor.to_str())?; let sig_tmpl = alloc_c_string(&utxo_data.utxo.scriptsig_template.to_hex())?; let asset = alloc_c_string(&utxo_data.asset.get_unblind_asset()?)?; let error_code = unsafe { @@ -4612,12 +4797,12 @@ impl ConfidentialTxOperation { for txin_data in txin_list { let _err = { let txid = alloc_c_string(&txin_data.utxo.outpoint.get_txid().to_hex())?; - let descriptor = alloc_c_string(&txin_data.utxo.descriptor.to_str())?; + let descriptor = alloc_c_string(txin_data.utxo.descriptor.to_str())?; let sig_tmpl = alloc_c_string(&txin_data.utxo.scriptsig_template.to_hex())?; let asset = alloc_c_string(&txin_data.asset.get_unblind_asset()?)?; - let fedpeg_script = alloc_c_string(&txin_data.option.fedpeg_script.to_hex())?; + let claim_script = alloc_c_string(&txin_data.option.claim_script.to_hex())?; let error_code = unsafe { - CfdAddTxInTemplateForFundRawTx( + CfdAddTxInputForFundRawTx( handle.as_handle(), fund_handle, txid.as_ptr(), @@ -4628,8 +4813,9 @@ impl ConfidentialTxOperation { txin_data.option.is_issuance, txin_data.option.is_blind_issuance, txin_data.option.is_pegin, + claim_script.as_ptr(), txin_data.option.pegin_btc_tx_size, - fedpeg_script.as_ptr(), + txin_data.option.pegin_txoutproof_size, sig_tmpl.as_ptr(), ) }; @@ -4642,7 +4828,7 @@ impl ConfidentialTxOperation { for utxo_data in utxo_list { let _err = { let txid = alloc_c_string(&utxo_data.utxo.outpoint.get_txid().to_hex())?; - let descriptor = alloc_c_string(&utxo_data.utxo.descriptor.to_str())?; + let descriptor = alloc_c_string(utxo_data.utxo.descriptor.to_str())?; let sig_tmpl = alloc_c_string(&utxo_data.utxo.scriptsig_template.to_hex())?; let asset = alloc_c_string(&utxo_data.asset.get_unblind_asset()?)?; let error_code = unsafe { diff --git a/src/descriptor.rs b/src/descriptor.rs index 6dbb9d6..96f705c 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -684,6 +684,11 @@ impl Descriptor { Descriptor::multisig_base(pubkey_list, require_num, hash_type, network_type, true) } + pub fn taproot_single(schnorr_pubkey: &SchnorrPubkey) -> Result { + let desc = format!("tr({})", schnorr_pubkey.to_hex()); + Descriptor::new(&desc, &Network::Mainnet) + } + fn multisig_base( pubkey_list: &[Pubkey], require_num: u8, @@ -798,15 +803,15 @@ impl Descriptor { let schnorr_pubkey_obj = &str_list[6]; let tree_string_obj = &str_list[7]; let addr = match addr_str.is_empty() { - false => Address::from_string(&addr_str)?, + false => Address::from_string(addr_str)?, _ => Address::default(), }; let script = match script_str.is_empty() { - false => Script::from_hex(&script_str)?, + false => Script::from_hex(script_str)?, _ => Script::default(), }; let script_tree = match tree_string_obj.is_empty() { - false => TapBranch::from_string(&tree_string_obj)?, + false => TapBranch::from_string(tree_string_obj)?, _ => TapBranch::default(), }; if is_multisig { @@ -818,10 +823,10 @@ impl Descriptor { DescriptorKeyType::Null => KeyData::default(), _ => Descriptor::collect_key_data( key_type, - &pubkey_obj, - &ext_pubkey_obj, - &ext_privkey_obj, - &schnorr_pubkey_obj, + pubkey_obj, + ext_pubkey_obj, + ext_privkey_obj, + schnorr_pubkey_obj, )?, }; Ok(DescriptorScriptData { @@ -897,10 +902,10 @@ impl Descriptor { let mut addr = Address::default(); let mut script = Script::default(); if !addr_str.is_empty() { - addr = Address::from_string(&addr_str)?; + addr = Address::from_string(addr_str)?; } if !script_str.is_empty() { - script = Script::from_hex(&script_str)?; + script = Script::from_hex(script_str)?; } let type_obj = DescriptorScriptType::from_c_value(script_type); let hash_type_obj = HashType::from_c_value(hash_type); @@ -908,9 +913,9 @@ impl Descriptor { DescriptorScriptType::Pk | DescriptorScriptType::Pkh | DescriptorScriptType::Wpkh => { let key_data = Descriptor::collect_key_data( key_type, - &pubkey_obj, - &ext_pubkey_obj, - &ext_privkey_obj, + pubkey_obj, + ext_pubkey_obj, + ext_privkey_obj, "", )?; Ok(DescriptorScriptData::from_pubkey( @@ -971,9 +976,9 @@ impl Descriptor { } else { let key_data = Descriptor::collect_key_data( key_type, - &pubkey_obj, - &ext_pubkey_obj, - &ext_privkey_obj, + pubkey_obj, + ext_pubkey_obj, + ext_privkey_obj, "", )?; Ok(DescriptorScriptData::from_pubkey( @@ -1105,6 +1110,10 @@ impl Descriptor { self.root_data.script_type == DescriptorScriptType::Taproot } + pub fn has_tapscript(&self) -> bool { + self.has_taproot() && !self.root_data.script_tree.to_str().is_empty() + } + pub fn get_key_data(&self) -> Result<&KeyData, CfdError> { match self.root_data.key_data.key_type { DescriptorKeyType::Null => Err(CfdError::IllegalState("Not exist key data.".to_string())), diff --git a/src/hdwallet.rs b/src/hdwallet.rs index a5acff1..af355f3 100644 --- a/src/hdwallet.rs +++ b/src/hdwallet.rs @@ -15,7 +15,7 @@ use std::str::FromStr; use self::cfd_sys::{ CfdConvertEntropyToMnemonic, CfdConvertMnemonicToSeed, CfdCreateExtPubkey, CfdCreateExtkey, CfdCreateExtkeyFromParent, CfdCreateExtkeyFromParentPath, CfdCreateExtkeyFromSeed, - CfdFreeMnemonicWordList, CfdGetExtkeyInformation, CfdGetMnemonicWord, CfdGetPrivkeyFromExtkey, + CfdFreeMnemonicWordList, CfdGetExtkeyInfo, CfdGetMnemonicWord, CfdGetPrivkeyFromExtkey, CfdGetPubkeyFromExtkey, CfdInitializeMnemonicWordList, }; @@ -36,12 +36,20 @@ pub(in crate) enum ExtKeyType { } impl ExtKeyType { - pub fn to_c_value(&self) -> c_int { + pub fn to_c_value(self) -> c_int { match self { ExtKeyType::Privkey => 0, ExtKeyType::Pubkey => 1, } } + + pub fn from_c_value(key_type: c_int) -> Result { + match key_type { + 0 => Ok(ExtKeyType::Privkey), + 1 => Ok(ExtKeyType::Pubkey), + _ => Err(CfdError::IllegalArgument("Invalid extkeytype".to_string())), + } + } } impl fmt::Display for ExtKeyType { @@ -115,7 +123,7 @@ fn generate_privkey(extkey: &str, network_type: Network) -> Result Result { + fn from_extkey(extkey: &str) -> Result<(ExtKey, ExtKeyType), CfdError> { let extkey_str = alloc_c_string(extkey)?; let mut handle = ErrorHandle::new()?; let mut version: *mut c_char = ptr::null_mut(); @@ -123,8 +131,10 @@ impl ExtKey { let mut chain_code: *mut c_char = ptr::null_mut(); let mut depth: c_uint = 0; let mut child_number: c_uint = 0; + let mut key_type: c_int = 0; + let mut network_type: c_int = 0; let error_code = unsafe { - CfdGetExtkeyInformation( + CfdGetExtkeyInfo( handle.as_handle(), extkey_str.as_ptr(), &mut version, @@ -132,6 +142,8 @@ impl ExtKey { &mut chain_code, &mut depth, &mut child_number, + &mut key_type, + &mut network_type, ) }; let result = match error_code { @@ -144,24 +156,20 @@ impl ExtKey { let version_byte = byte_from_hex_unsafe(version_str); let fingerprint_byte = byte_from_hex_unsafe(fingerprint_obj); let chain_code_byte = byte_from_hex_unsafe(chain_code_obj); - let net_type = match &version_str as &str { - XPRIV_MAINNET_VERSION => Ok(Network::Mainnet), - XPRIV_TESTNET_VERSION => Ok(Network::Testnet), - XPUB_MAINNET_VERSION => Ok(Network::Mainnet), - XPUB_TESTNET_VERSION => Ok(Network::Testnet), - _ => Err(CfdError::IllegalArgument( - "unsupported version.".to_string(), - )), - }?; - Ok(ExtKey { - extkey: extkey.to_string(), - version: ByteData::from_slice(&version_byte), - fingerprint: ByteData::from_slice(&fingerprint_byte), - chain_code: ByteData::from_slice(&chain_code_byte), - depth: depth as u8, - child_number, - network_type: net_type, - }) + let net_type = Network::from_c_value(network_type); + let extkey_type = ExtKeyType::from_c_value(key_type)?; + Ok(( + ExtKey { + extkey: extkey.to_string(), + version: ByteData::from_slice(&version_byte), + fingerprint: ByteData::from_slice(&fingerprint_byte), + chain_code: ByteData::from_slice(&chain_code_byte), + depth: depth as u8, + child_number, + network_type: net_type, + }, + extkey_type, + )) } _ => Err(handle.get_error(error_code)), }; @@ -192,7 +200,8 @@ impl ExtKey { let result = match error_code { 0 => { let extkey_obj = unsafe { collect_cstring_and_free(extkey_hex) }?; - ExtKey::from_extkey(&extkey_obj) + let (extkey, _) = ExtKey::from_extkey(&extkey_obj)?; + Ok(extkey) } _ => Err(handle.get_error(error_code)), }; @@ -210,7 +219,7 @@ impl ExtKey { } let mut temp_extkey = self.clone(); for child_number in number_list { - temp_extkey = temp_extkey.derive_from_number(*child_number, false, &key_type)?; + temp_extkey = temp_extkey.derive_from_number(*child_number, false, key_type)?; } Ok(temp_extkey) } @@ -237,7 +246,8 @@ impl ExtKey { let result = match error_code { 0 => { let extkey_obj = unsafe { collect_cstring_and_free(extkey_hex) }?; - ExtKey::from_extkey(&extkey_obj) + let (extkey, _) = ExtKey::from_extkey(&extkey_obj)?; + Ok(extkey) } _ => Err(handle.get_error(error_code)), }; @@ -359,11 +369,11 @@ impl ExtPrivkey { /// let extkey = ExtPrivkey::new(key).expect("Fail"); /// ``` pub fn new(extkey: &str) -> Result { - let extkey_ret = ExtKey::from_extkey(extkey); - if let Err(ret) = extkey_ret { - return Err(ret); + let (extkey_ret, key_type) = ExtKey::from_extkey(extkey)?; + if key_type != ExtKeyType::Privkey { + return Err(CfdError::IllegalArgument("Invalid key type".to_string())); } - ExtPrivkey::from_key(extkey_ret.unwrap()) + ExtPrivkey::from_key(extkey_ret) } fn from_key(extkey: ExtKey) -> Result { @@ -447,7 +457,7 @@ impl ExtPrivkey { /// let ext_pubkey = extkey.get_ext_pubkey().expect("Fail"); /// ``` pub fn get_ext_pubkey(&self) -> Result { - let extkey_str = alloc_c_string(&self.extkey.to_str())?; + let extkey_str = alloc_c_string(self.extkey.to_str())?; let mut handle = ErrorHandle::new()?; let mut ext_pubkey_hex: *mut c_char = ptr::null_mut(); let error_code = unsafe { @@ -626,7 +636,10 @@ impl ExtPubkey { /// let extkey = ExtPubkey::new(key).expect("Fail"); /// ``` pub fn new(extkey: &str) -> Result { - let extkey_ret = ExtKey::from_extkey(extkey)?; + let (extkey_ret, key_type) = ExtKey::from_extkey(extkey)?; + if key_type != ExtKeyType::Pubkey { + return Err(CfdError::IllegalArgument("Invalid key type".to_string())); + } ExtPubkey::from_key(extkey_ret) } @@ -930,7 +943,7 @@ pub enum MnemonicLanguage { } impl MnemonicLanguage { - pub(in crate) fn to_str(&self) -> String { + pub(in crate) fn to_str(self) -> String { match self { MnemonicLanguage::EN => "en".to_string(), MnemonicLanguage::ES => "es".to_string(), @@ -1045,7 +1058,7 @@ impl HDWallet { /// let mnemonic = HDWallet::mnemonic_from_entropy(&entropy, MnemonicLanguage::EN).expect("Fail"); /// ``` pub fn mnemonic_from_entropy(entropy: &[u8], lang: MnemonicLanguage) -> Result { - let entropy_hex = alloc_c_string(&hex_from_bytes(&entropy))?; + let entropy_hex = alloc_c_string(&hex_from_bytes(entropy))?; let language = alloc_c_string(&lang.to_str())?; let mut handle = ErrorHandle::new()?; let mut mnemonic: *mut c_char = ptr::null_mut(); @@ -1251,7 +1264,7 @@ impl HDWallet { network_type: &Network, bip32path: &str, ) -> Result { - let ext_priv = ExtPrivkey::from_seed(&self.seed, &network_type)?; + let ext_priv = ExtPrivkey::from_seed(&self.seed, network_type)?; ext_priv.derive_from_path(bip32path) } @@ -1276,7 +1289,7 @@ impl HDWallet { child_number: u32, hardened: bool, ) -> Result { - let ext_priv = ExtPrivkey::from_seed(&self.seed, &network_type)?; + let ext_priv = ExtPrivkey::from_seed(&self.seed, network_type)?; ext_priv.derive_from_number(child_number, hardened) } @@ -1300,7 +1313,7 @@ impl HDWallet { network_type: &Network, child_number_list: &[u32], ) -> Result { - let ext_priv = ExtPrivkey::from_seed(&self.seed, &network_type)?; + let ext_priv = ExtPrivkey::from_seed(&self.seed, network_type)?; ext_priv.derive_from_number_list(child_number_list) } @@ -1318,7 +1331,7 @@ impl HDWallet { /// let extkey = hdwallet.get_pubkey(&Network::Testnet).expect("Fail"); /// ``` pub fn get_pubkey(&self, network_type: &Network) -> Result { - let ext_priv = ExtPrivkey::from_seed(&self.seed, &network_type)?; + let ext_priv = ExtPrivkey::from_seed(&self.seed, network_type)?; ext_priv.get_ext_pubkey() } @@ -1342,7 +1355,7 @@ impl HDWallet { network_type: &Network, bip32path: &str, ) -> Result { - let ext_priv = ExtPrivkey::from_seed(&self.seed, &network_type)?; + let ext_priv = ExtPrivkey::from_seed(&self.seed, network_type)?; ext_priv.derive_pubkey_from_path(bip32path) } @@ -1367,7 +1380,7 @@ impl HDWallet { child_number: u32, hardened: bool, ) -> Result { - let ext_priv = ExtPrivkey::from_seed(&self.seed, &network_type)?; + let ext_priv = ExtPrivkey::from_seed(&self.seed, network_type)?; ext_priv.derive_pubkey_from_number(child_number, hardened) } @@ -1391,7 +1404,7 @@ impl HDWallet { network_type: &Network, child_number_list: &[u32], ) -> Result { - let ext_priv = ExtPrivkey::from_seed(&self.seed, &network_type)?; + let ext_priv = ExtPrivkey::from_seed(&self.seed, network_type)?; ext_priv.derive_pubkey_from_number_list(child_number_list) } } diff --git a/src/key.rs b/src/key.rs index 310b981..5ad1b99 100644 --- a/src/key.rs +++ b/src/key.rs @@ -45,7 +45,7 @@ impl Privkey { net_type: Network::Mainnet, is_compressed: true, }; - privkey.key = copy_array_32byte(&key); + privkey.key = copy_array_32byte(key); privkey } @@ -161,7 +161,7 @@ impl Privkey { let str_list = unsafe { collect_multi_cstring_and_free(&[pubkey_hex, privkey_hex, wif]) }?; let privkey_obj = &str_list[1]; let wif_str = &str_list[2]; - let privkey_bytes = byte_from_hex_unsafe(&privkey_obj); + let privkey_bytes = byte_from_hex_unsafe(privkey_obj); let mut privkey = Privkey::from_bytes(&privkey_bytes); privkey.wif = wif_str.clone(); privkey.net_type = *network_type; @@ -1159,7 +1159,7 @@ impl SigHashType { SigHashType::new(&base_type, anyone_can_pay, is_rangeproof) } - pub(in crate) fn to_c_value(&self) -> c_int { + pub(in crate) fn to_c_value(self) -> c_int { match self { SigHashType::Default => 0, SigHashType::All => 1, @@ -1284,11 +1284,10 @@ impl SignParameter { pub fn set_use_der_encode(mut self, sighash_type: &SigHashType) -> SignParameter { if self.data.len() > 65 { // target is already der-encoded. unused sighash-type. - self.set_signature_hash(&sighash_type) } else { self.use_der_encode = true; - self.set_signature_hash(&sighash_type) } + self.set_signature_hash(sighash_type) } /// Set a related pubkey. Used to sort multisig signatures. diff --git a/src/lib.rs b/src/lib.rs index e53873a..b4607a4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ #![crate_name = "cfd_rust"] pub mod address; +pub mod block; pub mod common; pub mod confidential_address; pub mod confidential_transaction; @@ -25,6 +26,8 @@ pub use address::Address; pub use address::AddressType; pub use address::HashType; pub use address::WitnessVersion; +pub use block::Block; +pub use block::BlockHeader; pub use confidential_address::ConfidentialAddress; pub use confidential_transaction::decode_raw_transaction; pub use confidential_transaction::get_default_blinding_key; diff --git a/src/schnorr.rs b/src/schnorr.rs index 293ac8f..d3666d3 100644 --- a/src/schnorr.rs +++ b/src/schnorr.rs @@ -556,7 +556,7 @@ pub struct SchnorrPubkey { impl SchnorrPubkey { fn from_bytes(data: &[u8]) -> SchnorrPubkey { SchnorrPubkey { - data: copy_array_32byte(&data), + data: copy_array_32byte(data), } } diff --git a/src/script.rs b/src/script.rs index 2d16a69..416d28c 100644 --- a/src/script.rs +++ b/src/script.rs @@ -134,7 +134,7 @@ impl Script { /// ``` #[inline] pub fn from_data(data: &ByteData) -> Result { - Script::from_slice(&data.to_slice()) + Script::from_slice(data.to_slice()) } /// Generate from asm string. @@ -389,7 +389,7 @@ impl TapBranch { /// ``` pub fn from_tapscript(tapscript: &Script) -> Result { let arr: Vec<[u8; TAPROOT_HASH_SIZE]> = vec![]; - TapBranch::from_string_by_tapscript(&format!("tl({})", tapscript.to_hex()), &tapscript, &arr) + TapBranch::from_string_by_tapscript(&format!("tl({})", tapscript.to_hex()), tapscript, &arr) } /// Create TapBranch from branch hash only. @@ -468,7 +468,7 @@ impl TapBranch { let pubkey_str = unsafe { collect_cstring_and_free(output) }?; let schnorr_pubkey = SchnorrPubkey::from_str(&pubkey_str)?; let nodes: Vec<[u8; 32]> = vec![]; - let branch = Self::get_branch_data(&handle, &tapscript, &nodes)?; + let branch = Self::get_branch_data(&handle, tapscript, &nodes)?; Ok((branch, schnorr_pubkey)) } _ => Err(handle.get_error(error_code)), @@ -501,7 +501,7 @@ impl TapBranch { let handle = ScriptTreeHandle::new()?; Self::load_by_tree_string(&handle, tree_str, tapscript, target_nodes)?; let nodes: Vec<[u8; 32]> = vec![]; - Self::get_branch_data(&handle, &tapscript, &nodes) + Self::get_branch_data(&handle, tapscript, &nodes) } fn load_by_tree_string( @@ -516,7 +516,7 @@ impl TapBranch { } let leaf_version: u8 = TAPSCRIPT_LEAF_VERSION; let script_str = alloc_c_string(&tapscript.to_hex())?; - let tree_string = alloc_c_string(&tree_str)?; + let tree_string = alloc_c_string(tree_str)?; let control_nodes = alloc_c_string(&target_nodes_str)?; let error_code = unsafe { CfdSetScriptTreeFromString( @@ -607,7 +607,7 @@ impl TapBranch { pub fn add_by_tree_string(&mut self, tree_str: &str) -> Result<(), CfdError> { let handle = ScriptTreeHandle::new()?; Self::load_by_tree_string(&handle, &self.tree_str, &self.tapscript, &self.target_nodes)?; - let tree_string = alloc_c_string(&tree_str)?; + let tree_string = alloc_c_string(tree_str)?; let error_code = unsafe { CfdAddTapBranchByScriptTreeString( handle.as_handle(), @@ -847,11 +847,11 @@ impl TapBranch { nodes: &[[u8; 32]], ) -> Result { let mut branch = TapBranch::default(); - let count = Self::get_branch_count_internal(&handle)?; + let mut tapscript: *mut c_char = ptr::null_mut(); + let mut leaf_version: c_uchar = 0; + let mut tap_leaf_hash: *mut c_char = ptr::null_mut(); + let count = Self::get_branch_count_internal(handle)?; if count == 0 { - let mut tapscript: *mut c_char = ptr::null_mut(); - let mut tap_leaf_hash: *mut c_char = ptr::null_mut(); - let mut leaf_version: c_uchar = 0; let error_code = unsafe { CfdGetBaseTapLeaf( handle.as_handle(), @@ -873,8 +873,6 @@ impl TapBranch { }?; } else { let mut branch_hash: *mut c_char = ptr::null_mut(); - let mut tapscript: *mut c_char = ptr::null_mut(); - let mut leaf_version: c_uchar = 0; let mut depth_by_leaf_or_end: c_uchar = 0; let index = count - 1; let error_code = unsafe { diff --git a/src/transaction.rs b/src/transaction.rs index 03a0a77..2ff3155 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -38,10 +38,10 @@ use self::cfd_sys::{ CfdGetTxOutCountByHandle, CfdGetTxOutIndexByHandle, CfdGetTxOutIndexWithOffsetByHandle, CfdInitializeCoinSelection, CfdInitializeEstimateFee, CfdInitializeFundRawTx, CfdInitializeMultisigSign, CfdInitializeTransaction, CfdInitializeTxDataHandle, - CfdSetOptionFundRawTx, CfdSetTransactionUtxoData, CfdSplitTxOut, CfdUpdateTxOutAmount, - CfdUpdateWitnessStack, CfdVerifySignature, CfdVerifyTxSign, CfdVerifyTxSignByHandle, - DEFAULT_BLIND_MINIMUM_BITS, FUND_OPT_DUST_FEE_RATE, FUND_OPT_KNAPSACK_MIN_CHANGE, - FUND_OPT_LONG_TERM_FEE_RATE, WITNESS_STACK_TYPE_NORMAL, + CfdSetOptionFundRawTx, CfdSetTransactionUtxoData, CfdSplitTxOut, CfdUpdateTxInSequence, + CfdUpdateTxOutAmount, CfdUpdateWitnessStack, CfdVerifySignature, CfdVerifyTxSign, + CfdVerifyTxSignByHandle, DEFAULT_BLIND_MINIMUM_BITS, FUND_OPT_DUST_FEE_RATE, + FUND_OPT_KNAPSACK_MIN_CHANGE, FUND_OPT_LONG_TERM_FEE_RATE, WITNESS_STACK_TYPE_NORMAL, }; // fund option @@ -1036,6 +1036,40 @@ impl Transaction { }) } + /// Update txin sequence. + /// + /// # Arguments + /// * `outpoint` - An outpoint. + /// * `sequence` - A sequence number. + /// + /// # Example + /// + /// ``` + /// use cfd_rust::{OutPoint, Transaction}; + /// use std::str::FromStr; + /// let outpoint = OutPoint::from_str( + /// "2fea883042440d030ca5929814ead927075a8f52fef5f4720fa3cec2e475d916", + /// 0).expect("Fail"); + /// let tx = Transaction::from_str("0200000000010116d975e4c2cea30f72f4f5fe528f5a0727d9ea149892a50c030d44423088ea2f0000000000ffffffff0130f1029500000000160014164e985d0fc92c927a66c0cbaf78e6ea389629d5014161f75636003a870b7a1685abae84eedf8c9527227ac70183c376f7b3a35b07ebcbea14749e58ce1a87565b035b2f3963baa5ae3ede95e89fd607ab7849f208720200000000").expect("Fail"); + /// let tx2 = tx.update_txin_sequence(&outpoint, 0xfffffffe).expect("Fail"); + /// ``` + pub fn update_txin_sequence( + &self, + outpoint: &OutPoint, + sequence: u32, + ) -> Result { + let mut ope = TransactionOperation::new(&Network::Mainnet); + let tx = ope.update_txin_sequence(&hex_from_bytes(&self.tx), outpoint, sequence)?; + let data = ope.get_last_tx_data(); + Ok(Transaction { + tx, + data: data.clone(), + txin_list: ope.get_txin_list_cache().to_vec(), + txout_list: self.txout_list.clone(), + txin_utxo_list: self.txin_utxo_list.clone(), + }) + } + /// Update witness stack. /// /// # Arguments @@ -1420,7 +1454,7 @@ impl Transaction { &hex_from_bytes(&self.tx), outpoint, &String::default(), - &redeem_script, + redeem_script, &option, ) } @@ -1536,7 +1570,7 @@ impl Transaction { let tx = ope.add_pubkey_hash_sign(&tx_hex, outpoint, hash_type, pubkey, signature)?; let new_tx_hex = ope.get_last_tx(); let mut ope2 = ope.clone(); - let new_txin = ope2.get_txin_by_outpoint(&new_tx_hex, outpoint)?; + let new_txin = ope2.get_txin_by_outpoint(new_tx_hex, outpoint)?; let index = ope2.get_last_txin_index(); let data = ope2.get_last_tx_data().clone(); let mut tx_obj = Transaction { @@ -1651,7 +1685,7 @@ impl Transaction { let tx = ope.sign_with_privkey(&tx_hex, outpoint, hash_type, &key, &option, true)?; let new_tx_hex = ope.get_last_tx(); let mut ope2 = ope.clone(); - let new_txin = ope2.get_txin_by_outpoint(&new_tx_hex, outpoint)?; + let new_txin = ope2.get_txin_by_outpoint(new_tx_hex, outpoint)?; let index = ope2.get_last_txin_index(); let data = ope2.get_last_tx_data().clone(); let mut tx_obj = Transaction { @@ -1708,10 +1742,10 @@ impl Transaction { let mut option = SigHashOption::new(*sighash_type, 0); option.annex = annex.to_vec(); option.aux_rand = aux_rand.to_vec(); - let tx = ope.sign_with_privkey_by_utxo_list(&tx_hex, outpoint, &privkey, &option, true)?; + let tx = ope.sign_with_privkey_by_utxo_list(&tx_hex, outpoint, privkey, &option, true)?; let new_tx_hex = ope.get_last_tx(); let mut ope2 = ope.clone(); - let new_txin = ope2.get_txin_by_outpoint(&new_tx_hex, outpoint)?; + let new_txin = ope2.get_txin_by_outpoint(new_tx_hex, outpoint)?; let index = ope2.get_last_txin_index(); let data = ope2.get_last_tx_data().clone(); let mut tx_obj = Transaction { @@ -1781,7 +1815,7 @@ impl Transaction { let tx = ope.add_multisig_sign(&tx_hex, outpoint, hash_type, redeem_script, signature_list)?; let new_tx_hex = ope.get_last_tx(); let mut ope2 = ope.clone(); - let new_txin = ope2.get_txin_by_outpoint(&new_tx_hex, outpoint)?; + let new_txin = ope2.get_txin_by_outpoint(new_tx_hex, outpoint)?; let index = ope2.get_last_txin_index(); let data = ope2.get_last_tx_data().clone(); let mut tx_obj = Transaction { @@ -1840,7 +1874,7 @@ impl Transaction { let tx = ope.add_sign(&tx_hex, outpoint, hash_type, sign_data, clear_stack)?; let new_tx_hex = ope.get_last_tx(); let mut ope2 = ope.clone(); - let new_txin = ope2.get_txin_by_outpoint(&new_tx_hex, outpoint)?; + let new_txin = ope2.get_txin_by_outpoint(new_tx_hex, outpoint)?; let index = ope2.get_last_txin_index(); let data = ope2.get_last_tx_data().clone(); let mut tx_obj = Transaction { @@ -1911,7 +1945,7 @@ impl Transaction { )?; let new_tx_hex = ope.get_last_tx(); let mut ope2 = ope.clone(); - let new_txin = ope2.get_txin_by_outpoint(&new_tx_hex, outpoint)?; + let new_txin = ope2.get_txin_by_outpoint(new_tx_hex, outpoint)?; let index = ope2.get_last_txin_index(); let data = ope2.get_last_tx_data().clone(); let mut tx_obj = Transaction { @@ -2441,6 +2475,66 @@ impl TransactionOperation { self.create_tx(0, 0, tx, txin_list, txout_list) } + pub fn update_txin_sequence( + &mut self, + tx: &str, + outpoint: &OutPoint, + sequence: u32, + ) -> Result, CfdError> { + let mut handle = ErrorHandle::new()?; + let result = { + let tx_handle = TxDataHandle::new(&handle, &self.network, tx)?; + let tx_result = { + TransactionOperation::update_txin_sequence_internal( + &CreateTxData::default(), + &handle, + &tx_handle, + outpoint, + sequence, + )?; + self.get_txin_by_outpoint_internal(&handle, &tx_handle, &String::default(), outpoint)?; + self.get_tx_internal(&handle, &tx_handle, &String::default()) + }?; + tx_handle.free_handle(&handle); + tx_result + }; + handle.free_handle(); + Ok(result) + } + + pub fn update_txin_sequence_internal( + tx: &CreateTxData, + handle: &ErrorHandle, + tx_handle: &TxDataHandle, + outpoint: &OutPoint, + sequence: u32, + ) -> Result<(), CfdError> { + let tx_data_handle = match tx_handle.is_null() { + false => tx_handle.clone(), + _ => TxDataHandle::new(handle, &tx.network, &tx.tx)?, + }; + let result = { + let txid = alloc_c_string(&outpoint.txid.to_hex())?; + let error_code = unsafe { + CfdUpdateTxInSequence( + handle.as_handle(), + tx_data_handle.as_handle(), + txid.as_ptr(), + outpoint.get_vout(), + sequence, + ) + }; + match error_code { + 0 => Ok(()), + _ => Err(handle.get_error(error_code)), + } + }; + if tx_handle.is_null() { + tx_data_handle.free_handle(handle); + } + result + } + pub fn update_witness_stack( &mut self, tx: &str, @@ -2482,7 +2576,7 @@ impl TransactionOperation { ) -> Result<(), CfdError> { let tx_data_handle = match tx_handle.is_null() { false => tx_handle.clone(), - _ => TxDataHandle::new(&handle, &tx.network, &tx.tx)?, + _ => TxDataHandle::new(handle, &tx.network, &tx.tx)?, }; let result = { let txid = alloc_c_string(&outpoint.txid.to_hex())?; @@ -2504,7 +2598,7 @@ impl TransactionOperation { } }; if tx_handle.is_null() { - tx_data_handle.free_handle(&handle); + tx_data_handle.free_handle(handle); } result } @@ -2588,7 +2682,7 @@ impl TransactionOperation { ) -> Result<(), CfdError> { let tx_data_handle = match tx_handle.is_null() { false => tx_handle.clone(), - _ => TxDataHandle::new(&handle, network, tx)?, + _ => TxDataHandle::new(handle, network, tx)?, }; let result = { let split_handle = { @@ -2609,9 +2703,9 @@ impl TransactionOperation { for txout in txout_list { { let address = match txout.confidential_address.to_str().is_empty() { - false => alloc_c_string(&txout.confidential_address.to_str()), + false => alloc_c_string(txout.confidential_address.to_str()), true => match txout.address.is_valid() { - true => alloc_c_string(&txout.address.to_str()), + true => alloc_c_string(txout.address.to_str()), false => alloc_c_string(""), }, }?; @@ -2661,7 +2755,7 @@ impl TransactionOperation { split_ret }; if tx_handle.is_null() { - tx_data_handle.free_handle(&handle); + tx_data_handle.free_handle(handle); } result } @@ -2686,23 +2780,22 @@ impl TransactionOperation { ) -> Result { let tx_data_handle = match tx_handle.is_null() { false => tx_handle.clone(), - _ => TxDataHandle::new(&handle, &self.network, tx)?, + _ => TxDataHandle::new(handle, &self.network, tx)?, }; let result = { - let data = self.get_tx_data_internal(&handle, &tx_data_handle, tx)?; - let in_count = Self::get_count_internal(&self.network, &handle, &tx_data_handle, tx, true)?; - let out_count = Self::get_count_internal(&self.network, &handle, &tx_data_handle, tx, false)?; + let data = self.get_tx_data_internal(handle, &tx_data_handle, tx)?; + let in_count = Self::get_count_internal(&self.network, handle, &tx_data_handle, tx, true)?; + let out_count = Self::get_count_internal(&self.network, handle, &tx_data_handle, tx, false)?; let in_indexes = TransactionOperation::create_index_list(in_count); let out_indexes = TransactionOperation::create_index_list(out_count); - let in_data = self.get_tx_input_list_internal(&handle, &tx_data_handle, tx, &in_indexes)?; - let out_data = - self.get_tx_output_list_internal(&handle, &tx_data_handle, tx, &out_indexes)?; + let in_data = self.get_tx_input_list_internal(handle, &tx_data_handle, tx, &in_indexes)?; + let out_data = self.get_tx_output_list_internal(handle, &tx_data_handle, tx, &out_indexes)?; self.txin_list = in_data; self.txout_list = out_data; Ok(data) }; if tx_handle.is_null() { - tx_data_handle.free_handle(&handle); + tx_data_handle.free_handle(handle); } result } @@ -2715,7 +2808,7 @@ impl TransactionOperation { ) -> Result, CfdError> { let tx_data_handle = match tx_handle.is_null() { false => tx_handle.clone(), - _ => TxDataHandle::new(&handle, &self.network, tx)?, + _ => TxDataHandle::new(handle, &self.network, tx)?, }; let mut output: *mut c_char = ptr::null_mut(); let result = { @@ -2732,7 +2825,7 @@ impl TransactionOperation { } }; if tx_handle.is_null() { - tx_data_handle.free_handle(&handle); + tx_data_handle.free_handle(handle); } result } @@ -2773,7 +2866,7 @@ impl TransactionOperation { ) -> Result { let tx_data_handle = match tx_handle.is_null() { false => tx_handle.clone(), - _ => TxDataHandle::new(&handle, &self.network, tx)?, + _ => TxDataHandle::new(handle, &self.network, tx)?, }; let mut data: TxData = TxData::default(); let mut txid: *mut c_char = ptr::null_mut(); @@ -2803,7 +2896,7 @@ impl TransactionOperation { _ => Err(handle.get_error(error_code)), }; if tx_handle.is_null() { - tx_data_handle.free_handle(&handle); + tx_data_handle.free_handle(handle); } result } @@ -2859,7 +2952,7 @@ impl TransactionOperation { ) -> Result { let tx_data_handle = match tx_handle.is_null() { false => tx_handle.clone(), - _ => TxDataHandle::new(&handle, &self.network, tx)?, + _ => TxDataHandle::new(handle, &self.network, tx)?, }; let list_result = { let index = { @@ -2881,8 +2974,8 @@ impl TransactionOperation { }?; let indexes = vec![index]; - let list_result = self.get_tx_input_list_internal(&handle, &tx_data_handle, tx, &indexes)?; - let data_result = self.get_tx_data_internal(&handle, &tx_data_handle, tx)?; + let list_result = self.get_tx_input_list_internal(handle, &tx_data_handle, tx, &indexes)?; + let data_result = self.get_tx_data_internal(handle, &tx_data_handle, tx)?; self.tx_data = data_result; if list_result.is_empty() { Err(CfdError::Internal("Failed to empty list.".to_string())) @@ -2893,7 +2986,7 @@ impl TransactionOperation { } }; if tx_handle.is_null() { - tx_data_handle.free_handle(&handle); + tx_data_handle.free_handle(handle); } list_result } @@ -2907,7 +3000,7 @@ impl TransactionOperation { ) -> Result, CfdError> { let tx_data_handle = match tx_handle.is_null() { false => tx_handle.clone(), - _ => TxDataHandle::new(&handle, &self.network, tx)?, + _ => TxDataHandle::new(handle, &self.network, tx)?, }; let mut list: Vec = vec![]; list.reserve(indexes.len()); @@ -2935,7 +3028,7 @@ impl TransactionOperation { let txid_ret = Txid::from_str(&str_list[0])?; let script_ret = Script::from_hex(&str_list[1])?; let script_witness = Self::get_tx_input_witness( - &handle, + handle, &tx_data_handle, *index, WITNESS_STACK_TYPE_NORMAL, @@ -2959,7 +3052,7 @@ impl TransactionOperation { } }; if tx_handle.is_null() { - tx_data_handle.free_handle(&handle); + tx_data_handle.free_handle(handle); } result } @@ -2973,7 +3066,7 @@ impl TransactionOperation { ) -> Result, CfdError> { let tx_data_handle = match tx_handle.is_null() { false => tx_handle.clone(), - _ => TxDataHandle::new(&handle, &self.network, tx)?, + _ => TxDataHandle::new(handle, &self.network, tx)?, }; let mut list: Vec = vec![]; list.reserve(indexes.len()); @@ -3015,7 +3108,7 @@ impl TransactionOperation { } }; if tx_handle.is_null() { - tx_data_handle.free_handle(&handle); + tx_data_handle.free_handle(handle); } result } @@ -3039,7 +3132,7 @@ impl TransactionOperation { ) -> Result { let tx_data_handle = match tx_handle.is_null() { false => tx_handle.clone(), - _ => TxDataHandle::new(&handle, network, tx)?, + _ => TxDataHandle::new(handle, network, tx)?, }; let mut count: c_uint = 0; let error_code = unsafe { @@ -3054,7 +3147,7 @@ impl TransactionOperation { _ => Err(handle.get_error(error_code)), }; if tx_handle.is_null() { - tx_data_handle.free_handle(&handle); + tx_data_handle.free_handle(handle); } result } @@ -3201,7 +3294,7 @@ impl TransactionOperation { let result = { self.set_utxo_list(&handle, &tx_handle, &String::default())?; let txid = alloc_c_string(&outpoint.txid.to_hex())?; - let pubkey_str = alloc_c_string(&pubkey)?; + let pubkey_str = alloc_c_string(pubkey)?; let script_str = alloc_c_string(&redeem_script.to_hex())?; let tapleaf_hash = alloc_c_string(&hex_from_bytes(&option.tap_leaf_hash))?; let annex = alloc_c_string(&ByteData::from_slice(&option.annex).to_hex())?; @@ -3776,7 +3869,7 @@ impl TransactionOperation { ) -> Result<(), CfdError> { let tx_data_handle = match tx_handle.is_null() { false => tx_handle.clone(), - _ => TxDataHandle::new(&handle, &self.network, tx)?, + _ => TxDataHandle::new(handle, &self.network, tx)?, }; let result = { @@ -3812,7 +3905,7 @@ impl TransactionOperation { Ok(()) }; if tx_handle.is_null() { - tx_data_handle.free_handle(&handle); + tx_data_handle.free_handle(handle); } result } @@ -3826,7 +3919,7 @@ impl TransactionOperation { ) -> Result<(), CfdError> { let tx_data_handle = match tx_handle.is_null() { false => tx_handle.clone(), - _ => TxDataHandle::new(&handle, &self.network, tx)?, + _ => TxDataHandle::new(handle, &self.network, tx)?, }; let txid = alloc_c_string(&outpoint.txid.to_hex())?; let error_code = unsafe { @@ -3842,7 +3935,7 @@ impl TransactionOperation { _ => Err(handle.get_error(error_code)), }; if tx_handle.is_null() { - tx_data_handle.free_handle(&handle); + tx_data_handle.free_handle(handle); } result } @@ -3870,7 +3963,7 @@ impl TransactionOperation { for txin_data in txin_list { let _err = { let txid = alloc_c_string(&txin_data.outpoint.txid.to_hex())?; - let descriptor = alloc_c_string(&txin_data.descriptor.to_str())?; + let descriptor = alloc_c_string(txin_data.descriptor.to_str())?; let sig_tmpl = alloc_c_string(&txin_data.scriptsig_template.to_hex())?; let error_code = unsafe { CfdAddTxInTemplateForEstimateFee( @@ -3953,7 +4046,7 @@ impl TransactionOperation { for (index, utxo_data) in utxo_list.iter().enumerate() { let _err = { let txid = alloc_c_string(&utxo_data.outpoint.txid.to_hex())?; - let descriptor = alloc_c_string(&utxo_data.descriptor.to_str())?; + let descriptor = alloc_c_string(utxo_data.descriptor.to_str())?; let sig_tmpl = alloc_c_string(&utxo_data.scriptsig_template.to_hex())?; let error_code = unsafe { CfdAddCoinSelectionUtxoTemplate( @@ -4087,7 +4180,7 @@ impl TransactionOperation { for txin_data in txin_list { let _err = { let txid = alloc_c_string(&txin_data.outpoint.txid.to_hex())?; - let descriptor = alloc_c_string(&txin_data.descriptor.to_str())?; + let descriptor = alloc_c_string(txin_data.descriptor.to_str())?; let sig_tmpl = alloc_c_string(&txin_data.scriptsig_template.to_hex())?; let error_code = unsafe { CfdAddTxInTemplateForFundRawTx( @@ -4115,7 +4208,7 @@ impl TransactionOperation { for utxo_data in utxo_list { let _err = { let txid = alloc_c_string(&utxo_data.outpoint.txid.to_hex())?; - let descriptor = alloc_c_string(&utxo_data.descriptor.to_str())?; + let descriptor = alloc_c_string(utxo_data.descriptor.to_str())?; let sig_tmpl = alloc_c_string(&utxo_data.scriptsig_template.to_hex())?; let error_code = unsafe { CfdAddUtxoTemplateForFundRawTx( diff --git a/tests/address_test.rs b/tests/address_test.rs index 3efafef..48a778d 100644 --- a/tests/address_test.rs +++ b/tests/address_test.rs @@ -2,14 +2,16 @@ extern crate cfd_rust; #[cfg(test)] mod tests { - use cfd_rust::{Address, AddressType, Network, Pubkey, SchnorrPubkey, Script, WitnessVersion}; + use cfd_rust::{ + Address, AddressType, HashType, Network, Pubkey, SchnorrPubkey, Script, WitnessVersion, + }; use std::str::FromStr; #[test] fn address_test() { // default let empty_addr = Address::default(); - assert_eq!(false, empty_addr.valid()); + assert!(!empty_addr.valid()); // default: bitcoin let pubkey = Pubkey::from_str("036b67e1bd3bd3efbc37fdc738ab159a4aa527057eae12a0c4b07d3132580dcdfd") @@ -83,7 +85,7 @@ mod tests { "a91405bc4d5d12925f008cef06ba387ade16a49d7a3187", p2sh_addr.get_locking_script().to_hex() ); - assert_eq!(true, p2sh_addr.valid()); + assert!(p2sh_addr.valid()); // get_multisig_addresses let multisig_script = Script::from_hex("522102522952c3fc2a53a8651b08ce10988b7506a3b40a5c26f9648a911be33e73e1a0210340b52ae45bc1be5de083f1730fe537374e219c4836400623741d2a874e60590c21024a3477bc8b933a320eb5667ee72c35a81aa155c8e20cc51c65fb666de3a43b8253ae").expect("fail"); @@ -178,5 +180,62 @@ mod tests { "tb1pzamhq9jglfxaj0r5ahvatr8uc77u973s5tm04yytdltsey5r8naskf8ee6", addr_taproot2.to_str() ); + + let fedpeg_script = Script::from_hex("522102baae8e066e4f2a1da4b731017697bb8fcacc60e4569f3ec27bc31cf3fb13246221026bccd050e8ecf7a702bc9fb63205cfdf278a22ba8b1f1d3ca3d8e5b38465a9702103430d354b89d1fbe43eb54ea138a4aee1076e4c54f4c805f62f9cee965351a1d053ae").expect("Fail"); + let pegin_pubkey = + Pubkey::from_str("027592aab5d43618dda13fba71e3993cd7517a712d3da49664c06ee1bd3d1f70af") + .expect("Fail"); + let pegin_addr_data = Address::pegin_by_pubkey( + &fedpeg_script, + &pegin_pubkey, + &HashType::P2shP2wsh, + &Network::Mainnet, + ) + .expect("Fail"); + assert_eq!( + "39cTKhjjh9YWDQT5hhSRkQwjvmpc4d1C7k", + pegin_addr_data.address.to_str() + ); + assert_eq!( + "0014925d4028880bd0c9d68fbc7fc7dfee976698629c", + pegin_addr_data.claim_script.to_hex() + ); + assert_eq!("522103e3b215b75e015a5948efb043079d325a90e68b19112211ae3c1ff62366d441732102779396d5c2348c33bcbdcfd87bf59646ccbebc94bacf4750a9c5245dd297213021036416a1c936d3dc84747d5e544c200578cccfb6ec62dda48df79a0a6a8c7e63fa53ae", + pegin_addr_data.tweaked_fedpeg_script.to_hex()); + + let redeem_script = Script::from_hex("522103a7bd50beb3aff9238336285c0a790169eca90b7ad807abc4b64897ca1f6dedb621039cbaf938d050dd2582e4c2f56d1f75cfc9d165f2f3270532363d9871fb7be14252ae").expect("Fail"); + let pegin_addr_data2 = Address::pegin_by_script( + &fedpeg_script, + &redeem_script, + &HashType::P2shP2wsh, + &Network::Mainnet, + ) + .expect("Fail"); + assert_eq!( + "3DZHAW3TmdwfGuJTGKatD7XpCNJvnX6GiE", + pegin_addr_data2.address.to_str() + ); + assert_eq!( + "0020c45384fa00fe363ed60968fff46541c89bc1766686c279ffdf0a335b80cad728", + pegin_addr_data2.claim_script.to_hex() + ); + assert_eq!("52210272d86fcc18fc129a3fe72ed268356735a176f01ba1bb6b5a6e5181735570fca021021909156e0a206a5a8f47bee2418eebd6db0ecae9b4810d761117fa7891f86f7021026e90023fe74aff9f5a26c76ca88eb19fd4477ae43cebb9d2e81e197961b263b753ae", + pegin_addr_data2.tweaked_fedpeg_script.to_hex()); + + let desc1 = "wpkh(tpubDASgDECJvTMzUgS7GkSCxQAAWPveW7BeTPSvbi1wpUe1Mq1v743FRw1i7vTavjAb3D3Y8geCTYw2ezgiVS7SFXDXS6NpZmvr6XPjPvg632y)"; + let (pegout_addr, base_desc) = Address::pegout(Network::Regtest, desc1, 0).expect("Fail"); + assert_eq!( + "bcrt1qa77w63m523kq82z4fn3d5f7qxqxfm4pmdthkdf", + pegout_addr.to_str() + ); + assert_eq!("wpkh(tpubDASgDECJvTMzUgS7GkSCxQAAWPveW7BeTPSvbi1wpUe1Mq1v743FRw1i7vTavjAb3D3Y8geCTYw2ezgiVS7SFXDXS6NpZmvr6XPjPvg632y)", + base_desc); + + let pegout_pubkey2 = "xpub67v4wfueMiZVkc7UbutFgPiptQw4kkNs89ooNMrwht8xEjnZZim1rNZHhEdrLejB99fiBdnWNNAB8hmUK7tCo5Ua6UtHzwVLj2Bzpch7vB2"; + let (pegout_addr2, base_desc2) = + Address::pegout(Network::Mainnet, pegout_pubkey2, 0).expect("Fail"); + assert_eq!("1MMxsm4QG8NRHqaFZaUTFQQ9c9dEHUPWnD", pegout_addr2.to_str()); + assert_eq!("pkh(xpub67v4wfueMiZVkc7UbutFgPiptQw4kkNs89ooNMrwht8xEjnZZim1rNZHhEdrLejB99fiBdnWNNAB8hmUK7tCo5Ua6UtHzwVLj2Bzpch7vB2)", + base_desc2); } } diff --git a/tests/block_test.rs b/tests/block_test.rs new file mode 100644 index 0000000..fa17e77 --- /dev/null +++ b/tests/block_test.rs @@ -0,0 +1,132 @@ +extern crate cfd_rust; + +#[cfg(test)] +mod tests { + use cfd_rust::{Block, Txid}; + use std::str::FromStr; + + #[test] + fn block_test1() { + let block_hex = "00000030957958949bad814d1666ed0d4a005c8aed6b7fd56df5d12c81d584c71e5fae2dfe391f9150dcfb06d54d4eb6621672590bf46bed6893da825c076b841794cec5414e2660ffff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0502d5000101ffffffff0200f9029500000000160014164e985d0fc92c927a66c0cbaf78e6ea389629d50000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000"; + + let block = Block::from_str(block_hex).expect("Fail"); + let hash = block.get_hash().to_hex(); + assert_eq!( + "53fd7b794cf751a148b2be637df6c7daf663f1be509cb35294bd69400fdc694e", + hash + ); + let header = block.get_header(); + assert_eq!(805306368, header.version); + assert_eq!( + "2dae5f1ec784d5812cd1f56dd57f6bed8a5c004a0ded66164d81ad9b94587995", + header.prev_block_hash.to_hex() + ); + assert_eq!( + "c5ce9417846b075c82da9368ed6bf40b59721662b64e4dd506fbdc50911f39fe", + header.merkle_root.to_hex() + ); + assert_eq!(1613123137, header.time); + assert_eq!(0x207fffff, header.bits); + assert_eq!(0, header.nonce); + let count = block.get_tx_count(); + assert_eq!(1, count); + + let txid = Txid::from_str("c5ce9417846b075c82da9368ed6bf40b59721662b64e4dd506fbdc50911f39fe") + .expect("Fail"); + let txid_list = block.get_txid_list(); + assert_eq!(1, txid_list.len()); + if txid_list.len() == 1 { + assert_eq!(txid, txid_list[0]); + } + + let (tx, proof) = block.get_tx_data(&txid).expect("Fail"); + assert_eq!( + "020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0502d5000101ffffffff0200f9029500000000160014164e985d0fc92c927a66c0cbaf78e6ea389629d50000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + tx.to_str()); + assert_eq!( + "00000030957958949bad814d1666ed0d4a005c8aed6b7fd56df5d12c81d584c71e5fae2dfe391f9150dcfb06d54d4eb6621672590bf46bed6893da825c076b841794cec5414e2660ffff7f20000000000100000001fe391f9150dcfb06d54d4eb6621672590bf46bed6893da825c076b841794cec50101", + proof.to_hex()); + + assert!(block.exist_txid(&txid)); + assert!(!block.exist_txid( + &Txid::from_str("f5ce9417846b075c82da9368ed6bf40b59721662b64e4dd506fbdc50911f39fe") + .expect("Fail") + )); + } + + #[test] + fn block_test2() { + let block_hex = "00000020d987e1f7cc030f4272beda5a081f8f8969f044ef72a3b2c2e544afc8230b9642d8b5de43b746fa65aaab7cfa0b521b41e4eb0d7c0e2fb834380259df581daf03157eb360ffff7f200100000015020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff050277020101ffffffff02246aa01200000000160014aef2e2877c45ada6b9eaef2bdb9131630ae12dca0000000000000000266a24aa21a9ed2af9d1c54b61988d37ce9bcde367fba7f3c5910cecaf8be1b6b443e937e39cec0120000000000000000000000000000000000000000000000000000000000000000000000000020000000001013d067178968e8e7469a61a82c365508ee3615bed93ed421ddefe19da412171080000000000feffffff02a0860100000000001600143df45aa3e4c76b1f2f4693675770ba4e3db2acee13373f2500000000160014a9b62806472c7b70c9f753bf41573e1506534dc40247304402205de2d7b0acf8e6027fcb1e197745ca8d23c1a4a7f4dc449762265e2aab2022f202204d35e5866f31595616b44f77e218fbddbfed702b830eb4c2aac087c5c1ad0648012102b30fc0ddd4de67700667921a0c73f9e773d473c4827abe8c63b5060725b745d476020000020000000001019421ca1de8781f070262511333197ab44f1629dbb704bd923f48bae4fa67a9f90000000000feffffff0213373f250000000016001455d6fbae5d95d2b03e5210abbe5a15ddbdb62c47a0860100000000001600143df45aa3e4c76b1f2f4693675770ba4e3db2acee0247304402206f590ce48f6f7a93821c116c3a4a9659d9739d8a9bc62fcae12e34cf0e4b26500220361867ad6dcd30af0bec09a9571a8888452d2812275201f4878de296a78e8627012102b30fc0ddd4de67700667921a0c73f9e773d473c4827abe8c63b5060725b745d476020000020000000001018e4212da7a883762b80efdf512263fd8d412771515b8b81cf992c01314fc93210000000000feffffff0213373f2500000000160014563423d5881cddbb72a1d6fea1af5c56bbea6a3fa0860100000000001600143df45aa3e4c76b1f2f4693675770ba4e3db2acee024730440220185d48c45b2e83f56249bfda4e2f0e1a211165c3c1175bd358cc7e4024e4764202201835811415ee2e5efbf42445b0113f54ae87b99e77e59252a69960759fdd8cf7012102b30fc0ddd4de67700667921a0c73f9e773d473c4827abe8c63b5060725b745d46302000002000000000101f0d8cef892eb52f81ac0e86bce4df8eeb9d0c1336cb62a069626c173e65321f80000000000feffffff02a0860100000000001600143df45aa3e4c76b1f2f4693675770ba4e3db2acee13373f2500000000160014e53cad733f173a80f1402d16123321535454048e0247304402207bbea0204f17fb98370ada2158666b4554d1354409efbd326835413041cd24410220323a16ee7b50f298446db61cd197cc44dd27fd90d45adb1a4fd780574300be7b012102b30fc0ddd4de67700667921a0c73f9e773d473c4827abe8c63b5060725b745d47602000002000000000101106a9ee2f6bbc4e58cbff2b1c99a53cdddec1a153f8a699350c00969500097210000000000feffffff02a0860100000000001600143df45aa3e4c76b1f2f4693675770ba4e3db2acee13373f2500000000160014f0321c988998afdb2b8788ce862402110792be8c0247304402207f6e3931036bb80b127b3d25ecf92bf5507cf057ec5af7c3a70b37e0c74575eb02205da9e647d92c86b2e17533050edd95e7eb887981e6145ade05728e0447a357bf012102b30fc0ddd4de67700667921a0c73f9e773d473c4827abe8c63b5060725b745d47602000002000000000101ea826992d745371bd6d762692369b94b2ac047df92d8b83cf9f46f6c9dbb13450000000000feffffff02a0860100000000001600143df45aa3e4c76b1f2f4693675770ba4e3db2acee13373f2500000000160014008e9141e1a0fd29384d41585598d2d1dc90ad380247304402202aeae79aa171eb28d21ee22fff4b58794d77e1ceda4c0bdd02fe87b4b6260c17022067184229e67f0ac2729e30206700fb50f0691e248690b6b103788552ebfb8b37012102b30fc0ddd4de67700667921a0c73f9e773d473c4827abe8c63b5060725b745d476020000020000000001011723ce44d3f606a6fbd3de7e5204ad22f6b48154e19e0e37fdb547c84e57bdfe0000000000feffffff0213373f2500000000160014b30e6003f0a61a3c594678af24bfe170894c15cca0860100000000001600143df45aa3e4c76b1f2f4693675770ba4e3db2acee0247304402202876093a9dec94f9ce1fb3b7c487a8cf38b09a9f3e438c2a1e56d2ff8e2287df02204bba8b7936cccad0302d4f0e39da4b27779a2e8a5ba5a506fe00907544224633012102b30fc0ddd4de67700667921a0c73f9e773d473c4827abe8c63b5060725b745d476020000020000000001016de1c5853fd550cb2fdd67f25b32496bb182404e2f127b5e82e48c587622eabc0000000000feffffff0213373f250000000016001496864cef7241cc0c24e8914f4ec75e34da0a70a6a0860100000000001600143df45aa3e4c76b1f2f4693675770ba4e3db2acee0247304402207dde78431c3e5ede2a90af0b3e3d32fadb5712e5ec04e3fac2dc6137d747187902202fc5603f63ce4498ad9062ed35b37ca5fc9a19fc90a9ef40ddec55b30820862c012102b30fc0ddd4de67700667921a0c73f9e773d473c4827abe8c63b5060725b745d476020000020000000001013e22c22ad4afedfac4642f54ebc1fb93f94f3af1c7cedd78fb17242975e00e650000000000feffffff02a0860100000000001600143df45aa3e4c76b1f2f4693675770ba4e3db2acee13373f250000000016001485fe6084fcec5323e4647ccb6781f2975ce78a690247304402202d4676c01c0f5f39d98f3e0435101c283baff3f2168bb20fccc99ef514abc77c02205703439a4ca4c289f9ab36e31ba88b81d5503ad705a30b036b628e505ef2b07f012102b30fc0ddd4de67700667921a0c73f9e773d473c4827abe8c63b5060725b745d476020000020000000001018e637219b2c53a395f6b61b85ff720e7380161b31473556d470878ccc9077fe80000000000feffffff02a0860100000000001600143df45aa3e4c76b1f2f4693675770ba4e3db2acee13373f2500000000160014d9a72d531686342f1f81a447f9643d22ec7bd0ab02473044022010df9caa2ae04bf2b04cce039d859e8fe9f04add799ce02ce4f5848a48eebb9802204e11ae33d32a7c99af8dcc85797b5dc0b7a864c5f9848be41604740fac2bdb89012102b30fc0ddd4de67700667921a0c73f9e773d473c4827abe8c63b5060725b745d4760200000200000000010124c74f712076cb581a3ee4ae502e094487139ca3da724edb9c0acfd905bd8d340000000000feffffff0213373f250000000016001465eab055d88f1ac853fe1f790740ce24c8623e4ea0860100000000001600143df45aa3e4c76b1f2f4693675770ba4e3db2acee02473044022053373da5b4b0583d7ef8e743b0fad5688d5a81c82dd33fb6a614a0cf7234431a0220192e5802c1bf8d2e05bca416e3e42b1fb7947169333c40a33bfda2bf1170237d012102b30fc0ddd4de67700667921a0c73f9e773d473c4827abe8c63b5060725b745d4760200000200000000010145df9bc5da442ff71110c0872dc58939138aba50f2e12bdf13ef7e75ab2f893c0000000000feffffff0213373f250000000016001427880ac035c111a8e8f71e4ae6a5bb4df79518c4a0860100000000001600143df45aa3e4c76b1f2f4693675770ba4e3db2acee0247304402200a13fd5ae3a2dd9bb210316fea853cc8ad9ada202a58c91f53c61a0741b63833022012a15e4bb30938b31da9606d03e2692e12ce87afe816df19ca20934dfadb7641012102b30fc0ddd4de67700667921a0c73f9e773d473c4827abe8c63b5060725b745d4760200000200000000010140b280318583b4e346fab2a2a126201799ddaffa169d3ac375b9434b3937a0750000000000feffffff0213373f2500000000160014e11569e65a6a7bbe75ca0322070eb0745201b99ca0860100000000001600143df45aa3e4c76b1f2f4693675770ba4e3db2acee024730440220655e813dcd37ee11f44d82eddc1540225866e3cc730b768c6c5f9b80cd1c447502200e538e03ed2a3c4f5da9396e884890556e42bf5d25ae49eb1b6c8a0101096fb0012102b30fc0ddd4de67700667921a0c73f9e773d473c4827abe8c63b5060725b745d476020000020000000001012fb0c024a0ae79e6217dc8889c6af40853b2b230a0e9f79d765c8b5525e0e2320000000000feffffff0213373f25000000001600147f44238db9775e0e738fb949724a7ffb66f4ac47a0860100000000001600143df45aa3e4c76b1f2f4693675770ba4e3db2acee02473044022032778f2c844abedb675ef947bdc7a11271800b5a11c98be5c0c9fdc6b2037f7302206acf28de27d327dc5a9d93998edad27f7509aa8479a1a2be1cb28f0eee28bf6a012102b30fc0ddd4de67700667921a0c73f9e773d473c4827abe8c63b5060725b745d47602000002000000000101892c26005096da187a5de107320c08a02e458be0184af915edbacaf5ad898c160000000000feffffff02a0860100000000001600143df45aa3e4c76b1f2f4693675770ba4e3db2acee13373f250000000016001460524bb60b4dc68abe9ba195376d572dd6cc20fa0247304402206b43d3fcceff2ee92380f6e112b99907b94df56c9ed2ab7df4fa750fd5010ed70220526807188cb56ff1944e19db3910b06d944c8772a76fd91b83cca791c740da14012102b30fc0ddd4de67700667921a0c73f9e773d473c4827abe8c63b5060725b745d4760200000200000000010128877cbe42170fca382e506d745a333a1e1eed9ed5c3597cf904cd441f7fef050000000000feffffff02a0860100000000001600143df45aa3e4c76b1f2f4693675770ba4e3db2acee13373f250000000016001462bf5d506758c4075c1484ed199c12b1d070dcc9024730440220514defa364f4cf78355fb64a79f0be487a0515f2c383cca2c7572b862f389b8b022040fb39e0cef457968c22c7a778b3225bf6d95e661c6bfaeea40dc6c9ae7fd9d5012102b30fc0ddd4de67700667921a0c73f9e773d473c4827abe8c63b5060725b745d476020000020000000001019b34c725b2b7de36389cec07b79109d482dab48e1641c2ba143fe1e0ab80f86d0000000000feffffff02a0860100000000001600143df45aa3e4c76b1f2f4693675770ba4e3db2acee13373f250000000016001437586a889710f537d70d511e41f45ade16ae96b80247304402205e1560130977bf5584e1938c34daa77e3dd0393eff6cfb18fa3d485a622a9f1d02200d55678c7c274442b0aa99d0a047094051b125ff74e8582be20d52dbb1825889012102b30fc0ddd4de67700667921a0c73f9e773d473c4827abe8c63b5060725b745d476020000020000000001017883189114213697b8adc8069c8bafc80d9972c9fc1949a478c57bde58daacbb0000000000feffffff02a0860100000000001600143df45aa3e4c76b1f2f4693675770ba4e3db2acee13373f25000000001600144b69012485912f125d6121323d1b2c55e24b3a8f0247304402203bf784686661951078c64dce1410677127d92015d018a1233a9be6351f26ad2302203b6287e552aed0abcf8740cc464d5843dbd3712e58b33dfa2be6947ba88e7b8f012102b30fc0ddd4de67700667921a0c73f9e773d473c4827abe8c63b5060725b745d4760200000200000000010180143a2ecddd4d3b32eb7c1e6378a054a2a02b278811a5ffbddf4db4e17f0ad70000000000feffffff0213373f2500000000160014fe956a004e01b6cbe82bf6a351f9370a60917abba0860100000000001600143df45aa3e4c76b1f2f4693675770ba4e3db2acee024730440220769b4f0bc75725b686fcc131af5b31722eeb0e7835bdeb812e16982183045d66022070a2f04e7619e75a9abd62170a1dbffceb11e398119c559bdb66cf49d91d7b43012102b30fc0ddd4de67700667921a0c73f9e773d473c4827abe8c63b5060725b745d47602000002000000000101f33b3ce193ef8a4450c6b4db2184538c0e5c5c5406e549478d8afe10b3d7e1760000000000feffffff02a0860100000000001600143df45aa3e4c76b1f2f4693675770ba4e3db2acee13373f25000000001600147235fdc337715c994998751dbfb0f3a38e87594e02473044022071323b810bed75c508337a442268503d70ac598f8db2fd0af57fb7ff6b913450022075157811bc930b2a7e2dc2cf5d6b075ca99e3e81bef2992111e43b8aebe9a0ac012102b30fc0ddd4de67700667921a0c73f9e773d473c4827abe8c63b5060725b745d434020000"; + + let block = Block::from_str(block_hex).expect("Fail"); + let hash = block.get_hash().to_hex(); + assert_eq!( + "0ae1754425645e84cf354366150db602bd1ca38a5b64b6d7949ffc7f5480ab41", + hash + ); + let header = block.get_header(); + assert_eq!(536870912, header.version); + assert_eq!( + "42960b23c8af44e5c2b2a372ef44f069898f1f085adabe72420f03ccf7e187d9", + header.prev_block_hash.to_hex() + ); + assert_eq!( + "03af1d58df59023834b82f0e7c0debe4411b520bfa7cabaa65fa46b743deb5d8", + header.merkle_root.to_hex() + ); + assert_eq!(1622375957, header.time); + assert_eq!(0x207fffff, header.bits); + assert_eq!(1, header.nonce); + let count = block.get_tx_count(); + assert_eq!(21, count); + + let txid = Txid::from_str("cb3f209415bd73c709740fa0742ba960679cf22e86f691d11eb08e4a85cef95f") + .expect("Fail"); + let txid_list = block.get_txid_list(); + assert_eq!(21, txid_list.len()); + if txid_list.len() == 21 { + let exp_txid_list = vec![ + "7f5fb624f5cdce391362aa6befea307c4e778e008e799b40ca7119046f26ab31", + "b4bcb584d0ee9c1e687c69ad0497b2686f7d47529affc0f1df8210b2a074c40c", + "7af0cb6d0a0ded748790daa5e20b079e30cc82d90a267cad982328ed11409c17", + "8d0b1863957eaa5b9c82a07c4e8b78801e496a8af4ed11450186fb1e7bdbfa29", + "b42e9550b5129b34152950843ca09b0674a51ef4d273688366b216db7da16442", + "d4ebf5a67e891b059c6aa67dd06c0ac3e129bf959919e2077c6519d6d460b347", + "5edd72b9fef5225167c11862063c8cd955e648e01470b9784693d3868eaadf49", + "d6f11f1fa8efb17911c1918ec1f2964d20b6bd5ddcefc60acc751094344f2b5e", + "cb3f209415bd73c709740fa0742ba960679cf22e86f691d11eb08e4a85cef95f", + "f4be3e47478145959d2d0978bf1900db2521be4d4f2964b277c35b754133bc7d", + "9c9a3d9783dd9ac6c14c0ee487fa94f2e53053a7c96d10c37f0289edcdeb2b7e", + "a5ab7f31660deb709d4ab2a70f4ce16a7cb02a16b03e843a39aba43115d3217f", + "dc11069c2643ff09717a290e7dc0e38863316ec68b24fbb7d47d4e670f74777f", + "4b244572aaec7a7b92431f7371b42547aca705b7ede430081be6374e8a672282", + "4ae603bfb1689c29b1e5feb2cbd2f1ebb950df3ed4b25b6ad98f2f56da8cac93", + "18b54774739e59b7bb0ec6a7196000c0f8fe42b441502636bdb5adde40f9e8a8", + "587b9d5224a54fb3427cd99dc276b8acab4d4322c1b5681408d74a2927cd62ac", + "98bdb3d84051b02a8bb147bb34d2e34c5b32339aebcccff696429c04538a45df", + "695eddd38e01b5f67f93d3dcbdca033e1d8fd3feaefbdbcc2a2bd1326a6b7be4", + "2bc841beb4de23e39e9674f96afc7a8b3c6db60c6d3c645c06a747eeb5135ae8", + "be37763a766b5aa48d31a44a2c34ff1355e55e7f0efae58de9594d4eae3ca8ed", + ]; + let mut index = 0; + while index < count { + assert_eq!(exp_txid_list[index], txid_list[index].to_hex()); + index += 1; + } + } + + let (tx, proof) = block.get_tx_data(&txid).expect("Fail"); + assert_eq!( + "020000000001016de1c5853fd550cb2fdd67f25b32496bb182404e2f127b5e82e48c587622eabc0000000000feffffff0213373f250000000016001496864cef7241cc0c24e8914f4ec75e34da0a70a6a0860100000000001600143df45aa3e4c76b1f2f4693675770ba4e3db2acee0247304402207dde78431c3e5ede2a90af0b3e3d32fadb5712e5ec04e3fac2dc6137d747187902202fc5603f63ce4498ad9062ed35b37ca5fc9a19fc90a9ef40ddec55b30820862c012102b30fc0ddd4de67700667921a0c73f9e773d473c4827abe8c63b5060725b745d476020000", + tx.to_str()); + assert_eq!( + "00000020d987e1f7cc030f4272beda5a081f8f8969f044ef72a3b2c2e544afc8230b9642d8b5de43b746fa65aaab7cfa0b521b41e4eb0d7c0e2fb834380259df581daf03157eb360ffff7f20010000001500000006774b1a7f9e060f94a1c7bd9d8109e233014e4e74a09a5b85a42add1837c18de15ff9ce854a8eb01ed191f6862ef29c6760a92b74a00f7409c773bd1594203fcb7dbc3341755bc377b264294f4dbe2125db0019bf78092d9d95458147473ebef40b484381159b8168441d718d2855f98b076d7f319e08fc129fc6684a10364d6cab62141fa7cf9455e1db2b83d9746dcb4151f71cbde29b8074d9c280cf2329858c705d27704a43f47e3a3066b9253a3d7380cb20874e67178450d2ab376f06ee027b00", + proof.to_hex()); + + assert!(block.exist_txid(&txid)); + assert!(!block.exist_txid( + &Txid::from_str("f5ce9417846b075c82da9368ed6bf40b59721662b64e4dd506fbdc50911f39fe") + .expect("Fail") + )); + } +} diff --git a/tests/confidential_transaction_test.rs b/tests/confidential_transaction_test.rs index 4b4a3aa..3c9b210 100644 --- a/tests/confidential_transaction_test.rs +++ b/tests/confidential_transaction_test.rs @@ -5,12 +5,12 @@ mod elements_tests { use cfd_rust::{ decode_raw_transaction, get_default_blinding_key, get_issuance_blinding_key, Address, BlindFactor, BlindOption, BlockHash, ByteData, ConfidentialAddress, ConfidentialAsset, - ConfidentialNonce, ConfidentialTransaction, ConfidentialTxOutData, ConfidentialValue, - Descriptor, ElementsUtxoData, ExtPrivkey, ExtPubkey, FeeOption, FundTargetOption, - FundTransactionData, HashType, InputAddress, IssuanceInputData, IssuanceKeyMap, - IssuanceOutputData, KeyIndexMap, Network, OutPoint, PeginInputData, PegoutInputData, Privkey, - Pubkey, ReissuanceInputData, Script, SigHashType, SignParameter, Transaction, TxInData, - TxOutData, Txid, UtxoData, + ConfidentialNonce, ConfidentialTransaction, ConfidentialTxOut, ConfidentialTxOutData, + ConfidentialValue, Descriptor, ElementsUtxoData, ExtPrivkey, ExtPubkey, FeeOption, + FundTargetOption, FundTransactionData, HashType, InputAddress, IssuanceInputData, + IssuanceKeyMap, IssuanceOutputData, KeyIndexMap, Network, OutPoint, PeginInputData, + PegoutInputData, Privkey, Pubkey, ReissuanceInputData, Script, SigHashType, SignParameter, + Transaction, TxInData, TxOutData, Txid, UtxoData, }; use std::str::FromStr; @@ -139,7 +139,7 @@ mod elements_tests { .sign_with_privkey( &outpoint2, &HashType::P2wpkh, - &privkey1, + privkey1, &sighash_type, &value1, ) @@ -659,7 +659,7 @@ mod elements_tests { let outpoint = OutPoint::new(&txid, vout); let sighash = tx - .create_sighash_by_pubkey(&outpoint, &hash_type, &pubkey, &sighash_type, &value) + .create_sighash_by_pubkey(&outpoint, hash_type, &pubkey, &sighash_type, &value) .expect("Fail"); let sighash_byte = ByteData::from_slice(&sighash); assert_eq!( @@ -674,7 +674,7 @@ mod elements_tests { signature = signature.set_use_der_encode(&sighash_type); tx = tx - .add_pubkey_hash_sign(&outpoint, &hash_type, &pubkey, &signature) + .add_pubkey_hash_sign(&outpoint, hash_type, &pubkey, &signature) .expect("Fail"); let exp_tx_hex = "0200000001020f231181a6d8fa2c5f7020948464110fbcc925f94d673d5752ce66d00250a1570000000000ffffffff0f231181a6d8fa2c5f7020948464110fbcc925f94d673d5752ce66d00250a1570100008000ffffffffd8bbe31bc590cbb6a47d2e53a956ec25d8890aefd60dcfc93efd34727554890b0683fe0819a4f9770c8a7cd5824e82975c825e017aff8ba0d6a5eb4959cf9c6f010000000023c346000004017981c1f171d7973a1fd922652f559f47d6d1506a4be2394b27a54951957f6c1801000000003b947f6002200d8510dfcf8e2330c0795c771d1e6064daab2f274ac32a6e2708df9bfa893d17a914ef3e40882e17d6e477082fcafeb0f09dc32d377b87010bad521bafdac767421d45b71b29a349c7b2ca2a06b5d8e3b5898c91df2769ed010000000029b9270002cc645552109331726c0ffadccab21620dd7a5a33260c6ac7bd1c78b98cb1e35a1976a9146c22e209d36612e0d9d2a20b814d7d8648cc7a7788ac017981c1f171d7973a1fd922652f559f47d6d1506a4be2394b27a54951957f6c1801000000000000c350000001cdb0ed311810e61036ac9255674101497850f5eee5e4320be07479c05473cbac010000000023c3460003ce4c4eac09fe317f365e45c00ffcf2e9639bc0fd792c10f72cdc173c4e5ed8791976a9149bdcb18911fa9faad6632ca43b81739082b0a19588ac0000000000000247304402200268633a57723c6612ef217c49bdf804c632a14be2967c76afec4fd5781ad4c20220131f358b2381a039c8c502959c64fbfeccf287be7dae710b4446968553aefbea012103f942716865bb9b62678d99aa34de4632249d066d99de2b5a2e542e54908450d600000000000000000000000000"; assert_eq!(exp_tx_hex, tx.to_str()); @@ -866,12 +866,12 @@ mod elements_tests { let verify = pubkey .verify_ec_signature(&sighash, sig.to_slice()) .expect("Fail"); - assert_eq!(true, verify); + assert!(verify); let is_verify = tx .verify_signature_by_pubkey(&outpoint, desc.get_hash_type(), &pubkey, &signature, &value) .expect("Fail"); - assert_eq!(true, is_verify); + assert!(is_verify); } #[test] @@ -956,12 +956,12 @@ mod elements_tests { &outpoint, desc.get_hash_type(), &pubkey, - &redeem_script, + redeem_script, &signature, &value, ) .expect("Fail"); - assert_eq!(true, is_verify); + assert!(is_verify); } #[test] @@ -1015,7 +1015,7 @@ mod elements_tests { &BlindFactor::from_str("62e36e1f0fa4916b031648a6b6903083069fa587572a88b729250cde528cfd3b") .expect("Fail"), ) - .set_option_info(true, true, false, 0, &Script::default()), + .set_option_info(true, true, false, &Script::default(), 0, 0), ]; // estimate fee on blind tx @@ -1094,14 +1094,14 @@ mod elements_tests { .expect("Fail"); let used_addr = data.reserved_address_list; - assert_eq!("0200000000020bfa8774c5f753ce2f801a8106413b470af94edbff5b4242ed4c5a26d20e72b90000000000ffffffff040b0000000000000000000000000000000000000000000000000000000000000000000000ffffffff050100000000000000000000000000000000000000000000000000000000000000aa010000000000989680001600144352a1a6e86311f22274f7ebb2746de21b09b15d0100000000000000000000000000000000000000000000000000000000000000bb01000000000007a120001600148beaaac4654cf4ebd8e46ca5062b0e7fb3e7470c0100000000000000000000000000000000000000000000000000000000000000aa0100000000000001ff00000100000000000000000000000000000000000000000000000000000000000000bb010000000001124c1e00160014a53be40113bb50f2b8b2d0bfea1e823e75632b5f0100000000000000000000000000000000000000000000000000000000000000aa0100000000004b595f0016001478eb9fc2c9e1cdf633ecb646858ba862b21384ab00000000", + assert_eq!("0200000000020bfa8774c5f753ce2f801a8106413b470af94edbff5b4242ed4c5a26d20e72b90000000000ffffffff040b0000000000000000000000000000000000000000000000000000000000000000000000ffffffff050100000000000000000000000000000000000000000000000000000000000000aa010000000000989680001600144352a1a6e86311f22274f7ebb2746de21b09b15d0100000000000000000000000000000000000000000000000000000000000000bb01000000000007a120001600148beaaac4654cf4ebd8e46ca5062b0e7fb3e7470c0100000000000000000000000000000000000000000000000000000000000000aa0100000000000001f500000100000000000000000000000000000000000000000000000000000000000000bb010000000001124c1e00160014a53be40113bb50f2b8b2d0bfea1e823e75632b5f0100000000000000000000000000000000000000000000000000000000000000aa0100000000004b59690016001478eb9fc2c9e1cdf633ecb646858ba862b21384ab00000000", tx.to_str()); assert_eq!(2, used_addr.len()); if used_addr.len() == 2 { assert_eq!(addr2.to_str(), used_addr[0].to_str()); assert_eq!(addr1.to_str(), used_addr[1].to_str()); } - assert_eq!(511, data.fee_amount); + assert_eq!(501, data.fee_amount); // calc fee let fee_utxos = [utxos[5].clone(), utxos[9].clone()]; @@ -1135,7 +1135,7 @@ mod elements_tests { &BlindFactor::from_str("62e36e1f0fa4916b031648a6b6903083069fa587572a88b729250cde528cfd3b") .expect("Fail"), ) - .set_option_info(true, true, false, 0, &Script::default()); + .set_option_info(true, true, false, &Script::default(), 0, 0); let out_addr1 = Address::from_str("2djHX9wtrtdyGw9cer1u6zB6Yq4SRD8V5zw").expect("Fail"); let out_addr2 = Address::from_str("2dodsWJgP3pTWWidK5hDxuYHqC1U4CEnT3n").expect("Fail"); let mut tx = ConfidentialTransaction::create_tx( @@ -1221,14 +1221,14 @@ mod elements_tests { .expect("Fail"); let used_addr = data.reserved_address_list; - assert_eq!("0200000000030f231181a6d8fa2c5f7020948464110fbcc925f94d673d5752ce66d00250a1570100008000ffffffffd8bbe31bc590cbb6a47d2e53a956ec25d8890aefd60dcfc93efd34727554890b0683fe0819a4f9770c8a7cd5824e82975c825e017aff8ba0d6a5eb4959cf9c6f010000000023c34600000bfa8774c5f753ce2f801a8106413b470af94edbff5b4242ed4c5a26d20e72b90000000000ffffffff040b0000000000000000000000000000000000000000000000000000000000000000000000ffffffff07010bad521bafdac767421d45b71b29a349c7b2ca2a06b5d8e3b5898c91df2769ed010000000029b92700001976a9146c22e209d36612e0d9d2a20b814d7d8648cc7a7788ac01cdb0ed311810e61036ac9255674101497850f5eee5e4320be07479c05473cbac010000000023c34600001976a9149bdcb18911fa9faad6632ca43b81739082b0a19588ac0100000000000000000000000000000000000000000000000000000000000000aa010000000000989680001600144352a1a6e86311f22274f7ebb2746de21b09b15d0100000000000000000000000000000000000000000000000000000000000000bb01000000000007a120001600148beaaac4654cf4ebd8e46ca5062b0e7fb3e7470c0100000000000000000000000000000000000000000000000000000000000000aa01000000000000037200000100000000000000000000000000000000000000000000000000000000000000bb010000000001124c1e00160014a53be40113bb50f2b8b2d0bfea1e823e75632b5f0100000000000000000000000000000000000000000000000000000000000000aa0100000000004b57ec0016001478eb9fc2c9e1cdf633ecb646858ba862b21384ab00000000", + assert_eq!("0200000000030f231181a6d8fa2c5f7020948464110fbcc925f94d673d5752ce66d00250a1570100008000ffffffffd8bbe31bc590cbb6a47d2e53a956ec25d8890aefd60dcfc93efd34727554890b0683fe0819a4f9770c8a7cd5824e82975c825e017aff8ba0d6a5eb4959cf9c6f010000000023c34600000bfa8774c5f753ce2f801a8106413b470af94edbff5b4242ed4c5a26d20e72b90000000000ffffffff040b0000000000000000000000000000000000000000000000000000000000000000000000ffffffff07010bad521bafdac767421d45b71b29a349c7b2ca2a06b5d8e3b5898c91df2769ed010000000029b92700001976a9146c22e209d36612e0d9d2a20b814d7d8648cc7a7788ac01cdb0ed311810e61036ac9255674101497850f5eee5e4320be07479c05473cbac010000000023c34600001976a9149bdcb18911fa9faad6632ca43b81739082b0a19588ac0100000000000000000000000000000000000000000000000000000000000000aa010000000000989680001600144352a1a6e86311f22274f7ebb2746de21b09b15d0100000000000000000000000000000000000000000000000000000000000000bb01000000000007a120001600148beaaac4654cf4ebd8e46ca5062b0e7fb3e7470c0100000000000000000000000000000000000000000000000000000000000000aa01000000000000036800000100000000000000000000000000000000000000000000000000000000000000bb010000000001124c1e00160014a53be40113bb50f2b8b2d0bfea1e823e75632b5f0100000000000000000000000000000000000000000000000000000000000000aa0100000000004b57f60016001478eb9fc2c9e1cdf633ecb646858ba862b21384ab00000000", tx.to_str()); assert_eq!(2, used_addr.len()); if used_addr.len() == 2 { assert_eq!(addr2.to_str(), used_addr[0].to_str()); assert_eq!(addr1.to_str(), used_addr[1].to_str()); } - assert_eq!(882, data.fee_amount); + assert_eq!(872, data.fee_amount); // calc fee let fee_utxos = [input_utxo, utxos[5].clone(), utxos[9].clone()]; @@ -1307,14 +1307,14 @@ mod elements_tests { .expect("Fail"); let used_addr = data.reserved_address_list; - assert_eq!("0200000000020bfa8774c5f753ce2f801a8106413b470af94edbff5b4242ed4c5a26d20e72b90000000000ffffffff040b0000000000000000000000000000000000000000000000000000000000000000000000ffffffff050100000000000000000000000000000000000000000000000000000000000000aa010000000000989680001600144352a1a6e86311f22274f7ebb2746de21b09b15d0100000000000000000000000000000000000000000000000000000000000000bb01000000000007a120001600148beaaac4654cf4ebd8e46ca5062b0e7fb3e7470c0100000000000000000000000000000000000000000000000000000000000000aa0100000000000001ff00000100000000000000000000000000000000000000000000000000000000000000bb010000000001124c1e00160014a53be40113bb50f2b8b2d0bfea1e823e75632b5f0100000000000000000000000000000000000000000000000000000000000000aa0100000000004b595f034082879df418331794e4a55b87cd94d2d23cf1f22aa07081aa28b91c28b5e5a116001478eb9fc2c9e1cdf633ecb646858ba862b21384ab00000000", + assert_eq!("0200000000020bfa8774c5f753ce2f801a8106413b470af94edbff5b4242ed4c5a26d20e72b90000000000ffffffff040b0000000000000000000000000000000000000000000000000000000000000000000000ffffffff050100000000000000000000000000000000000000000000000000000000000000aa010000000000989680001600144352a1a6e86311f22274f7ebb2746de21b09b15d0100000000000000000000000000000000000000000000000000000000000000bb01000000000007a120001600148beaaac4654cf4ebd8e46ca5062b0e7fb3e7470c0100000000000000000000000000000000000000000000000000000000000000aa0100000000000001f500000100000000000000000000000000000000000000000000000000000000000000bb010000000001124c1e00160014a53be40113bb50f2b8b2d0bfea1e823e75632b5f0100000000000000000000000000000000000000000000000000000000000000aa0100000000004b5969034082879df418331794e4a55b87cd94d2d23cf1f22aa07081aa28b91c28b5e5a116001478eb9fc2c9e1cdf633ecb646858ba862b21384ab00000000", tx.to_str()); assert_eq!(2, used_addr.len()); if used_addr.len() == 2 { assert_eq!(addr2.to_str(), used_addr[0].to_str()); assert_eq!(ct_addr1.get_address().to_str(), used_addr[1].to_str()); } - assert_eq!(511, data.fee_amount); + assert_eq!(501, data.fee_amount); // calc fee let fee_utxos = [utxos[5].clone(), utxos[9].clone()]; @@ -1748,6 +1748,24 @@ mod elements_tests { tx.to_str()); } + #[test] + fn update_txin_sequence_test() { + let mut tx = ConfidentialTransaction::from_str("020000000101319bff5f4311e6255ecf4dd472650a6ef85fde7d11cd10d3e6ba5974174aeb560100008000ffffffff6f1a4b6bd5571b5f08ab79c314dc6483f9b952af2f5ef206cd6f8e68eb1186f36f2a4b6bd5571b5f08ab79c314dc6483f9b952af2f5ef206cd6f8e68eb1186f301000000000011223301000000000011224400000000000800110011001100110800110011001100220000").expect("Fail"); + tx = tx + .update_txin_sequence( + &OutPoint::from_str( + "56eb4a177459bae6d310cd117dde5ff86e0a6572d44dcf5e25e611435fff9b31", + 1, + ) + .expect("Fail"), + 4294967294, + ) + .expect("Fail"); + assert_eq!( + "020000000101319bff5f4311e6255ecf4dd472650a6ef85fde7d11cd10d3e6ba5974174aeb560100008000feffffff6f1a4b6bd5571b5f08ab79c314dc6483f9b952af2f5ef206cd6f8e68eb1186f36f2a4b6bd5571b5f08ab79c314dc6483f9b952af2f5ef206cd6f8e68eb1186f301000000000011223301000000000011224400000000000800110011001100110800110011001100220000", + tx.to_str()); + } + #[test] fn update_witness_stack_test() { let mut tx = ConfidentialTransaction::from_str("0200000001010e3c60901da7ffc518253e5736b9b73fd8aa5f79f249fa75bfe662c0f6ee42c301000000171600140c2eade9f3c984d0b2cedc79075a5793b0f5ce05ffffffff0201f38611eb688e6fcd06f25e2faf52b9f98364dc14c379ab085f1b57d56b4b1a6f010000000005f5e100001976a914b3c03c18599d13a481d1eb8a0ac2cc156564b4c688ac01f38611eb688e6fcd06f25e2faf52b9f98364dc14c379ab085f1b57d56b4b1a6f01000000000007a1200000000000000000024730440220437d443d290dcbd21b9dfdc612ac6cc5134f5acca19aa3c90b870ec41480839d02205662e29994c06cbeba70640aa74c7a4aafa50dba52ff45117800a1680240af6b0104111111110000000000").expect("Fail"); @@ -2168,5 +2186,58 @@ mod elements_tests { .expect("Fail"); assert_eq!("020000000001a38845c1a19b389f27217b91e2120273b447db3e595bba628f0be833f301a24a0000000000fdffffff030125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000befe33cc397c0017a914001d6db698e75a5a8af771730c4ab258af30546b870125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a01000000003b9aca0000a06a2006226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f1976a914efbced4774546c03a8554ce2da27c0300c9dd43b88ac2103700dcb030588ed828d85f645b48971de0d31e8c0244da46710d18681627f5a4a4101044e949dcf8ac2daac82a3e4999ee28e2711661793570c4daab34cd38d76a425d6bfe102f3fea8be12109925fad32c78b65afea4de1d17a826e7375d0e2d00660125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000000001c84000000000000", tx.to_str()); + + assert!(tx.has_pegout_txout(1).expect("Fail")); + let pegout_addr = tx.get_pegout_address(1, Network::Mainnet).expect("Fail"); + assert_eq!("1NrcpiZmCxjC7KVKAYT22SzVhhcXtp5o4v", pegout_addr.to_str()); + } + + #[test] + fn get_unblind_data_test() { + let locking_script = + Script::from_hex("a914001d6db698e75a5a8af771730c4ab258af30546b87").expect("Fail"); + let asset_commitment = ConfidentialAsset::from_str( + "0bb0852f9c11249a0c8ebb1c1bc3f99c5f643fa3426d4e5c730e702aaf3f2581fc", + ) + .expect("Fail"); + let value_commitment = ConfidentialValue::from_str( + "091dd6cd19781f14385175b586607221d1f11b3f19f149e707810de78f7c7f6f79", + ) + .expect("Fail"); + let nonce_commitment = ConfidentialNonce::from_str( + "0398e7cd1cb3c9c13506f91b946f5586cc8fa45f36dde615f2bdb48c1dfe904270", + ) + .expect("Fail"); + let rangeproof = ByteData::from_str( + "6033000000000000000121579e0109f21bb7cd0326804abb14059b54fa186892f060384435402393a6589fb54df6ede461ce206af5b13abbe1a564404abf7ab1cc4ed6bd1d93a91728224b21c10a540d76f0ccc047ffa3e06a8abad69687213373d5bcfd4fcf62ecd11c2aff9e1a9d64602cab441e3777d771f88f7e805223a5f192ed3d63b937e93e0e170e6b76e8a05fc5bb46826967d4850dbd2e9128ed615e71149f9aac9304194e968cd8b1ad28a96230b4064795040d16554776ee40b3793bdc9758285df2bc90a5c4be023d206293c071962939160f640ecedbba5a3731aa0aa60afd94f2d9a9d366b4e55ec8c561455ba6a849f8f0df0b19eaf98993655102500a47b76ad320522e4c1f9f829333331017cd0040226f60e426fc00b3844d08e364f6c9f346e3eb7dcf8de6e12a2ac98f11bed6b0c3e06c0bf767e96414ec276a2eb145f64eccb663b46135a19ac17cce785f15b1b2cb7206483329f4c38236ad3cd6cf1646a95ddb94beccb237dc6a854098b139df24f2c8ce7ce7e6d799a434f415ba52ce643bd51619edd786df734b0cee6a5a9ff0442f50a0ca011d8e5b695e6a44016884dbf2f6f681bc3faa5a1a9be514b87ab47183a85bd98b6eff7d5865246b7564a3008cba9b5bcac11e8b3b76dcc38c5915f14a1c7c08a76a31de11d9084cc0553871d0fb9e6ca25b2d191eb292c8f14c1b0cf9c4fedd0a85989a388c675e51003722bae92e356dd680a68f9861fc99be81bdc4f57fa0bf6f63613f80598960aacb8867a94cfbea8d4b776a4771ce1e8b20cf8506cd0524ba85e117085addf4de1d45c2ec6f8e441f74081b792208050ae890a91d5554e37d33ddba2b2c0bbdc2b4a31d0f7eaa1538e5a9fcbd86a87fdf5c6f161c0de5bdc9331b5936b06470c16778077887b3c80a53c5372914d2c3fffd5cb88ee00ffbbbdb10d7ce0fbbca1e725438b7f51a81b611b9f0c4330c3ec3b8d191218fc720c3165305412425f73efacdf44fb0cda9bd1f5290cac09a7f27ca68cb9b485d83c822282cadbfab69ef4f079d1d9e6042033a4a2c8ee9203509f9669f0553ece40d2958d3a733b81232b6ef6c21adc2e2716942588146d6dcadcdc94a13326c6828d04692da1a129e73a3f60cdd30d16b19b29f15a734ddcee491159fedec88a6c986e0243e99b9d2ceed1b9b8c7b3180857f067d8d778f8c0d19ef059f4bf2de3de7f3fc26c86a37cf046fae93cbaaf06e9d95ed73e95957aa69c2680087c6b36d51f93d8e3b9596ab4d793619e70a61edd12c14dc928cc56d1047ea3383b77d8d7527fe43317b21c86a323ed982ed1b766698dcda6c6a91bf50d3f01d7f1d8c20b44441cab3eeb5fac0995298eb7a7a6877bc420119a9acc713e221ddcd2038423c431247dd328372744aea39b9797a9757e46f9d83c5bcce8e2af2baef8416d27a2e5274c21ebdf432f844511081cede5f794ac5e4521d432a6497946d014af706cf431f3437d9d8ad04a3c84cbec65c5596569bdd268a2d7bf0025e6debf4209f7a7a6ae29d9357f84007e72358869caa02ce25813115c98ae6054e9bf48732b55bed6cfe87e7ae05eb435a6eece76046dc2da86d0c33283ff6fb4ffb65e8c943a8c298146c31b48eddc0e0255094c5761d9a8e7b155058efc755579301781355607f369724dd81b58d76977c19a9787ed92760ecce6b2ff0b03093f0936ba6b5872cdf0dcad63f4080f9501a813df248c3484f3445e75f8ca7ab028409bcf63c191b9bd352687397a0cab873dbf6c4fec4cf364cb2e7966f4b6d77e6b9a8477d44d3cf3ef5ecdb1faebd35dff45f39d660accf3bb3fa86cbd021e572eba6014e5c2e48702ab874bde9314c20e9073c20bad928b672249d01d8d8c89b368962a2e9cabca801fb27e59b1a58fd11fcf4d697746e1a7e72a8e32186155dd0f90468e6bb40e39e1d599434e7d504e577f2aee60479a21152c8c64c57f11930611385a605c150cb5c582489dd8e268ba8e1dd4b38fb337f347f3aa953a1d437f69209c2672c755d84957522938f6e69ec39a59725fe786e442a3f39083283dcb6177cde1a4abe38d17c4a45e7b1e78460474bee3eb8ccd4a1d0bd9ac7cc4dcac3dc9263117b0f9e05ff85853d9b28444ee840bd3f674dc2abc53fa5d2db8cd64a1739eec76063ffd93352128135b02377f6ca684b11add9c9434f6060f98c1c0f14ad941c12a4c6ca753afd36f22e353cf7147ab62c7245871a87166b7ca5d5e179953ee4d0328d0c7d69fd4128e06f6e546109732bd7d213e1559b280c0f2304ab874fe87410a77ed8c41378e5530e6ba6eb605f87fc75a4763244433366866ea9227cea868d67dde1287460351f8bc132c398bd4aaeadfe2959394ff96b3cbe1a3265777ea0fe676ecfd71daaf213d93edcc4a83fb9d159f858f61f8c28476430d97fd8879df97bb89914bc8e767a008b952976fb54d44492da79036004c36de129118f8fca1528dae9becd6c1471c9b1690fc00d64af653b1672f0db041ae7a0592a85dff25ca470892f8064b9ed01085a929d7b0ef03775fd5546bdab4ffd494a4af9c35ca0b6d3313c2be2c817522ff79fc54d28baf7707463dfe13423ae368bb1c80e7e2e509617f41c54f57ef67c6a786c28f1578be5a64e36cfb3b63c5e1c07619503619031772505987b515faabf7203b4d4413d6abbf8a6c8f00cd69a24e6c0f9c278b0f166763dbeed28ff447814e2d61c92d31840811f2b4e69323e7a35670b7629dbbe04afc7167ee217fe0f74930cf10ef5c07240c70ff3b36d200c1ce866bf108d5566fbff4860389f532871e2d8075fa28c39c85bd68a95f3a1e23265cbc5ed1657711239a32c4c67245d70eb93082323fcc7f113f912c1e0b818186e044b19dfc22d33c82e2cdfb88ead2f152790f47c1b432bce6d899e9c2dcf03969ab2cafd22e4cf7bbefe10bd2b8fb0078e8b5e006cf898259061efbeaa41aa46bd5cc19d3efe05a8c590bd8212b25f862b635876a9a63cde5fb194358c619fd39ef389b60eb7688513ea4dcf6dacc8cc97456a5131bf8de5b424edff078604456e8b6bce2b1504b8715e301a2957cd79f5f942524af676279645ba9f41f141544b0adac60703027cab8c5d9b51ec8103e2da72c3f7c61803cd94765493506e82921ca469b919cbce716ebe10864655fe6fc7177bba55baf3276007b196c81eb97b1fc7d925eb3c91da45a5ea5c5121f109e73f05937a33ecce115a325914bec1cb5590bc01b57fdba899f5e048ab18fb47c71e8cf351dbcf4140c6961a10ef1c3e322bf760ed222ba83b363977172ea2d7c40e23bcd307e28d69c868af7f1f0ace4965d68ee540ef2ba0b81a698db7239a40cf7845d7bf322e444178921dfcf9c23fbcbfc4d306146ccae6ecb707b7fcc7f43aa92071caba893507117621032d9a2c7ac602f013186b7faaa8596105bfdfe47b6e0e93538f322e7417db403a0288d7a6f635ba1c13f43927061717014c80c88b65840a6ca83d59abce9ef4873e34b936650ab0158d145e89e6aaf2d17fc6a9a8bbf8c01906404aac849189b3865687350764be2872532a2271e05d02f820644a33bf6b64c7bef615d6b8dc27250e58a55039b41c6d97f6d472bed31e76b042d4c79c770c242179acbaa6dc625b4b1e7d6525de8aa4cbc4dfbd5d9562ea60be9eafcda1ca7328c4c9db4064550c5268f9259dfa1a2aa3cffdd02ef19c76d32650da3b22ea83e6c04a063ece816fa9371d7669feb1a9a03eca17a9798eeb1626cb4cc996f2cbc8d8a0c5d78ef3e921a276eb03717a423e5cde35a878bf3961aeb3eacb26332bf7eecb5259074d865478bde6810233217cfd1f91c8c85ffd89285e8579ece30591fac67f863b000d665d4298be4142a0f9991c51ec03b828e7620e71b9eee7753b35328028ba0e73e65191a6516f842c65a423f015f3f8edba667a756f4e479d3f8a6d40a45a6698cf8b6a226649b17192fdc39977d9913eafb917fb9ad25ce26cda7f51e10535d3a29a3fb0fe5fe566f9ab8097d4b6c8f6236c42fde414cf1bdf88f83638d152c3504aa9758778c7107b2b43e3a1b5ade047afe4c527afe7c8bc1ae4559f9f393b6c4c35fbcd5089cb9fc96c43a15c7e052e28073046817b969c0e624bd7c147e3e2de3bc8eac41c160f400568bedeb1549f5b4081e1cbf106eff16c546fd03b552960abc0b64969bcdc85797e14bc73eaa45ca04ddbf228308190eed13503934f60b3b715bc3089241745b1df8439e7f08309fe873ea31ce35a6ccdb634dc9f27ee0cbfff9f4602bcd8f8b10a05f2fd7d46948caad11c09ca71effbe0ee63458874df827d9f652cbf1e55402c2a69b8a483029bf807ad63eb41cc92216d9f171284eb5d7dddb8e5d791d746ec35677a0b0b3eb435f65ecbf8dcd5ae2536eccbd554416e070ce4aaa566e2c5f925e6129617f93e531d17d06a18f1049a16e1e6aff5e46d48e0a6406c5a480c9884690c13ec302b9c03491be7bfe7981663a6716c6bc45ffd45b0c8ec581ec1ad7b1f7f409697bb39b6da1e27cf5355d9b6eca4a306c908083e3a81026ba1be096fdb6d9b7004cc21d439d5c6ce1a45afc951c84c7b26bcf9b4de4aef365ed514edc4a04e6999c1b9fa3f1ee332669228f3cdedd0edec4aa56824f4a64f295835b8830d153b0a0bf3f80c32d11d4b541be45d2c2522503d4bb3440829daf60ff383d71748becce66a78c2dab29fb82a6d7692c0da0326e65b8101a8099f7e2fdb60bdb08ed1e627747492c18b9f2f4653c6a8181cadc56cb684e878acc4583cc2f53ddbb18990291a26a750c422025b29de72d36581ef8fb047e7854cf04b4bba931a7a560d8cb4394a047c44926cee25d0b457e86ffaf4ad4f419df6e6c9d89b8f971310f109eaaa39403a9a5e4dc22ab5ce98afafd4f9b97c4202999ea0b62c20995c4c5b3cd466a99622980fb0478ee471168137cba6266ed7ce5caaaeec8df1921ce3749bcb6a6a488d40bc1f84df8f37847efd4833ec9bc39b5890bcda0ba97acab58ac1e389c752340ad20fbd2d6885f1ce7349376302cb3d5070f30288e55b033c4242f328b9ae4565af08519f052f758b4f6eff1e8fb1ef6d0a96eddc4f6d135cdd930d37ce9e9a0699989e5f54c9104a710070a5458c38af044b6335457d6ffa477fdaa8507b6043d8639e30190613ae5667c6a757522345ee1c1ca73b279255f2cf7b7ddfbdb60fa0e218e0675a9c0fc13d8f043230bae9db8073cd0ae2627c663fdedf7b8fe7341b3817623894874932797320ef582943b8fb5ea96827aef251193bc50dc4400cc7f9bc44d83651c05ff17904367f66d736eede1964f90d7fe7ff086b3849ce32a1554182b1ea8703447a61b2d2d6e2753558f1355a3fd84af25fd89fdf495b641880081d974ca641846c8d4495ce11b79933f1c47a1fef41adc1c7992fb11479ec8d117d06668580cf3558ae681626e50d559bf4147b2b1ec59c4979e19ef851612c3c888d57d512a073c0ff9fa7dfb7e7d9552925baf3e95a83f41a6a5bbd867820e791ae13b0923ebbfca3adeb46323c2c85c3fceb9525b5fc50a078f0b0a9c7820fef73429a617b476e89fa77627fe9816be6ba912da6353092c5953c4ff2911500c4e88f4a0124db5edbdce22cb34235d9c9c9d0e00559eabb222aab6dede02d6b0c46adbf6e9437339e267b26b9f2471e94e41a72a4445ff0a855f72bd04e028f845ec445f13f1d28f173a0494d769b552c85721ac10aed7e8a79b72adf8f5e4f409637a0541579cfa918dd50d3d93d00dabe7dac95675b07ac078fbb31e35e77baa280e6b5b510dfafbc0ee5445524e8a4ddc0c6df98080d74df263bf022566e2791d1fa4a72ebf880852e57b1eac8").expect("Fail"); + let blinding_key = + Privkey::from_str("66e4df5035a64acef16b4aa52ddc8bebd22b22c9eca150774e355abc72909d83") + .expect("Fail"); + let unblind_data = ConfidentialTxOut::unblind( + &blinding_key, + &locking_script, + &asset_commitment, + &value_commitment, + &nonce_commitment, + &rangeproof, + ) + .expect("Fail"); + + assert_eq!( + "5ac9f65c0efcc4775e0baec4ec03abdde22473cd3cf33c0419ca290e0751b225", + unblind_data.asset.as_str() + ); + assert_eq!( + 209998999992700, + unblind_data.amount.as_amount().as_satoshi_amount() + ); + assert_eq!( + "6b49938ded88d5c2c335133665158134041769882dd560ca47c14631052a981c", + unblind_data.asset_blind_factor.to_hex() + ); + assert_eq!( + "0e396bcbc4c0b74329712b1b5c7f8c9c4f054996da3748b8820563f68a07dedd", + unblind_data.amount_blind_factor.to_hex() + ); } } diff --git a/tests/descriptor_test.rs b/tests/descriptor_test.rs index d59624a..837f9d0 100644 --- a/tests/descriptor_test.rs +++ b/tests/descriptor_test.rs @@ -21,9 +21,9 @@ mod tests { "OP_DUP OP_HASH160 06afd46bcdfd22ef94ac122aa11f241244a37ecc OP_EQUALVERIFY OP_CHECKSIG", descriptor.get_address().get_locking_script().to_asm() ); - assert_eq!(false, descriptor.has_multisig()); - assert_eq!(false, descriptor.has_script_hash()); - assert_eq!(true, descriptor.has_key_hash()); + assert!(!descriptor.has_multisig()); + assert!(!descriptor.has_script_hash()); + assert!(descriptor.has_key_hash()); assert_eq!(1, descriptor.get_script_list().len()); let key_data = descriptor.get_key_data().expect("fail"); assert_eq!(&DescriptorKeyType::Public, key_data.get_type()); @@ -50,9 +50,9 @@ mod tests { "OP_0 7dd65592d0ab2fe0d0257d571abf032cd9db93dc", descriptor.get_address().get_locking_script().to_asm() ); - assert_eq!(false, descriptor.has_multisig()); - assert_eq!(false, descriptor.has_script_hash()); - assert_eq!(true, descriptor.has_key_hash()); + assert!(!descriptor.has_multisig()); + assert!(!descriptor.has_script_hash()); + assert!(descriptor.has_key_hash()); assert_eq!(1, descriptor.get_script_list().len()); let key_data = descriptor.get_key_data().expect("fail"); assert_eq!(&DescriptorKeyType::Public, key_data.get_type()); @@ -79,9 +79,9 @@ mod tests { "OP_HASH160 cc6ffbc0bf31af759451068f90ba7a0272b6b332 OP_EQUAL", descriptor.get_address().get_locking_script().to_asm() ); - assert_eq!(false, descriptor.has_multisig()); - assert_eq!(false, descriptor.has_script_hash()); - assert_eq!(true, descriptor.has_key_hash()); + assert!(!descriptor.has_multisig()); + assert!(!descriptor.has_script_hash()); + assert!(descriptor.has_key_hash()); assert_eq!(2, descriptor.get_script_list().len()); let key_data = descriptor.get_key_data().expect("fail"); assert_eq!(DescriptorKeyType::Public, *key_data.get_type()); @@ -116,9 +116,9 @@ mod tests { "OP_2 022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01 03acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe OP_2 OP_CHECKMULTISIG", descriptor.get_redeem_script().expect("Fail").to_asm() ); - assert_eq!(true, descriptor.has_multisig()); - assert_eq!(true, descriptor.has_script_hash()); - assert_eq!(false, descriptor.has_key_hash()); + assert!(descriptor.has_multisig()); + assert!(descriptor.has_script_hash()); + assert!(!descriptor.has_key_hash()); assert_eq!(1, descriptor.get_script_list().len()); let key_list = descriptor.get_multisig_key_list().expect("Fail"); assert_eq!(2, key_list.len()); @@ -153,9 +153,9 @@ mod tests { assert_eq!("OP_2 03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7 03774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb 03d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a OP_3 OP_CHECKMULTISIG", descriptor.get_redeem_script().expect("Fail").to_asm()); assert_eq!(1, descriptor.get_script_list().len()); - assert_eq!(true, descriptor.has_multisig()); - assert_eq!(true, descriptor.has_script_hash()); - assert_eq!(false, descriptor.has_key_hash()); + assert!(descriptor.has_multisig()); + assert!(descriptor.has_script_hash()); + assert!(!descriptor.has_key_hash()); let key_list = descriptor.get_multisig_key_list().expect("Fail"); assert_eq!(3, key_list.len()); assert_eq!( @@ -193,9 +193,9 @@ mod tests { "OP_1 03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8 03499fdf9e895e719cfd64e67f07d38e3226aa7b63678949e6e49b241a60e823e4 02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e OP_3 OP_CHECKMULTISIG", descriptor.get_redeem_script().expect("Fail").to_asm() ); - assert_eq!(true, descriptor.has_multisig()); - assert_eq!(true, descriptor.has_script_hash()); - assert_eq!(false, descriptor.has_key_hash()); + assert!(descriptor.has_multisig()); + assert!(descriptor.has_script_hash()); + assert!(!descriptor.has_key_hash()); assert_eq!(2, descriptor.get_script_list().len()); let key_list = descriptor.get_multisig_key_list().expect("Fail"); assert_eq!(3, key_list.len()); @@ -233,9 +233,9 @@ mod tests { "OP_0 c7a1f1a4d6b4c1802a59631966a18359de779e8a6a65973735a3ccdfdabc407d", descriptor.get_address().get_locking_script().to_asm() ); - assert_eq!(false, descriptor.has_multisig()); - assert_eq!(false, descriptor.has_script_hash()); - assert_eq!(false, descriptor.has_key_hash()); + assert!(!descriptor.has_multisig()); + assert!(!descriptor.has_script_hash()); + assert!(!descriptor.has_key_hash()); assert_eq!(1, descriptor.get_script_list().len()); } @@ -247,9 +247,9 @@ mod tests { "raw(6a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e)#zf2avljj", descriptor.to_str() ); - assert_eq!(false, descriptor.has_multisig()); - assert_eq!(false, descriptor.has_script_hash()); - assert_eq!(false, descriptor.has_key_hash()); + assert!(!descriptor.has_multisig()); + assert!(!descriptor.has_script_hash()); + assert!(!descriptor.has_key_hash()); assert_eq!(1, descriptor.get_script_list().len()); } @@ -270,9 +270,9 @@ mod tests { "OP_0 751e76e8199196d454941c45d1b3a323f1433bd6", descriptor.get_address().get_locking_script().to_asm() ); - assert_eq!(false, descriptor.has_multisig()); - assert_eq!(false, descriptor.has_script_hash()); - assert_eq!(true, descriptor.has_key_hash()); + assert!(!descriptor.has_multisig()); + assert!(!descriptor.has_script_hash()); + assert!(descriptor.has_key_hash()); assert_eq!(4, descriptor.get_script_list().len()); let key_data = descriptor.get_key_data().expect("fail"); assert_eq!(&DescriptorKeyType::Public, key_data.get_type()); @@ -307,9 +307,9 @@ mod tests { "OP_DUP OP_HASH160 c42e7ef92fdb603af844d064faad95db9bcdfd3d OP_EQUALVERIFY OP_CHECKSIG", descriptor.get_redeem_script().expect("Fail").to_asm() ); - assert_eq!(false, descriptor.has_multisig()); - assert_eq!(true, descriptor.has_script_hash()); - assert_eq!(false, descriptor.has_key_hash()); + assert!(!descriptor.has_multisig()); + assert!(descriptor.has_script_hash()); + assert!(!descriptor.has_key_hash()); assert_eq!(3, descriptor.get_script_list().len()); let key_data = descriptor.get_key_data().expect("fail"); assert_eq!(&DescriptorKeyType::Public, key_data.get_type()); @@ -336,9 +336,9 @@ mod tests { "OP_DUP OP_HASH160 f833c08f02389c451ae35ec797fccf7f396616bf OP_EQUALVERIFY OP_CHECKSIG", descriptor.get_address().get_locking_script().to_asm() ); - assert_eq!(false, descriptor.has_multisig()); - assert_eq!(false, descriptor.has_script_hash()); - assert_eq!(true, descriptor.has_key_hash()); + assert!(!descriptor.has_multisig()); + assert!(!descriptor.has_script_hash()); + assert!(descriptor.has_key_hash()); assert_eq!(1, descriptor.get_script_list().len()); let key_data = descriptor.get_key_data().expect("fail"); assert_eq!(&DescriptorKeyType::Bip32, key_data.get_type()); @@ -366,9 +366,9 @@ mod tests { "OP_DUP OP_HASH160 c21178dfb721039b6936b167657cd31ab60b1bbd OP_EQUALVERIFY OP_CHECKSIG", descriptor.get_address().get_locking_script().to_asm() ); - assert_eq!(false, descriptor.has_multisig()); - assert_eq!(false, descriptor.has_script_hash()); - assert_eq!(true, descriptor.has_key_hash()); + assert!(!descriptor.has_multisig()); + assert!(!descriptor.has_script_hash()); + assert!(descriptor.has_key_hash()); assert_eq!(1, descriptor.get_script_list().len()); let key_data = descriptor.get_key_data().expect("fail"); assert_eq!(&DescriptorKeyType::Bip32, key_data.get_type()); @@ -399,9 +399,9 @@ mod tests { "OP_SIZE 32 OP_EQUALVERIFY OP_SHA256 38df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b6 OP_EQUAL OP_IFDUP OP_NOTIF OP_IF 499999999 OP_CHECKLOCKTIMEVERIFY OP_0NOTEQUAL OP_ELSE OP_0 OP_ENDIF OP_NOTIF OP_0 OP_ELSE 4194305 OP_CHECKSEQUENCEVERIFY OP_ENDIF OP_ENDIF", descriptor.get_redeem_script().expect("Fail").to_asm() ); - assert_eq!(false, descriptor.has_multisig()); - assert_eq!(true, descriptor.has_script_hash()); - assert_eq!(false, descriptor.has_key_hash()); + assert!(!descriptor.has_multisig()); + assert!(descriptor.has_script_hash()); + assert!(!descriptor.has_key_hash()); assert_eq!(1, descriptor.get_script_list().len()); } @@ -426,9 +426,9 @@ mod tests { "OP_2 03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7 036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a00 OP_2 OP_CHECKMULTISIG OP_TOALTSTACK OP_1 036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a00 OP_1 OP_CHECKMULTISIG OP_FROMALTSTACK OP_ADD OP_TOALTSTACK 022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01 OP_CHECKSIG OP_FROMALTSTACK OP_ADD OP_2 OP_EQUAL", descriptor.get_redeem_script().expect("Fail").to_asm() ); - assert_eq!(false, descriptor.has_multisig()); - assert_eq!(true, descriptor.has_script_hash()); - assert_eq!(false, descriptor.has_key_hash()); + assert!(!descriptor.has_multisig()); + assert!(descriptor.has_script_hash()); + assert!(!descriptor.has_key_hash()); assert_eq!(1, descriptor.get_script_list().len()); } @@ -454,9 +454,9 @@ mod tests { "OP_IF OP_DUP OP_HASH160 520e6e72bcd5b616bc744092139bd759c31d6bbe OP_EQUALVERIFY OP_CHECKSIG OP_NOTIF OP_DUP OP_HASH160 06afd46bcdfd22ef94ac122aa11f241244a37ecc OP_EQUALVERIFY OP_ELSE OP_DUP OP_HASH160 5ab62f0be26fe9d6205a155403f33e2ad2d31efe OP_EQUALVERIFY OP_ENDIF OP_ELSE 02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e OP_ENDIF OP_CHECKSIG", descriptor.get_redeem_script().expect("Fail").to_asm() ); - assert_eq!(false, descriptor.has_multisig()); - assert_eq!(true, descriptor.has_script_hash()); - assert_eq!(false, descriptor.has_key_hash()); + assert!(!descriptor.has_multisig()); + assert!(descriptor.has_script_hash()); + assert!(!descriptor.has_key_hash()); assert_eq!(2, descriptor.get_script_list().len()); } @@ -470,17 +470,17 @@ mod tests { ); assert_eq!(&HashType::Taproot, descriptor.get_hash_type()); assert_eq!( - "bcrt1paag57xhtzja2dnzh4vex37ejnjj5p3yy2nmlgem3a4e3ud962gdqqctzwn", + "bcrt1pvv8jm84ye0xr7p9h8l2k58rm287nryk73cnw0nvfxyjfqqpn60gssz7u5f", descriptor.get_address().to_str() ); assert_eq!( - "OP_1 ef514f1aeb14baa6cc57ab3268fb329ca540c48454f7f46771ed731e34ba521a", + "OP_1 630f2d9ea4cbcc3f04b73fd56a1c7b51fd3192de8e26e7cd893124900033d3d1", descriptor.get_address().get_locking_script().to_asm() ); - assert_eq!(false, descriptor.has_multisig()); - assert_eq!(false, descriptor.has_script_hash()); - assert_eq!(false, descriptor.has_key_hash()); - assert_eq!(true, descriptor.has_taproot()); + assert!(!descriptor.has_multisig()); + assert!(!descriptor.has_script_hash()); + assert!(!descriptor.has_key_hash()); + assert!(descriptor.has_taproot()); assert_eq!(1, descriptor.get_script_list().len()); assert_eq!("", descriptor.get_script_tree().to_str()); let key_data = descriptor.get_key_data().expect("fail"); @@ -501,17 +501,17 @@ mod tests { ); assert_eq!(&HashType::Taproot, descriptor.get_hash_type()); assert_eq!( - "bc1p33h4j4kre3e9r4yrl35rlgrtyt2w9hw8f94zty9vacmvfgcnlqtq0txdxt", + "bc1p4jueea9m897g4me0ef8eyqg9x5n02jzpwnl0yydvdtrl459r3fyqg8wvnj", descriptor.get_address().to_str() ); assert_eq!( - "OP_1 8c6f5956c3cc7251d483fc683fa06b22d4e2ddc7496a2590acee36c4a313f816", + "OP_1 acb99cf4bb397c8aef2fca4f9201053526f5484174fef211ac6ac7fad0a38a48", descriptor.get_address().get_locking_script().to_asm() ); - assert_eq!(false, descriptor.has_multisig()); - assert_eq!(false, descriptor.has_script_hash()); - assert_eq!(false, descriptor.has_key_hash()); - assert_eq!(true, descriptor.has_taproot()); + assert!(!descriptor.has_multisig()); + assert!(!descriptor.has_script_hash()); + assert!(!descriptor.has_key_hash()); + assert!(descriptor.has_taproot()); assert_eq!(1, descriptor.get_script_list().len()); assert_eq!("", descriptor.get_script_tree().to_str()); let key_data = descriptor.get_key_data().expect("fail"); @@ -539,10 +539,10 @@ mod tests { "OP_1 5347c06cc9ed4b2286efcf4ed292a810ee451bdc50a4f0ab4a534a3f594763d5", descriptor.get_address().get_locking_script().to_asm() ); - assert_eq!(false, descriptor.has_multisig()); - assert_eq!(false, descriptor.has_script_hash()); - assert_eq!(false, descriptor.has_key_hash()); - assert_eq!(true, descriptor.has_taproot()); + assert!(!descriptor.has_multisig()); + assert!(!descriptor.has_script_hash()); + assert!(!descriptor.has_key_hash()); + assert!(descriptor.has_taproot()); assert_eq!(1, descriptor.get_script_list().len()); assert_eq!( "tl(208c6f5956c3cc7251d483fc683fa06b22d4e2ddc7496a2590acee36c4a313f816ac)", @@ -573,10 +573,10 @@ mod tests { "OP_1 4f009acbd8c905be4470df1b92c70be16a71d354ba55cc0e6517853f77d79651", descriptor.get_address().get_locking_script().to_asm() ); - assert_eq!(false, descriptor.has_multisig()); - assert_eq!(false, descriptor.has_script_hash()); - assert_eq!(false, descriptor.has_key_hash()); - assert_eq!(true, descriptor.has_taproot()); + assert!(!descriptor.has_multisig()); + assert!(!descriptor.has_script_hash()); + assert!(!descriptor.has_key_hash()); + assert!(descriptor.has_taproot()); assert_eq!(1, descriptor.get_script_list().len()); assert_eq!( "{tl(208c6f5956c3cc7251d483fc683fa06b22d4e2ddc7496a2590acee36c4a313f816ac),{tl(208c6f5956c3cc7251d483fc683fa06b22d4e2ddc7496a2590acee36c4a313f816ac),tl(205cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bcac7c82012088a820e38990d0c7fc009880a9c07c23842e886c6bbdc964ce6bdd5817ad357335ee6f87936b82012088a914dd69735817e0e3f6f826a9238dc2e291184f0131876c935287)}}", @@ -589,4 +589,41 @@ mod tests { key_data.to_str() ); } + + #[test] + fn descriptor_taproot_hashonly_test() { + let desc = "tr(ef514f1aeb14baa6cc57ab3268fb329ca540c48454f7f46771ed731e34ba521a,{1717a480c2e3a474eed8dba83f684731243cff8ef384521936cf3a730dd0a286,{1717a480c2e3a474eed8dba83f684731243cff8ef384521936cf3a730dd0a286,80039cda864c4f2f1c87f161b0038e57fb7a4a59ff37517048696b85cdaaf911}})"; + let desc_checksum = desc.to_string() + "#xffhk3u4"; + let derive_path = "1"; + let desc_obj = + Descriptor::with_derive_bip32path(desc, derive_path, &Network::Regtest).expect("Fail"); + assert_eq!(desc_checksum, desc_obj.to_str()); + assert_eq!(&HashType::Taproot, desc_obj.get_hash_type()); + assert_eq!( + "bcrt1pfuqf4j7ceyzmu3rsmude93ctu948r565hf2ucrn9z7zn7a7hjegskj3rsv", + desc_obj.get_address().to_str() + ); + assert_eq!( + "OP_1 4f009acbd8c905be4470df1b92c70be16a71d354ba55cc0e6517853f77d79651", + desc_obj.get_address().get_locking_script().to_asm() + ); + assert!(!desc_obj.has_script_hash()); + assert_eq!(1, desc_obj.get_script_list().len()); + assert!(desc_obj.has_tapscript()); + assert_eq!( + "{1717a480c2e3a474eed8dba83f684731243cff8ef384521936cf3a730dd0a286,{1717a480c2e3a474eed8dba83f684731243cff8ef384521936cf3a730dd0a286,80039cda864c4f2f1c87f161b0038e57fb7a4a59ff37517048696b85cdaaf911}}", + desc_obj.get_script_tree().to_str()); + assert_eq!( + &DescriptorKeyType::Schnorr, + desc_obj.get_key_data().expect("Fail").get_type() + ); + assert_eq!( + "ef514f1aeb14baa6cc57ab3268fb329ca540c48454f7f46771ed731e34ba521a", + desc_obj + .get_key_data() + .expect("Fail") + .get_schnorr_pubkey() + .to_hex() + ); + } } diff --git a/tests/hdwallet_test.rs b/tests/hdwallet_test.rs index 2eb2f03..da48649 100644 --- a/tests/hdwallet_test.rs +++ b/tests/hdwallet_test.rs @@ -9,7 +9,7 @@ mod tests { fn ext_pubkey_test() { // default let empty_key = ExtPubkey::default(); - assert_eq!(false, empty_key.valid()); + assert!(!empty_key.valid()); // fail let extkey_fail = ExtPubkey::new("xprv9zt1onyw8BdEf7SQ6wUVH3bQQdGD9iy9QzXveQQRhX7i5iUN7jZgLbqFEe491LfjozztYa6bJAGZ65GmDCNcbjMdjZcgmdisPJwVjcfcDhV"); assert!(extkey_fail.is_err(), "err: \"{}\"", extkey_fail.unwrap()); @@ -24,7 +24,7 @@ mod tests { "038746b92b722894e533dbbda3fb7fa673da00f4b309bf98a2cf586c27100004b0", extkey.get_pubkey().to_hex() ); - assert_eq!(true, extkey.valid()); + assert!(extkey.valid()); // create let extkey2 = ExtPubkey::from_parent_info( Network::Testnet, @@ -64,7 +64,7 @@ mod tests { fn ext_privkey_test() { // empty let empty_key = ExtPrivkey::default(); - assert_eq!(false, empty_key.valid()); + assert!(!empty_key.valid()); // fail let extkey_fail = ExtPrivkey::new("xpub6DsNDJWpxZBXsbWsCy1VeBY8xf6hZBgznDTXSnp3FregxWoWfGsvtQ9j5wBJNPebZXD5YmhpQBV7nVjhUsUgkG9R7yE31mh6sVh2w854a1o"); assert!(extkey_fail.is_err(), "err: \"{}\"", extkey_fail.unwrap()); @@ -83,7 +83,7 @@ mod tests { "73a2361673d25f998d1e9d94aabdeba8ac1ddd4628bc4f55341397d263bd560c", extkey.get_privkey().to_hex() ); - assert_eq!(true, extkey.valid()); + assert!(extkey.valid()); // derive let derive_key1 = extkey.derive_from_number(2, true).expect("Fail"); assert_eq!( diff --git a/tests/key_test.rs b/tests/key_test.rs index 2543907..808b57d 100644 --- a/tests/key_test.rs +++ b/tests/key_test.rs @@ -14,9 +14,9 @@ mod tests { assert!(pubkey_ret.is_ok(), "err: \"{}\"", pubkey_ret.unwrap_err()); let pubkey = pubkey_ret.unwrap(); assert_eq!(pubkey_str, pubkey.to_hex()); - assert_eq!(true, pubkey.valid()); + assert!(pubkey.valid()); let pubkey_empty = Pubkey::default(); - assert_eq!(false, pubkey_empty.valid()); + assert!(!pubkey_empty.valid()); // from_slice let pubkey1 = Pubkey::from_str("031d7463018f867de51a27db866f869ceaf52abab71827a6051bab8a0fd020f4c1") @@ -34,7 +34,7 @@ mod tests { Pubkey::from_str("0261e37f277f02a977b4f11eb5055abab4990bbf8dee701119d88df382fcc1fafe") .expect("Fail"); let combine_key = Pubkey::combine(&[comb_pubkey1, comb_pubkey2]).expect("Fail"); - assert_eq!(true, combine_key.valid()); + assert!(combine_key.valid()); assert_eq!( "022a66efd1ea9b1ad3acfcc62a5ce8c756fa6fc3917fce3d4952a8701244ed1049", combine_key.to_hex() @@ -87,25 +87,25 @@ mod tests { let verify1 = pubkey_ec .verify_ec_signature(sighash.to_slice(), signature.to_slice()) .expect("Fail"); - assert_eq!(true, verify1); + assert!(verify1); let verify2 = pubkey_ec .verify_ec_signature(sighash.to_slice(), bad_signature.to_slice()) .expect("Fail"); - assert_eq!(false, verify2); + assert!(!verify2); } #[test] fn privkey_test() { // default let empty_key = Privkey::default(); - assert_eq!(false, empty_key.valid()); + assert!(!empty_key.valid()); let key = Privkey::from_str("305e293b010d29bf3c888b617763a438fee9054c8cab66eb12ad078f819d9f27") .expect("fail"); assert_eq!( "305e293b010d29bf3c888b617763a438fee9054c8cab66eb12ad078f819d9f27", key.to_hex() ); - assert_eq!(true, key.valid()); + assert!(key.valid()); let wif = Privkey::from_wif("5JBb5A38fjjeBnngkvRmCsXN6EY4w8jWvckik3hDvYQMcddGY23").expect("fail"); assert_eq!( @@ -117,11 +117,11 @@ mod tests { wif.to_wif() ); assert_eq!(Network::Mainnet, *wif.to_network()); - assert_eq!(false, wif.is_compressed_pubkey()); - assert_eq!(true, wif.valid()); + assert!(!wif.is_compressed_pubkey()); + assert!(wif.valid()); // generate let gen_key = Privkey::generate(&Network::Testnet, true).expect("Fail"); - assert_eq!(true, gen_key.valid()); + assert!(gen_key.valid()); // get_wif let wif_base = Privkey::from_str("305e293b010d29bf3c888b617763a438fee9054c8cab66eb12ad078f819d9f27") diff --git a/tests/schnorr_test.rs b/tests/schnorr_test.rs index 2f743cd..a2ef484 100644 --- a/tests/schnorr_test.rs +++ b/tests/schnorr_test.rs @@ -44,7 +44,7 @@ mod tests { let is_verify = obj .verify(&pair.signature, &pair.proof, &adaptor, &msg, &pubkey) .expect("Fail"); - assert_eq!(true, is_verify); + assert!(is_verify); let signature = obj.adapt(&adaptor_sig2, &secret).expect("Fail"); assert_eq!(expect_sig.to_hex(), signature.to_hex()); @@ -96,7 +96,7 @@ mod tests { assert_eq!(expected_sig_point, sig_point.to_hex()); let is_verify = obj.verify(&sig1, &msg, &pubkey).expect("Fail"); - assert_eq!(true, is_verify); + assert!(is_verify); let expected_nonce = "6470fd1303dda4fda717b9837153c24a6eab377183fc438f939e0ed2b620e9ee"; let expected_privkey = "5077c4a8b8dca28963d772a94f5f0ddf598e1c47c137f91933274c7c3edadce8"; @@ -126,30 +126,30 @@ mod tests { let (schnorr_pubkey, parity) = SchnorrPubkey::from_privkey(&sk).expect("Fail"); assert_eq!(pubkey.to_hex(), schnorr_pubkey.to_hex()); - assert_eq!(true, parity); + assert!(parity); let (schnorr_pubkey, parity) = SchnorrPubkey::from_pubkey(&pk).expect("Fail"); assert_eq!(pubkey.to_hex(), schnorr_pubkey.to_hex()); - assert_eq!(true, parity); + assert!(parity); let (tweaked_pubkey, tweaked_parity) = pubkey.tweak_add(tweak.to_slice()).expect("Fail"); assert_eq!(exp_tweaked_pk.to_hex(), tweaked_pubkey.to_hex()); - assert_eq!(true, tweaked_parity); + assert!(tweaked_parity); let gen_key_ret = SchnorrPubkey::get_tweak_add_from_privkey(&sk, tweak.to_slice()).expect("Fail"); let (tweaked_pubkey, tweaked_parity, tweaked_privkey) = gen_key_ret; assert_eq!(exp_tweaked_pk.to_hex(), tweaked_pubkey.to_hex()); - assert_eq!(true, tweaked_parity); + assert!(tweaked_parity); assert_eq!(exp_tweaked_sk.to_hex(), tweaked_privkey.to_hex()); let is_valid = tweaked_pubkey .is_tweaked(true, &pubkey, tweak.to_slice()) .expect("Fail"); - assert_eq!(true, is_valid); + assert!(is_valid); let is_valid = tweaked_pubkey .is_tweaked(false, &pubkey, tweak.to_slice()) .expect("Fail"); - assert_eq!(false, is_valid); + assert!(!is_valid); } } diff --git a/tests/script_test.rs b/tests/script_test.rs index 9748347..ebc1fa7 100644 --- a/tests/script_test.rs +++ b/tests/script_test.rs @@ -3,7 +3,7 @@ extern crate sha2; #[cfg(test)] mod tests { - use cfd_rust::{ByteData, Privkey, Pubkey, SchnorrPubkey, Script, TapBranch}; + use cfd_rust::{ByteData, Network, Privkey, Pubkey, SchnorrPubkey, Script, TapBranch}; use std::str::FromStr; #[test] @@ -105,8 +105,8 @@ mod tests { .expect("Fail") .to_32byte_array(), ]; - let tree2 = TapBranch::from_string_by_tapscript(&tree_str, &script_op_true, &control_nodes) - .expect("Fail"); + let tree2 = + TapBranch::from_string_by_tapscript(tree_str, &script_op_true, &control_nodes).expect("Fail"); assert_eq!(5, tree2.get_branch_count().expect("Fail")); assert_eq!(tree_str, tree2.to_str()); let node_list = tree2.get_target_nodes(); @@ -124,11 +124,44 @@ mod tests { let empty_nodes: Vec<[u8; 32]> = vec![]; let mut tree3 = TapBranch::from_string_by_tapscript( "{{tl(20ac52f50b28cdd4d3bcb7f0d5cb533f232e4c4ef12fbf3e718420b84d4e3c3440ac),{tl(2057bf643684f6c5c75e1cdf45990036502a0d897394013210858cdabcbb95a05aac),tl(51)}},tl(2057bf643684f6c5c75e1cdf45990036502a0d897394013210858cdabcbb95a05aad205bec1a08fa3443176edd0a08e2a64642f45e57543b62bffe43ec350edc33dc22ac)}", - &&script_op_true, - &&empty_nodes, + &script_op_true, + &empty_nodes, ).expect("Fail"); tree3.add_by_tapbranch(&branch).expect("Fail"); tree3.add_by_tree_string("tl(2008f8280d68e02e807ccffee141c4a6b7ac31d3c283ae0921892d95f691742c44ad20b0f8ce3e1df406514a773414b5d9e5779d8e68ce816e9db39b8e53255ac3b406ac)").expect("Fail"); assert_eq!(tree2.to_str(), tree3.to_str()); } + + #[test] + fn empty_taproot_test() { + let tree = TapBranch::default(); + let internal_pubkey = + SchnorrPubkey::from_str("1777701648fa4dd93c74edd9d58cfcc7bdc2fa30a2f6fa908b6fd70c92833cfb") + .expect("Fail"); + let internal_privkey = + Privkey::from_str("305e293b010d29bf3c888b617763a438fee9054c8cab66eb12ad078f819d9f27") + .expect("Fail"); + + let (tweaked_pubkey, addr, control_block) = tree + .get_tweaked_pubkey(&internal_pubkey, &Network::Mainnet) + .expect("Fail"); + assert_eq!( + "cc3b1538e0c8144375f71e848b12d609d743992fddfc60dd6ca9b33b8392f27a", + tweaked_pubkey.to_hex() + ); + assert_eq!("", tree.get_tapscript().to_hex()); + assert_eq!( + "bc1pesa32w8qeq2yxa0hr6zgkykkp8t58xf0mh7xphtv4xenhquj7faqrux5cd", + addr.to_str(), + ); + assert_eq!( + "c11777701648fa4dd93c74edd9d58cfcc7bdc2fa30a2f6fa908b6fd70c92833cfb", + control_block.to_hex(), + ); + let key = tree.get_tweaked_privkey(&internal_privkey).expect("Fail"); + assert_eq!( + "3a56ec9129732312a78db4b845138a3180c102621d7381ae6e6a5d530f14856a", + key.to_hex() + ); + } } diff --git a/tests/transaction_test.rs b/tests/transaction_test.rs index c92e6aa..52c994d 100644 --- a/tests/transaction_test.rs +++ b/tests/transaction_test.rs @@ -181,14 +181,14 @@ mod tests { let verify_sig = tx .verify_signature_by_pubkey(&outpoint1, &HashType::P2wpkh, &pubkey1, &signature, &amount) .expect("Fail"); - assert_eq!(true, verify_sig); + assert!(verify_sig); } #[test] fn get_tx_info_test() { let privkey = ExtPrivkey::new("xprv9zt1onyw8BdEf7SQ6wUVH3bQQdGD9iy9QzXveQQRhX7i5iUN7jZgLbqFEe491LfjozztYa6bJAGZ65GmDCNcbjMdjZcgmdisPJwVjcfcDhV").expect("Fail"); let addr1 = Address::p2wpkh( - &privkey + privkey .derive_pubkey_from_number(1, false) .expect("Fail") .get_pubkey(), @@ -196,7 +196,7 @@ mod tests { ) .expect("Fail"); let addr2 = Address::p2wpkh( - &privkey + privkey .derive_pubkey_from_number(2, false) .expect("Fail") .get_pubkey(), @@ -204,7 +204,7 @@ mod tests { ) .expect("Fail"); let addr3 = Address::p2wpkh( - &privkey + privkey .derive_pubkey_from_number(3, false) .expect("Fail") .get_pubkey(), @@ -275,17 +275,14 @@ mod tests { assert_eq!(2, tx.get_txout_index_by_address(&addr3).expect("Fail")); assert_eq!( 1, - tx.get_txout_index_by_script(&addr2.get_locking_script()) + tx.get_txout_index_by_script(addr2.get_locking_script()) .expect("Fail") ); - assert_eq!(true, outpoint2.eq(&tx.get_txin_list()[1].outpoint)); - assert_eq!( - true, - addr2 - .get_locking_script() - .eq(&tx.get_txout_list()[1].locking_script) - ); + assert!(outpoint2.eq(&tx.get_txin_list()[1].outpoint)); + assert!(addr2 + .get_locking_script() + .eq(&tx.get_txout_list()[1].locking_script)); } #[test] @@ -403,7 +400,7 @@ mod tests { let tx_ret3 = tx.sign_with_privkey( &outpoint1, &HashType::P2wpkh, - &privkey1, + privkey1, &sighash_type, &amount, ); @@ -477,7 +474,7 @@ mod tests { &amount, ) .expect("Fail"); - assert_eq!(true, is_verify); + assert!(is_verify); } #[test] @@ -560,7 +557,7 @@ mod tests { &Amount::default(), ) .expect("Fail"); - assert_eq!(true, verify); + assert!(verify); } #[test] @@ -570,12 +567,12 @@ mod tests { let utxos = get_bitcoin_bnb_utxo_list(&Network::Mainnet); let key = ExtPubkey::new("xpub661MyMwAqRbcGB88KaFbLGiYAat55APKhtWg4uYMkXAmfuSTbq2QYsn9sKJCj1YqZPafsboef4h4YbXXhNhPwMbkHTpkf3zLhx7HvFw1NDy").expect("Fail"); let set_addr1 = Address::p2wpkh( - &key.derive_from_number(11).expect("Fail").get_pubkey(), + key.derive_from_number(11).expect("Fail").get_pubkey(), &network, ) .expect("Fail"); let set_addr2 = Address::p2wpkh( - &key.derive_from_number(12).expect("Fail").get_pubkey(), + key.derive_from_number(12).expect("Fail").get_pubkey(), &network, ) .expect("Fail"); @@ -612,12 +609,12 @@ mod tests { let utxos = get_bitcoin_bnb_utxo_list(&Network::Mainnet); let key = ExtPubkey::new("xpub661MyMwAqRbcGB88KaFbLGiYAat55APKhtWg4uYMkXAmfuSTbq2QYsn9sKJCj1YqZPafsboef4h4YbXXhNhPwMbkHTpkf3zLhx7HvFw1NDy").expect("Fail"); let set_addr1 = Address::p2wpkh( - &key.derive_from_number(11).expect("Fail").get_pubkey(), + key.derive_from_number(11).expect("Fail").get_pubkey(), &network, ) .expect("Fail"); let set_addr2 = Address::p2wpkh( - &key.derive_from_number(12).expect("Fail").get_pubkey(), + key.derive_from_number(12).expect("Fail").get_pubkey(), &network, ) .expect("Fail"); @@ -634,7 +631,7 @@ mod tests { .expect("Fail"); let addr1 = Address::p2wpkh( - &key.derive_from_number(1).expect("Fail").get_pubkey(), + key.derive_from_number(1).expect("Fail").get_pubkey(), &network, ) .expect("Fail"); @@ -658,12 +655,12 @@ mod tests { let utxos = get_bitcoin_bnb_utxo_list(&Network::Mainnet); let key = ExtPubkey::new("xpub661MyMwAqRbcGB88KaFbLGiYAat55APKhtWg4uYMkXAmfuSTbq2QYsn9sKJCj1YqZPafsboef4h4YbXXhNhPwMbkHTpkf3zLhx7HvFw1NDy").expect("Fail"); let set_addr1 = Address::p2wpkh( - &key.derive_from_number(11).expect("Fail").get_pubkey(), + key.derive_from_number(11).expect("Fail").get_pubkey(), &network, ) .expect("Fail"); let set_addr2 = Address::p2wpkh( - &key.derive_from_number(12).expect("Fail").get_pubkey(), + key.derive_from_number(12).expect("Fail").get_pubkey(), &network, ) .expect("Fail"); @@ -687,7 +684,7 @@ mod tests { let input_utxos = [utxos[1].clone(), utxos[2].clone()]; let addr1 = Address::p2wpkh( - &key.derive_from_number(1).expect("Fail").get_pubkey(), + key.derive_from_number(1).expect("Fail").get_pubkey(), &network, ) .expect("Fail"); @@ -728,12 +725,12 @@ mod tests { let utxos = get_bitcoin_bnb_utxo_list(&network); let key = ExtPubkey::new("xpub661MyMwAqRbcGB88KaFbLGiYAat55APKhtWg4uYMkXAmfuSTbq2QYsn9sKJCj1YqZPafsboef4h4YbXXhNhPwMbkHTpkf3zLhx7HvFw1NDy").expect("Fail"); let set_addr1 = Address::p2wpkh( - &key.derive_from_number(11).expect("Fail").get_pubkey(), + key.derive_from_number(11).expect("Fail").get_pubkey(), &network, ) .expect("Fail"); let set_addr2 = Address::p2wpkh( - &key.derive_from_number(12).expect("Fail").get_pubkey(), + key.derive_from_number(12).expect("Fail").get_pubkey(), &network, ) .expect("Fail"); @@ -750,7 +747,7 @@ mod tests { .expect("Fail"); let addr1 = Address::p2wpkh( - &key.derive_from_number(1).expect("Fail").get_pubkey(), + key.derive_from_number(1).expect("Fail").get_pubkey(), &network, ) .expect("Fail"); @@ -770,7 +767,7 @@ mod tests { fn get_bitcoin_bnb_utxo_list(network: &Network) -> Vec { let desc = "sh(wpkh([ef735203/0'/0'/7']022c2409fbf657ba25d97bb3dab5426d20677b774d4fc7bd3bfac27ff96ada3dd1))#4z2vy08x"; - let descriptor = Descriptor::new(desc, &network).expect("Fail"); + let descriptor = Descriptor::new(desc, network).expect("Fail"); vec![ UtxoData::from_descriptor( &OutPoint::from_str( @@ -833,7 +830,7 @@ mod tests { let network = &Network::Mainnet; let desc = "wpkh([ef735203/0'/0'/7']022c2409fbf657ba25d97bb3dab5426d20677b774d4fc7bd3bfac27ff96ada3dd1)"; - let descriptor = Descriptor::new(desc, &network).expect("Fail"); + let descriptor = Descriptor::new(desc, network).expect("Fail"); vec![ UtxoData::from_descriptor( &OutPoint::from_str( @@ -908,7 +905,7 @@ mod tests { let mut fee_param = FeeOption::new(&network); fee_param.fee_rate = 20.0; let selected_list = Transaction::select_coins(&utxos, 0, 0, &fee_param).expect("Fail"); - assert_eq!(true, selected_list.select_utxo_list.is_empty()); + assert!(selected_list.select_utxo_list.is_empty()); assert_eq!(0, selected_list.utxo_fee_amount); } @@ -1160,7 +1157,7 @@ mod tests { let is_verify = util .verify(&signature, &sighash_bytes, &pubkey) .expect("Fail"); - assert_eq!(true, is_verify); + assert!(is_verify); } #[test] @@ -1309,7 +1306,7 @@ mod tests { assert_eq!("f5aa6b260f9df687786cd3813ba83b476e195041bccea800f2571212f4aae9848a538b6175a4f8ea291d38e351ea7f612a3d700dca63cd3aff05d315c5698ee9", sig.to_hex()); tx = tx - .add_tapscript_sign(&outpoint, &[sig], &&script_checksig, &control_block, &annex) + .add_tapscript_sign(&outpoint, &[sig], &script_checksig, &control_block, &annex) .expect("Fail"); assert_eq!("020000000001015b80a1af0e00c700bee9c8e4442bec933fcdc0c686dac2dc336caaaf186c5d190000000000ffffffff0130f1029500000000160014164e985d0fc92c927a66c0cbaf78e6ea389629d50341f5aa6b260f9df687786cd3813ba83b476e195041bccea800f2571212f4aae9848a538b6175a4f8ea291d38e351ea7f612a3d700dca63cd3aff05d315c5698ee90122201777701648fa4dd93c74edd9d58cfcc7bdc2fa30a2f6fa908b6fd70c92833cfbac61c01777701648fa4dd93c74edd9d58cfcc7bdc2fa30a2f6fa908b6fd70c92833cfb4d18084bb47027f47d428b2ed67e1ccace5520fdc36f308e272394e288d53b6ddc82121e4ff8d23745f3859e8939ecb0a38af63e6ddea2fff97a7fd61a1d2d5400000000", tx.to_str()); @@ -1324,7 +1321,7 @@ mod tests { let is_verify = util .verify(&signature, &sighash_bytes, &pubkey) .expect("Fail"); - assert_eq!(true, is_verify); + assert!(is_verify); } #[test] @@ -1362,6 +1359,24 @@ mod tests { tx.to_str()); } + #[test] + fn update_txin_sequence_test() { + let mut tx = Transaction::from_str("02000000000101ffa8db90b81db256874ff7a98fb7202cdc0b91b5b02d7c3427c4190adc66981f0000000000ffffffff0118f50295000000002251201777701648fa4dd93c74edd9d58cfcc7bdc2fa30a2f6fa908b6fd70c92833cfb02473044022018b10265080f8c491c43595000461a19212239fea9ee4c6fd26498f358b1760d0220223c1389ac26a2ed5f77ad73240af2fa6eb30ef5d19520026c2f7b7e817592530121023179b32721d07deb06cade59f56dedefdc932e89fde56e998f7a0e93a3e30c4400000000").expect("Fail"); + tx = tx + .update_txin_sequence( + &OutPoint::from_str( + "1f9866dc0a19c427347c2db0b5910bdc2c20b78fa9f74f8756b21db890dba8ff", + 0, + ) + .expect("Fail"), + 4294967294, + ) + .expect("Fail"); + assert_eq!( + "02000000000101ffa8db90b81db256874ff7a98fb7202cdc0b91b5b02d7c3427c4190adc66981f0000000000feffffff0118f50295000000002251201777701648fa4dd93c74edd9d58cfcc7bdc2fa30a2f6fa908b6fd70c92833cfb02473044022018b10265080f8c491c43595000461a19212239fea9ee4c6fd26498f358b1760d0220223c1389ac26a2ed5f77ad73240af2fa6eb30ef5d19520026c2f7b7e817592530121023179b32721d07deb06cade59f56dedefdc932e89fde56e998f7a0e93a3e30c4400000000", + tx.to_str()); + } + #[test] fn update_witness_stack_test() { let mut tx = Transaction::from_str("020000000001014cdeada737db97af334f0fa4e87432d6068759eea65a3067d1f14a979e5a9dea0000000000ffffffff010cdff5050000000017a91426b9ba9cf5d822b70cf490ad0394566f9db20c63870247304402200b3ca71e82551a333fe5c8ce9a8f8454eb8f08aa194180e5a87c79ccf2e46212022065c1f2a363ebcb155a80e234258394140d08f6ab807581953bb21a58f2d229a6012102fd54c734e48c544c3c3ad1aab0607f896eb95e23e7058b174a580826a7940ad800000000").expect("Fail");