From 6154848c7884ff1d830852ccf9df8d8a10980041 Mon Sep 17 00:00:00 2001 From: coolu <13291859621@163.com> Date: Fri, 16 Nov 2018 21:15:38 +0800 Subject: [PATCH] Feature/btc interface (#107) * Fix receive_address bug * Add register channels * Change channel type from String to Vec * Add blockhash in TxSet --- Cargo.lock | 35 +++++++++++---- cxrml/bridge/btc/src/blockchain.rs | 10 ++++- cxrml/bridge/btc/src/lib.rs | 24 +++++++--- cxrml/bridge/btc/src/tests.rs | 11 ++--- cxrml/bridge/btc/src/tx/mod.rs | 72 +++++++++++++++++++++++------- src/genesis_config.rs | 2 + 6 files changed, 115 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 25e3757541e7a..7fe1e35a8c386 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -161,7 +161,7 @@ source = "git+https://github.com/chainx-org/bit-vec.git#ced2a13de722307d5c966aa8 [[package]] name = "bitcrypto" version = "0.1.0" -source = "git+https://github.com/chainx-org/bitcoin-rust#59a74b6ffde7a0f1b9891c81fd467231b6bcc35e" +source = "git+https://github.com/chainx-org/bitcoin-rust#221a76ec2a7995d497965c4ee2bf6b76a1372870" dependencies = [ "primitives 0.1.0 (git+https://github.com/chainx-org/bitcoin-rust)", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", @@ -248,7 +248,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "chain" version = "0.1.0" -source = "git+https://github.com/chainx-org/bitcoin-rust#59a74b6ffde7a0f1b9891c81fd467231b6bcc35e" +source = "git+https://github.com/chainx-org/bitcoin-rust#221a76ec2a7995d497965c4ee2bf6b76a1372870" dependencies = [ "bitcrypto 0.1.0 (git+https://github.com/chainx-org/bitcoin-rust)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -637,6 +637,11 @@ name = "crunchy" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "crunchy" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ctr" version = "0.1.0" @@ -993,7 +998,7 @@ dependencies = [ [[package]] name = "eth-secp256k1" version = "0.5.7" -source = "git+https://github.com/koushiro/rust-secp256k1?branch=add_no_std_support#fcb8d60a7a9043b23d99a07a45caf8fdfc5c4445" +source = "git+https://github.com/koushiro/rust-secp256k1?branch=add_no_std_support#4be05902db0d46a0c1c28b8eaecd83b124cf8b18" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1386,7 +1391,7 @@ dependencies = [ [[package]] name = "keys" version = "0.1.0" -source = "git+https://github.com/chainx-org/bitcoin-rust#59a74b6ffde7a0f1b9891c81fd467231b6bcc35e" +source = "git+https://github.com/chainx-org/bitcoin-rust#221a76ec2a7995d497965c4ee2bf6b76a1372870" dependencies = [ "base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitcrypto 0.1.0 (git+https://github.com/chainx-org/bitcoin-rust)", @@ -2217,15 +2222,15 @@ dependencies = [ [[package]] name = "primitives" version = "0.1.0" -source = "git+https://github.com/chainx-org/bitcoin-rust#59a74b6ffde7a0f1b9891c81fd467231b6bcc35e" +source = "git+https://github.com/chainx-org/bitcoin-rust#221a76ec2a7995d497965c4ee2bf6b76a1372870" dependencies = [ "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crunchy 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 0.1.0 (git+https://github.com/chainx-org/sr-std)", - "uint 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "uint 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2536,7 +2541,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "script" version = "0.1.0" -source = "git+https://github.com/chainx-org/bitcoin-rust#59a74b6ffde7a0f1b9891c81fd467231b6bcc35e" +source = "git+https://github.com/chainx-org/bitcoin-rust#221a76ec2a7995d497965c4ee2bf6b76a1372870" dependencies = [ "bitcrypto 0.1.0 (git+https://github.com/chainx-org/bitcoin-rust)", "chain 0.1.0 (git+https://github.com/chainx-org/bitcoin-rust)", @@ -2615,7 +2620,7 @@ dependencies = [ [[package]] name = "serialization" version = "0.1.0" -source = "git+https://github.com/chainx-org/bitcoin-rust#59a74b6ffde7a0f1b9891c81fd467231b6bcc35e" +source = "git+https://github.com/chainx-org/bitcoin-rust#221a76ec2a7995d497965c4ee2bf6b76a1372870" dependencies = [ "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "primitives 0.1.0 (git+https://github.com/chainx-org/bitcoin-rust)", @@ -3773,6 +3778,16 @@ dependencies = [ "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "uint" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crunchy 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicase" version = "1.4.2" @@ -4086,6 +4101,7 @@ dependencies = [ "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" "checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015" "checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" +"checksum crunchy 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c240f247c278fa08a6d4820a6a222bfc6e0d999e51ba67be94f44c905b2161f2" "checksum ctr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50ac3add446ec1f8fe3dc007cd838f5b22bbf33186394feac505451ecc43c018" "checksum ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "630391922b1b893692c6334369ff528dcc3a9d8061ccf4c803aa8f83cb13db5e" "checksum datastore 0.1.0 (git+https://github.com/tomaka/libp2p-rs?rev=8111062f0177fd7423626f2db9560273644a4c4d)" = "" @@ -4362,6 +4378,7 @@ dependencies = [ "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" "checksum uint 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "754ba11732b9161b94c41798e5197e5e75388d012f760c42adb5000353e98646" +"checksum uint 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "082df6964410f6aa929a61ddfafc997e4f32c62c22490e439ac351cec827f436" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d3218ea14b4edcaccfa0df0a64a3792a2c32cc706f1b336e48867f9d3147f90" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" diff --git a/cxrml/bridge/btc/src/blockchain.rs b/cxrml/bridge/btc/src/blockchain.rs index 42e57c610dbb3..de993752b3042 100644 --- a/cxrml/bridge/btc/src/blockchain.rs +++ b/cxrml/bridge/btc/src/blockchain.rs @@ -13,8 +13,8 @@ use primitives::hash::H256; use script::Script; use { - AccountMap, BestIndex, BlockHeaderFor, DepositCache, HashsForNumber, NumberForHash, Params, - ParamsInfo, Trait, TxProposal, + AccountMap, BestIndex, BlockHeaderFor, CertCache, DepositCache, HashsForNumber, NumberForHash, + Params, ParamsInfo, Trait, TxProposal, }; use tx::{Proposal, RollBack, TxStorage}; @@ -242,6 +242,12 @@ impl Chain { } } + // SendCert + if let Some(certInfo) = >::take() { + runtime_io::print("------CertCache take"); + //TO DO + } + >::insert(new_best_header.hash.clone(), new_best_header.number); runtime_io::print("------------"); runtime_io::print(new_best_header.hash.to_vec().as_slice()); diff --git a/cxrml/bridge/btc/src/lib.rs b/cxrml/bridge/btc/src/lib.rs index a1cd39651eed7..e9c7ba00d48c5 100644 --- a/cxrml/bridge/btc/src/lib.rs +++ b/cxrml/bridge/btc/src/lib.rs @@ -80,7 +80,7 @@ use blockchain::Chain; use keys::DisplayLayout; pub use keys::{Address, Error as AddressError}; pub use tx::RelayTx; -use tx::{handle_input, handle_output, handle_proposal, validate_transaction, UTXO}; +use tx::{handle_input, handle_output, handle_proposal, handle_cert, validate_transaction, UTXO}; pub trait Trait: system::Trait + balances::Trait + timestamp::Trait + financial_records::Trait @@ -175,6 +175,7 @@ pub enum TxType { Deposit, Register, RegisterDeposit, + SendCert, } #[derive(PartialEq, Clone, Encode, Decode)] @@ -213,20 +214,23 @@ decl_storage! { // tx pub ReceiveAddress get(receive_address) config(): Option
; pub RedeemScript get(redeem_script) config(): Option>; + pub CertAddress get(cert_address) config(): Option; + pub CertRedeemScript get(cert_redeem_script) config(): Option>; pub UTXOSet get(utxo_set): map u64 => UTXO; pub UTXOMaxIndex get(utxo_max_index) config(): u64; pub IrrBlock get(irr_block) config(): u32; pub BtcFee get(btc_fee) config(): u64; - pub TxSet get(tx_set): map H256 => Option<(T::AccountId, Address, TxType, u64, BTCTransaction)>; // Address, type, balance + pub TxSet get(tx_set): map H256 => Option<(T::AccountId, keys::Address, TxType, u64, BTCTransaction, H256)>; // Address, type, balance pub BlockTxids get(block_txids): map H256 => Vec; pub AddressMap get(address_map): map Address => Option; pub AccountMap get(account_map): map T::AccountId => Option
; pub TxProposal get(tx_proposal): Option>; pub DepositCache get(deposit_cache): Option>; // account_id, amount, H256 - pub AccountsMaxIndex get(accounts_max_index) config(): u64; - pub AccountsSet get(accounts_set): map u64 => Option<(H256, Address, T::AccountId, T::BlockNumber, TxType)>; + pub RegInfoMaxIndex get(accounts_max_index) config(): u64; + pub RegInfoSet get(accounts_set): map u64 => Option<(H256, keys::Address, T::AccountId, T::BlockNumber, Vec, TxType)>; + pub CertCache get(cert_cache): Option<(Vec, T::AccountId)>; // ===== // others @@ -339,12 +343,20 @@ impl Module { } else { return Err("should set RECEIVE_address first"); }; - - let tx_type = validate_transaction::(&tx, &receive_address).unwrap(); + let cert_address: keys::Address = if let Some(h) = >::get() { + h + } else { + return Err("should set CERT_address first"); + }; + let tx_type = validate_transaction::(&tx, (&receive_address, &cert_address)).unwrap(); match tx_type { TxType::Withdraw => { handle_input::(&tx.raw, &tx.block_hash, &who, &receive_address); } + TxType::SendCert => { + handle_cert::(&tx.raw, &tx.block_hash, &who, &cert_address); + + } _ => { let _utxos = handle_output::( &tx.raw, diff --git a/cxrml/bridge/btc/src/tests.rs b/cxrml/bridge/btc/src/tests.rs index 3f3248ba3c473..1f3688ded93d9 100644 --- a/cxrml/bridge/btc/src/tests.rs +++ b/cxrml/bridge/btc/src/tests.rs @@ -6,6 +6,7 @@ use self::base58::FromBase58; use super::*; use runtime_io; use runtime_io::with_externalities; +use self::keys::DisplayLayout; use runtime_primitives::testing::{Digest, DigestItem, Header}; use runtime_primitives::traits::BlakeTwo256; use runtime_primitives::BuildStorage; @@ -112,7 +113,7 @@ pub fn new_test_ext() -> runtime_io::TestExternalities { irr_block: 6, btc_fee: 10, accounts_max_index: 0, - receive_address: keys::Address::from_layout(&"mjKE11gjVN4JaC9U8qL6ZB5vuEBgmwik7b".from_base58().unwrap()).unwrap(), + receive_address: keys::Address::from_layout(&"2N4C127fBSmqBsNuHeLmAbZEVSPfV6GB2j2".from_base58().unwrap()).unwrap(), redeem_script: b"52210257aff1270e3163aaae9d972b3d09a2385e0d4877501dbeca3ee045f8de00d21c2103fd58c689594b87bbe20a9a00091d074dc0d9f49a988a7ad4c2575adeda1b507c2102bb2a5aa53ba7c0d77bdd86bb9553f77dd0971d3a6bb6ad609787aa76eb17b6b653ae".to_vec(), fee: 0, }.build_storage() @@ -156,7 +157,7 @@ pub fn new_test_ext_err_genesisblock() -> runtime_io::TestExternalities runtime_io::TestExternalities { irr_block: 6, btc_fee: 10, accounts_max_index: 0, - receive_address: keys::Address::from_layout(&"mjKE11gjVN4JaC9U8qL6ZB5vuEBgmwik7b".from_base58().unwrap()).unwrap(), + receive_address: keys::Address::from_layout(&"2N4C127fBSmqBsNuHeLmAbZEVSPfV6GB2j2".from_base58().unwrap()).unwrap(), redeem_script: b"52210257aff1270e3163aaae9d972b3d09a2385e0d4877501dbeca3ee045f8de00d21c2103fd58c689594b87bbe20a9a00091d074dc0d9f49a988a7ad4c2575adeda1b507c2102bb2a5aa53ba7c0d77bdd86bb9553f77dd0971d3a6bb6ad609787aa76eb17b6b653ae".to_vec(), fee: 0, }.build_storage() @@ -650,7 +651,7 @@ pub fn new_test_ext2() -> runtime_io::TestExternalities { irr_block: 6, btc_fee: 10, accounts_max_index: 0, - receive_address: keys::Address::from_layout(&"mjKE11gjVN4JaC9U8qL6ZB5vuEBgmwik7b".from_base58().unwrap()).unwrap(), + receive_address: keys::Address::from_layout(&"2N4C127fBSmqBsNuHeLmAbZEVSPfV6GB2j2".from_base58().unwrap()).unwrap(), redeem_script: b"52210257aff1270e3163aaae9d972b3d09a2385e0d4877501dbeca3ee045f8de00d21c2103fd58c689594b87bbe20a9a00091d074dc0d9f49a988a7ad4c2575adeda1b507c2102bb2a5aa53ba7c0d77bdd86bb9553f77dd0971d3a6bb6ad609787aa76eb17b6b653ae".to_vec(), fee: 0, }.build_storage() @@ -723,7 +724,7 @@ pub fn new_test_ext3() -> runtime_io::TestExternalities { irr_block: 6, btc_fee: 10, accounts_max_index: 0, - receive_address: keys::Address::from_layout(&"mjKE11gjVN4JaC9U8qL6ZB5vuEBgmwik7b".from_base58().unwrap()).unwrap(), + receive_address: keys::Address::from_layout(&"2N4C127fBSmqBsNuHeLmAbZEVSPfV6GB2j2".from_base58().unwrap()).unwrap(), redeem_script: b"52210257aff1270e3163aaae9d972b3d09a2385e0d4877501dbeca3ee045f8de00d21c2103fd58c689594b87bbe20a9a00091d074dc0d9f49a988a7ad4c2575adeda1b507c2102bb2a5aa53ba7c0d77bdd86bb9553f77dd0971d3a6bb6ad609787aa76eb17b6b653ae".to_vec(), fee: 0, }.build_storage() diff --git a/cxrml/bridge/btc/src/tx/mod.rs b/cxrml/bridge/btc/src/tx/mod.rs index 38087afbde445..e756d881bb38e 100644 --- a/cxrml/bridge/btc/src/tx/mod.rs +++ b/cxrml/bridge/btc/src/tx/mod.rs @@ -10,9 +10,9 @@ use runtime_support::{StorageMap, StorageValue}; pub use self::proposal::{handle_proposal, Proposal}; use super::{ - AccountMap, AccountsMaxIndex, AccountsSet, AddressMap, BlockHeaderFor, BlockTxids, CandidateTx, - DepositCache, NetworkId, NumberForHash, ReceiveAddress, RedeemScript, Trait, TxProposal, TxSet, - TxType, UTXOMaxIndex, UTXOSet, + AccountMap, AddressMap, BlockHeaderFor, BlockTxids, CertCache, CandidateTx, DepositCache, + NetworkId, NumberForHash, RegInfoMaxIndex, RegInfoSet, ReceiveAddress, RedeemScript, Trait, + TxProposal, TxSet, TxType, UTXOMaxIndex, UTXOSet, }; use b58::from; use chain::{OutPoint, Transaction, TransactionInput, TransactionOutput}; @@ -147,9 +147,9 @@ impl TxStorage { let tx = tx.clone(); // todo 检查block是否存在 - >::mutate(block_hash, |v| v.push(hash.clone())); + >::mutate(block_hash.clone(), |v| v.push(hash.clone())); - >::insert(hash, (who.clone(), address, tx_type, balance, tx)); + >::insert(hash, (who.clone(), address, tx_type, balance, tx, block_hash)); } fn find_tx(txid: &H256) -> Option { @@ -171,7 +171,7 @@ impl RollBack for TxStorage { let txids = >::get(header); for txid in txids.iter() { - let (_, _, tx_type, _, tx) = >::get(txid).unwrap(); + let (_, _, tx_type, _, tx, _,) = >::get(txid).unwrap(); match tx_type { TxType::Withdraw => { let out_point_set = tx @@ -217,20 +217,20 @@ impl RollBack for TxStorage { } } -struct AccountsStorage(PhantomData); +struct RegInfoStorage(PhantomData); -impl AccountsStorage { - fn add(accounts: (H256, keys::Address, T::AccountId, T::BlockNumber, TxType)) { - let mut index = >::get(); - >::insert(index, accounts.clone()); +impl RegInfoStorage { + fn add(accounts: (H256, keys::Address, T::AccountId, T::BlockNumber, Vec, TxType)) { + let mut index = >::get(); + >::insert(index, accounts.clone()); index += 1; - >::mutate(|inc| *inc = index); + >::mutate(|inc| *inc = index); } } pub fn validate_transaction( tx: &RelayTx, - receive_address: &keys::Address, + address: (&keys::Address, &keys::Address), ) -> StdResult { if >::exists(&tx.block_hash) == false { return Err("this tx's block not in the main chain"); @@ -260,17 +260,26 @@ pub fn validate_transaction( if previous_txid != tx.raw.inputs[0].previous_output.hash { return Err("previous tx id not right"); } + // detect cert + for input in tx.raw.inputs.iter() { + let outpoint = input.previous_output.clone(); + let send_address = inspect_address::(&tx.previous_raw, outpoint).unwrap(); + if send_address.hash == address.1.hash { + return Ok(TxType::SendCert); + } + } + // detect withdraw for input in tx.raw.inputs.iter() { let outpoint = input.previous_output.clone(); let send_address = inspect_address::(&tx.previous_raw, outpoint).unwrap(); - if send_address.hash == receive_address.hash { + if send_address.hash == address.0.hash { return Ok(TxType::Withdraw); } } // detect deposit for output in tx.raw.outputs.iter() { - if is_key(&output.script_pubkey, &receive_address) { + if is_key(&output.script_pubkey, &address.0) { return Ok(TxType::RegisterDeposit); } } @@ -406,6 +415,7 @@ pub fn handle_output( let mut register = false; let mut new_account = false; let tx_type; + let mut channel = Vec::::new(); // Add utxo let outpoint = tx.inputs[0].previous_output.clone(); let send_address = inspect_address::(previous_tx, outpoint).unwrap(); @@ -426,6 +436,7 @@ pub fn handle_output( Some(_a) => new_account = false, None => { runtime_io::print("------new account-----"); + channel = script.extract_pre(':'); new_account = true } }; @@ -488,14 +499,41 @@ pub fn handle_output( runtime_io::print("----new account-------"); let time = >::block_number(); let chainxaddr = >::get(send_address.clone()).unwrap(); - let account = (tx.hash(), send_address.clone(), chainxaddr, time, tx_type); - >::add(account); + let account = (tx.hash(), send_address.clone(), chainxaddr, time, + channel[2..].to_vec(),tx_type); + >::add(account); runtime_io::print("------insert new account in AccountsMap-----"); } runtime_io::print("------store tx success-----"); new_utxos } +pub fn handle_cert( + tx: &Transaction, + block_hash: &H256, + who: &T::AccountId, + cert_address: &keys::Address, +) { + for (index, output) in tx.outputs.iter().enumerate() { + let script = &output.script_pubkey; + let script: Script = script.clone().into(); + if script.is_null_data_script() { + runtime_io::print("------opreturn cert data-----"); + let owner = script.extract_rear(':'); + let name = script.extract_pre(':'); + + let slice = from(owner).unwrap(); + let slice = slice.as_slice(); + let mut account: Vec = Vec::new(); + account.extend_from_slice(&slice[1..33]); + runtime_io::print(&account[..]); + let id: T::AccountId = Decode::decode(&mut account.as_slice()).unwrap(); + + >::put((name[2..].to_vec(),id)); + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/genesis_config.rs b/src/genesis_config.rs index 7d073121b1fd4..76e8cab64cdf5 100644 --- a/src/genesis_config.rs +++ b/src/genesis_config.rs @@ -174,6 +174,8 @@ pub fn testnet_genesis(chainspec: ChainSpec) -> GenesisConfig { irr_block: 0, btc_fee: 10, accounts_max_index: 0, + cert_address: keys::Address::from_layout(&"2N4C127fBSmqBsNuHeLmAbZEVSPfV6GB2j2".from_base58().unwrap()).unwrap(), + cert_redeem_script: b"52210257aff1270e3163aaae9d972b3d09a2385e0d4877501dbeca3ee045f8de00d21c2103fd58c689594b87bbe20a9a00091d074dc0d9f49a988a7ad4c2575adeda1b507c2102bb2a5aa53ba7c0d77bdd86bb9553f77dd0971d3a6bb6ad609787aa76eb17b6b653ae".to_vec(), receive_address: keys::Address::from_layout(&"2N4C127fBSmqBsNuHeLmAbZEVSPfV6GB2j2".from_base58().unwrap()).unwrap(), redeem_script: b"52210257aff1270e3163aaae9d972b3d09a2385e0d4877501dbeca3ee045f8de00d21c2103fd58c689594b87bbe20a9a00091d074dc0d9f49a988a7ad4c2575adeda1b507c2102bb2a5aa53ba7c0d77bdd86bb9553f77dd0971d3a6bb6ad609787aa76eb17b6b653ae".to_vec(), fee: 0,