Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[r2r] Mm2 error refactoring #1444

Merged
merged 28 commits into from
Sep 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
cf0fabd
ValidatePaymentError refactored
borngraced Aug 16, 2022
41b6db7
cargo fmt
borngraced Aug 16, 2022
d9d5717
ValidatePaymentError review fixes
borngraced Aug 16, 2022
a01bc66
Completed MyAddress refactoring
borngraced Aug 17, 2022
18754a2
fixed WASM
borngraced Aug 17, 2022
73ee826
pr review fixes for ValidatePaymentError
borngraced Aug 19, 2022
3a7a31d
ValidatePaymentError fix
borngraced Aug 31, 2022
dd3d3b8
pr review fixes - failing tests
borngraced Sep 1, 2022
5ac5c91
pr review fixes — ValidatePaymentError
borngraced Sep 1, 2022
2c16b1c
ValidatePaymentError review fixes
borngraced Sep 5, 2022
50cf92a
final fix for PaymentValidationError
borngraced Sep 6, 2022
bd2cae0
last review fixes
borngraced Sep 12, 2022
844304c
Merge remote-tracking branch 'origin/dev' into mm2_error_refactoring
borngraced Sep 12, 2022
77f3b2c
fix conflicts
borngraced Sep 12, 2022
8a6f28f
fixed test_validate_htlc_invalid_slp_utxo
borngraced Sep 12, 2022
531faf2
fixed validate_slp_utxos errors
borngraced Sep 12, 2022
87c41a8
Merge remote-tracking branch 'origin/dev' into mm2_error_refactoring
borngraced Sep 12, 2022
fc7142b
fix conflicts
borngraced Sep 12, 2022
5e5b07a
Merge remote-tracking branch 'origin/dev' into mm2_error_refactoring
borngraced Sep 13, 2022
b2b8ea9
fix fmt && import
borngraced Sep 13, 2022
278d22c
fix review notes
borngraced Sep 13, 2022
6ef2525
fix pr review notes
borngraced Sep 13, 2022
3719ef3
fix pr review notes
borngraced Sep 14, 2022
ee42a99
review fixes
borngraced Sep 15, 2022
b32c7bb
Merge remote-tracking branch 'origin/dev' into mm2_error_refactoring
borngraced Sep 15, 2022
d10bf61
Merge remote-tracking branch 'origin/dev' into mm2_error_refactoring
borngraced Sep 27, 2022
9e5f49e
updated watcher_validate_taker_payment to return ValidatePaymentError
borngraced Sep 27, 2022
95b9818
fix InvalidInput
borngraced Sep 27, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions mm2src/coins/coin_errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
use crate::{my_tx_history_v2::MyTxHistoryErrorV2, utxo::rpc_clients::UtxoRpcError, DelegationError, NumConversError,
TxHistoryError, UnexpectedDerivationMethod, WithdrawError};
use futures01::Future;
use mm2_err_handle::prelude::MmError;
use spv_validation::helpers_validation::SPVError;

pub type ValidatePaymentFut<T> = Box<dyn Future<Item = T, Error = MmError<ValidatePaymentError>> + Send>;

#[derive(Debug, Display)]
pub enum ValidatePaymentError {
InternalError(String),
// Problem with deserializing the transaction, or one of the transaction parts is invalid.
TxDeserializationError(String),
InvalidInput(String),
InvalidRpcResponse(String),
SPVError(SPVError),
UnexpectedPaymentState(String),
Transport(String),
// Transaction has wrong properties, for example, it has been sent to a wrong address
WrongPaymentTx(String),
artemii235 marked this conversation as resolved.
Show resolved Hide resolved
}

impl From<rlp::DecoderError> for ValidatePaymentError {
fn from(err: rlp::DecoderError) -> Self { Self::TxDeserializationError(err.to_string()) }
}

impl From<web3::Error> for ValidatePaymentError {
fn from(err: web3::Error) -> Self { Self::Transport(err.to_string()) }
}

impl From<NumConversError> for ValidatePaymentError {
fn from(err: NumConversError) -> Self { Self::InternalError(err.to_string()) }
}

impl From<SPVError> for ValidatePaymentError {
fn from(err: SPVError) -> Self { Self::SPVError(err) }
}

impl From<serialization::Error> for ValidatePaymentError {
fn from(err: serialization::Error) -> Self { Self::TxDeserializationError(err.to_string()) }
}

impl From<UnexpectedDerivationMethod> for ValidatePaymentError {
fn from(err: UnexpectedDerivationMethod) -> Self { Self::InternalError(err.to_string()) }
}

impl From<UtxoRpcError> for ValidatePaymentError {
fn from(err: UtxoRpcError) -> Self {
match err {
UtxoRpcError::Transport(e) => Self::Transport(e.to_string()),
UtxoRpcError::Internal(e) => Self::InternalError(e),
_ => Self::InvalidRpcResponse(err.to_string()),
}
}
}

#[derive(Debug, Display)]
pub enum MyAddressError {
UnexpectedDerivationMethod(String),
InternalError(String),
}

impl From<UnexpectedDerivationMethod> for MyAddressError {
fn from(err: UnexpectedDerivationMethod) -> Self { Self::UnexpectedDerivationMethod(err.to_string()) }
}

impl From<MyAddressError> for WithdrawError {
fn from(err: MyAddressError) -> Self { Self::InternalError(err.to_string()) }
}

impl From<MyAddressError> for UtxoRpcError {
fn from(err: MyAddressError) -> Self { Self::Internal(err.to_string()) }
}

impl From<MyAddressError> for DelegationError {
fn from(err: MyAddressError) -> Self { Self::InternalError(err.to_string()) }
}

impl From<MyAddressError> for TxHistoryError {
fn from(err: MyAddressError) -> Self { Self::InternalError(err.to_string()) }
}

impl From<MyAddressError> for MyTxHistoryErrorV2 {
fn from(err: MyAddressError) -> Self { Self::Internal(err.to_string()) }
}
179 changes: 102 additions & 77 deletions mm2src/coins/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@ use web3::{self, Web3};
use web3_transport::{EthFeeHistoryNamespace, Web3Transport, Web3TransportNode};

use super::{coin_conf, AsyncMutex, BalanceError, BalanceFut, CoinBalance, CoinProtocol, CoinTransportMetrics,
CoinsContext, FeeApproxStage, FoundSwapTxSpend, HistorySyncState, MarketCoinOps, MmCoin,
CoinsContext, FeeApproxStage, FoundSwapTxSpend, HistorySyncState, MarketCoinOps, MmCoin, MyAddressError,
NegotiateSwapContractAddrErr, NumConversError, NumConversResult, RawTransactionError, RawTransactionFut,
RawTransactionRequest, RawTransactionRes, RawTransactionResult, RpcClientType, RpcTransportEventHandler,
RpcTransportEventHandlerShared, SearchForSwapTxSpendInput, SignatureError, SignatureResult, SwapOps,
TradeFee, TradePreimageError, TradePreimageFut, TradePreimageResult, TradePreimageValue, Transaction,
TransactionDetails, TransactionEnum, TransactionErr, TransactionFut, TxMarshalingErr,
UnexpectedDerivationMethod, ValidateAddressResult, ValidatePaymentInput, VerificationError,
VerificationResult, WatcherValidatePaymentInput, WithdrawError, WithdrawFee, WithdrawFut, WithdrawRequest,
WithdrawResult};
UnexpectedDerivationMethod, ValidateAddressResult, ValidatePaymentError, ValidatePaymentFut,
ValidatePaymentInput, VerificationError, VerificationResult, WatcherValidatePaymentInput, WithdrawError,
WithdrawFee, WithdrawFut, WithdrawRequest, WithdrawResult};

pub use rlp;

Expand Down Expand Up @@ -685,7 +685,7 @@ async fn withdraw_impl(coin: EthCoin, req: WithdrawRequest) -> WithdrawResult {
if coin.coin_type == EthCoinType::Eth {
spent_by_me += &fee_details.total_fee;
}
let my_address = coin.my_address().map_to_mm(WithdrawError::InternalError)?;
let my_address = coin.my_address()?;
Ok(TransactionDetails {
to: vec![checksum_address(&format!("{:#02x}", to_addr))],
from: vec![my_address],
Expand Down Expand Up @@ -970,8 +970,11 @@ impl SwapOps for EthCoin {
Box::new(fut.boxed().compat())
}

fn validate_maker_payment(&self, input: ValidatePaymentInput) -> Box<dyn Future<Item = (), Error = String> + Send> {
let swap_contract_address = try_fus!(input.swap_contract_address.try_to_address());
fn validate_maker_payment(&self, input: ValidatePaymentInput) -> ValidatePaymentFut<()> {
let swap_contract_address = try_f!(input
.swap_contract_address
.try_to_address()
.map_to_mm(ValidatePaymentError::InvalidInput));
self.validate_payment(
&input.payment_tx,
input.time_lock,
Expand All @@ -982,8 +985,11 @@ impl SwapOps for EthCoin {
)
}

fn validate_taker_payment(&self, input: ValidatePaymentInput) -> Box<dyn Future<Item = (), Error = String> + Send> {
let swap_contract_address = try_fus!(input.swap_contract_address.try_to_address());
fn validate_taker_payment(&self, input: ValidatePaymentInput) -> ValidatePaymentFut<()> {
let swap_contract_address = try_f!(input
.swap_contract_address
.try_to_address()
.map_to_mm(ValidatePaymentError::InvalidInput));
self.validate_payment(
&input.payment_tx,
input.time_lock,
Expand All @@ -997,7 +1003,7 @@ impl SwapOps for EthCoin {
fn watcher_validate_taker_payment(
&self,
_input: WatcherValidatePaymentInput,
) -> Box<dyn Future<Item = (), Error = String> + Send> {
) -> Box<dyn Future<Item = (), Error = MmError<ValidatePaymentError>> + Send> {
unimplemented!();
}

Expand Down Expand Up @@ -1140,7 +1146,9 @@ impl SwapOps for EthCoin {
impl MarketCoinOps for EthCoin {
fn ticker(&self) -> &str { &self.ticker[..] }

fn my_address(&self) -> Result<String, String> { Ok(checksum_address(&format!("{:#02x}", self.my_address))) }
fn my_address(&self) -> MmResult<String, MyAddressError> {
Ok(checksum_address(&format!("{:#02x}", self.my_address)))
}

fn get_public_key(&self) -> Result<String, MmError<UnexpectedDerivationMethod>> {
let uncompressed_without_prefix = hex::encode(self.key_pair.public());
Expand Down Expand Up @@ -2693,150 +2701,167 @@ impl EthCoin {
secret_hash: &[u8],
amount: BigDecimal,
expected_swap_contract_address: Address,
) -> Box<dyn Future<Item = (), Error = String> + Send> {
let unsigned: UnverifiedTransaction = try_fus!(rlp::decode(payment_tx));
let tx = try_fus!(SignedEthTx::new(unsigned));
let sender = try_fus!(addr_from_raw_pubkey(sender_pub));
let expected_value = try_fus!(wei_from_big_decimal(&amount, self.decimals));
) -> ValidatePaymentFut<()> {
let unsigned: UnverifiedTransaction = try_f!(rlp::decode(payment_tx));
let tx =
try_f!(SignedEthTx::new(unsigned)
.map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string())));
let sender = try_f!(addr_from_raw_pubkey(sender_pub).map_to_mm(ValidatePaymentError::InvalidInput));
let expected_value = try_f!(wei_from_big_decimal(&amount, self.decimals));
let selfi = self.clone();
let secret_hash = secret_hash.to_vec();
let fut = async move {
let swap_id = selfi.etomic_swap_id(time_lock, &secret_hash);
let status = try_s!(
selfi
.payment_status(expected_swap_contract_address, Token::FixedBytes(swap_id.clone()))
.compat()
.await
);
let status = selfi
.payment_status(expected_swap_contract_address, Token::FixedBytes(swap_id.clone()))
.compat()
.await
.map_to_mm(ValidatePaymentError::Transport)?;
if status != PAYMENT_STATE_SENT.into() {
return ERR!("Payment state is not PAYMENT_STATE_SENT, got {}", status);
return MmError::err(ValidatePaymentError::UnexpectedPaymentState(format!(
"Payment state is not PAYMENT_STATE_SENT, got {}",
status
)));
}

let tx_from_rpc = try_s!(
selfi
.web3
.eth()
.transaction(TransactionId::Hash(tx.hash))
.compat()
.await
);
let tx_from_rpc = selfi
.web3
.eth()
.transaction(TransactionId::Hash(tx.hash))
.compat()
.await?;
let tx_from_rpc = match tx_from_rpc {
Some(t) => t,
None => return ERR!("Didn't find provided tx {:?} on ETH node", tx),
None => {
return MmError::err(ValidatePaymentError::UnexpectedPaymentState(format!(
"Didn't find provided tx {:?} on ETH node",
tx
)))
},
};

if tx_from_rpc.from != sender {
return ERR!(
return MmError::err(ValidatePaymentError::WrongPaymentTx(format!(
"Payment tx {:?} was sent from wrong address, expected {:?}",
tx_from_rpc,
sender
);
tx_from_rpc, sender
)));
}

match &selfi.coin_type {
EthCoinType::Eth => {
if tx_from_rpc.to != Some(expected_swap_contract_address) {
return ERR!(
return MmError::err(ValidatePaymentError::WrongPaymentTx(format!(
"Payment tx {:?} was sent to wrong address, expected {:?}",
sergeyboyko0791 marked this conversation as resolved.
Show resolved Hide resolved
tx_from_rpc,
expected_swap_contract_address
);
tx_from_rpc, expected_swap_contract_address,
)));
}

if tx_from_rpc.value != expected_value {
return ERR!(
"Payment tx {:?} value is invalid, expected {:?}",
tx_from_rpc,
expected_value
);
return MmError::err(ValidatePaymentError::WrongPaymentTx(format!(
"Payment tx value arg {:?} is invalid, expected {:?}",
tx_from_rpc, expected_value
)));
}

let function = try_s!(SWAP_CONTRACT.function("ethPayment"));
let decoded = try_s!(function.decode_input(&tx_from_rpc.input.0));
let function = SWAP_CONTRACT
.function("ethPayment")
.map_to_mm(|err| ValidatePaymentError::InternalError(err.to_string()))?;
let decoded = function
.decode_input(&tx_from_rpc.input.0)
.map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?;
if decoded[0] != Token::FixedBytes(swap_id.clone()) {
return ERR!("Invalid 'swap_id' {:?}, expected {:?}", decoded, swap_id);
return MmError::err(ValidatePaymentError::WrongPaymentTx(format!(
"Invalid 'swap_id' {:?}, expected {:?}",
decoded, swap_id
)));
}

if decoded[1] != Token::Address(selfi.my_address) {
return ERR!(
return MmError::err(ValidatePaymentError::WrongPaymentTx(format!(
"Payment tx receiver arg {:?} is invalid, expected {:?}",
decoded[1],
Token::Address(selfi.my_address)
);
)));
}

if decoded[2] != Token::FixedBytes(secret_hash.to_vec()) {
return ERR!(
return MmError::err(ValidatePaymentError::WrongPaymentTx(format!(
"Payment tx secret_hash arg {:?} is invalid, expected {:?}",
decoded[2],
Token::FixedBytes(secret_hash.to_vec())
);
Token::FixedBytes(secret_hash.to_vec()),
)));
}

if decoded[3] != Token::Uint(U256::from(time_lock)) {
return ERR!(
return MmError::err(ValidatePaymentError::WrongPaymentTx(format!(
"Payment tx time_lock arg {:?} is invalid, expected {:?}",
decoded[3],
Token::Uint(U256::from(time_lock))
);
Token::Uint(U256::from(time_lock)),
)));
}
},
EthCoinType::Erc20 {
platform: _,
token_addr,
} => {
if tx_from_rpc.to != Some(expected_swap_contract_address) {
return ERR!(
return MmError::err(ValidatePaymentError::WrongPaymentTx(format!(
"Payment tx {:?} was sent to wrong address, expected {:?}",
tx_from_rpc,
expected_swap_contract_address
);
tx_from_rpc, expected_swap_contract_address,
)));
}

let function = try_s!(SWAP_CONTRACT.function("erc20Payment"));
let decoded = try_s!(function.decode_input(&tx_from_rpc.input.0));
let function = SWAP_CONTRACT
.function("erc20Payment")
.map_to_mm(|err| ValidatePaymentError::InternalError(err.to_string()))?;
let decoded = function
.decode_input(&tx_from_rpc.input.0)
.map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?;
if decoded[0] != Token::FixedBytes(swap_id.clone()) {
return ERR!("Invalid 'swap_id' {:?}, expected {:?}", decoded, swap_id);
return MmError::err(ValidatePaymentError::WrongPaymentTx(format!(
"Invalid 'swap_id' {:?}, expected {:?}",
decoded, swap_id
)));
}

if decoded[1] != Token::Uint(expected_value) {
return ERR!(
return MmError::err(ValidatePaymentError::WrongPaymentTx(format!(
"Payment tx value arg {:?} is invalid, expected {:?}",
decoded[1],
Token::Uint(expected_value)
);
Token::Uint(expected_value),
)));
}

if decoded[2] != Token::Address(*token_addr) {
return ERR!(
return MmError::err(ValidatePaymentError::WrongPaymentTx(format!(
"Payment tx token_addr arg {:?} is invalid, expected {:?}",
decoded[2],
Token::Address(*token_addr)
);
)));
}

if decoded[3] != Token::Address(selfi.my_address) {
return ERR!(
return MmError::err(ValidatePaymentError::WrongPaymentTx(format!(
"Payment tx receiver arg {:?} is invalid, expected {:?}",
decoded[3],
Token::Address(selfi.my_address)
);
Token::Address(selfi.my_address),
)));
}

if decoded[4] != Token::FixedBytes(secret_hash.to_vec()) {
return ERR!(
return MmError::err(ValidatePaymentError::WrongPaymentTx(format!(
"Payment tx secret_hash arg {:?} is invalid, expected {:?}",
decoded[4],
Token::FixedBytes(secret_hash.to_vec())
);
Token::FixedBytes(secret_hash.to_vec()),
)));
}

if decoded[5] != Token::Uint(U256::from(time_lock)) {
return ERR!(
return MmError::err(ValidatePaymentError::WrongPaymentTx(format!(
"Payment tx time_lock arg {:?} is invalid, expected {:?}",
decoded[5],
Token::Uint(U256::from(time_lock))
);
Token::Uint(U256::from(time_lock)),
)));
}
},
}
Expand Down
Loading