diff --git a/customs/bitcoin/bitcoin_customs.did b/customs/bitcoin/bitcoin_customs.did index 51d9a7ce..d2de5fba 100644 --- a/customs/bitcoin/bitcoin_customs.did +++ b/customs/bitcoin/bitcoin_customs.did @@ -54,6 +54,7 @@ type Event = variant { destination : Destination; utxos : vec Utxo; }; + added_runes_oracle : record { "principal" : principal }; removed_ticket_request : record { txid : blob }; sent_transaction : record { fee : opt nat64; diff --git a/customs/bitcoin/src/hub.rs b/customs/bitcoin/src/hub.rs index 5e62e4a0..34d2636b 100644 --- a/customs/bitcoin/src/hub.rs +++ b/customs/bitcoin/src/hub.rs @@ -1,6 +1,7 @@ use crate::call_error::{CallError, Reason}; use candid::Principal; use omnity_types::Directive; +use omnity_types::TicketId; use omnity_types::Topic; use omnity_types::{self, ChainId, Seq, Ticket}; @@ -70,3 +71,22 @@ pub async fn query_directives( })?; Ok(data) } + +pub async fn batch_update_tx_hash( + hub_principal: Principal, + ticket_ids: Vec, + tx_hash: String, +) -> Result<(), CallError> { + let resp: (Result<(), omnity_types::Error>,) = + ic_cdk::api::call::call(hub_principal, "batch_update_tx_hash", (ticket_ids, tx_hash)) + .await + .map_err(|(code, message)| CallError { + method: "batch_update_tx_hash".to_string(), + reason: Reason::from_reject(code, message), + })?; + resp.0.map_err(|err| CallError { + method: "batch_update_tx_hash".to_string(), + reason: Reason::CanisterError(err.to_string()), + })?; + Ok(()) +} diff --git a/customs/bitcoin/src/lib.rs b/customs/bitcoin/src/lib.rs index b3adfb4c..f55090d1 100644 --- a/customs/bitcoin/src/lib.rs +++ b/customs/bitcoin/src/lib.rs @@ -625,7 +625,12 @@ async fn finalize_requests() { } }); + for tx in &confirmed_transactions { + update_tx_hash_to_hub(tx).await; + } + for tx in &unstuck_transactions { + update_tx_hash_to_hub(tx).await; state::read_state(|s| { if let Some(replacement_txid) = s.find_last_replacement_tx(&tx.txid) { maybe_finalized_transactions.remove(replacement_txid); @@ -826,6 +831,16 @@ async fn finalize_requests() { } } +async fn update_tx_hash_to_hub(tx: &SubmittedBtcTransactionV2) { + let hub_principal = read_state(|s| s.hub_principal); + let ticket_ids = tx.requests.iter().map(|r| r.ticket_id.clone()).collect(); + if let Err(err) = + hub::batch_update_tx_hash(hub_principal, ticket_ids, tx.txid.to_string()).await + { + log!(P0, "failed to update tx hash to hub: {}", err) + } +} + fn new_build_tx_req(requests: Vec) -> BuildTxReq { if requests[0].action == TxAction::Mint { BuildTxReq::MintTxReq(requests[0].address.clone()) diff --git a/hub/src/service.rs b/hub/src/service.rs index dca494df..3d9ab750 100644 --- a/hub/src/service.rs +++ b/hub/src/service.rs @@ -193,6 +193,15 @@ pub async fn update_tx_hash(ticket_id: TicketId, tx_hash: String) -> Result<(), with_state_mut(|hub_state| hub_state.update_tx_hash(ticket_id, tx_hash)) } +#[update(guard = "auth_update")] +pub async fn batch_update_tx_hash(ticket_ids: Vec, tx_hash: String) -> Result<(), Error> { + debug!("batch update tx({:?}) hash: {:?}", ticket_ids, tx_hash); + for ticket_id in ticket_ids { + with_state_mut(|hub_state| hub_state.update_tx_hash(ticket_id, tx_hash.clone()))?; + } + Ok(()) +} + #[query(guard = "auth_query")] pub async fn query_tx_hash(ticket_id: TicketId) -> Result { with_state(|hub_state| hub_state.get_tx_hash(&ticket_id)) diff --git a/mock/hub/src/main.rs b/mock/hub/src/main.rs index 96bd9827..f8657970 100644 --- a/mock/hub/src/main.rs +++ b/mock/hub/src/main.rs @@ -1,7 +1,7 @@ use candid::candid_method; use ic_cdk::query; use ic_cdk_macros::{init, update}; -use omnity_types::{self, ChainId, Directive, Seq, Ticket, Topic}; +use omnity_types::{self, ChainId, Directive, Seq, Ticket, TicketId, Topic}; use std::{cell::RefCell, collections::BTreeMap}; fn main() {} @@ -117,5 +117,17 @@ pub async fn push_directives(directives: Vec) -> Result<(), omnity_ty }) } +#[candid_method(update)] +#[update] +pub async fn update_tx_hash(_: TicketId, _: String) -> Result<(), omnity_types::Error> { + Ok(()) +} + +#[candid_method(update)] +#[update] +pub async fn batch_update_tx_hash(_: Vec, _: String) -> Result<(), omnity_types::Error> { + Ok(()) +} + // Enable Candid export ic_cdk::export_candid!(); diff --git a/route/evm/src/evm_scan.rs b/route/evm/src/evm_scan.rs index 26c64182..dcc8aeeb 100644 --- a/route/evm/src/evm_scan.rs +++ b/route/evm/src/evm_scan.rs @@ -1,6 +1,6 @@ use anyhow::anyhow; -use cketh_common::{eth_rpc::LogEntry, eth_rpc_client::RpcConfig, numeric::BlockNumber}; use cketh_common::eth_rpc::Hash; +use cketh_common::{eth_rpc::LogEntry, eth_rpc_client::RpcConfig, numeric::BlockNumber}; use ethers_core::abi::RawLog; use ethers_core::utils::hex::ToHexExt; use evm_rpc::{ @@ -10,12 +10,15 @@ use evm_rpc::{ use itertools::Itertools; use log::{error, info}; -use crate::*; use crate::const_args::{MAX_SCAN_BLOCKS, SCAN_EVM_CYCLES, SCAN_EVM_TASK_NAME}; -use crate::contract_types::{AbiSignature, DecodeLog, DirectiveExecuted, RunesMintRequested, TokenAdded, TokenBurned, TokenMinted, TokenTransportRequested}; +use crate::contract_types::{ + AbiSignature, DecodeLog, DirectiveExecuted, RunesMintRequested, TokenAdded, TokenBurned, + TokenMinted, TokenTransportRequested, +}; use crate::eth_common::get_evm_finalized_height; use crate::state::{mutate_state, read_state}; use crate::types::{ChainState, Directive, Ticket}; +use crate::*; pub fn scan_evm_task() { ic_cdk::spawn(async { @@ -66,9 +69,12 @@ pub async fn handle_port_events() -> anyhow::Result<()> { }); //rewrite tx to hub let hub_principal = read_state(|s| s.hub_principal); - match hub::rewrite_ticket_mint_hash(hub_principal, token_mint.ticket_id, tx_hash).await { + match hub::update_tx_hash(hub_principal, token_mint.ticket_id, tx_hash).await { Err(err) => { - log::error!("[rewrite tx_hash] failed to write mint tx hash, reason: {}", err); + log::error!( + "[rewrite tx_hash] failed to write mint tx hash, reason: {}", + err + ); } _ => {} } @@ -156,7 +162,7 @@ pub async fn handle_runes_mint( event: RunesMintRequested, ) -> anyhow::Result<()> { let ticket = Ticket::from_runes_mint_event(log_entry, event); - ic_cdk::call(crate::state::hub_addr(), "send_ticket", (ticket, )) + ic_cdk::call(crate::state::hub_addr(), "send_ticket", (ticket,)) .await .map_err(|(_, s)| Error::HubError(s))?; Ok(()) diff --git a/route/evm/src/hub.rs b/route/evm/src/hub.rs index 1de0654a..d9c8dd1a 100644 --- a/route/evm/src/hub.rs +++ b/route/evm/src/hub.rs @@ -1,9 +1,9 @@ use candid::Principal; use crate::call_error::{CallError, Reason}; +use crate::types::Topic; use crate::types::{ChainId, Directive, TicketId}; use crate::types::{Seq, Ticket}; -use crate::types::Topic; pub async fn send_ticket(hub_principal: Principal, ticket: Ticket) -> Result<(), CallError> { // TODO determine how many cycle it will cost. @@ -70,28 +70,21 @@ pub async fn query_directives( Ok(data) } -pub async fn rewrite_ticket_mint_hash( +pub async fn update_tx_hash( hub_principal: Principal, ticket_id: TicketId, mint_tx_hash: String, ) -> Result<(), CallError> { - let resp: (Result<(), crate::types::Error>, ) = ic_cdk::api::call::call( - hub_principal, - "update_tx_hash", - ( - ticket_id, - mint_tx_hash - ), - ) - .await - .map_err(|(code, message)| CallError { - method: "update_tx_hash".to_string(), - reason: Reason::from_reject(code, message), - })?; + let resp: (Result<(), crate::types::Error>,) = + ic_cdk::api::call::call(hub_principal, "update_tx_hash", (ticket_id, mint_tx_hash)) + .await + .map_err(|(code, message)| CallError { + method: "update_tx_hash".to_string(), + reason: Reason::from_reject(code, message), + })?; resp.0.map_err(|err| CallError { method: "update_tx_hash".to_string(), reason: Reason::CanisterError(err.to_string()), })?; Ok(()) } - diff --git a/route/icp/src/hub.rs b/route/icp/src/hub.rs index 5e62e4a0..83fe0394 100644 --- a/route/icp/src/hub.rs +++ b/route/icp/src/hub.rs @@ -1,6 +1,7 @@ use crate::call_error::{CallError, Reason}; use candid::Principal; use omnity_types::Directive; +use omnity_types::TicketId; use omnity_types::Topic; use omnity_types::{self, ChainId, Seq, Ticket}; @@ -70,3 +71,22 @@ pub async fn query_directives( })?; Ok(data) } + +pub async fn update_tx_hash( + hub_principal: Principal, + ticket_id: TicketId, + mint_tx_hash: String, +) -> Result<(), CallError> { + let resp: (Result<(), omnity_types::Error>,) = + ic_cdk::api::call::call(hub_principal, "update_tx_hash", (ticket_id, mint_tx_hash)) + .await + .map_err(|(code, message)| CallError { + method: "update_tx_hash".to_string(), + reason: Reason::from_reject(code, message), + })?; + resp.0.map_err(|err| CallError { + method: "update_tx_hash".to_string(), + reason: Reason::CanisterError(err.to_string()), + })?; + Ok(()) +} diff --git a/route/icp/src/updates/mint_token.rs b/route/icp/src/updates/mint_token.rs index 49c614e9..fb9177ca 100644 --- a/route/icp/src/updates/mint_token.rs +++ b/route/icp/src/updates/mint_token.rs @@ -1,4 +1,4 @@ -use crate::state::{audit, mutate_state, read_state}; +use crate::{hub, state::{audit, mutate_state, read_state}}; use candid::{CandidType, Deserialize, Nat, Principal}; use icrc_ledger_client_cdk::{CdkRuntime, ICRC1Client}; use icrc_ledger_types::icrc1::{ @@ -49,6 +49,12 @@ pub async fn mint_token(req: &MintTokenRequest) -> Result<(), MintTokenError> { let block_index = mint(ledger_id, req.amount, req.receiver).await?; + let hub_principal = read_state(|s| s.hub_principal); + let mint_tx_hash = format!("{}_{}", ledger_id.to_string(), block_index); + if let Err(err) = hub::update_tx_hash(hub_principal, req.ticket_id.clone(), mint_tx_hash).await { + log::error!("failed to update tx hash after mint token:{}", err); + } + mutate_state(|s| audit::finalize_mint_token_req(s, req.ticket_id.clone(), block_index)); Ok(()) }