Skip to content

Commit

Permalink
add tests for withdraw from witness and p2pkh with trezor, add trezor…
Browse files Browse the repository at this point in the history
… emulator support (via udp), add test config helpers, add layer to connect to Trezor or emulator over usb and udp
  • Loading branch information
dimxy committed Oct 29, 2023
1 parent fbc0c46 commit cdcb384
Show file tree
Hide file tree
Showing 19 changed files with 555 additions and 41 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

64 changes: 64 additions & 0 deletions mm2src/coins/utxo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1901,6 +1901,70 @@ fn parse_hex_encoded_u32(hex_encoded: &str) -> Result<u32, MmError<String>> {
Ok(u32::from_be_bytes(be_bytes))
}

#[cfg(not(target_arch = "wasm32"))]
pub mod for_tests {
use super::UtxoCoinFields;
use crate::rpc_command::init_withdraw::WithdrawStatusRequest;
use crate::rpc_command::init_withdraw::{init_withdraw, withdraw_status};
use crate::WithdrawFrom;
use crate::{utxo::{utxo_standard::UtxoStandardCoin, UtxoArc},
WithdrawRequest};
use crate::{MarketCoinOps, TransactionDetails, WithdrawError};
use common::executor::Timer;
use common::{now_ms, wait_until_ms};
use mm2_core::mm_ctx::MmArc;
use mm2_err_handle::prelude::MmResult;
use mm2_number::BigDecimal;
use rpc_task::RpcTaskStatus;
use std::str::FromStr;

/// Helper to call init_withdraw and wait for completion
pub async fn test_withdraw_init_loop(
ctx: MmArc,
fields: UtxoCoinFields,
ticker: &str,
to: &str,
amount: &str,
from_derivation_path: &str,
) -> MmResult<TransactionDetails, WithdrawError> {
let arc: UtxoArc = fields.into();
let coin: UtxoStandardCoin = arc.into();

let withdraw_req = WithdrawRequest {
amount: BigDecimal::from_str(amount).unwrap(),
from: Some(WithdrawFrom::DerivationPath {
derivation_path: from_derivation_path.to_owned(),
}),
to: to.to_owned(),
coin: ticker.to_owned(),
max: false,
fee: None,
memo: None,
};
let init = init_withdraw(ctx.clone(), withdraw_req).await.unwrap();
let timeout = wait_until_ms(150000);
loop {
if now_ms() > timeout {
panic!("{} init_withdraw timed out", coin.ticker());
}
let status = withdraw_status(ctx.clone(), WithdrawStatusRequest {
task_id: init.task_id,
forget_if_finished: true,
})
.await;
if let Ok(status) = status {
match status {
RpcTaskStatus::Ok(tx_details) => break Ok(tx_details),
RpcTaskStatus::Error(e) => break Err(e),
_ => Timer::sleep(1.).await,
}
} else {
panic!("{} could not get withdraw_status", coin.ticker())
}
}
}
}

#[test]
fn test_parse_hex_encoded_u32() {
assert_eq!(parse_hex_encoded_u32("0x892f2085"), Ok(2301567109));
Expand Down
4 changes: 3 additions & 1 deletion mm2src/coins_activation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@ mod tendermint_token_activation;
mod tendermint_with_assets_activation;
mod token;
mod utxo_activation;
#[cfg(not(target_arch = "wasm32"))]
pub use utxo_activation::for_tests;
#[cfg(not(target_arch = "wasm32"))] mod z_coin_activation;

pub use l2::{cancel_init_l2, init_l2, init_l2_status, init_l2_user_action};
pub use platform_coin_with_tokens::enable_platform_coin_with_tokens;
pub use standalone_coin::{cancel_init_standalone_coin, init_standalone_coin, init_standalone_coin_status,
init_standalone_coin_user_action};
init_standalone_coin_user_action, InitStandaloneCoinReq, InitStandaloneCoinStatusRequest};
pub use token::enable_token;
3 changes: 2 additions & 1 deletion mm2src/coins_activation/src/standalone_coin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod init_standalone_coin_error;

pub use init_standalone_coin::{cancel_init_standalone_coin, init_standalone_coin, init_standalone_coin_status,
init_standalone_coin_user_action, InitStandaloneCoinActivationOps,
InitStandaloneCoinInitialStatus, InitStandaloneCoinTask, InitStandaloneCoinTaskHandle,
InitStandaloneCoinInitialStatus, InitStandaloneCoinReq,
InitStandaloneCoinStatusRequest, InitStandaloneCoinTask, InitStandaloneCoinTaskHandle,
InitStandaloneCoinTaskManagerShared};
pub use init_standalone_coin_error::InitStandaloneCoinError;
49 changes: 49 additions & 0 deletions mm2src/coins_activation/src/utxo_activation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,52 @@ mod utxo_standard_activation_result;

pub use init_qtum_activation::QtumTaskManagerShared;
pub use init_utxo_standard_activation::UtxoStandardTaskManagerShared;

/// helpers for use in tests in other modules
#[cfg(not(target_arch = "wasm32"))]
pub mod for_tests {
use common::{executor::Timer, now_ms, wait_until_ms};
use mm2_core::mm_ctx::MmArc;
use mm2_err_handle::prelude::{MmResult, NotEqual};
use rpc_task::RpcTaskStatus;
//use serde_json::{Value, self};

use crate::{init_standalone_coin, init_standalone_coin_status,
standalone_coin::{InitStandaloneCoinActivationOps, InitStandaloneCoinError,
InitStandaloneCoinInitialStatus},
InitStandaloneCoinReq, InitStandaloneCoinStatusRequest};

/// test helper to activate standalone coin with waiting for the result
pub async fn init_standalone_coin_loop<Standalone>(
ctx: MmArc,
request: InitStandaloneCoinReq<Standalone::ActivationRequest>,
) -> MmResult<Standalone::ActivationResult, InitStandaloneCoinError>
where
Standalone: InitStandaloneCoinActivationOps + Send + Sync + 'static,
Standalone::InProgressStatus: InitStandaloneCoinInitialStatus,
InitStandaloneCoinError: From<Standalone::ActivationError>,
(Standalone::ActivationError, InitStandaloneCoinError): NotEqual,
{
let init_result = init_standalone_coin::<Standalone>(ctx.clone(), request).await.unwrap();
let timeout = wait_until_ms(150000);
loop {
if now_ms() > timeout {
panic!("init_standalone_coin timed out");
}
let status_req = InitStandaloneCoinStatusRequest {
task_id: init_result.task_id,
forget_if_finished: true,
};
let status_res = init_standalone_coin_status::<Standalone>(ctx.clone(), status_req).await;
if let Ok(status) = status_res {
match status {
RpcTaskStatus::Ok(result) => break Ok(result),
RpcTaskStatus::Error(e) => break Err(e),
_ => Timer::sleep(1.).await,
}
} else {
panic!("could not get init_standalone_coin status");
}
}
}
}
3 changes: 3 additions & 0 deletions mm2src/crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,6 @@ mm2_eth = { path = "../mm2_eth" }
mm2_metamask = { path = "../mm2_metamask" }
wasm-bindgen-test = { version = "0.3.2" }
web3 = { git = "https://github.com/KomodoPlatform/rust-web3", tag = "v0.19.0", default-features = false }

[features]
trezor-udp = ["trezor/trezor-udp"]
24 changes: 18 additions & 6 deletions mm2src/crypto/src/hw_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub enum HwWalletType {
Trezor,
}

#[derive(Clone, Debug, Serialize)]
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum HwDeviceInfo {
Trezor(TrezorDeviceInfo),
Expand Down Expand Up @@ -124,26 +124,38 @@ impl HwClient {
) -> MmResult<TrezorClient, HwProcessingError<Processor::Error>> {
use common::custom_futures::timeout::TimeoutError;
use common::executor::Timer;

async fn try_to_connect() -> HwResult<Option<TrezorClient>> {
let mut devices = trezor::transport::usb::find_devices()?;
use trezor::transport::{ConnectableDeviceWrapper, Transport};

async fn try_to_connect<C>() -> HwResult<Option<TrezorClient>>
where
C: ConnectableDeviceWrapper,
<C as ConnectableDeviceWrapper>::T: Transport + Sync + Send + 'static,
{
let mut devices = C::find_devices().await?;
if devices.is_empty() {
return Ok(None);
}
if devices.len() != 1 {
return MmError::err(HwError::CannotChooseDevice { count: devices.len() });
}
let device = devices.remove(0);
let transport = device.connect()?;
let transport = device.connect().await?;
let trezor = TrezorClient::from_transport(transport);
Ok(Some(trezor))
}

let fut = async move {
loop {
if let Some(trezor) = try_to_connect().await? {
if let Some(trezor) = try_to_connect::<trezor::transport::usb::UsbAvailableDevice>().await? {
return Ok(trezor);
}

#[cfg(feature = "trezor-udp")]
// try also to connect to emulator over UDP
if let Some(trezor) = try_to_connect::<trezor::transport::udp::UdpAvailableDevice>().await? {
return Ok(trezor);
}

Timer::sleep(1.).await;
}
};
Expand Down
2 changes: 2 additions & 0 deletions mm2src/mm2_main/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ run-docker-tests = []
# TODO
enable-solana = []
default = []
trezor-udp = ["crypto/trezor-udp"] # use for tests to connect to trezor emulator over udp

[dependencies]
async-std = { version = "1.5", features = ["unstable"] }
Expand Down Expand Up @@ -113,6 +114,7 @@ rcgen = "0.10"
rustls = { version = "0.20", default-features = false }
rustls-pemfile = "1.0.2"
tokio = { version = "1.20", features = ["io-util", "rt-multi-thread", "net"] }
mm2_test_helpers = { path = "../mm2_test_helpers" }

[target.'cfg(windows)'.dependencies]
winapi = "0.3"
Expand Down
2 changes: 1 addition & 1 deletion mm2src/mm2_main/src/lp_init/init_hw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ pub struct InitHwRequest {
device_pubkey: Option<HwPubkey>,
}

#[derive(Clone, Serialize)]
#[derive(Clone, Serialize, Debug, Deserialize)]
pub struct InitHwResponse {
#[serde(flatten)]
device_info: HwDeviceInfo,
Expand Down
1 change: 1 addition & 0 deletions mm2src/mm2_main/src/mm2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ use std::ptr::null;
use std::str;

#[path = "lp_native_dex.rs"] mod lp_native_dex;
pub use self::lp_native_dex::init_hw;
pub use self::lp_native_dex::lp_init;
use coins::update_coins_config;
use mm2_err_handle::prelude::*;
Expand Down
3 changes: 2 additions & 1 deletion mm2src/mm2_main/tests/integration_tests_common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,9 @@ pub async fn enable_utxo_v2_electrum(
coin: &str,
servers: Vec<Json>,
timeout: u64,
priv_key_policy: Option<&str>,
) -> UtxoStandardActivationResult {
let init = init_utxo_electrum(mm, coin, servers).await;
let init = init_utxo_electrum(mm, coin, servers, priv_key_policy).await;
let init: RpcV2Response<InitTaskResult> = json::from_value(init).unwrap();
let timeout = wait_until_ms(timeout * 1000);

Expand Down
Loading

0 comments on commit cdcb384

Please sign in to comment.