From 5c9dbac8936136a648fad41302ef2dc281ca6f92 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Thu, 12 Sep 2024 14:04:54 +0300 Subject: [PATCH] bch standalone activation via task manager --- mm2src/coins/utxo/bch.rs | 23 ++-- mm2src/coins_activation/src/context.rs | 4 +- mm2src/coins_activation/src/prelude.rs | 5 + .../utxo_activation/init_bch_activation.rs | 116 ++++++++++++++++++ .../src/utxo_activation/mod.rs | 2 + .../mm2_main/src/rpc/dispatcher/dispatcher.rs | 27 ++++ 6 files changed, 165 insertions(+), 12 deletions(-) create mode 100644 mm2src/coins_activation/src/utxo_activation/init_bch_activation.rs diff --git a/mm2src/coins/utxo/bch.rs b/mm2src/coins/utxo/bch.rs index bb5768e2b7..ce2ec726f0 100644 --- a/mm2src/coins/utxo/bch.rs +++ b/mm2src/coins/utxo/bch.rs @@ -45,8 +45,8 @@ pub type BchUnspentMap = HashMap; #[derive(Clone, Debug, Deserialize, Serialize)] pub struct BchActivationRequest { #[serde(default)] - allow_slp_unsafe_conf: bool, - bchd_urls: Vec, + pub allow_slp_unsafe_conf: bool, + pub bchd_urls: Vec, #[serde(flatten)] pub utxo_params: UtxoActivationParams, } @@ -162,6 +162,15 @@ impl From for IsSlpUtxoError { } impl BchCoin { + pub fn new(utxo_arc: UtxoArc, slp_addr_prefix: CashAddrPrefix, bchd_urls: Vec) -> Self { + BchCoin { + utxo_arc, + slp_addr_prefix, + bchd_urls, + slp_tokens_infos: Arc::new(Mutex::new(HashMap::new())), + } + } + pub fn slp_prefix(&self) -> &CashAddrPrefix { &self.slp_addr_prefix } pub fn slp_address(&self, address: &Address) -> Result { @@ -631,15 +640,7 @@ pub async fn bch_coin_with_policy( } let bchd_urls = params.bchd_urls; - let slp_tokens_infos = Arc::new(Mutex::new(HashMap::new())); - let constructor = { - move |utxo_arc| BchCoin { - utxo_arc, - slp_addr_prefix: slp_addr_prefix.clone(), - bchd_urls: bchd_urls.clone(), - slp_tokens_infos: slp_tokens_infos.clone(), - } - }; + let constructor = { move |utxo_arc| BchCoin::new(utxo_arc, slp_addr_prefix.clone(), bchd_urls.clone()) }; let coin = try_s!( UtxoArcBuilder::new(ctx, ticker, conf, ¶ms.utxo_params, priv_key_policy, constructor) diff --git a/mm2src/coins_activation/src/context.rs b/mm2src/coins_activation/src/context.rs index b26f24e3b6..d3fe4265cf 100644 --- a/mm2src/coins_activation/src/context.rs +++ b/mm2src/coins_activation/src/context.rs @@ -4,7 +4,7 @@ use crate::init_erc20_token_activation::Erc20TokenTaskManagerShared; use crate::lightning_activation::LightningTaskManagerShared; #[cfg(feature = "enable-sia")] use crate::sia_coin_activation::SiaCoinTaskManagerShared; -use crate::utxo_activation::{QtumTaskManagerShared, UtxoStandardTaskManagerShared}; +use crate::utxo_activation::{BchTaskManagerShared, QtumTaskManagerShared, UtxoStandardTaskManagerShared}; use crate::z_coin_activation::ZcoinTaskManagerShared; use mm2_core::mm_ctx::{from_ctx, MmArc}; use rpc_task::RpcTaskManager; @@ -12,6 +12,7 @@ use std::sync::Arc; pub struct CoinsActivationContext { pub(crate) init_utxo_standard_task_manager: UtxoStandardTaskManagerShared, + pub(crate) init_bch_task_manager: BchTaskManagerShared, pub(crate) init_qtum_task_manager: QtumTaskManagerShared, #[cfg(feature = "enable-sia")] pub(crate) init_sia_task_manager: SiaCoinTaskManagerShared, @@ -30,6 +31,7 @@ impl CoinsActivationContext { #[cfg(feature = "enable-sia")] init_sia_task_manager: RpcTaskManager::new_shared(ctx.event_stream_manager.clone()), init_utxo_standard_task_manager: RpcTaskManager::new_shared(ctx.event_stream_manager.clone()), + init_bch_task_manager: RpcTaskManager::new_shared(ctx.event_stream_manager.clone()), init_qtum_task_manager: RpcTaskManager::new_shared(ctx.event_stream_manager.clone()), init_z_coin_task_manager: RpcTaskManager::new_shared(ctx.event_stream_manager.clone()), init_eth_task_manager: RpcTaskManager::new_shared(ctx.event_stream_manager.clone()), diff --git a/mm2src/coins_activation/src/prelude.rs b/mm2src/coins_activation/src/prelude.rs index d000170fa3..0fd890fa64 100644 --- a/mm2src/coins_activation/src/prelude.rs +++ b/mm2src/coins_activation/src/prelude.rs @@ -1,5 +1,6 @@ #[cfg(feature = "enable-sia")] use coins::siacoin::SiaCoinActivationParams; +use coins::utxo::bch::BchActivationRequest; use coins::utxo::UtxoActivationParams; use coins::z_coin::ZcoinActivationParams; use coins::{coin_conf, CoinBalance, CoinProtocol, DerivationMethodResponse, MmCoinEnum}; @@ -22,6 +23,10 @@ impl TxHistory for UtxoActivationParams { fn tx_history(&self) -> bool { self.tx_history } } +impl TxHistory for BchActivationRequest { + fn tx_history(&self) -> bool { self.utxo_params.tx_history } +} + #[cfg(feature = "enable-sia")] impl TxHistory for SiaCoinActivationParams { fn tx_history(&self) -> bool { self.tx_history } diff --git a/mm2src/coins_activation/src/utxo_activation/init_bch_activation.rs b/mm2src/coins_activation/src/utxo_activation/init_bch_activation.rs new file mode 100644 index 0000000000..07574944ba --- /dev/null +++ b/mm2src/coins_activation/src/utxo_activation/init_bch_activation.rs @@ -0,0 +1,116 @@ +use crate::context::CoinsActivationContext; +use crate::prelude::TryFromCoinProtocol; +use crate::standalone_coin::{InitStandaloneCoinActivationOps, InitStandaloneCoinTaskHandleShared, + InitStandaloneCoinTaskManagerShared}; +use crate::utxo_activation::common_impl::{get_activation_result, priv_key_build_policy, + start_history_background_fetching}; +use crate::utxo_activation::init_utxo_standard_activation_error::InitUtxoStandardError; +use crate::utxo_activation::init_utxo_standard_statuses::{UtxoStandardAwaitingStatus, UtxoStandardInProgressStatus, + UtxoStandardUserAction}; +use crate::utxo_activation::utxo_standard_activation_result::UtxoStandardActivationResult; +use async_trait::async_trait; +use coins::my_tx_history_v2::TxHistoryStorage; +use coins::utxo::bch::CashAddrPrefix; +use coins::utxo::bch::{BchActivationRequest, BchCoin}; +use coins::utxo::utxo_builder::{UtxoArcBuilder, UtxoCoinBuilder}; +use coins::CoinProtocol; +use mm2_core::mm_ctx::MmArc; +use mm2_err_handle::prelude::*; +use mm2_metrics::MetricsArc; +use mm2_number::BigDecimal; +use serde_json::Value as Json; +use std::collections::HashMap; +use std::str::FromStr; + +pub type BchTaskManagerShared = InitStandaloneCoinTaskManagerShared; +pub type BchRpcTaskHandleShared = InitStandaloneCoinTaskHandleShared; + +#[derive(Clone)] +pub struct BchProtocolInfo { + slp_prefix: String, +} + +impl TryFromCoinProtocol for BchProtocolInfo { + fn try_from_coin_protocol(proto: CoinProtocol) -> Result> + where + Self: Sized, + { + match proto { + CoinProtocol::BCH { slp_prefix } => Ok(BchProtocolInfo { slp_prefix }), + protocol => MmError::err(protocol), + } + } +} + +#[async_trait] +impl InitStandaloneCoinActivationOps for BchCoin { + type ActivationRequest = BchActivationRequest; + type StandaloneProtocol = BchProtocolInfo; + type ActivationResult = UtxoStandardActivationResult; + type ActivationError = InitUtxoStandardError; + type InProgressStatus = UtxoStandardInProgressStatus; + type AwaitingStatus = UtxoStandardAwaitingStatus; + type UserAction = UtxoStandardUserAction; + + fn rpc_task_manager(activation_ctx: &CoinsActivationContext) -> &BchTaskManagerShared { + &activation_ctx.init_bch_task_manager + } + + async fn init_standalone_coin( + ctx: MmArc, + ticker: String, + coin_conf: Json, + activation_request: &Self::ActivationRequest, + protocol_info: Self::StandaloneProtocol, + _task_handle: BchRpcTaskHandleShared, + ) -> Result> { + if activation_request.bchd_urls.is_empty() && !activation_request.allow_slp_unsafe_conf { + Err(InitUtxoStandardError::CoinCreationError { + ticker: ticker.clone(), + error: "Using empty bchd_urls is unsafe for SLP users!".into(), + })?; + } + let prefix = CashAddrPrefix::from_str(&protocol_info.slp_prefix).map_err(|e| { + InitUtxoStandardError::CoinCreationError { + ticker: ticker.clone(), + error: format!("Couldn't parse cash address prefix: {e:?}"), + } + })?; + let priv_key_policy = priv_key_build_policy(&ctx, activation_request.utxo_params.priv_key_policy)?; + + let bchd_urls = activation_request.bchd_urls.clone(); + let constructor = { move |utxo_arc| BchCoin::new(utxo_arc, prefix.clone(), bchd_urls.clone()) }; + + let coin = UtxoArcBuilder::new( + &ctx, + &ticker, + &coin_conf, + &activation_request.utxo_params, + priv_key_policy, + constructor, + ) + .build() + .await + .mm_err(|e| InitUtxoStandardError::from_build_err(e, ticker.clone()))?; + + Ok(coin) + } + + async fn get_activation_result( + &self, + ctx: MmArc, + task_handle: BchRpcTaskHandleShared, + activation_request: &Self::ActivationRequest, + ) -> MmResult { + get_activation_result(&ctx, self, task_handle, &activation_request.utxo_params).await + } + + fn start_history_background_fetching( + &self, + metrics: MetricsArc, + storage: impl TxHistoryStorage, + current_balances: HashMap, + ) { + start_history_background_fetching(self.clone(), metrics, storage, current_balances) + } +} diff --git a/mm2src/coins_activation/src/utxo_activation/mod.rs b/mm2src/coins_activation/src/utxo_activation/mod.rs index 5ef6021199..52244ed2dc 100644 --- a/mm2src/coins_activation/src/utxo_activation/mod.rs +++ b/mm2src/coins_activation/src/utxo_activation/mod.rs @@ -1,10 +1,12 @@ mod common_impl; +mod init_bch_activation; mod init_qtum_activation; mod init_utxo_standard_activation; mod init_utxo_standard_activation_error; mod init_utxo_standard_statuses; mod utxo_standard_activation_result; +pub use init_bch_activation::BchTaskManagerShared; pub use init_qtum_activation::QtumTaskManagerShared; pub use init_utxo_standard_activation::UtxoStandardTaskManagerShared; diff --git a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs index 16b2cba07c..2195962579 100644 --- a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs +++ b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs @@ -256,6 +256,10 @@ async fn rpc_task_dispatcher( "create_new_account::init" => handle_mmrpc(ctx, request, init_create_new_account).await, "create_new_account::status" => handle_mmrpc(ctx, request, init_create_new_account_status).await, "create_new_account::user_action" => handle_mmrpc(ctx, request, init_create_new_account_user_action).await, + "enable_bch::cancel" => handle_mmrpc(ctx, request, cancel_init_standalone_coin::).await, + "enable_bch::init" => handle_mmrpc(ctx, request, init_standalone_coin::).await, + "enable_bch::status" => handle_mmrpc(ctx, request, init_standalone_coin_status::).await, + "enable_bch::user_action" => handle_mmrpc(ctx, request, init_standalone_coin_user_action::).await, "enable_qtum::cancel" => handle_mmrpc(ctx, request, cancel_init_standalone_coin::).await, "enable_qtum::init" => handle_mmrpc(ctx, request, init_standalone_coin::).await, "enable_qtum::status" => handle_mmrpc(ctx, request, init_standalone_coin_status::).await, @@ -276,6 +280,29 @@ async fn rpc_task_dispatcher( "enable_erc20::init" => handle_mmrpc(ctx, request, init_token::).await, "enable_erc20::status" => handle_mmrpc(ctx, request, init_token_status::).await, "enable_erc20::user_action" => handle_mmrpc(ctx, request, init_token_user_action::).await, + // // FIXME: tendermint with tokens + // "enable_tendermint::cancel" => { + // handle_mmrpc(ctx, request, cancel_init_platform_coin_with_tokens::).await + // }, + // "enable_tendermint::init" => handle_mmrpc(ctx, request, init_platform_coin_with_tokens::).await, + // "enable_tendermint::status" => { + // handle_mmrpc(ctx, request, init_platform_coin_with_tokens_status::).await + // }, + // "enable_tendermint::user_action" => { + // handle_mmrpc( + // ctx, + // request, + // init_platform_coin_with_tokens_user_action::, + // ) + // .await + // }, + // // FIXME: tendermint tokens + // "enable_tendermint_token::cancel" => handle_mmrpc(ctx, request, cancel_init_token::).await, + // "enable_tendermint_token::init" => handle_mmrpc(ctx, request, init_token::).await, + // "enable_tendermint_token::status" => handle_mmrpc(ctx, request, init_token_status::).await, + // "enable_tendermint_token::user_action" => { + // handle_mmrpc(ctx, request, init_token_user_action::).await + // }, "get_new_address::cancel" => handle_mmrpc(ctx, request, cancel_get_new_address).await, "get_new_address::init" => handle_mmrpc(ctx, request, init_get_new_address).await, "get_new_address::status" => handle_mmrpc(ctx, request, init_get_new_address_status).await,