Skip to content

Commit

Permalink
Eprod 1003 use batched mint order processing in btc bridge (#164)
Browse files Browse the repository at this point in the history
  • Loading branch information
veeso authored Oct 2, 2024
1 parent 452264f commit 1bbeb19
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 92 deletions.
37 changes: 10 additions & 27 deletions src/bridge-did/src/operations/btc.rs
Original file line number Diff line number Diff line change
@@ -1,40 +1,23 @@
use candid::CandidType;
use did::H160;
use did::{H160, H256};
use serde::{Deserialize, Serialize};

use crate::events::{BurntEventData, MintedEventData};
use crate::order::SignedMintOrder;
use crate::order::{MintOrder, SignedOrders};

#[derive(Debug, Serialize, Deserialize, CandidType, Clone)]
pub enum BtcBridgeOp {
// Deposit operations:
UpdateCkBtcBalance {
eth_address: H160,
},
CollectCkBtcBalance {
eth_address: H160,
},
TransferCkBtc {
eth_address: H160,
amount: u64,
},
CreateMintOrder {
eth_address: H160,
amount: u64,
},
MintErc20 {
eth_address: H160,
order: SignedMintOrder,
},
ConfirmErc20Mint {
order: SignedMintOrder,
eth_address: H160,
},
UpdateCkBtcBalance { eth_address: H160 },
CollectCkBtcBalance { eth_address: H160 },
TransferCkBtc { eth_address: H160, amount: u64 },
CreateMintOrder { eth_address: H160, amount: u64 },
SignMintOrder { order: MintOrder },
MintErc20 { order: SignedOrders },
ConfirmErc20Mint { order: SignedOrders, tx_id: H256 },
Erc20MintConfirmed(MintedEventData),

// Withdraw operations:
WithdrawBtc(BurntEventData),
BtcWithdrawConfirmed {
eth_address: H160,
},
BtcWithdrawConfirmed { eth_address: H160 },
}
44 changes: 37 additions & 7 deletions src/btc-bridge/src/canister.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ mod inspect;
use std::cell::RefCell;
use std::rc::Rc;

use bridge_canister::runtime::service::mint_tx::SendMintTxService;
use bridge_canister::runtime::service::sign_orders::SignMintOrdersService;
use bridge_canister::runtime::service::ServiceOrder;
use bridge_canister::runtime::state::config::ConfigStorage;
use bridge_canister::runtime::state::SharedConfig;
use bridge_canister::runtime::{BridgeRuntime, RuntimeState};
Expand All @@ -11,7 +14,7 @@ use bridge_did::error::BftResult;
use bridge_did::init::BtcBridgeConfig;
use bridge_did::op_id::OperationId;
use bridge_did::operation_log::Memo;
use bridge_did::order::SignedMintOrder;
use bridge_did::order::SignedOrders;
use bridge_utils::common::Pagination;
use candid::Principal;
use did::build::BuildData;
Expand All @@ -27,7 +30,10 @@ use ic_log::canister::{LogCanister, LogState};
use ic_metrics::{Metrics, MetricsStorage};
use ic_storage::IcStorage;

use crate::ops::BtcBridgeOpImpl;
use crate::ops::{
BtcBridgeOpImpl, BtcMintOrderHandler, BtcMintTxHandler, SEND_MINT_TX_SERVICE_ID,
SIGN_MINT_ORDER_SERVICE_ID,
};
use crate::state::{State, WrappedTokenConfig};

type SharedRuntime = Rc<RefCell<BridgeRuntime<BtcBridgeOpImpl>>>;
Expand Down Expand Up @@ -72,7 +78,7 @@ impl BtcBridge {
&self,
wallet_address: H160,
pagination: Option<Pagination>,
) -> Vec<(u32, SignedMintOrder)> {
) -> Vec<(u32, SignedOrders)> {
Self::token_mint_orders(wallet_address, pagination)
}

Expand All @@ -83,7 +89,7 @@ impl BtcBridge {
wallet_address: H160,
operation_id: u32,
pagination: Option<Pagination>,
) -> Option<SignedMintOrder> {
) -> Option<SignedOrders> {
Self::token_mint_orders(wallet_address, pagination)
.into_iter()
.find(|(nonce, _)| *nonce == operation_id)
Expand Down Expand Up @@ -140,7 +146,7 @@ impl BtcBridge {
fn token_mint_orders(
wallet_address: H160,
pagination: Option<Pagination>,
) -> Vec<(u32, SignedMintOrder)> {
) -> Vec<(u32, SignedOrders)> {
let offset = pagination.as_ref().map(|p| p.offset).unwrap_or(0);
let count = pagination.as_ref().map(|p| p.count).unwrap_or(usize::MAX);
get_runtime_state()
Expand Down Expand Up @@ -193,11 +199,35 @@ impl LogCanister for BtcBridge {
}
}

fn init_runtime() -> SharedRuntime {
let runtime = BridgeRuntime::default(ConfigStorage::get());
let state = runtime.state();

let sign_orders_handler = BtcMintOrderHandler::new(state.clone(), runtime.scheduler().clone());
let sign_mint_orders_service = Rc::new(SignMintOrdersService::new(sign_orders_handler));

let mint_tx_handler = BtcMintTxHandler::new(state.clone());
let mint_tx_service = Rc::new(SendMintTxService::new(mint_tx_handler));

let services = state.borrow().services.clone();
services.borrow_mut().add_service(
ServiceOrder::ConcurrentWithOperations,
SIGN_MINT_ORDER_SERVICE_ID,
sign_mint_orders_service,
);
services.borrow_mut().add_service(
ServiceOrder::ConcurrentWithOperations,
SEND_MINT_TX_SERVICE_ID,
mint_tx_service,
);

Rc::new(RefCell::new(runtime))
}

thread_local! {
pub static STATE: Rc<RefCell<State>> = Rc::default();

pub static RUNTIME: SharedRuntime =
Rc::new(RefCell::new(BridgeRuntime::default(ConfigStorage::get())));
pub static RUNTIME: SharedRuntime = init_runtime();
}

pub fn get_state() -> Rc<RefCell<State>> {
Expand Down
118 changes: 60 additions & 58 deletions src/btc-bridge/src/ops.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
mod mint_order_handler;
mod mint_tx_handler;

use std::cell::RefCell;

use bridge_canister::bridge::{Operation, OperationAction, OperationContext, OperationProgress};
use bridge_canister::runtime::service::ServiceId;
use bridge_canister::runtime::RuntimeState;
use bridge_did::error::{BftResult, Error};
use bridge_did::event_data::*;
use bridge_did::id256::Id256;
use bridge_did::op_id::OperationId;
use bridge_did::operations::BtcBridgeOp;
use bridge_did::order::{MintOrder, SignedMintOrder};
use bridge_did::order::{MintOrder, SignedOrders};
use bridge_did::reason::BtcDeposit;
use candid::{CandidType, Decode, Principal};
use did::H160;
Expand All @@ -20,6 +24,8 @@ use ic_task_scheduler::task::TaskOptions;
use num_traits::ToPrimitive;
use serde::{Deserialize, Serialize};

pub use self::mint_order_handler::BtcMintOrderHandler;
pub use self::mint_tx_handler::BtcMintTxHandler;
use crate::canister::{eth_address_to_subaccount, get_state};
use crate::ckbtc_client::{
CkBtcLedgerClient, CkBtcMinterClient, RetrieveBtcError, RetrieveBtcOk, UpdateBalanceError,
Expand All @@ -28,6 +34,9 @@ use crate::ckbtc_client::{
use crate::interface::{BtcBridgeError, BtcWithdrawError};
use crate::state::State;

pub const SIGN_MINT_ORDER_SERVICE_ID: ServiceId = 0;
pub const SEND_MINT_TX_SERVICE_ID: ServiceId = 1;

#[derive(Debug, Serialize, Deserialize, CandidType, Clone)]
pub struct BtcBridgeOpImpl(pub BtcBridgeOp);

Expand Down Expand Up @@ -80,18 +89,19 @@ impl Operation for BtcBridgeOpImpl {
amount,
} => {
log::debug!("CreateMintOrder: Eth address {eth_address}, amount {amount}");
let mint_order = Self::mint_erc20(ctx, &eth_address, id.nonce(), amount).await?;
let order = Self::mint_erc20(ctx, &eth_address, id.nonce(), amount).await?;

Ok(Self(BtcBridgeOp::MintErc20 {
order: mint_order,
eth_address,
}))
Ok(Self(BtcBridgeOp::SignMintOrder { order }))
}
BtcBridgeOp::SignMintOrder { order } => {
log::debug!("BtcBridgeOp::SignMintOrder {order:?}");

return Ok(OperationProgress::AddToService(SIGN_MINT_ORDER_SERVICE_ID));
}
BtcBridgeOp::MintErc20 { eth_address, order } => {
log::debug!("MintErc20: Eth address {eth_address}");
ctx.send_mint_transaction(&order).await?;
BtcBridgeOp::MintErc20 { order } => {
log::debug!("MintErc20: {order:?}");

Ok(Self(BtcBridgeOp::ConfirmErc20Mint { order, eth_address }))
return Ok(OperationProgress::AddToService(SEND_MINT_TX_SERVICE_ID));
}
BtcBridgeOp::ConfirmErc20Mint { .. } => Err(Error::FailedToProgress(
"ConfirmErc20Mint task should progress only on the Minted EVM event".into(),
Expand Down Expand Up @@ -121,6 +131,7 @@ impl Operation for BtcBridgeOpImpl {
BtcBridgeOp::CollectCkBtcBalance { .. } => false,
BtcBridgeOp::TransferCkBtc { .. } => false,
BtcBridgeOp::CreateMintOrder { .. } => false,
BtcBridgeOp::SignMintOrder { .. } => false,
BtcBridgeOp::MintErc20 { .. } => false,
BtcBridgeOp::ConfirmErc20Mint { .. } => false,
BtcBridgeOp::Erc20MintConfirmed { .. } => true,
Expand All @@ -134,9 +145,10 @@ impl Operation for BtcBridgeOpImpl {
BtcBridgeOp::BtcWithdrawConfirmed { eth_address } => eth_address.clone(),
BtcBridgeOp::CollectCkBtcBalance { eth_address } => eth_address.clone(),
BtcBridgeOp::CreateMintOrder { eth_address, .. } => eth_address.clone(),
BtcBridgeOp::ConfirmErc20Mint { eth_address, .. } => eth_address.clone(),
BtcBridgeOp::ConfirmErc20Mint { order, .. } => order.reader().get_recipient(),
BtcBridgeOp::Erc20MintConfirmed(MintedEventData { recipient, .. }) => recipient.clone(),
BtcBridgeOp::MintErc20 { eth_address, .. } => eth_address.clone(),
BtcBridgeOp::MintErc20 { order } => order.reader().get_recipient(),
BtcBridgeOp::SignMintOrder { order } => order.recipient.clone(),
BtcBridgeOp::TransferCkBtc { eth_address, .. } => eth_address.clone(),
BtcBridgeOp::UpdateCkBtcBalance { eth_address } => eth_address.clone(),
BtcBridgeOp::WithdrawBtc(BurntEventData { sender, .. }) => sender.clone(),
Expand All @@ -151,8 +163,9 @@ impl Operation for BtcBridgeOpImpl {
.with_backoff_policy(BackoffPolicy::Fixed { secs: 5 }),
),
BtcBridgeOp::CollectCkBtcBalance { .. }
| BtcBridgeOp::MintErc20 { .. }
| BtcBridgeOp::CreateMintOrder { .. }
| BtcBridgeOp::MintErc20 { .. }
| BtcBridgeOp::SignMintOrder { .. }
| BtcBridgeOp::TransferCkBtc { .. }
| BtcBridgeOp::WithdrawBtc(_) => Some(
TaskOptions::new()
Expand Down Expand Up @@ -224,14 +237,6 @@ impl Operation for BtcBridgeOpImpl {
}

impl BtcBridgeOpImpl {
pub fn get_signed_mint_order(&self) -> Option<SignedMintOrder> {
match &self.0 {
BtcBridgeOp::ConfirmErc20Mint { order, .. } => Some(*order),
BtcBridgeOp::MintErc20 { order, .. } => Some(*order),
_ => None,
}
}

async fn update_ckbtc_balance(ckbtc_minter: Principal, eth_address: &H160) -> BftResult<()> {
let self_id = ic::id();
let subaccount = eth_address_to_subaccount(eth_address);
Expand Down Expand Up @@ -360,7 +365,7 @@ impl BtcBridgeOpImpl {
eth_address: &H160,
nonce: u32,
amount: u64,
) -> BftResult<SignedMintOrder> {
) -> BftResult<MintOrder> {
let state = get_state();

log::debug!(
Expand Down Expand Up @@ -406,46 +411,35 @@ impl BtcBridgeOpImpl {
eth_address: H160,
amount: u64,
nonce: u32,
) -> BftResult<SignedMintOrder> {
) -> BftResult<MintOrder> {
log::trace!("preparing mint order");

let (signer, mint_order) = {
let state_ref = state.borrow();

let sender_chain_id = state_ref.btc_chain_id();
let sender = Id256::from_evm_address(&eth_address, sender_chain_id);
let src_token = (&state_ref.ck_btc_ledger()).into();

let recipient_chain_id = ctx.get_evm_params()?.chain_id;

let mint_order = MintOrder {
amount: amount.into(),
sender,
src_token,
recipient: eth_address,
dst_token: state_ref.token_address().clone(),
nonce,
sender_chain_id,
recipient_chain_id,
name: state_ref.token_name(),
symbol: state_ref.token_symbol(),
decimals: state_ref.decimals(),
approve_spender: Default::default(),
approve_amount: Default::default(),
fee_payer: H160::zero(),
};

let signer = ctx.get_signer()?;

(signer, mint_order)
let state_ref = state.borrow();

let sender_chain_id = state_ref.btc_chain_id();
let sender = Id256::from_evm_address(&eth_address, sender_chain_id);
let src_token = (&state_ref.ck_btc_ledger()).into();

let recipient_chain_id = ctx.get_evm_params()?.chain_id;

let mint_order = MintOrder {
amount: amount.into(),
sender,
src_token,
recipient: eth_address,
dst_token: state_ref.token_address().clone(),
nonce,
sender_chain_id,
recipient_chain_id,
name: state_ref.token_name(),
symbol: state_ref.token_symbol(),
decimals: state_ref.decimals(),
approve_spender: Default::default(),
approve_amount: Default::default(),
fee_payer: H160::zero(),
};

let signed_mint_order = mint_order
.encode_and_sign(&signer)
.await
.map_err(|err| BtcBridgeError::Sign(format!("{err:?}")))?;

Ok(signed_mint_order)
Ok(mint_order)
}

/// Get the withdrawal account for the ckbtc minter.
Expand Down Expand Up @@ -520,4 +514,12 @@ impl BtcBridgeOpImpl {

Ok(result)
}

pub fn get_signed_mint_order(&self) -> Option<SignedOrders> {
match &self.0 {
BtcBridgeOp::ConfirmErc20Mint { order, .. } => Some(order.clone()),
BtcBridgeOp::MintErc20 { order, .. } => Some(order.clone()),
_ => None,
}
}
}
Loading

0 comments on commit 1bbeb19

Please sign in to comment.