Skip to content

Commit

Permalink
add tests for swap v1 mycoin to mycoin with dex pubkey as Alice (to t…
Browse files Browse the repository at this point in the history
…est DexFee::NoFee)

fix tests for versioned negotiation to use env var instead of feature
  • Loading branch information
dimxy committed Aug 24, 2024
1 parent 5cc210e commit 69cbfa4
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 51 deletions.
21 changes: 20 additions & 1 deletion mm2src/coins/lp_coins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#![feature(hash_raw_entry)]
#![feature(stmt_expr_attributes)]
#![feature(result_flattening)]
#![feature(local_key_cell_methods)] // for tests

#[macro_use] extern crate common;
#[macro_use] extern crate gstuff;
Expand Down Expand Up @@ -89,6 +90,10 @@ use std::time::Duration;
use std::{fmt, iter};
use utxo_signer::with_key_pair::UtxoSignWithKeyPairError;
use zcash_primitives::transaction::Transaction as ZTransaction;

#[cfg(feature = "for-tests")]
pub static mut TEST_DEX_FEE_ADDR_RAW_PUBKEY: Option<Vec<u8>> = None;

cfg_native! {
use crate::lightning::LightningCoin;
use crate::lightning::ln_conf::PlatformCoinConfirmationTargets;
Expand Down Expand Up @@ -1221,7 +1226,17 @@ pub trait SwapOps {

fn maker_locktime_multiplier(&self) -> f64 { 2.0 }

fn dex_pubkey(&self) -> &[u8] { &DEX_FEE_ADDR_RAW_PUBKEY }
fn dex_pubkey(&self) -> &[u8] {
#[cfg(feature = "for-tests")]
{
unsafe {
if let Some(ref test_pk) = TEST_DEX_FEE_ADDR_RAW_PUBKEY {
return test_pk.as_slice();
}
}
}
&DEX_FEE_ADDR_RAW_PUBKEY
}

fn burn_pubkey(&self) -> &[u8] { &DEX_BURN_ADDR_RAW_PUBKEY }
}
Expand Down Expand Up @@ -3687,7 +3702,11 @@ impl DexFee {
const DEX_FEE_SHARE: &str = "0.75";

/// Recreates a `DexFee` from separate fields (usually stored in db).
#[cfg(any(test, feature = "for-tests"))]
pub fn create_from_fields(fee_amount: MmNumber, burn_amount: MmNumber, ticker: &str) -> DexFee {
if fee_amount == MmNumber::default() && burn_amount == MmNumber::default() {
return DexFee::NoFee;
}
if burn_amount > MmNumber::default() {
let burn_destination = match ticker {
"KMD" => DexFeeBurnDestination::KmdOpReturn,
Expand Down
12 changes: 12 additions & 0 deletions mm2src/common/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ cfg_native! {
use findshlibs::{IterationControl, Segment, SharedLibrary, TargetSharedLibrary};
use std::env;
use std::sync::Mutex;
use std::str::FromStr;
}

cfg_wasm32! {
Expand Down Expand Up @@ -631,6 +632,17 @@ pub fn var(name: &str) -> Result<String, String> {
}
}

#[cfg(not(target_arch = "wasm32"))]
pub fn env_var_as_bool(name: &str) -> bool {
match env::var(name) {
Ok(v) => FromStr::from_str(&v).unwrap_or_default(),
Err(_err) => false,
}
}

#[cfg(target_arch = "wasm32")]
pub fn env_var_as_bool(_name: &str) -> bool { false }

/// TODO make it wasm32 only
#[cfg(target_arch = "wasm32")]
pub fn var(_name: &str) -> Result<String, String> { ERR!("Environment variable not supported in WASM") }
Expand Down
2 changes: 0 additions & 2 deletions mm2src/mm2_main/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ default = []
trezor-udp = ["crypto/trezor-udp"] # use for tests to connect to trezor emulator over udp
run-device-tests = []
enable-sia = []
test-use-old-maker = []
test-use-old-taker = []

[dependencies]
async-std = { version = "1.5", features = ["unstable"] }
Expand Down
19 changes: 13 additions & 6 deletions mm2src/mm2_main/src/lp_swap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ use crate::lp_swap::taker_swap_v2::{TakerSwapStateMachine, TakerSwapStorage};
use bitcrypto::{dhash160, sha256};
use coins::{lp_coinfind, lp_coinfind_or_err, CoinFindError, DexFee, MmCoin, MmCoinEnum, TradeFee, TransactionEnum,
LEGACY_PROTOCOL_VERSION};
#[cfg(feature = "for-tests")] use common::env_var_as_bool;
use common::log::{debug, warn};
use common::now_sec;
use common::time_cache::DuplicateCache;
Expand Down Expand Up @@ -390,18 +391,24 @@ impl ProcessSwapMsg for SwapMsgExt {
fn swap_msg_to_store(self, msg_store: &mut SwapMsgStore) {
match self {
SwapMsgExt::NegotiationVersioned(data) => {
if cfg!(not(feature = "test-use-old-taker"))
// ignore to emulate old node in tests
#[cfg(feature = "for-tests")]
{
msg_store.negotiation = Some(data);
if env_var_as_bool("USE_NON_VERSIONED_TAKER") {
// ignore versioned msg to emulate old taker not supporting it
break;
}
}
msg_store.negotiation = Some(data);
},
SwapMsgExt::NegotiationReplyVersioned(data) => {
if cfg!(not(feature = "test-use-old-maker"))
// ignore to emulate old node in tests
#[cfg(feature = "for-tests")]
{
msg_store.negotiation_reply = Some(data);
if env_var_as_bool("USE_NON_VERSIONED_MAKER") {
// ignore versioned reply to emulate old maker not supporting it
break;
}
}
msg_store.negotiation_reply = Some(data);
},
}
}
Expand Down
26 changes: 16 additions & 10 deletions mm2src/mm2_main/src/lp_swap/maker_swap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,20 @@ use crate::lp_ordermatch::MakerOrderBuilder;
use crate::lp_swap::swap_v2_common::mark_swap_as_finished;
use crate::lp_swap::{broadcast_swap_message, swap_ext_topic, taker_payment_spend_duration, SwapMsgWrapper,
MAX_STARTED_AT_DIFF};
#[cfg(not(feature = "test-use-old-maker"))]
use crate::lp_swap::{NegotiationDataMsgVersion, SwapMsgExt};
use coins::lp_price::fetch_swap_coins_price;
use coins::swap_features::SwapFeature;
#[cfg(not(feature = "test-use-old-maker"))]
use coins::SWAP_PROTOCOL_VERSION;
use coins::{CanRefundHtlc, CheckIfMyPaymentSentArgs, ConfirmPaymentInput, FeeApproxStage, FoundSwapTxSpend, MmCoin,
MmCoinEnum, PaymentInstructionArgs, PaymentInstructions, PaymentInstructionsErr, RefundPaymentArgs,
SearchForSwapTxSpendInput, SendPaymentArgs, SpendPaymentArgs, SwapTxTypeWithSecretHash, TradeFee,
TradePreimageValue, TransactionEnum, ValidateFeeArgs, ValidatePaymentInput, MIN_SWAP_PROTOCOL_VERSION};
#[cfg(feature = "for-tests")]
use coins::TEST_DEX_FEE_ADDR_RAW_PUBKEY;
use coins::{CanRefundHtlc, CheckIfMyPaymentSentArgs, ConfirmPaymentInput, DexFee, FeeApproxStage, FoundSwapTxSpend,
MmCoin, MmCoinEnum, PaymentInstructionArgs, PaymentInstructions, PaymentInstructionsErr,
RefundPaymentArgs, SearchForSwapTxSpendInput, SendPaymentArgs, SpendPaymentArgs, SwapTxTypeWithSecretHash,
TradeFee, TradePreimageValue, TransactionEnum, ValidateFeeArgs, ValidatePaymentInput,
MIN_SWAP_PROTOCOL_VERSION};
use common::log::{debug, error, info, warn};
use common::{bits256, executor::Timer, now_ms};
use common::{now_sec, wait_until_sec};
use common::{env_var_as_bool, now_sec, wait_until_sec};
use crypto::privkey::SerializableSecp256k1Keypair;
use crypto::CryptoCtx;
use futures::{compat::Future01CompatExt, select, FutureExt};
Expand Down Expand Up @@ -486,6 +487,13 @@ impl MakerSwap {
}

async fn start(&self) -> Result<(Option<MakerSwapCommand>, Vec<MakerSwapEvent>), String> {
#[cfg(feature = "for-tests")]
if let Ok(env_pubkey) = std::env::var("TEST_DEX_FEE_ADDR_RAW_PUBKEY") {
unsafe {
TEST_DEX_FEE_ADDR_RAW_PUBKEY = Some(hex::decode(env_pubkey).expect("valid hex"));
}
}

// do not use self.r().data here as it is not initialized at this step yet
let preimage_value = TradePreimageValue::Exact(self.maker_amount.clone());
let stage = FeeApproxStage::StartSwap;
Expand Down Expand Up @@ -600,9 +608,7 @@ impl MakerSwap {
let mut msgs = vec![];

// Important to try the new versioned negotiation message first
// (Run swap tests with "test-use-old-maker" feature to emulate old maker, sending non-versioned message only)
#[cfg(not(feature = "test-use-old-maker"))]
{
if cfg!(not(feature = "for-tests")) || !env_var_as_bool("USE_NON_VERSIONED_MAKER") {
let maker_versioned_negotiation_msg = SwapMsgExt::NegotiationVersioned(NegotiationDataMsgVersion {
version: SWAP_PROTOCOL_VERSION,
msg: negotiation_data.clone(),
Expand Down
54 changes: 30 additions & 24 deletions mm2src/mm2_main/src/lp_swap/taker_swap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@ use crate::lp_swap::taker_restart::get_command_based_on_maker_or_watcher_activit
use crate::lp_swap::{broadcast_p2p_tx_msg, broadcast_swap_msg_every_delayed, swap_ext_topic, tx_helper_topic,
wait_for_maker_payment_conf_duration, SwapMsgWrapper, TakerSwapWatcherData, MAX_STARTED_AT_DIFF,
PRE_BURN_ACCOUNT_ACTIVE};
#[cfg(not(feature = "test-use-old-taker"))]
use crate::lp_swap::{NegotiationDataMsgVersion, SwapMsgExt};
use coins::lp_price::fetch_swap_coins_price;
use coins::swap_features::SwapFeature;
#[cfg(not(feature = "test-use-old-taker"))]
use coins::SWAP_PROTOCOL_VERSION;
#[cfg(feature = "for-tests")]
use coins::TEST_DEX_FEE_ADDR_RAW_PUBKEY;
use coins::{lp_coinfind, CanRefundHtlc, CheckIfMyPaymentSentArgs, ConfirmPaymentInput, DexFee, FeeApproxStage,
FoundSwapTxSpend, MmCoin, MmCoinEnum, PaymentInstructionArgs, PaymentInstructions, PaymentInstructionsErr,
RefundPaymentArgs, SearchForSwapTxSpendInput, SendPaymentArgs, SpendPaymentArgs, SwapTxTypeWithSecretHash,
TradeFee, TradePreimageValue, ValidatePaymentInput, WaitForHTLCTxSpendArgs, MIN_SWAP_PROTOCOL_VERSION};
use common::executor::Timer;
use common::log::{debug, error, info, warn};
use common::{bits256, now_ms, now_sec, wait_until_sec};
use common::{bits256, env_var_as_bool, now_ms, now_sec, wait_until_sec};
use crypto::{privkey::SerializableSecp256k1Keypair, CryptoCtx};
use futures::{compat::Future01CompatExt, future::try_join, select, FutureExt};
use http::Response;
Expand Down Expand Up @@ -1005,6 +1005,13 @@ impl TakerSwap {
}

async fn start(&self) -> Result<(Option<TakerSwapCommand>, Vec<TakerSwapEvent>), String> {
#[cfg(feature = "for-tests")]
if let Ok(env_pubkey) = std::env::var("TEST_DEX_FEE_ADDR_RAW_PUBKEY") {
unsafe {
TEST_DEX_FEE_ADDR_RAW_PUBKEY = Some(hex::decode(env_pubkey).expect("valid hex"));
}
}

// do not use self.r().data here as it is not initialized at this step yet
let stage = FeeApproxStage::StartSwap;
let dex_fee = dex_fee_from_taker_coin(
Expand Down Expand Up @@ -1251,28 +1258,27 @@ impl TakerSwap {
taker_coin_swap_contract_bytes,
);

// Emulate old node (not supporting version in negotiation msg)
// (Run swap tests with "test-use-old-taker" feature to emulate old taker, sending non-versioned message)
#[cfg(feature = "test-use-old-taker")]
let (topic, taker_data) = (
swap_topic(&self.uuid),
SwapMsgWrapper::Legacy(SwapMsg::NegotiationReply(my_negotiation_data)),
);

// Normal path
#[cfg(not(feature = "test-use-old-taker"))]
let (topic, taker_data) = match remote_version >= SWAP_PROTOCOL_VERSION {
true => (
swap_ext_topic(&self.uuid),
SwapMsgWrapper::Ext(SwapMsgExt::NegotiationReplyVersioned(NegotiationDataMsgVersion {
version: SWAP_PROTOCOL_VERSION,
msg: my_negotiation_data,
})),
),
false => (
let (topic, taker_data) = if cfg!(feature = "for-tests") && env_var_as_bool("USE_NON_VERSIONED_TAKER") {
// emulate old taker, sending non-versioned message
(
swap_topic(&self.uuid),
SwapMsgWrapper::Legacy(SwapMsg::NegotiationReply(my_negotiation_data)), // remote node is old
),
SwapMsgWrapper::Legacy(SwapMsg::NegotiationReply(my_negotiation_data)),
)
} else {
// Normal path for versioned taker
match remote_version >= SWAP_PROTOCOL_VERSION {
true => (
swap_ext_topic(&self.uuid),
SwapMsgWrapper::Ext(SwapMsgExt::NegotiationReplyVersioned(NegotiationDataMsgVersion {
version: SWAP_PROTOCOL_VERSION,
msg: my_negotiation_data,
})),
),
false => (
swap_topic(&self.uuid),
SwapMsgWrapper::Legacy(SwapMsg::NegotiationReply(my_negotiation_data)), // remote node is old
),
}
};

debug!("Sending taker negotiation data {:?}", taker_data);
Expand Down
38 changes: 33 additions & 5 deletions mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use coins::utxo::utxo_standard::{utxo_standard_coin_with_priv_key, UtxoStandardC
use coins::utxo::{coin_daemon_data_dir, sat_from_big_decimal, zcash_params_path, UtxoActivationParams,
UtxoAddressFormat, UtxoCoinFields, UtxoCommonOps};
use coins::{ConfirmPaymentInput, MarketCoinOps, Transaction};
use crypto::privkey::key_pair_from_seed;
use crypto::privkey::{key_pair_from_secret, key_pair_from_seed};
use crypto::Secp256k1Secret;
use ethabi::Token;
use ethereum_types::{H160 as H160Eth, U256};
Expand All @@ -41,6 +41,7 @@ use script::Builder;
use secp256k1::Secp256k1;
pub use secp256k1::{PublicKey, SecretKey};
use serde_json::{self as json, Value as Json};
pub use std::cell::Cell;
use std::process::{Command, Stdio};
pub use std::{env, thread};
use std::{path::PathBuf, str::FromStr, sync::Mutex, time::Duration};
Expand Down Expand Up @@ -105,6 +106,14 @@ pub static mut SEPOLIA_ERC1155_CONTRACT: H160Eth = H160Eth::zero();
pub static GETH_RPC_URL: &str = "http://127.0.0.1:8545";
pub static SEPOLIA_RPC_URL: &str = "https://ethereum-sepolia-rpc.publicnode.com";

// use thread local to affect only the current running test
thread_local! {
/// Set test dex pubkey as Taker (to check DexFee::NoFee)
pub static SET_DEX_PUBKEY_TO_ALICE: Cell<bool> = Cell::new(false);
pub static USE_NON_VERSIONED_MAKER: Cell<bool> = Cell::new(false);
pub static USE_NON_VERSIONED_TAKER: Cell<bool> = Cell::new(false);
}

pub const UTXO_ASSET_DOCKER_IMAGE: &str = "docker.io/artempikulin/testblockchain";
pub const UTXO_ASSET_DOCKER_IMAGE_WITH_TAG: &str = "docker.io/artempikulin/testblockchain:multiarch";
pub const GETH_DOCKER_IMAGE: &str = "docker.io/ethereum/client-go";
Expand Down Expand Up @@ -857,6 +866,23 @@ pub fn trade_base_rel((base, rel): (&str, &str)) {

let bob_priv_key = generate_and_fill_priv_key(base);
let alice_priv_key = generate_and_fill_priv_key(rel);
let alice_pubkey_str = hex::encode(
key_pair_from_secret(alice_priv_key.as_ref())
.expect("valid test key pair")
.public()
.to_vec(),
);

let mut envs = vec![];
if SET_DEX_PUBKEY_TO_ALICE.get() {
envs.push(("TEST_DEX_FEE_ADDR_RAW_PUBKEY", alice_pubkey_str.as_str()));
}
if USE_NON_VERSIONED_MAKER.get() {
envs.push(("USE_NON_VERSIONED_MAKER", "true"));
}
if USE_NON_VERSIONED_TAKER.get() {
envs.push(("USE_NON_VERSIONED_TAKER", "true"));
}

let confpath = unsafe { QTUM_CONF_PATH.as_ref().expect("Qtum config is not set yet") };
let coins = json! ([
Expand All @@ -873,7 +899,7 @@ pub fn trade_base_rel((base, rel): (&str, &str)) {
{"coin":"FORSLP","asset":"FORSLP","required_confirmations":0,"txversion":4,"overwintered":1,"txfee":1000,"protocol":{"type":"BCH","protocol_data":{"slp_prefix":"slptest"}}},
{"coin":"ADEXSLP","protocol":{"type":"SLPTOKEN","protocol_data":{"decimals":8,"token_id":get_slp_token_id(),"platform":"FORSLP"}}}
]);
let mut mm_bob = MarketMakerIt::start(
let mut mm_bob = block_on(MarketMakerIt::start_with_envs(
json! ({
"gui": "nogui",
"netid": 9000,
Expand All @@ -885,12 +911,13 @@ pub fn trade_base_rel((base, rel): (&str, &str)) {
}),
"pass".to_string(),
None,
)
envs.as_slice(),
))
.unwrap();
let (_bob_dump_log, _bob_dump_dashboard) = mm_dump(&mm_bob.log_path);
block_on(mm_bob.wait_for_log(22., |log| log.contains(">>>>>>>>> DEX stats "))).unwrap();

let mut mm_alice = MarketMakerIt::start(
let mut mm_alice = block_on(MarketMakerIt::start_with_envs(
json! ({
"gui": "nogui",
"netid": 9000,
Expand All @@ -902,7 +929,8 @@ pub fn trade_base_rel((base, rel): (&str, &str)) {
}),
"pass".to_string(),
None,
)
envs.as_slice(),
))
.unwrap();
let (_alice_dump_log, _alice_dump_dashboard) = mm_dump(&mm_alice.log_path);
block_on(mm_alice.wait_for_log(22., |log| log.contains(">>>>>>>>> DEX stats "))).unwrap();
Expand Down
27 changes: 24 additions & 3 deletions mm2src/mm2_main/tests/docker_tests/docker_tests_inner.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use crate::docker_tests::docker_tests_common::{generate_utxo_coin_with_privkey, trade_base_rel, GETH_RPC_URL, MM_CTX};
use crate::docker_tests::docker_tests_common::{generate_utxo_coin_with_privkey, trade_base_rel, GETH_RPC_URL, MM_CTX,
SET_DEX_PUBKEY_TO_ALICE};
use crate::docker_tests::eth_docker_tests::{erc20_coin_with_random_privkey, erc20_contract_checksum,
fill_eth_erc20_with_private_key, swap_contract};
use crate::integration_tests_common::*;
use crate::{fill_address, generate_utxo_coin_with_random_privkey, random_secp256k1_secret, rmd160_from_priv,
utxo_coin_from_privkey};
use crate::{integration_tests_common::*, USE_NON_VERSIONED_MAKER, USE_NON_VERSIONED_TAKER};
use bitcrypto::dhash160;
use chain::OutPoint;
use coins::utxo::rpc_clients::UnspentInfo;
Expand Down Expand Up @@ -3890,10 +3891,30 @@ fn test_eth_swap_negotiation_fails_maker_no_fallback() {
#[test]
fn test_trade_base_rel_eth_erc20_coins() { trade_base_rel(("ETH", "ERC20DEV")); }

// run this test also with features "test-use-old-maker" or "test-use-old-taker" to emulate non-versioned nodes
#[test]
fn test_trade_base_rel_mycoin_mycoin1_coins() { trade_base_rel(("MYCOIN", "MYCOIN1")); }

// run swap with dex pubkey set to alice
#[test]
fn test_trade_base_rel_mycoin_mycoin1_coins_dex_as_alice() {
SET_DEX_PUBKEY_TO_ALICE.set(true);
trade_base_rel(("MYCOIN", "MYCOIN1"));
}

// run swap with old maker (before version added to protocol)
#[test]
fn test_trade_base_rel_mycoin_mycoin1_coins_old_maker() {
USE_NON_VERSIONED_MAKER.set(true);
trade_base_rel(("MYCOIN", "MYCOIN1"));
}

// run swap with old taker (before version added to protocol)
#[test]
fn test_trade_base_rel_mycoin_mycoin1_coins_old_taker() {
USE_NON_VERSIONED_TAKER.set(true);
trade_base_rel(("MYCOIN", "MYCOIN1"));
}

fn withdraw_and_send(
mm: &MarketMakerIt,
coin: &str,
Expand Down
Loading

0 comments on commit 69cbfa4

Please sign in to comment.