From 68673016dc31d8f8c017b1817176ba405af2dbad Mon Sep 17 00:00:00 2001 From: xsb <389483673@qq.com> Date: Thu, 9 Jan 2025 20:44:39 +0800 Subject: [PATCH] chore[doge_customs]: remove useless codes --- Cargo.lock | 1 + assets/doge_customs/service.did.d.ts | 5 +- assets/doge_customs/service.did.js | 18 +- customs/doge/Cargo.toml | 3 +- customs/doge/doge_customs.did | 5 +- customs/doge/src/custom_to_dogecoin.rs | 142 +---------- customs/doge/src/doge/ecdsa.rs | 22 +- customs/doge/src/doge/rpc.rs | 17 +- customs/doge/src/doge/sighash.rs | 70 +----- customs/doge/src/doge/tatum_rpc.rs | 8 - customs/doge/src/doge/transaction.rs | 334 +------------------------ customs/doge/src/dogeoin_to_custom.rs | 162 ++++++------ customs/doge/src/errors.rs | 4 +- customs/doge/src/generate_ticket.rs | 1 - customs/doge/src/hub.rs | 5 - customs/doge/src/lib.rs | 21 +- customs/doge/src/management.rs | 23 +- customs/doge/src/service.rs | 168 ++----------- customs/doge/src/state.rs | 28 +-- customs/doge/src/types.rs | 185 +++++++------- 20 files changed, 248 insertions(+), 974 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5f5984f0..351d5df9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1483,6 +1483,7 @@ dependencies = [ "bs58", "candid", "ciborium", + "futures", "getrandom 0.2.15", "hex-conservative 0.2.1", "ic-base-types 0.9.0 (git+https://github.com/dfinity/ic?tag=release-2024-01-18_23-01)", diff --git a/assets/doge_customs/service.did.d.ts b/assets/doge_customs/service.did.d.ts index e6cce4ec..cafff3bb 100644 --- a/assets/doge_customs/service.did.d.ts +++ b/assets/doge_customs/service.did.d.ts @@ -17,7 +17,6 @@ export type ChainType = { 'SettlementChain' : null } | { 'ExecutionChain' : null }; export type CustomsError = { 'SendTicketErr' : string } | { 'RpcError' : string } | - { 'HttpOutExceedLimit' : null } | { 'TemporarilyUnavailable' : string } | { 'HttpOutCallError' : [string, string, string] } | { 'AlreadyProcessed' : null } | @@ -36,6 +35,7 @@ export type CustomsError = { 'SendTicketErr' : string } | { 'InvalidTxReceiver' : null } | { 'UnsupportedChainId' : string } | { 'ECDSAPublicKeyNotFound' : null } | + { 'HttpOutExceedRetryLimit' : null } | { 'DepositUtxoNotFound' : [string, Destination] } | { 'UnsupportedToken' : string } | { 'CustomError' : string }; @@ -63,6 +63,7 @@ export interface InitArgs { 'fee_token' : string, 'hub_principal' : Principal, 'chain_id' : string, + 'default_doge_rpc_config' : RpcConfig, 'admins' : Array, } export interface LockTicketRequest { @@ -177,8 +178,8 @@ export interface _SERVICE { >, 'set_fee_collector' : ActorMethod<[string], undefined>, 'set_min_deposit_amount' : ActorMethod<[bigint], undefined>, + 'set_multi_rpc_config' : ActorMethod<[MultiRpcConfig], undefined>, 'set_tatum_api_config' : ActorMethod<[string, [] | [string]], undefined>, - 'tmp_fix' : ActorMethod<[], undefined>, } export declare const idlFactory: IDL.InterfaceFactory; export declare const init: (args: { IDL: typeof IDL }) => IDL.Type[]; diff --git a/assets/doge_customs/service.did.js b/assets/doge_customs/service.did.js index 37d3da01..e29a58ab 100644 --- a/assets/doge_customs/service.did.js +++ b/assets/doge_customs/service.did.js @@ -1,8 +1,13 @@ export const idlFactory = ({ IDL }) => { + const RpcConfig = IDL.Record({ + 'url' : IDL.Text, + 'api_key' : IDL.Opt(IDL.Text), + }); const InitArgs = IDL.Record({ 'fee_token' : IDL.Text, 'hub_principal' : IDL.Principal, 'chain_id' : IDL.Text, + 'default_doge_rpc_config' : RpcConfig, 'admins' : IDL.Vec(IDL.Principal), }); const GenerateTicketArgs = IDL.Record({ @@ -18,7 +23,6 @@ export const idlFactory = ({ IDL }) => { const CustomsError = IDL.Variant({ 'SendTicketErr' : IDL.Text, 'RpcError' : IDL.Text, - 'HttpOutExceedLimit' : IDL.Null, 'TemporarilyUnavailable' : IDL.Text, 'HttpOutCallError' : IDL.Tuple(IDL.Text, IDL.Text, IDL.Text), 'AlreadyProcessed' : IDL.Null, @@ -37,6 +41,7 @@ export const idlFactory = ({ IDL }) => { 'InvalidTxReceiver' : IDL.Null, 'UnsupportedChainId' : IDL.Text, 'ECDSAPublicKeyNotFound' : IDL.Null, + 'HttpOutExceedRetryLimit' : IDL.Null, 'DepositUtxoNotFound' : IDL.Tuple(IDL.Text, Destination), 'UnsupportedToken' : IDL.Text, 'CustomError' : IDL.Text, @@ -90,10 +95,6 @@ export const idlFactory = ({ IDL }) => { 'name' : IDL.Text, 'symbol' : IDL.Text, }); - const RpcConfig = IDL.Record({ - 'url' : IDL.Text, - 'api_key' : IDL.Opt(IDL.Text), - }); const MultiRpcConfig = IDL.Record({ 'rpc_list' : IDL.Vec(RpcConfig), 'minimum_response_count' : IDL.Nat32, @@ -211,15 +212,20 @@ export const idlFactory = ({ IDL }) => { ), 'set_fee_collector' : IDL.Func([IDL.Text], [], []), 'set_min_deposit_amount' : IDL.Func([IDL.Nat64], [], []), + 'set_multi_rpc_config' : IDL.Func([MultiRpcConfig], [], []), 'set_tatum_api_config' : IDL.Func([IDL.Text, IDL.Opt(IDL.Text)], [], []), - 'tmp_fix' : IDL.Func([], [], []), }); }; export const init = ({ IDL }) => { + const RpcConfig = IDL.Record({ + 'url' : IDL.Text, + 'api_key' : IDL.Opt(IDL.Text), + }); const InitArgs = IDL.Record({ 'fee_token' : IDL.Text, 'hub_principal' : IDL.Principal, 'chain_id' : IDL.Text, + 'default_doge_rpc_config' : RpcConfig, 'admins' : IDL.Vec(IDL.Principal), }); return [InitArgs]; diff --git a/customs/doge/Cargo.toml b/customs/doge/Cargo.toml index a41bee11..5993fb7c 100644 --- a/customs/doge/Cargo.toml +++ b/customs/doge/Cargo.toml @@ -70,4 +70,5 @@ k256 = { git = "https://github.com/altkdf/elliptic-curves", branch = "schnorr_ca rust_decimal = "1.36" rust_decimal_macros = "1.36" log = "0.4.22" -bincode = "1.3.3" \ No newline at end of file +bincode = "1.3.3" +futures = "0.3.30" \ No newline at end of file diff --git a/customs/doge/doge_customs.did b/customs/doge/doge_customs.did index b5817039..e4a0474b 100644 --- a/customs/doge/doge_customs.did +++ b/customs/doge/doge_customs.did @@ -12,7 +12,6 @@ type ChainType = variant { SettlementChain; ExecutionChain }; type CustomsError = variant { SendTicketErr : text; RpcError : text; - HttpOutExceedLimit; TemporarilyUnavailable : text; HttpOutCallError : record { text; text; text }; AlreadyProcessed; @@ -31,6 +30,7 @@ type CustomsError = variant { InvalidTxReceiver; UnsupportedChainId : text; ECDSAPublicKeyNotFound; + HttpOutExceedRetryLimit; DepositUtxoNotFound : record { text; Destination }; UnsupportedToken : text; CustomError : text; @@ -56,6 +56,7 @@ type InitArgs = record { fee_token : text; hub_principal : principal; chain_id : text; + default_doge_rpc_config : RpcConfig; admins : vec principal; }; type LockTicketRequest = record { @@ -147,6 +148,6 @@ service : (InitArgs) -> { set_default_doge_rpc_config : (text, opt text) -> (); set_fee_collector : (text) -> (); set_min_deposit_amount : (nat64) -> (); + set_multi_rpc_config : (MultiRpcConfig) -> (); set_tatum_api_config : (text, opt text) -> (); - tmp_fix : () -> (); } diff --git a/customs/doge/src/custom_to_dogecoin.rs b/customs/doge/src/custom_to_dogecoin.rs index 1e5224ad..a1860031 100644 --- a/customs/doge/src/custom_to_dogecoin.rs +++ b/customs/doge/src/custom_to_dogecoin.rs @@ -14,7 +14,7 @@ use thiserror::Error; use crate::constants::{FINALIZE_UNLOCK_TICKET_NAME, SUBMIT_UNLOCK_TICKETS_NAME}; use crate::doge::ecdsa::sign_with; -use crate::doge::fee::{fee_by_size, DUST_LIMIT}; +use crate::doge::fee::{fee_by_size, DOGE_AMOUNT, DUST_LIMIT}; use crate::doge::rpc::DogeRpc; use crate::doge::script; use crate::doge::sighash::SighashCache; @@ -35,8 +35,6 @@ use crate::state::{finalization_time_estimate, mutate_state, read_state}; pub enum CustomToBitcoinError { #[error("bitcoin sign error: {0}")] SignFailed(String), - // #[error("build a brc20 transfer error: {0}")] - // BuildTransactionFailed(String), #[error("ArgumentError: {0}")] ArgumentError(String), #[error("InsufficientFunds")] @@ -77,10 +75,8 @@ pub async fn send_tickets_to_bitcoin() { s.doge_fee_rate, ) }); - // let to = read_state(|s| s.next_ticket_seq); if from < to { log!(INFO, "submit unlock tx: from {} to {}", from, to); - // let fee_rate = estimate_fee_per_vbyte().await / 1000; for seq in from..to { let r = process_unlock_ticket(seq, fee_rate).await; match r { @@ -120,7 +116,6 @@ pub async fn process_unlock_ticket( ); mutate_state(|s| { s.flight_unlock_ticket_map.insert(seq,r); - // s.reveal_utxo_index.insert(reveal_utxo_index); }); } Ok(()) @@ -142,16 +137,12 @@ pub async fn finalize_flight_unlock_tickets() { for (seq, send_result) in can_check_finalizations.clone() { let need_check_txid = send_result.txid.clone(); let transfer_txid = need_check_txid.to_string(); - // let tx = query_transaction((transfer_txid.clone(), "".to_string())).await; let tx = doge_rpc.get_tx_out(&transfer_txid).await; match tx { Ok(t) => { if t.confirmations >= min_confirmations { mutate_state(|s| { let r = s.flight_unlock_ticket_map.remove(&seq).unwrap(); - // let reveal_utxo_index = format!("{}:0", r.tx[1].txid()); - // s.reveal_utxo_index.remove(&reveal_utxo_index); - // s.finalized_unlock_ticket_map.insert(seq, r); s.finalized_unlock_ticket_results_map.insert(seq, r); }); let (hub_principal, ticket) = @@ -201,17 +192,14 @@ pub async fn build_and_send_transaction( .map_err(|e| ArgumentError(e.to_string()))?; let ( key_name, - // _ecdsa_public_key_opt, change_address_ret, ) = read_state(|s| { ( s.ecdsa_key_name.clone(), - // s.ecdsa_public_key.clone(), s.get_address(Destination::change_address()), ) }); let (change_address, _) = change_address_ret.map_err(|e| ArgumentError(e.to_string()))?; - // let ecdsa_public_key = ecdsa_public_key_opt.ok_or(ArgumentError("ecdsa_public_key is None".to_string()))?; let mut send_tx = Transaction { version: Transaction::CURRENT_VERSION, lock_time: 0, @@ -264,7 +252,6 @@ pub async fn build_and_send_transaction( let mut sighasher = SighashCache::new(&mut send_tx); for (i, (_utxo, destination)) in all_utxos.iter().enumerate() { - // let account = let (address, pk) = read_state(|s| s.get_address(destination.clone())) .map_err(|e| ArgumentError(e.to_string()))?; let hash = sighasher @@ -305,11 +292,9 @@ pub async fn submit_unlock_ticket( Some(ticket) => { // check ticket if read_state(|s| s.finalized_unlock_ticket_results_map.contains_key(&seq)) { - // return Ok(None); return Err(CustomToBitcoinError::ArgumentError("ticket already finalized".to_string())); } if read_state(|s| s.flight_unlock_ticket_map.contains_key(&seq)) { - // return Ok(None); return Err(CustomToBitcoinError::ArgumentError("ticket already in flight".to_string())); } @@ -329,130 +314,19 @@ pub async fn submit_unlock_ticket( )); } - // 1. select utxos + // select utxos let (utxos, total) = select_utxos(amount)?; - // let (fee_payment_address, _) = - // read_state(|s| s.get_address(Destination::fee_payment_address())) - // .map_err(|e| ArgumentError(e.to_string()))?; - // let fee_payment_address_str = fee_payment_address.to_string(); let fee_utxo = mutate_state(|s| { let fee_utxo = s.fee_payment_utxo.clone(); s.fee_payment_utxo.clear(); fee_utxo }); - // let all_utxos: Vec<(Utxo, Destination)> = utxos - // .clone() - // .into_iter() - // .chain( - // fee_utxo - // .iter() - // .map(|e| (e.clone(), Destination::fee_payment_address())), - // ) - // .collect(); - // let total_fee_utxo_amount: u64 = fee_utxo.iter().map(|u| u.value).sum(); - - // 2. build transaction - // let ( - // key_name, - // // _ecdsa_public_key_opt, - // change_address_ret, - // ) = read_state(|s| { - // ( - // s.ecdsa_key_name.clone(), - // // s.ecdsa_public_key.clone(), - // s.get_address(Destination::change_address()), - // ) - // }); - // let (change_address, _) = - // change_address_ret.map_err(|e| ArgumentError(e.to_string()))?; - // // let ecdsa_public_key = ecdsa_public_key_opt.ok_or(ArgumentError("ecdsa_public_key is None".to_string()))?; - // let mut send_tx = Transaction { - // version: Transaction::CURRENT_VERSION, - // lock_time: 0, - // input: utxos - // .iter() - // .map(|(utxo, _)| { - // TxIn::with_outpoint(OutPoint { - // txid: utxo.txid.clone().into(), - // vout: utxo.vout, - // }) - // }) - // .chain(fee_utxo.iter().map(|utxo| { - // TxIn::with_outpoint(OutPoint { - // txid: utxo.txid.clone().into(), - // vout: utxo.vout, - // }) - // })) - // .collect(), - // output: vec![ - // TxOut { - // value: amount, - // script_pubkey: receiver.to_script(chain_params), - // }, - // TxOut { - // value: total.saturating_sub(amount), - // script_pubkey: change_address.to_script(chain_params), - // }, - // TxOut { - // value: total_fee_utxo_amount, - // script_pubkey: fee_payment_address.to_script(chain_params), - // }, - // ], - // }; - // let fee = fee_by_size(send_tx.estimate_size() as u64, fee_rate); - // log!( - // INFO, - // "send ticket fee: {}, total_fee_utxo_amount: {}", - // fee, - // total_fee_utxo_amount - // ); - // if fee > total_fee_utxo_amount { - // return Err(CustomToBitcoinError::InsufficientFee); - // } - // send_tx.output[2].value = total_fee_utxo_amount.saturating_sub(fee); - // if send_tx.output[2].value <= DUST_LIMIT { - // send_tx.output.pop(); - // } - - // // 3. sign transaction - - // let mut sighasher = SighashCache::new(&mut send_tx); - // for (i, (_utxo, destination)) in all_utxos.iter().enumerate() { - // // let account = - // let (address, pk) = read_state(|s| s.get_address(destination.clone())) - // .map_err(|e| ArgumentError(e.to_string()))?; - // let hash = sighasher - // .signature_hash(i, &address.to_script(chain_params), EcdsaSighashType::All) - // .map_err(|e| SignFailed(e.to_string()))?; - // let sig = sign_with(&key_name, destination.derivation_path(), *hash) - // .await - // .map_err(|e| SignFailed(e.to_string()))?; - // let signature = - // Signature::from_compact(&sig).map_err(|e| SignFailed(e.to_string()))?; - // sighasher - // .set_input_script( - // i, - // &SighashSignature { - // signature, - // sighash_type: EcdsaSighashType::All, - // }, - // &PublicKey::from_slice(&pk).map_err(|e| SignFailed(e.to_string()))?, - // ) - // .map_err(|e| SignFailed(e.to_string()))?; - // } - - // // 4. send transaction - - // let doge_rpc: DogeRpc = read_state(|s| s.default_rpc_config.clone()).into(); - // let txid = doge_rpc - // .send_transaction(&send_tx) - // .await - // .map_err(|e| SendTransactionFailed(e.to_string()))?; match build_and_send_transaction(fee_utxo.clone(), utxos.clone(), amount, total, fee_rate, receiver).await { Ok((send_tx, txid)) => { mutate_state(|s| { if send_tx.output.len() >= 2 { + // save change address utxo s.deposited_utxo.push(( Utxo { txid: crate::types::Txid::from(txid).into(), @@ -464,11 +338,15 @@ pub async fn submit_unlock_ticket( } if send_tx.output.len() >= 3 { + // save fee payment utxo s.fee_payment_utxo.push(Utxo { txid: crate::types::Txid::from(txid).into(), vout: 2, value: send_tx.output[2].value, }); + if s.fee_payment_utxo.iter().map(|u| u.value).sum::() < 5 * DOGE_AMOUNT { + log!(ERROR, "Doge Customs fee_payment_utxo will not enough soon!"); + } } }); Ok(SendTicketResult { @@ -536,12 +414,9 @@ pub fn submit_unlock_tickets_task() { } #[test] -pub fn show_txid() { +pub fn show_txid_from_vec_u8_data() { fn parse_hex_string(input: &str) -> Result, Box> { - // 移除所有的反斜杠和空格 let cleaned = input.replace("\\", "").replace(" ", ""); - - // 每两个字符解析成一个字节 let bytes: Result, _> = (0..cleaned.len()) .step_by(2) .map(|i| u8::from_str_radix(&cleaned[i..i + 2], 16)) @@ -552,6 +427,5 @@ pub fn show_txid() { let txid = r"\a2\44\f5\b0\69\73\4e\5d\15\de\14\8d\50\d5\60\08\21\07\83\09\2a\8d\78\cf\31\a5\77\19\2a\ef\c5\2a"; let v = parse_hex_string(&txid).unwrap(); dbg!(&hex::DisplayHex::to_upper_hex_string(&v)); - // let txid = Txid::from(txid).unwrap(); dbg!(&txid.to_string()); } diff --git a/customs/doge/src/doge/ecdsa.rs b/customs/doge/src/doge/ecdsa.rs index 07281ee8..230d7a3a 100644 --- a/customs/doge/src/doge/ecdsa.rs +++ b/customs/doge/src/doge/ecdsa.rs @@ -39,24 +39,4 @@ pub async fn sign_with( .map_err(|err| format!("sign_with_ecdsa failed {:?}", err))?; Ok(response.signature) -} - -// pub async fn public_key_with( -// key_name: &str, -// derivation_path: Vec>, -// ) -> Result { -// let args = ecdsa::EcdsaPublicKeyArgument { -// canister_id: None, -// derivation_path, -// key_id: ecdsa::EcdsaKeyId { -// curve: ecdsa::EcdsaCurve::Secp256k1, -// name: key_name.to_string(), -// }, -// }; - -// let (response,): (ecdsa::EcdsaPublicKeyResponse,) = ecdsa::ecdsa_public_key(args) -// .await -// .map_err(|err| format!("ecdsa_public_key failed {:?}", err))?; - -// Ok(response) -// } +} \ No newline at end of file diff --git a/customs/doge/src/doge/rpc.rs b/customs/doge/src/doge/rpc.rs index c201a9f3..3b224c0b 100644 --- a/customs/doge/src/doge/rpc.rs +++ b/customs/doge/src/doge/rpc.rs @@ -5,7 +5,7 @@ use omnity_types::ic_log::ERROR; use serde_json::json; use ic_canister_log::log; -use crate::{constants::{KB, KB100}, errors::CustomsError, types::{deserialize_hex, http_request_with_retry, serialize_hex, wrap_to_customs_error}}; +use crate::{constants::{KB, KB100}, errors::CustomsError, types::{deserialize_hex, http_request_with_retry, serialize_hex, wrap_to_customs_error, RpcConfig}}; use super::transaction::{DogeRpcResponse, RpcTxOut, Transaction, Txid}; @@ -13,14 +13,13 @@ pub const PROXY_URL: &str = "https://common-rpc-proxy-398338012986.us-central1.r pub const IDEMPOTENCY_KEY: &str = "X-Idempotency"; pub const FORWARD_RPC: &str = "X-Forward-Host"; +#[derive(Clone, Debug)] pub struct DogeRpc { pub url: String, pub api_key: Option, } impl DogeRpc { - // const HTTP_OUT_CALL_CYCLE: u128 = 60_000_000_000; - // const RPC_RETRY_TIMES: u32 = 3; pub async fn get_raw_transaction( &self, txid: &str @@ -37,7 +36,7 @@ impl DogeRpc { value: self.api_key.clone().unwrap(), }); } - let request = CanisterHttpRequestArgument { + let mut request = CanisterHttpRequestArgument { url: self.url.clone(), method: HttpMethod::POST, body: Some(json!({ @@ -56,6 +55,7 @@ impl DogeRpc { }), headers }; + self.proxy_request(&mut request); let response = http_request_with_retry(request).await?; let raw_tx: DogeRpcResponse = serde_json::from_slice(&response.body).map_err(|e| { log!(ERROR, "json error {:?}", e); @@ -86,7 +86,7 @@ impl DogeRpc { value: self.api_key.clone().unwrap(), }); } - let request = CanisterHttpRequestArgument { + let mut request = CanisterHttpRequestArgument { url: self.url.clone(), method: HttpMethod::POST, body: Some(json!({ @@ -105,6 +105,7 @@ impl DogeRpc { }), headers }; + self.proxy_request(&mut request); let response = http_request_with_retry(request).await?; let tx_out_response: DogeRpcResponse = serde_json::from_slice(&response.body).map_err(|e| { log!(ERROR, "json error {:?}", e); @@ -157,7 +158,6 @@ impl DogeRpc { self.proxy_request(&mut request); let response = http_request_with_retry(request.clone()).await?; - // log!(INFO, "send transaction, request: {:?}, response: {:?}",request, response); let rpc_response: DogeRpcResponse = serde_json::from_slice(&response.body).map_err(|e| { log!(ERROR, "json error {:?}", e); CustomsError::RpcError( @@ -186,4 +186,7 @@ impl DogeRpc { } - +pub async fn get_raw_transaction_by_rpc( txid: &str, rpc_config: RpcConfig) -> Result { + let doge_rpc = DogeRpc::from(rpc_config); + doge_rpc.get_raw_transaction(txid).await +} diff --git a/customs/doge/src/doge/sighash.rs b/customs/doge/src/doge/sighash.rs index 2a61d78b..5f82c99b 100644 --- a/customs/doge/src/doge/sighash.rs +++ b/customs/doge/src/doge/sighash.rs @@ -13,7 +13,6 @@ pub use bitcoin::EcdsaSighashType; use crate::doge::script::ScriptBuf; use super::transaction::*; -// use crate::{err_string, transaction::*}; hash_newtype! { /// Hash of a transaction according to the legacy signature algorithm. @@ -197,21 +196,6 @@ impl> SighashCache { } } -// // https://en.bitcoin.it/wiki/Wallet_import_format -// pub fn decode_secretkey_wif(sk: &str) -> Result { -// match base58::decode_check(sk) { -// Ok(data) => { -// let chain = chain_from_wif(sk); -// if data[0] != chain.pkey_prefix { -// return Err("wrong key prefix".to_string()); -// } -// let key = SecretKey::from_slice(&data[1..33]).map_err(err_string)?; -// Ok(key) -// } -// Err(_) => Err("invalid base58 secret key".to_string()), -// } -// } - fn split_anyonecanpay_flag(st: EcdsaSighashType) -> (EcdsaSighashType, bool) { use EcdsaSighashType::*; match st { @@ -230,56 +214,4 @@ fn is_invalid_use_of_sighash_single( outputs_len: usize, ) -> bool { ty == EcdsaSighashType::Single && input_index >= outputs_len -} - -// #[cfg(test)] -// mod tests { -// use super::*; -// use bitcoin::script::ScriptBuf; -// use bitcoin::PubkeyHash; -// use hex::test_hex_unwrap as hex; - -// #[test] -// fn test_sighash() { -// // https://dogechain.info/tx/f875c9959d2013caedf7b3acce278d1bed7be0e7d45aa266db1c262e6743cb99 -// // https://sochain.com/tx/DOGE/f875c9959d2013caedf7b3acce278d1bed7be0e7d45aa266db1c262e6743cb99 -// let tx_data = hex!("0100000003607ee3f9c2c8eb4db9297d38c3ed1493fbdd257283eabf5a89999ebd5676f13f000000006a473044022045228179cc4fed581b5d9e6411402fd34c40866397094f0d97843ee257b30abc0220310c33c4452d47113c51257883c780d40928ba6b9e2bf14c234f1bd5991607e6012102ca3e8f77965b91cbe15203817cce0170bc066d5d7a9acb2070e9b3e4b2077bb8feffffff538cde51d37d84ec955410476c18c7dddaf5531a7aa07e60b75dd106ca50b447000000006b483045022100b58824fe1e036320a5cc267fe65fec100988df2a0d0ea594b945088c4945765b0220091e3dead2cec11ce5c4139f126452437b8ba8d957ae7dcee0fba60d854d46df0121026079f574275f68fd88fbd01c0af3364524b3071419dc24bddbf60003be974288feffffff7e24f4f31a3a6eaf109c3368352975c1e0ef10d175905e991553e4040b049e8c010000006b483045022100f3d369af38220916afb0c805581cd14b08ff0ee83b093c71fdeccb9b8fea197f022053e648c6a0ed5e1b42042d0e4654be8e039082c8106f147726e420cf1c986d03012103a0e805a231331c414b0423adef1ddedb23cc801acfd90ba7bd95907048a3b908feffffff02a4700106000000001976a91467f5672ce989470f4dcba16c1e930f80c03c887488acf23b03c3360000001976a91489248eee4e9d99729ebebbca00efb75ceb1ed01888acf9ed4900"); - -// let tx = Transaction::try_from(&tx_data[..]).unwrap(); -// assert_eq!( -// tx.compute_txid().to_string(), -// "f875c9959d2013caedf7b3acce278d1bed7be0e7d45aa266db1c262e6743cb99" -// ); -// assert_eq!(tx.input.len(), 3); -// // https://sochain.com/tx/DOGE/3ff17656bd9e99895abfea837225ddfb9314edc3387d29b94debc8c2f9e37e60 -// // output 0: value: 27188437677 -// let script_pubkey = ScriptBuf::new_p2pkh( -// &PubkeyHash::from_slice(&hex!("e1209b366bebd881861c9aaeed0b780f531c6435")).unwrap(), -// ); -// println!("script: {:?}", tx.input[0].script); -// let mut ins = tx.input[0].script.instructions(); -// let sig = ins.next().unwrap().unwrap(); -// let sig = sig.push_bytes().unwrap(); -// let sig = SighashSignature::from_slice(sig.as_bytes()).unwrap(); - -// let pubkey = ins.next().unwrap().unwrap(); -// let pubkey = pubkey.push_bytes().unwrap(); -// let pubkey = PublicKey::from_slice(pubkey.as_bytes()).unwrap(); - -// let sighasher = SighashCache::new(&tx); -// let sighash = sighasher -// .signature_hash(0, &script_pubkey, EcdsaSighashType::All) -// .unwrap(); -// let msg = Message::from_digest(sighash.to_byte_array()); -// let secp = Secp256k1::verification_only(); -// assert!(secp.verify_ecdsa(&msg, &sig.signature, &pubkey).is_ok()); - -// let mut some_tx = tx.clone(); -// some_tx.input[0].script = ScriptBuf::new(); - -// let mut sighasher = SighashCache::new(&mut some_tx); -// assert!(sighasher.set_input_script(0, &sig, &pubkey).is_ok()); -// assert!(sighasher.set_input_script(3, &sig, &pubkey).is_err()); -// assert_eq!(some_tx.to_bytes(), tx_data); -// } -// } +} \ No newline at end of file diff --git a/customs/doge/src/doge/tatum_rpc.rs b/customs/doge/src/doge/tatum_rpc.rs index 3b513b44..961229a8 100644 --- a/customs/doge/src/doge/tatum_rpc.rs +++ b/customs/doge/src/doge/tatum_rpc.rs @@ -53,13 +53,6 @@ impl TatumDogeRpc { headers }; - // let txs: Vec = serde_json::from_slice(&response.body).map_err(|e| { - // log!(ERROR, "json error {:?}", e); - // CustomsError::RpcError( - // "failed to desc result from json".to_string(), - // ) - // })?; - let response = http_request_with_retry(request.clone()).await?; let rpc_response: Vec = serde_json::from_slice(&response.body).map_err(|_| { @@ -77,7 +70,6 @@ impl TatumDogeRpc { )?); } - // let v: Vec = rpc_response.iter().map(|tx| Txid::from_str(tx.hash.as_str())).collect(); Ok(txids) } } diff --git a/customs/doge/src/doge/transaction.rs b/customs/doge/src/doge/transaction.rs index ac0699c9..035645f4 100644 --- a/customs/doge/src/doge/transaction.rs +++ b/customs/doge/src/doge/transaction.rs @@ -15,8 +15,6 @@ use crate::errors::CustomsError; use super::chainparams::DOGE_MAIN_NET_CHAIN; use super::script::classify_script; -// use crate::{consensus_decode_from_vec, consensus_encode_vec, err_string}; - pub fn consensus_encode_vec(vv: &[T], w: &mut W) -> Result where T: Encodable, @@ -503,334 +501,4 @@ impl From<&Transaction> for Txid { fn from(tx: &Transaction) -> Txid { tx.compute_txid() } -} - -// #[cfg(test)] -// mod tests { -// use super::*; -// use hex::test_hex_unwrap as hex; -// use std::str::FromStr; - -// use crate::chainparams::DOGE_MAIN_NET_CHAIN; -// use crate::script::{classify_script, ScriptType}; - -// #[test] -// fn test_transaction() { -// // https://github.com/dogecoin/dogecoin/blob/master/src/test/data/tt-delin1-out.json -// let data = hex!("0100000014fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0260f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac41420f00000000001976a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac00000000"); -// let mut rd = &data[..]; -// let tx = Transaction::consensus_decode_from_finite_reader(&mut rd).unwrap(); -// println!("input: {}, output: {}", tx.input.len(), tx.output.len()); - -// let mut buf = Vec::new(); -// tx.consensus_encode(&mut buf).unwrap(); -// assert_eq!(buf, data); - -// assert_eq!( -// tx.compute_txid().to_string(), -// "81b2035be1da1abe745c6141174a73d151009ec17b3d5ebffa2e177408c50dfd" -// ); - -// assert_eq!(tx.version, 1); -// assert_eq!(tx.lock_time, 0); -// let input = vec![TxIn{ -// prevout: OutPoint { -// txid: Txid::from_str( -// "27871a1a27d833e99cd392a502a647beaaeda6da535417501c76312d52235cfd" -// ).unwrap(), -// vout: 332, -// }, -// script: ScriptBuf::from_hex("493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc").unwrap(), -// sequence: 4294967295, -// witness: Witness::default(), -// }, -// TxIn{ -// prevout: OutPoint { -// txid: Txid::from_str( -// "752f7f69b915637dc1c2f7aed1466ad676f6f3e24cf922809705f664e97ab3c1" -// ).unwrap(), -// vout: 1, -// }, -// script: ScriptBuf::from_hex("473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34").unwrap(), -// sequence: 4294967295, -// witness: Witness::default(), -// }, -// TxIn{ -// prevout: OutPoint { -// txid: Txid::from_str( -// "b0ac9cca2e69cd02410e31b1f4402a25758e71abd1ab06c265ef9077dc05d0ed" -// ).unwrap(), -// vout: 209, -// }, -// script: ScriptBuf::from_hex("48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc").unwrap(), -// sequence: 4294967295, -// witness: Witness::default(), -// }, -// TxIn{ -// prevout: OutPoint { -// txid: Txid::from_str( -// "a135eafb595eaf4c1ea59ccb111cdc0eae1b2c979b226a1e5aa8b76fe2d628df" -// ).unwrap(), -// vout: 0, -// }, -// script: ScriptBuf::from_hex("483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52").unwrap(), -// sequence: 4294967295, -// witness: Witness::default(), -// }, -// TxIn{ -// prevout: OutPoint { -// txid: Txid::from_str( -// "a5d6bf53ba21140b8a4d554feb00fe8bb9a62430ff9e4624aa2f58a120232aae" -// ).unwrap(), -// vout: 1, -// }, -// script: ScriptBuf::from_hex("493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc").unwrap(), -// sequence: 4294967295, -// witness: Witness::default(), -// }, -// TxIn{ -// prevout: OutPoint { -// txid: Txid::from_str( -// "1b299cf14f1a22e81ea56d71b7affbd7cf386807bf2b4d4b79a18a54125accb3" -// ).unwrap(), -// vout: 0, -// }, -// script: ScriptBuf::from_hex("483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52").unwrap(), -// sequence: 4294967295, -// witness: Witness::default(), -// }, -// TxIn{ -// prevout: OutPoint { -// txid: Txid::from_str( -// "071df1cdcb3f0070f9d6af7b0274f02d0be2324a274727cfd288383167531485" -// ).unwrap(), -// vout: 21, -// }, -// script: ScriptBuf::from_hex("483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c").unwrap(), -// sequence: 4294967295, -// witness: Witness::default(), -// }, -// TxIn{ -// prevout: OutPoint { -// txid: Txid::from_str( -// "b012e500eb7adf7a13ed332dd6ece849f94f7a62bb3eac5babab356d1fc19282" -// ).unwrap(), -// vout: 9, -// }, -// script: ScriptBuf::from_hex("48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c").unwrap(), -// sequence: 4294967295, -// witness: Witness::default(), -// }, -// TxIn{ -// prevout: OutPoint { -// txid: Txid::from_str( -// "58840fee9c833f2f2d40575842f30f4b8d2553094d06ad88b03d06869acf3d88" -// ).unwrap(), -// vout: 30, -// }, -// script: ScriptBuf::from_hex("4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c").unwrap(), -// sequence: 4294967295, -// witness: Witness::default(), -// }, -// TxIn{ -// prevout: OutPoint { -// txid: Txid::from_str( -// "e69f9cd16946e570a665245354428a3f507ea69f4568b581e4af98edb3db9766" -// ).unwrap(), -// vout: 114, -// }, -// script: ScriptBuf::from_hex("47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c").unwrap(), -// sequence: 4294967295, -// witness: Witness::default(), -// }, -// TxIn{ -// prevout: OutPoint { -// txid: Txid::from_str( -// "595d1257f654ed2cbe5a65421e8aefd2b4d70b5b6c89a03f1d7e518221fc3f02" -// ).unwrap(), -// vout: 103, -// }, -// script: ScriptBuf::from_hex("493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc").unwrap(), -// sequence: 4294967295, -// witness: Witness::default(), -// }, -// TxIn{ -// prevout: OutPoint { -// txid: Txid::from_str( -// "06fc818f9555a261248ecd7aad0993eafb5a82ceb2b5c87c3ddfb06671c7f816" -// ).unwrap(), -// vout: 1, -// }, -// script: ScriptBuf::from_hex("483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd").unwrap(), -// sequence: 4294967295, -// witness: Witness::default(), -// }, -// TxIn{ -// prevout: OutPoint { -// txid: Txid::from_str( -// "fb416c8155d6bb1d43f9395466ca90a638a7c2dd3ff617aadf3a7ac8f3967b19" -// ).unwrap(), -// vout: 0, -// }, -// script: ScriptBuf::from_hex("49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34").unwrap(), -// sequence: 4294967295, -// witness: Witness::default(), -// }, -// TxIn{ -// prevout: OutPoint { -// txid: Txid::from_str( -// "3940b9683bd6104ad24c978e640ba4095993cafdb27d2ed91baa27ee61a2d920" -// ).unwrap(), -// vout: 221, -// }, -// script: ScriptBuf::from_hex("483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc").unwrap(), -// sequence: 4294967295, -// witness: Witness::default(), -// }, -// TxIn{ -// prevout: OutPoint { -// txid: Txid::from_str( -// "711b5714d3b5136147c02194cd95bde94a4648c4263ca6f972d86cd1d579f150" -// ).unwrap(), -// vout: 1, -// }, -// script: ScriptBuf::from_hex("483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd").unwrap(), -// sequence: 4294967295, -// witness: Witness::default(), -// }, -// TxIn{ -// prevout: OutPoint { -// txid: Txid::from_str( -// "6364b5c5efe018430789e7fb4e338209546cae5d9c5f5e300aac68155d861b55" -// ).unwrap(), -// vout: 27, -// }, -// script: ScriptBuf::from_hex("48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c").unwrap(), -// sequence: 4294967295, -// witness: Witness::default(), -// }, -// TxIn{ -// prevout: OutPoint { -// txid: Txid::from_str( -// "0bb57f6e38012c86d4c5a28c904f2675082859147921a707d48961015a3e5057" -// ).unwrap(), -// vout: 1095, -// }, -// script: ScriptBuf::from_hex("48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c").unwrap(), -// sequence: 4294967295, -// witness: Witness::default(), -// }, -// TxIn{ -// prevout: OutPoint { -// txid: Txid::from_str( -// "9b34274814a2540bb062107117f8f3e75ef85d953e9372d8261a3e9dfbc1163f" -// ).unwrap(), -// vout: 37, -// }, -// script: ScriptBuf::from_hex("483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c").unwrap(), -// sequence: 4294967295, -// witness: Witness::default(), -// }, -// TxIn{ -// prevout: OutPoint { -// txid: Txid::from_str( -// "b86b5cc0d8a7374d94e277850b0a249cb26a7b42ddf014f28a49b8859da64241" -// ).unwrap(), -// vout: 20, -// }, -// script: ScriptBuf::from_hex("48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c").unwrap(), -// sequence: 4294967295, -// witness: Witness::default(), -// }, -// TxIn{ -// prevout: OutPoint { -// txid: Txid::from_str( -// "3d0a2353eeec44d3c10aed259038db321912122cd4150048f7bfa4c0ecfee236" -// ).unwrap(), -// vout: 242, -// }, -// script: ScriptBuf::from_hex("493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc").unwrap(), -// sequence: 4294967295, -// witness: Witness::default(), -// }]; - -// assert_eq!(input.len(), tx.input.len()); -// for (i, v) in tx.input.iter().enumerate() { -// assert_eq!(v, &input[i], "input[{}] mismatch: {}", i, v.prevout.txid); -// } - -// let output = [ -// TxOut { -// value: 137820000, -// script_pubkey: ScriptBuf::from_hex( -// "76a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac", -// ) -// .unwrap(), -// }, -// TxOut { -// value: 1000001, -// script_pubkey: ScriptBuf::from_hex( -// "76a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac", -// ) -// .unwrap(), -// }, -// ]; - -// // { -// // "value": 1.3782, -// // "n": 0, -// // "scriptPubKey": { -// // "asm": "OP_DUP OP_HASH160 8fd139bb39ced713f231c58a4d07bf6954d1c201 OP_EQUALVERIFY OP_CHECKSIG", -// // "hex": "76a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac", -// // "reqSigs": 1, -// // "type": "pubkeyhash", -// // "addresses": [ -// // "DJFXow7CYcBWKVjwe1VH4or5f6YetLH1hw" -// // ] -// // } -// // }, -// // { -// // "value": 0.01000001, -// // "n": 1, -// // "scriptPubKey": { -// // "asm": "OP_DUP OP_HASH160 6c772e9cf96371bba3da8cb733da70a2fcf20078 OP_EQUALVERIFY OP_CHECKSIG", -// // "hex": "76a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac", -// // "reqSigs": 1, -// // "type": "pubkeyhash", -// // "addresses": [ -// // "DF2cHtiK4xeXPUBhMdK7XWU5UNYSg2KFvt" -// // ] -// // } -// // } -// let s = ScriptBuf::from(hex!("76a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac")); -// println!("script: {:?}", s); - -// let (script_type, addr) = classify_script(s.as_bytes(), &DOGE_MAIN_NET_CHAIN); -// assert_eq!(script_type, ScriptType::PubKeyHash); -// assert_eq!( -// addr.unwrap().to_string(), -// "DJFXow7CYcBWKVjwe1VH4or5f6YetLH1hw" -// ); - -// let (script_type, addr) = classify_script( -// &hex!("76a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac"), -// &DOGE_MAIN_NET_CHAIN, -// ); -// assert_eq!(script_type, ScriptType::PubKeyHash); -// assert_eq!( -// addr.unwrap().to_string(), -// "DF2cHtiK4xeXPUBhMdK7XWU5UNYSg2KFvt" -// ); - -// assert_eq!(output.len(), tx.output.len()); -// for (i, v) in tx.output.iter().enumerate() { -// assert_eq!( -// v, -// &output[i], -// "output[{}] mismatch: {}", -// i, -// v.script_pubkey.to_hex_string() -// ); -// } -// } -// } +} \ No newline at end of file diff --git a/customs/doge/src/dogeoin_to_custom.rs b/customs/doge/src/dogeoin_to_custom.rs index d8a4bde2..10eacf21 100644 --- a/customs/doge/src/dogeoin_to_custom.rs +++ b/customs/doge/src/dogeoin_to_custom.rs @@ -4,7 +4,7 @@ use crate::constants::FINALIZE_LOCK_TICKET_NAME; use crate::doge::chainparams::DOGE_MAIN_NET_CHAIN; use crate::doge::rpc::DogeRpc; use crate::doge::script::classify_script; -use crate::doge::transaction::Transaction ; +use crate::doge::transaction::Transaction; use crate::errors::CustomsError; use crate::generate_ticket::GenerateTicketWithTxidArgs; use crate::hub; @@ -13,63 +13,65 @@ use crate::types::{Destination, LockTicketRequest, Txid, Utxo}; use ic_canister_log::log; use omnity_types::ic_log::{ERROR, INFO}; -pub async fn query_and_save_utxo_for_payment_address(txid: String)-> Result { - +pub async fn query_and_save_utxo_for_payment_address(txid: String) -> Result { if read_state(|s| s.deposit_fee_tx_set.get(&txid).is_some()) { Err(CustomsError::CustomError("already saved".to_string()))?; } let doge_rpc: DogeRpc = read_state(|s| s.default_doge_rpc_config.clone()).into(); let transaction = doge_rpc.get_raw_transaction(&txid).await?; - let (fee_payment_address, _) = read_state(|s| s.get_address(Destination::fee_payment_address()))?; + let (fee_payment_address, _) = + read_state(|s| s.get_address(Destination::fee_payment_address()))?; let typed_txid = Txid::from_str(&txid).map_err(|_| CustomsError::InvalidTxId)?; let mut total = 0; for (i, out) in transaction.output.iter().enumerate() { - let receiver = classify_script(out.script_pubkey.as_bytes(), &DOGE_MAIN_NET_CHAIN).1.ok_or( - CustomsError::CustomError("failed to get receiver from output".to_string()) - )?; + let receiver = classify_script(out.script_pubkey.as_bytes(), &DOGE_MAIN_NET_CHAIN) + .1 + .ok_or(CustomsError::CustomError( + "failed to get receiver from output".to_string(), + ))?; if receiver.eq(&fee_payment_address) { total += out.value; - mutate_state( - |s| { - s.fee_payment_utxo.push( - Utxo { - txid: typed_txid.clone(), - vout: i as u32, - value: out.value, - } - ); - } - ) + mutate_state(|s| { + s.fee_payment_utxo.push(Utxo { + txid: typed_txid.clone(), + vout: i as u32, + value: out.value, + }); + }) } } - if total>0 { - mutate_state( - |s| { - s.deposit_fee_tx_set.insert(txid, ()); - } - ) + if total > 0 { + mutate_state(|s| { + s.deposit_fee_tx_set.insert(txid, ()); + }) } - Ok(total) - } pub async fn check_transaction( req: GenerateTicketWithTxidArgs, -) -> Result<(Transaction, u64, String ), CustomsError> { - read_state(|s| s.tokens.get(&req.token_id).cloned()) - .ok_or(CustomsError::InvalidArgs(serde_json::to_string(&req).unwrap()))?; - read_state(|s| s.counterparties.get(&req.target_chain_id).cloned()) - .ok_or(CustomsError::InvalidArgs(serde_json::to_string(&req).unwrap()))?; - - let doge_rpc: DogeRpc = read_state(|s| s.default_doge_rpc_config.clone()).into(); +) -> Result<(Transaction, u64, String), CustomsError> { + read_state(|s| s.tokens.get(&req.token_id).cloned()).ok_or(CustomsError::InvalidArgs( + serde_json::to_string(&req).unwrap(), + ))?; + read_state(|s| s.counterparties.get(&req.target_chain_id).cloned()).ok_or( + CustomsError::InvalidArgs(serde_json::to_string(&req).unwrap()), + )?; + + // if let Some() = read_state(|s| s.multi_rpc_config) + let default_doge_rpc: DogeRpc = read_state(|s| s.default_doge_rpc_config.clone()).into(); + let multi_rpc_config = read_state(|s| s.multi_rpc_config.clone()); + let transaction = if multi_rpc_config.rpc_list.len() > 0 { + multi_rpc_config.get_raw_transaction(&req.txid).await? + } else { + default_doge_rpc.get_raw_transaction(&req.txid).await? + }; - let transaction = doge_rpc.get_raw_transaction(&req.txid).await?; log!(INFO, "check transaction: {:?}", transaction); - + //check whether need to pay fees for transfer. If fee is None, that means paying fees is not need let (fee, addr) = read_state(|s| s.get_transfer_fee_info(&req.target_chain_id)); match fee { @@ -97,24 +99,34 @@ pub async fn check_transaction( // receiver should be destination address let destination = Destination::new(req.target_chain_id.clone(), req.receiver.clone(), None); - let (destination_to_address, _ ) = read_state(|s| s.get_address(destination.clone()))?; + let (destination_to_address, _) = read_state(|s| s.get_address(destination.clone()))?; let mut amount = 0; - let first_input = transaction.input.first().ok_or(CustomsError::DepositUtxoNotFound(req.txid.clone(), destination.clone()))?; - // let sender = transaction.input.first().and_then(|input| { - // let (_, addr_opt) = classify_script(input.script.clone().as_bytes(), &DOGE_MAIN_NET_CHAIN); - // addr_opt.map(|e| e.to_string().clone()) - // }); - - let transaction_of_input = doge_rpc.get_raw_transaction(&first_input.prevout.txid.to_string()).await?; - let output_of_input = transaction_of_input.output.get(first_input.prevout.vout as usize) - .ok_or( - CustomsError::CustomError("input not found".to_string()) - )?; - - let sender = classify_script(output_of_input.script_pubkey.as_bytes(), &DOGE_MAIN_NET_CHAIN).1.map(|e| e.to_string().clone()).ok_or( - CustomsError::CustomError("failed to get sender from output_of_input".to_string()) - )?; + let first_input = transaction + .input + .first() + .ok_or(CustomsError::DepositUtxoNotFound( + req.txid.clone(), + destination.clone(), + ))?; + + let transaction_of_input = default_doge_rpc + .get_raw_transaction(&first_input.prevout.txid.to_string()) + .await?; + let output_of_input = transaction_of_input + .output + .get(first_input.prevout.vout as usize) + .ok_or(CustomsError::CustomError("input not found".to_string()))?; + + let sender = classify_script( + output_of_input.script_pubkey.as_bytes(), + &DOGE_MAIN_NET_CHAIN, + ) + .1 + .map(|e| e.to_string().clone()) + .ok_or(CustomsError::CustomError( + "failed to get sender from output_of_input".to_string(), + ))?; for tx_out in transaction.output.clone() { let (_, addr_opt) = classify_script(tx_out.script_pubkey.as_bytes(), &DOGE_MAIN_NET_CHAIN); @@ -126,9 +138,12 @@ pub async fn check_transaction( } if amount == 0 { - return Err(CustomsError::DepositUtxoNotFound(req.txid.clone(), destination)); + return Err(CustomsError::DepositUtxoNotFound( + req.txid.clone(), + destination, + )); } - + Ok((transaction, amount, sender)) } @@ -163,53 +178,46 @@ pub async fn finalize_lock_ticket_request() { match finalize_ticket(txid.clone().into()).await { Ok(_) => { log!(INFO, "finalize lock success: {:?}", txid); - }, + } Err(e) => { log!(ERROR, "finalize lock error: {:?}", e); - }, + } } - } - }, + } Err(e) => { log!(ERROR, "finalize lock error: {:?}", e); - }, + } } } } -pub async fn check_tx_confirmation( - txid: Txid, -)-> Result { - +pub async fn check_tx_confirmation(txid: Txid) -> Result { let doge_rpc: DogeRpc = read_state(|s| s.default_doge_rpc_config.clone()).into(); let tx_out = doge_rpc.get_tx_out(txid.to_string().as_str()).await?; let min_confirmations = read_state(|s| s.min_confirmations); return Ok(tx_out.confirmations >= min_confirmations); } -async fn finalize_ticket(txid: Txid)-> Result<(), CustomsError> { +async fn finalize_ticket(txid: Txid) -> Result<(), CustomsError> { let hub_principal = read_state(|s| s.hub_principal); hub::finalize_ticket(hub_principal, txid.to_string()) - .await - .map_err(|e| { - CustomsError::CallError( - hub_principal, - e.method, - e.reason.to_string() - ) - })?; + .await + .map_err(|e| CustomsError::CallError(hub_principal, e.method, e.reason.to_string()))?; mutate_state(|s| { - let v = s.pending_lock_ticket_requests.remove(&txid).ok_or( - CustomsError::CustomError("pending lock ticket request not found".to_string()) - )?; - // s.finalized_lock_ticket_requests.insert(txid, v.clone()); - s.finalized_lock_ticket_requests_map.insert( txid.clone(), v.clone()); + let v = s + .pending_lock_ticket_requests + .remove(&txid) + .ok_or(CustomsError::CustomError( + "pending lock ticket request not found".to_string(), + ))?; + s.finalized_lock_ticket_requests_map + .insert(txid.clone(), v.clone()); s.save_utxo(v)?; Ok(()) })?; Ok(()) -} \ No newline at end of file +} diff --git a/customs/doge/src/errors.rs b/customs/doge/src/errors.rs index 3c409440..09dba146 100644 --- a/customs/doge/src/errors.rs +++ b/customs/doge/src/errors.rs @@ -52,6 +52,6 @@ pub enum CustomsError { HttpOutCallError(String, String, String), #[error("Http status code: {0:?}, url: {1}, body: {2}")] HttpStatusError(Nat, String, String), - #[error("Http out call exceed limit")] - HttpOutExceedLimit, + #[error("Http out call exceed retry limit")] + HttpOutExceedRetryLimit, } \ No newline at end of file diff --git a/customs/doge/src/generate_ticket.rs b/customs/doge/src/generate_ticket.rs index 9e9aac1f..74d2f932 100644 --- a/customs/doge/src/generate_ticket.rs +++ b/customs/doge/src/generate_ticket.rs @@ -18,7 +18,6 @@ use crate::types::{serialize_hex, Destination, GenTicketStatus, LockTicketReques #[derive(Clone, CandidType, Serialize, Deserialize, Debug)] pub struct GenerateTicketWithTxidArgs { pub txid: String, - // pub amount: String, pub target_chain_id: String, pub token_id: String, pub receiver: String, diff --git a/customs/doge/src/hub.rs b/customs/doge/src/hub.rs index a4e5f15b..c5b632d8 100644 --- a/customs/doge/src/hub.rs +++ b/customs/doge/src/hub.rs @@ -66,11 +66,6 @@ pub async fn pending_ticket(hub_principal: Principal, ticket: Ticket) -> Result< call(hub_principal, "pending_ticket".into(), (ticket,)).await } -// pub async fn send_ticket(hub_principal: Principal, ticket: Ticket) -> Result<(), CallError> { -// let hub_principal = read_state(|s| s.hub_principal); -// call(hub_principal, "send_ticket".into(), (ticket,)).await -// } - pub async fn finalize_ticket(hub_principal: Principal, ticket_id: String) -> Result<(), CallError> { call(hub_principal, "finalize_ticket".into(), (ticket_id,)).await } diff --git a/customs/doge/src/lib.rs b/customs/doge/src/lib.rs index b5c446d0..af9cd5ee 100644 --- a/customs/doge/src/lib.rs +++ b/customs/doge/src/lib.rs @@ -9,7 +9,6 @@ mod guard; mod hub; mod hub_to_custom; mod management; -//mod psbt; pub mod service; mod stable_memory; pub(crate) mod state; @@ -23,25 +22,15 @@ pub mod constants { pub const FETCH_HUB_TICKET_NAME: &str = "FETCH_HUB_TICKET"; pub const FETCH_HUB_DIRECTIVE_NAME: &str = "FETCH_HUB_DIRECTIVE"; pub const FINALIZE_LOCK_TICKET_NAME: &str = "FINALIZE_GENERATE_TICKET_NAME"; - pub const FINALIZE_LOCK_TICKET_INTERVAL: u64 = 300; + pub const FINALIZE_LOCK_TICKET_INTERVAL: u64 = 120; pub const FINALIZE_UNLOCK_TICKET_NAME: &str = "FINALIZE_UNLOCK_TICKET_NAME"; - pub const FINALIZE_UNLOCK_TICKET_INTERVAL: u64 = 600; + pub const FINALIZE_UNLOCK_TICKET_INTERVAL: u64 = 120; pub const SUBMIT_UNLOCK_TICKETS_NAME: &str = "SUBMIT_UNLOCK_TICKETS_NAME"; pub const SUBMIT_UNLOCK_TICKETS_INTERVAL: u64 = 5; pub const BATCH_QUERY_LIMIT: u64 = 20; - pub const PROD_KEY: &str = "key_1"; - pub const RPC_RETRY_TIMES: u8 = 5; + pub const RPC_RETRY_TIMES: u8 = 3; pub const SEC_NANOS: u64 = 1_000_000_000; pub const MIN_NANOS: u64 = 60 * SEC_NANOS; - pub const COMMIT_TX_VBYTES: u64 = 153; - - pub const INPUT_SIZE_VBYTES: u64 = 68; - pub const OUTPUT_SIZE_VBYTES: u64 = 31; - pub const TX_OVERHEAD_VBYTES: u64 = 11; - pub const REVEAL_TX_VBYTES: u64 = 170; - pub const TRANSFER_TX_VBYTES: u64 = 120; - pub const FIXED_COMMIT_TX_VBYTES: u64 = - 2 * OUTPUT_SIZE_VBYTES + TX_OVERHEAD_VBYTES + REVEAL_TX_VBYTES + TRANSFER_TX_VBYTES; pub const KB: u64 = 1024; pub const KB100: u64 = 100 * KB; @@ -65,7 +54,7 @@ pub mod retry { ) -> Result { let mut rs = Err(E::default()); for i in 0..RPC_RETRY_TIMES { - log!(INFO, "[evm route]request rpc request times: {}", i + 1); + log!(INFO, "request rpc request times: {}", i + 1); let call_res = call_rpc(params.clone()).await; if call_res.is_ok() { rs = call_res; @@ -74,7 +63,7 @@ pub mod retry { let err = call_res.err().unwrap(); log!( ERROR, - "[evm route]call rpc error: {}", + "call rpc error: {}", err.clone().to_string() ); rs = Err(err); diff --git a/customs/doge/src/management.rs b/customs/doge/src/management.rs index 5a9ae4a8..6bd2c55e 100644 --- a/customs/doge/src/management.rs +++ b/customs/doge/src/management.rs @@ -60,25 +60,4 @@ pub async fn ecdsa_public_key( public_key: response.public_key, chain_code: response.chain_code, }) -} - -// pub async fn sign_with( -// key_name: &str, -// derivation_path: Vec>, -// message_hash: [u8; 32], -// ) -> Result, String> { -// let args = ecdsa::SignWithEcdsaArgument { -// message_hash: message_hash.to_vec(), -// derivation_path, -// key_id: ecdsa::EcdsaKeyId { -// curve: ecdsa::EcdsaCurve::Secp256k1, -// name: key_name.to_string(), -// }, -// }; - -// let (response,): (ecdsa::SignWithEcdsaResponse,) = ecdsa::sign_with_ecdsa(args) -// .await -// .map_err(|err| format!("sign_with_ecdsa failed {:?}", err))?; - -// Ok(response.signature) -// } \ No newline at end of file +} \ No newline at end of file diff --git a/customs/doge/src/service.rs b/customs/doge/src/service.rs index 7471757f..87e5f821 100644 --- a/customs/doge/src/service.rs +++ b/customs/doge/src/service.rs @@ -6,7 +6,7 @@ use crate::generate_ticket::{GenerateTicketArgs, GenerateTicketWithTxidArgs}; use crate::state::{mutate_state, read_state, replace_state, DogeState, StateProfile}; use crate::tasks::start_tasks; use crate::types::{ - Destination, LockTicketRequest, ReleaseTokenStatus, RpcConfig, TokenResp, + Destination, LockTicketRequest, MultiRpcConfig, ReleaseTokenStatus, RpcConfig, TokenResp }; use candid::{CandidType, Deserialize, Principal}; use ic_canister_log::log; @@ -35,102 +35,6 @@ fn post_upgrade() { start_tasks(); } -#[update(guard = "is_admin")] -pub fn tmp_fix() { - let v = vec![ - ( - 0, - SendTicketResult { - txid: crate::types::Txid::from_str("a2892cb2095e0446416a47c55ec7878aadf111875f6ec6b0baffc9c4dd618e21").unwrap(), - success: true, - time_at: 1_735_704_485_582_704_364, - }, - ), - ( - 1, - SendTicketResult { - txid: crate::types::Txid::from_str("d741f87bc99cae542997377069db0b8d25a2205aaf6ff344a682d606923d4117").unwrap(), - success: true, - time_at: 1_736_152_340_017_781_767, - }, - ), - ( - 2, - SendTicketResult { - txid: crate::types::Txid::from_str("62b68ffd3532d32225b9c3ce96a46af31ab9103918a3f3f80e5b86fa5fe62b85").unwrap(), - success: true, - time_at: 1_736_152_528_438_327_721, - }, - ), - ( - 3, - SendTicketResult { - txid: crate::types::Txid::from_str("02d4d2f94d2ded95bcba86ad51c5529225c6d96e8f62c77f7d8b25683ed14a4a").unwrap(), - success: true, - time_at: 1_736_158_610_935_813_349, - }, - ), - ( - 4, - SendTicketResult { - txid: crate::types::Txid::from_str("aebf2b3bb6e5c5773ce66af5645dba555bf40c35b73daa2edbf0ef4e5d2ab843").unwrap(), - success: true, - time_at: 1_736_216_381_913_371_532, - }, - ), - ( - 5, - SendTicketResult { - txid: crate::types::Txid::from_str("ec75e54b76befd0e4d6418704c2827e0bef3ed37a2d1daad7af6597f02c0332a").unwrap(), - success: true, - time_at: 1_736_246_946_415_382_518, - }, - ), - ( - 6, - SendTicketResult { - txid: crate::types::Txid::from_str("5fc3a7a2fc2f9fca6b53b191765d8219a63d9a561742ec508e233ee350cccabf").unwrap(), - success: true, - time_at: 1_736_251_053_091_159_392, - }, - ), - ]; - mutate_state( - |s| { - for e in v { - s.finalized_unlock_ticket_results_map.insert(e.0, e.1); - } - } - ); -} - -// #[update(guard = "is_admin")] -// pub fn save_tx_in_memory() { -// let request: Vec = mutate_state( -// |s| s.finalized_lock_ticket_requests.iter().map(|(txid, req)| { -// req.clone() -// }).collect() -// ); - -// let results: Vec = mutate_state( -// |s| s.finalized_unlock_ticket_results_map.iter().map(|(txid, req)| { -// req.clone() -// }).collect() -// ); - -// for req in request { -// mutate_state(|s| { -// s.finalized_lock_ticket_requests_map.insert(req.txid.clone(), req); -// }); -// } - -// for res in results { -// mutate_state(|s| { -// s.finalized_unlock_ticket_results_map.insert(res.txid.clone(), res); -// }); -// } -// } - #[query] pub fn get_finalized_lock_ticket_txids() -> Vec { read_state(|s| { @@ -151,60 +55,6 @@ pub fn get_finalized_unlock_ticket_results() -> Vec { }) } -// #[update(guard = "is_admin")] -// fn restore_utxo() { -// let change_destination = Destination::change_address(); -// // let change_address = read_state(|s| s.get_address(Destination::fee_payment_address()).0); - -// // let fee_payment_destination = Destination::fee_payment_address(); -// // let fee_payment_address = read_state(|s| s.get_address(Destination::fee_payment_address()).0); - -// let mut change_utxo = vec![ -// (Utxo { -// txid: crate::types::Txid::from_str("02d4d2f94d2ded95bcba86ad51c5529225c6d96e8f62c77f7d8b25683ed14a4a").unwrap(), -// vout: 1, -// value: 4 * DOGE_AMOUNT, -// }, change_destination.clone()), -// (Utxo { -// txid: crate::types::Txid::from_str("472eca0781c37646802481733535ab35b0d30755aad1f849877104b69807172d").unwrap(), -// vout: 1, -// value: DOGE_AMOUNT / 10, -// }, change_destination.clone()), -// (Utxo { -// txid: crate::types::Txid::from_str("5c7931d648bc3700bda7e24b6d39b59654f7778b6faf1596c71a563f423cd2d3").unwrap(), -// vout: 1, -// value: DOGE_AMOUNT, -// }, change_destination.clone()), -// ]; - -// let osmosis_destination = Destination::new("osmosis-1".to_string(), "osmo1uqwp92j0a2xdntfxfjrs4a8gmpvh5elre07l3s".to_string(), None); -// let mut osmosis_deposit = vec![ -// (Utxo { -// txid: crate::types::Txid::from_str("14013504a0f52b898a434bb08992e14cd3a864dfb61acff758b09590c83a1a3d").unwrap(), -// vout: 0, -// value: DOGE_AMOUNT, -// }, osmosis_destination.clone()), -// (Utxo { -// txid: crate::types::Txid::from_str("6794f9c15a9c1173fd615f7bd2aa28a95014eca71c43d3e0bcabdaaea46beee8").unwrap(), -// vout: 0, -// value: 2 * DOGE_AMOUNT, -// }, osmosis_destination.clone()), -// ]; - -// let mut payment_utxo = vec![ -// Utxo { -// txid: crate::types::Txid::from_str("f4d1f706e829d029045a2b3a41b1d31c0dc57e0b01376b2ab2207156a7e37380").unwrap(), -// vout: 0, -// value: 10 * DOGE_AMOUNT } -// ]; - -// mutate_state(|s| { -// s.deposited_utxo.append(&mut change_utxo); -// s.deposited_utxo.append(&mut osmosis_deposit); -// s.fee_payment_utxo.append(&mut payment_utxo); -// }); -// } - #[query(hidden = true)] fn http_request(req: HttpRequest) -> HttpResponse { if ic_cdk::api::data_certificate().is_none() { @@ -323,6 +173,15 @@ pub async fn set_default_doge_rpc_config(url: String, api_key: Option) { }); } +#[update(guard = "is_admin")] +pub async fn set_multi_rpc_config( + multi_rpc_config: MultiRpcConfig +) { + mutate_state(|s| { + s.multi_rpc_config = multi_rpc_config; + }); +} + #[query(hidden = true)] fn transform(raw: TransformArgs) -> http_request::HttpResponse { http_request::HttpResponse { @@ -352,6 +211,12 @@ pub async fn resend_unlock_ticket(seq: Seq, fee_rate: Option) -> Result Result { +// let doge_rpc = crate::doge::rpc::DogeRpc::from(rpc_config); +// doge_rpc.get_raw_transaction(txid.as_str()).await.map(|r| format!("{:?}", r)) +// } + #[query] fn get_token_list() -> Vec { read_state(|s| s.tokens.values().map(|t| t.clone().into()).collect()) @@ -371,6 +236,7 @@ pub struct InitArgs { pub chain_id: String, // pub indexer_principal: Principal, pub fee_token: String, + pub default_doge_rpc_config: RpcConfig, } fn is_admin() -> Result<(), String> { diff --git a/customs/doge/src/state.rs b/customs/doge/src/state.rs index 178359ed..b02538e9 100644 --- a/customs/doge/src/state.rs +++ b/customs/doge/src/state.rs @@ -2,7 +2,6 @@ use std::cell::RefCell; use std::collections::BTreeMap; use std::time::Duration; -// use bitcoin::Address; use candid::{CandidType, Principal}; use ic_canister_log::log; use ic_ic00_types::DerivationPath; @@ -52,7 +51,6 @@ pub struct DogeState { #[serde(skip, default = "crate::stable_memory::init_unlock_tickets_queue")] pub tickets_queue: StableBTreeMap, pub flight_unlock_ticket_map: BTreeMap, - // pub finalized_unlock_ticket_map: BTreeMap, pub ticket_id_seq_indexer: BTreeMap, #[serde(skip, default = "crate::stable_memory::init_unlock_ticket_results")] @@ -86,8 +84,6 @@ pub struct DogeState { #[serde(default)] pub multi_rpc_config: MultiRpcConfig, - // #[serde(default)] - // pub fee_payment_address: String, #[serde(skip, default = "crate::stable_memory::init_deposit_fee_tx_set")] pub deposit_fee_tx_set: StableBTreeMap, #[serde(default)] @@ -167,7 +163,6 @@ impl DogeState { doge_chain: MAIN_NET_DOGE, hub_principal: args.hub_principal, chain_id: args.chain_id, - // reveal_utxo_index: Default::default(), tokens: Default::default(), counterparties: Default::default(), chain_state: ChainState::Active, @@ -181,21 +176,17 @@ impl DogeState { directives_queue: StableBTreeMap::init(crate::stable_memory::get_directives_memory()), is_timer_running: Default::default(), pending_lock_ticket_requests: Default::default(), - // finalized_lock_ticket_requests: Default::default(), - // deposit_addr_utxo: vec![], fee_collector: "".to_string(), fee_token_factor: None, min_confirmations: 4, min_deposit_amount: 0, - // finalized_unlock_ticket_map: Default::default(), ticket_id_seq_indexer: Default::default(), target_chain_factor: Default::default(), fee_token: args.fee_token, deposited_utxo: vec![], tatum_api_config: RpcConfig::default(), - default_doge_rpc_config: RpcConfig::default(), + default_doge_rpc_config: args.default_doge_rpc_config, multi_rpc_config: MultiRpcConfig::default(), - // fee_payment_address: String::default(), deposit_fee_tx_set: StableBTreeMap::init(crate::stable_memory::get_deposit_tx_memory()), fee_payment_utxo: vec![], finalized_unlock_ticket_results_map: StableBTreeMap::init(crate::stable_memory::get_unlock_ticket_results_memory()), @@ -258,15 +249,6 @@ impl DogeState { } else { return GenTicketStatus::Unknown; } - - // match self - // .finalized_lock_ticket_requests - // .iter() - // .find(|req| req.1.txid == tx_id.clone().into()) - // { - // Some(req) => GenTicketStatus::Finalized(req.1.clone()), - // None => GenTicketStatus::Unknown, - // } } pub fn unlock_tx_status(&self, ticket_id: &TicketId) -> ReleaseTokenStatus { @@ -308,8 +290,6 @@ impl DogeState { pub fn save_utxo(&mut self, ticket_request: LockTicketRequest) -> Result<(), CustomsError> { let transaction: Transaction = deserialize_hex(&ticket_request.transaction_hex).map_err(wrap_to_customs_error)?; let destination = Destination::new(ticket_request.target_chain_id.clone(), ticket_request.receiver.clone(), None); - // let first_tx_out = transaction.output.first().cloned().ok_or(CustomsError::CustomError("transaction output is empty".to_string()))?; - // let receiver = first_tx_out.get_mainnet_address().ok_or(CustomsError::CustomError("first output receiver address is empty".to_string()))?; let destination_address = self.get_address(destination.clone())?.0.to_string(); for (i, tx_out) in transaction.output.iter().enumerate() { if let Some(tx_out_address) = tx_out.get_mainnet_address() { @@ -340,12 +320,6 @@ pub async fn init_ecdsa_public_key() -> Result { .unwrap_or_else(|e| ic_cdk::trap(&format!("failed to retrieve ECDSA public key: {e}"))); mutate_state(|s| { s.ecdsa_public_key = Some(pub_key.clone()); - // s.deposit_pubkey = Some(bytes_to_hex(pub_key.public_key.as_slice())); - // let doge_main_addr = script::p2pkh_address(&pub_key.public_key, s.chain_params())?; - // let address = pubkey_to_doge_address(&pub_key.clone()); - // let deposit_addr = doge_main_addr.to_string(); - // s.deposit_addr = Some(deposit_addr); - Ok(()) })?; Ok(pub_key) diff --git a/customs/doge/src/types.rs b/customs/doge/src/types.rs index 116f16be..5c314b73 100644 --- a/customs/doge/src/types.rs +++ b/customs/doge/src/types.rs @@ -2,23 +2,28 @@ use std::borrow::Cow; use bitcoin::consensus::{Decodable, Encodable, ReadExt}; use candid::{CandidType, Deserialize, Nat}; -use ic_cdk::api::management_canister::http_request::{http_request, CanisterHttpRequestArgument, HttpResponse, TransformContext}; +use ic_cdk::api::management_canister::http_request::{ + http_request, CanisterHttpRequestArgument, HttpResponse, TransformContext, +}; use ic_stable_structures::{storable::Bound, Storable}; -use omnity_types::ic_log::{INFO, WARNING}; +use omnity_types::ic_log::{ERROR, INFO, WARNING}; use serde::Serialize; // use std::str::FromStr; use hex::prelude::*; -use omnity_types::{Token, TokenId}; use ic_canister_log::log; +use omnity_types::{Token, TokenId}; -use crate::errors::CustomsError; -use serde_bytes::ByteArray; +use crate::{ + doge::{rpc::get_raw_transaction_by_rpc, transaction::Transaction}, + errors::CustomsError, +}; use bitcoin::hashes::{sha256d, Hash}; +use serde_bytes::ByteArray; pub type ECDSAPublicKey = ic_cdk::api::management_canister::ecdsa::EcdsaPublicKeyResponse; -#[derive(CandidType, PartialEq, Eq, Clone, Default, Deserialize, Serialize, PartialOrd, Ord)] +#[derive(CandidType, PartialEq, Eq, Clone, Default, Deserialize, Serialize, PartialOrd, Ord)] pub struct Txid(pub ByteArray<32>); impl std::str::FromStr for Txid { @@ -31,7 +36,6 @@ impl std::str::FromStr for Txid { } impl Storable for Txid { - fn to_bytes(&self) -> std::borrow::Cow<[u8]> { Cow::Owned(bincode::serialize(self).unwrap()) } @@ -95,19 +99,15 @@ impl Destination { } } - pub fn change_address()->Destination{ - Destination::new( - String::default(), - String::default(), - Option::None - ) + pub fn change_address() -> Destination { + Destination::new(String::default(), String::default(), Option::None) } - pub fn fee_payment_address()->Destination{ + pub fn fee_payment_address() -> Destination { Destination::new( - "fee_payment".to_string(), - "fee_payment".to_string(), - Option::None + "fee_payment".to_string(), + "fee_payment".to_string(), + Option::None, ) } @@ -182,7 +182,7 @@ pub struct LockTicketRequest { pub amount: String, pub txid: Txid, pub received_at: u64, - pub transaction_hex: String, + pub transaction_hex: String, } impl Storable for LockTicketRequest { @@ -197,59 +197,6 @@ impl Storable for LockTicketRequest { const BOUND: Bound = Bound::Unbounded; } -// impl Storable for LockTicketRequest { - -// } - -// /// Unspent transaction output to be used as input of a transaction -// #[derive(CandidType, Debug, Clone, Serialize, Deserialize)] -// pub struct UtxoArgs { -// pub id: String, -// pub index: u32, -// pub amount: u64, -// } - -// impl From for Utxo { -// fn from(value: UtxoArgs) -> Self { -// Utxo { -// id: bitcoin::Txid::from_str(&value.id).unwrap(), -// index: value.index, -// amount: Amount::from_sat(value.amount), -// } -// } -// } - -// #[derive(CandidType, Debug, Clone, Serialize, Deserialize)] -// pub struct FeesArgs { -// pub commit_fee: u64, -// pub reveal_fee: u64, -// pub spend_fee: u64, -// } - -// impl From for Fees { -// fn from(value: FeesArgs) -> Self { -// Fees { -// commit_fee: Amount::from_sat(value.commit_fee), -// reveal_fee: Amount::from_sat(value.reveal_fee), -// spend_fee: Amount::from_sat(value.spend_fee), -// } -// } -// } - -// pub fn create_query_brc20_transfer_args( -// gen_ticket_request: LockTicketRequest, -// deposit_addr: String, -// ticker_decimals: u8, -// ) -> QueryBrc20TransferArgs { -// QueryBrc20TransferArgs { -// tx_id: gen_ticket_request.txid.to_string(), -// ticker: gen_ticket_request.ticker, -// to_addr: deposit_addr, -// amt: gen_ticket_request.amount, -// decimals: ticker_decimals, -// } -// } - pub fn err_string(err: impl std::fmt::Display) -> String { err.to_string() } @@ -279,32 +226,30 @@ pub fn deserialize_hex(hex: &str) -> Result { pub async fn http_request_with_retry( mut request: CanisterHttpRequestArgument, ) -> Result { - request.transform = Some(TransformContext::from_name( - "transform".to_owned(), - vec![], - )); + request.transform = Some(TransformContext::from_name("transform".to_owned(), vec![])); - // let cycles = http_request_required_cycles(&request, 13); for _ in 0..3 { - let response = http_request(request.clone(), 60_000_000_000) - .await - .map_err(|(code, message)| { - CustomsError::HttpOutCallError( - format!("{:?}", code).to_string(), - message, - format!("{:?}", request), - ) - })? - .0; - - log!(INFO, "httpoutcall request:{:?} response: {:?}",request, response); + let response = match http_request(request.clone(), 60_000_000_000).await { + Ok((response,)) => response, + Err(e) => { + log!(ERROR, "http request error, request: {:?} \n, error {:?}",request, e); + continue; + } + }; + + log!( + INFO, + "httpoutcall request:{:?} response: {:?}", + request, + response + ); if response.status == Nat::from(200u64) { return Ok(response); } else { log!(WARNING, "http request error: {:?}", response); } } - Err(CustomsError::HttpOutExceedLimit) + Err(CustomsError::HttpOutExceedRetryLimit) } #[derive(CandidType, Clone, Debug, Default, Deserialize, Serialize)] @@ -342,4 +287,64 @@ impl From for crate::doge::rpc::DogeRpc { pub struct MultiRpcConfig { pub rpc_list: Vec, pub minimum_response_count: u32, -} \ No newline at end of file +} + +impl MultiRpcConfig { + pub fn check_config_valid(&self) -> Result<(), CustomsError> { + if self.minimum_response_count == 0 { + return Err(CustomsError::CustomError( + "minimum_response_count should be greater than 0".to_string(), + )); + } + if self.rpc_list.len() < self.minimum_response_count as usize { + return Err(CustomsError::CustomError( + "rpc_list length should be greater than minimum_response_count".to_string(), + )); + } + Ok(()) + } + + pub async fn get_raw_transaction(&self, txid: &str) -> Result { + self.check_config_valid()?; + + let mut fut = Vec::with_capacity(self.rpc_list.len()); + for rpc_config in self.rpc_list.iter() { + // let doge_rpc = DogeRpc::from(rpc_url.clone()); + fut.push(get_raw_transaction_by_rpc(txid, rpc_config.clone())); + } + + let res = futures::future::join_all(fut).await; + + self.valid_and_get_transaction(res) + } + + fn valid_and_get_transaction( + &self, + res: Vec>, + ) -> Result { + let success_res = res + .iter() + .filter_map(|r| r.as_ref().ok()) + .collect::>(); + self.check_config_valid()?; + if success_res.len() < self.minimum_response_count as usize { + return Err(CustomsError::CustomError(format!( + "Success res count({}) less than minimum_response_count: {}", + success_res.len(), + self.minimum_response_count + ))); + } + + for i in 1..success_res.len() { + if success_res[i] != success_res[i - 1] { + return Err(CustomsError::CustomError(format!( + "Success res not equal: {:?} != {:?}", + success_res[i], + success_res[i - 1] + ))); + } + } + + Ok(success_res[0].clone()) + } +}