Skip to content

Commit

Permalink
feat(trading-proto-upgrade): swap UTXO PoC using Storable State Machi…
Browse files Browse the repository at this point in the history
…ne (#1958)

This commit:
- Adds Storable State Machine abstraction with a goal to have as fewer changes to existing state machines as possible.
- Implements successful swap v2 of UTXO to UTXO coin. Adds tests for such swap using dockerized komodod daemons.
- Adds Swap V2 message exchange using Protobuf.
  • Loading branch information
artemii235 authored Sep 21, 2023
1 parent bd69fbd commit 6370fa5
Show file tree
Hide file tree
Showing 54 changed files with 4,147 additions and 641 deletions.
14 changes: 14 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ members = [
"mm2src/mm2_net",
"mm2src/mm2_number",
"mm2src/mm2_rpc",
"mm2src/mm2_state_machine",
"mm2src/rpc_task",
"mm2src/mm2_test_helpers",
"mm2src/trezor",
Expand Down
1 change: 1 addition & 0 deletions mm2src/coins/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ mm2_metrics = { path = "../mm2_metrics" }
mm2_net = { path = "../mm2_net" }
mm2_number = { path = "../mm2_number"}
mm2_rpc = { path = "../mm2_rpc" }
mm2_state_machine = { path = "../mm2_state_machine" }
mocktopus = "0.8.0"
num-traits = "0.2"
parking_lot = { version = "0.12.0", features = ["nightly"] }
Expand Down
17 changes: 15 additions & 2 deletions mm2src/coins/coin_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,36 @@ use crate::{eth::Web3RpcError, my_tx_history_v2::MyTxHistoryErrorV2, utxo::rpc_c
use futures01::Future;
use mm2_err_handle::prelude::MmError;
use spv_validation::helpers_validation::SPVError;
use std::num::TryFromIntError;

/// Helper type used as result for swap payment validation function(s)
pub type ValidatePaymentFut<T> = Box<dyn Future<Item = T, Error = MmError<ValidatePaymentError>> + Send>;

/// Enum covering possible error cases of swap payment validation
#[derive(Debug, Display)]
pub enum ValidatePaymentError {
/// Should be used to indicate internal MM2 state problems (e.g., DB errors, etc.).
InternalError(String),
// Problem with deserializing the transaction, or one of the transaction parts is invalid.
/// Problem with deserializing the transaction, or one of the transaction parts is invalid.
TxDeserializationError(String),
/// One of the input parameters is invalid.
InvalidParameter(String),
/// Coin's RPC returned unexpected/invalid response during payment validation.
InvalidRpcResponse(String),
/// Payment transaction doesn't exist on-chain.
TxDoesNotExist(String),
/// SPV client error.
SPVError(SPVError),
/// Payment transaction is in unexpected state. E.g., `Uninitialized` instead of `Sent` for ETH payment.
UnexpectedPaymentState(String),
/// Transport (RPC) error.
Transport(String),
// Transaction has wrong properties, for example, it has been sent to a wrong address
/// Transaction has wrong properties, for example, it has been sent to a wrong address.
WrongPaymentTx(String),
/// Indicates error during watcher reward calculation.
WatcherRewardError(String),
/// Input payment timelock overflows the type used by specific coin.
TimelockOverflow(TryFromIntError),
}

impl From<rlp::DecoderError> for ValidatePaymentError {
Expand Down
25 changes: 18 additions & 7 deletions mm2src/coins/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ use serde_json::{self as json, Value as Json};
use serialization::{CompactInteger, Serializable, Stream};
use sha3::{Digest, Keccak256};
use std::collections::HashMap;
use std::convert::TryFrom;
use std::convert::{TryFrom, TryInto};
use std::ops::Deref;
#[cfg(not(target_arch = "wasm32"))] use std::path::PathBuf;
use std::str::FromStr;
Expand Down Expand Up @@ -1137,7 +1137,10 @@ impl SwapOps for EthCoin {
&self,
if_my_payment_sent_args: CheckIfMyPaymentSentArgs,
) -> Box<dyn Future<Item = Option<TransactionEnum>, Error = String> + Send> {
let id = self.etomic_swap_id(if_my_payment_sent_args.time_lock, if_my_payment_sent_args.secret_hash);
let id = self.etomic_swap_id(
try_fus!(if_my_payment_sent_args.time_lock.try_into()),
if_my_payment_sent_args.secret_hash,
);
let swap_contract_address = try_fus!(if_my_payment_sent_args.swap_contract_address.try_to_address());
let selfi = self.clone();
let from_block = if_my_payment_sent_args.search_from_block;
Expand Down Expand Up @@ -1420,7 +1423,7 @@ impl WatcherOps for EthCoin {
fn create_maker_payment_spend_preimage(
&self,
maker_payment_tx: &[u8],
_time_lock: u32,
_time_lock: u64,
_maker_pub: &[u8],
_secret_hash: &[u8],
_swap_unique_data: &[u8],
Expand All @@ -1435,7 +1438,7 @@ impl WatcherOps for EthCoin {
fn create_taker_payment_refund_preimage(
&self,
taker_payment_tx: &[u8],
_time_lock: u32,
_time_lock: u64,
_maker_pub: &[u8],
_secret_hash: &[u8],
_swap_contract_address: &Option<BytesJson>,
Expand Down Expand Up @@ -1476,9 +1479,13 @@ impl WatcherOps for EthCoin {
.map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string())));
let sender = try_f!(addr_from_raw_pubkey(&input.taker_pub).map_to_mm(ValidatePaymentError::InvalidParameter));
let receiver = try_f!(addr_from_raw_pubkey(&input.maker_pub).map_to_mm(ValidatePaymentError::InvalidParameter));
let time_lock = try_f!(input
.time_lock
.try_into()
.map_to_mm(ValidatePaymentError::TimelockOverflow));

let selfi = self.clone();
let swap_id = selfi.etomic_swap_id(input.time_lock, &input.secret_hash);
let swap_id = selfi.etomic_swap_id(time_lock, &input.secret_hash);
let secret_hash = if input.secret_hash.len() == 32 {
ripemd160(&input.secret_hash).to_vec()
} else {
Expand Down Expand Up @@ -3023,7 +3030,7 @@ impl EthCoin {
fn send_hash_time_locked_payment(&self, args: SendPaymentArgs<'_>) -> EthTxFut {
let receiver_addr = try_tx_fus!(addr_from_raw_pubkey(args.other_pubkey));
let swap_contract_address = try_tx_fus!(args.swap_contract_address.try_to_address());
let id = self.etomic_swap_id(args.time_lock, args.secret_hash);
let id = self.etomic_swap_id(try_tx_fus!(args.time_lock.try_into()), args.secret_hash);
let trade_amount = try_tx_fus!(wei_from_big_decimal(&args.amount, self.decimals));

let time_lock = U256::from(args.time_lock);
Expand Down Expand Up @@ -3882,9 +3889,13 @@ impl EthCoin {
try_f!(SignedEthTx::new(unsigned)
.map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string())));
let sender = try_f!(addr_from_raw_pubkey(&input.other_pub).map_to_mm(ValidatePaymentError::InvalidParameter));
let time_lock = try_f!(input
.time_lock
.try_into()
.map_to_mm(ValidatePaymentError::TimelockOverflow));

let selfi = self.clone();
let swap_id = selfi.etomic_swap_id(input.time_lock, &input.secret_hash);
let swap_id = selfi.etomic_swap_id(time_lock, &input.secret_hash);
let decimals = self.decimals;
let secret_hash = if input.secret_hash.len() == 32 {
ripemd160(&input.secret_hash).to_vec()
Expand Down
10 changes: 5 additions & 5 deletions mm2src/coins/eth/eth_tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::*;
use crate::IguanaPrivKey;
use common::{block_on, now_sec_u32, wait_until_sec};
use common::{block_on, now_sec, wait_until_sec};
use crypto::privkey::key_pair_from_seed;
use ethkey::{Generator, Random};
use mm2_core::mm_ctx::{MmArc, MmCtxBuilder};
Expand Down Expand Up @@ -343,7 +343,7 @@ fn send_and_refund_erc20_payment() {
abortable_system: AbortableQueue::default(),
}));

let time_lock = now_sec_u32() - 200;
let time_lock = now_sec() - 200;
let secret_hash = &[1; 20];
let maker_payment_args = SendPaymentArgs {
time_lock_duration: 0,
Expand All @@ -360,7 +360,7 @@ fn send_and_refund_erc20_payment() {
let payment = coin.send_maker_payment(maker_payment_args).wait().unwrap();
log!("{:?}", payment);

let swap_id = coin.etomic_swap_id(time_lock, secret_hash);
let swap_id = coin.etomic_swap_id(time_lock.try_into().unwrap(), secret_hash);
let status = block_on(
coin.payment_status(
Address::from_str(ETH_DEV_SWAP_CONTRACT).unwrap(),
Expand Down Expand Up @@ -429,7 +429,7 @@ fn send_and_refund_eth_payment() {
abortable_system: AbortableQueue::default(),
}));

let time_lock = now_sec_u32() - 200;
let time_lock = now_sec() - 200;
let secret_hash = &[1; 20];
let send_maker_payment_args = SendPaymentArgs {
time_lock_duration: 0,
Expand All @@ -447,7 +447,7 @@ fn send_and_refund_eth_payment() {

log!("{:?}", payment);

let swap_id = coin.etomic_swap_id(time_lock, secret_hash);
let swap_id = coin.etomic_swap_id(time_lock.try_into().unwrap(), secret_hash);
let status = block_on(
coin.payment_status(
Address::from_str(ETH_DEV_SWAP_CONTRACT).unwrap(),
Expand Down
4 changes: 2 additions & 2 deletions mm2src/coins/lightning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -959,7 +959,7 @@ impl WatcherOps for LightningCoin {
fn create_maker_payment_spend_preimage(
&self,
_maker_payment_tx: &[u8],
_time_lock: u32,
_time_lock: u64,
_maker_pub: &[u8],
_secret_hash: &[u8],
_swap_unique_data: &[u8],
Expand All @@ -974,7 +974,7 @@ impl WatcherOps for LightningCoin {
fn create_taker_payment_refund_preimage(
&self,
_taker_payment_tx: &[u8],
_time_lock: u32,
_time_lock: u64,
_maker_pub: &[u8],
_secret_hash: &[u8],
_swap_contract_address: &Option<BytesJson>,
Expand Down
Loading

0 comments on commit 6370fa5

Please sign in to comment.