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

fix(tpu-v2): fix tpu-v2 wait for payment spend and extract secret #2261

Open
wants to merge 64 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 63 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
9d7f476
add wait_for_maker_payment_spend to MakerPaymentSpent, add wait_for_t…
laruh Oct 16, 2024
de3a970
support Eth in lp bob/alice and use start_taker/maker_swap_state_machine
laruh Oct 19, 2024
ea5475b
use wait_for_confirmations in MakerPaymentSpent and in TakerPaymentSpent
laruh Oct 29, 2024
934a2f0
rename wait_for_taker_payment_spend to find_taker_payment_spend_tx
laruh Oct 30, 2024
ca0ee56
EthCoin find_taker_payment_spend_tx_impl function now tries to find m…
laruh Oct 30, 2024
9449cca
provide extract_secret_v2 in TakerSwapOpsV2, implement EthCoin extrac…
laruh Oct 31, 2024
2e65abf
reuse utxo extract_secret_v2 in legacy extract_secret
laruh Nov 4, 2024
43a1baf
eth extract_secret_v2 tests
laruh Nov 4, 2024
c700b59
cargo fmt
laruh Nov 8, 2024
8d5ed46
review: remove unnecessary param from extract_secret_v2_impl, add eve…
laruh Nov 12, 2024
707946a
review: simplify "swap_version" field type, make it non-optional
laruh Nov 14, 2024
1e7a197
review: simplify `if let Some(tx_hash) = event.transaction_hash` block
laruh Nov 14, 2024
fb383fb
review: make spendTakerPayment transaction log message more informative
laruh Nov 14, 2024
9ec0bab
review: provide LEGACY_SWAP_V const in tests
laruh Nov 14, 2024
6c8b2c1
review: skip retrieving events if tx_hash is already found in find_ta…
laruh Nov 14, 2024
6dcb1c3
Merge remote-tracking branch 'origin/dev' into fix-tpu-v2-wait-for-pa…
laruh Nov 14, 2024
f817f5c
review: combine legacy fallback conditions
laruh Nov 14, 2024
ddac3c8
remove unnecessary quotation marks
laruh Nov 14, 2024
f437dde
review: remove as_ref, map, remove Timer::sleep from the end
laruh Nov 14, 2024
02736e4
return Timer sleep at the end of loop
laruh Nov 15, 2024
a08b500
leave todo above coin tuple pattern matching in ordermatch
laruh Nov 15, 2024
24cb4c3
use `events_from_block` function in `wait_for_htlc_tx_spend`
laruh Nov 15, 2024
5f666f3
review: use logs_block_range in find_taker_payment_spend_tx
laruh Nov 17, 2024
47f904c
use logs_block_range in legacy wait_for_htlc_tx_spend function
laruh Nov 18, 2024
2056f9b
remove time sleep from the end of loop
laruh Nov 18, 2024
0b3ab9a
remove legacy_spend_events function and use new one instead
laruh Nov 18, 2024
cf76cab
Merge remote-tracking branch 'origin/dev' into fix-tpu-v2-wait-for-pa…
laruh Nov 26, 2024
c1a5063
impl detect_secret_hash_algo_v2 function
laruh Nov 27, 2024
43c2d94
Add new addr_to_string function to ParseCoinAssocTypes trait and use …
laruh Nov 30, 2024
0ffffd9
require BlockNumber field in call_request func, use BlockNumber::Pend…
laruh Dec 1, 2024
c60a06f
add todo about EVM support for swap v2 kickstart
laruh Dec 2, 2024
7160045
accept funding tx in search_for_taker_funding_spend_impl instead of a…
laruh Dec 2, 2024
6201aae
fix sign_and_broadcast_taker_payment_spend_impl, improve doc comment
laruh Dec 2, 2024
0877d06
move block_number to payment_status_v2 fields
laruh Dec 3, 2024
d3e6ae1
review: remove swap_v == 2u32 restriction
laruh Dec 3, 2024
90b80a3
make trait extract_secret_v2 return [u8; 32]
laruh Dec 4, 2024
17b1c94
use maker_secret:[u8; 32] in SpendMakerPaymentArgs
laruh Dec 4, 2024
2df4dd9
use taker_secret: [u8; 32] in RefundMakerPaymentSecretArgs
laruh Dec 4, 2024
a2a448f
use taker_secret: [u8; 32] in RefundFundingSecretArgs
laruh Dec 4, 2024
95a2b2b
Merge remote-tracking branch 'origin/dev' into fix-tpu-v2-wait-for-pa…
laruh Dec 10, 2024
673cd11
review: use secret_hash_algo_v2 function for both maker and taker
laruh Dec 10, 2024
e3b4132
reuse extract_id_from_tx_data in find_taker_payment_spend_tx_impl and…
laruh Dec 10, 2024
9007f12
reduce code duplication providing find_spend_transaction_hash and wai…
laruh Dec 10, 2024
9d5beeb
Merge remote-tracking branch 'origin/dev' into fix-tpu-v2-wait-for-pa…
laruh Dec 11, 2024
5bd4ee2
review: fix taker payment log message
laruh Dec 11, 2024
2d80017
review: fix functions names
laruh Dec 11, 2024
46212fa
review: doc comms for require_maker_payment_spend_confirm and require…
laruh Dec 12, 2024
ae56f2d
review: use references
laruh Dec 12, 2024
b9cef2b
review: move StateMachineParams closer to LegacySwapParams. place the…
laruh Dec 12, 2024
ac9a5a3
review: rename taker/alice to taker_pubkey and maker to maker_pubkey
laruh Dec 12, 2024
ab56a12
fix clippy in tests
laruh Dec 12, 2024
0ca61fd
update maker and taker pubkey fields in test jsons
laruh Dec 12, 2024
653e074
update maker and taker pubkey fields in test jsons in swaps_file_lock…
laruh Dec 12, 2024
f8ba975
revert "swap_version" field
laruh Dec 16, 2024
0a5ff84
Merge remote-tracking branch 'origin/dev' into fix-tpu-v2-wait-for-pa…
laruh Dec 19, 2024
ec0d13c
review: remove leftover
laruh Dec 26, 2024
b04f217
review: use fixed-size array reference
laruh Dec 26, 2024
a9f481c
review: dont move block window if err
laruh Dec 26, 2024
67321a6
Merge remote-tracking branch 'origin/dev' into fix-tpu-v2-wait-for-pa…
laruh Dec 26, 2024
41f20f9
fix clippy
laruh Dec 26, 2024
43a0b8b
add `taker_pubkey` field in wasm test jsons
laruh Dec 26, 2024
49f46e0
review: move SpendTxSearchParams up
laruh Dec 27, 2024
869019b
Merge remote-tracking branch 'origin/dev' into fix-tpu-v2-wait-for-pa…
laruh Dec 27, 2024
0f31d07
review: remove "address" param from addr_to_string func and use self.…
laruh Dec 29, 2024
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
177 changes: 80 additions & 97 deletions mm2src/coins/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ pub mod erc20;
use erc20::get_token_decimals;

pub(crate) mod eth_swap_v2;
use eth_swap_v2::{EthPaymentType, PaymentMethod};
use eth_swap_v2::{extract_id_from_tx_data, EthPaymentType, PaymentMethod, SpendTxSearchParams};

/// https://github.com/artemii235/etomic-swap/blob/master/contracts/EtomicSwap.sol
/// Dev chain (195.201.137.5:8565) contract address: 0x83965C539899cC0F918552e5A26915de40ee8852
Expand Down Expand Up @@ -2587,73 +2587,27 @@ impl MarketCoinOps for EthCoin {
},
};

let payment_func = try_tx_s!(SWAP_CONTRACT.function(&func_name));
let decoded = try_tx_s!(decode_contract_call(payment_func, tx.unsigned().data()));
let id = match decoded.first() {
Some(Token::FixedBytes(bytes)) => bytes.clone(),
invalid_token => {
return Err(TransactionErr::Plain(ERRL!(
"Expected Token::FixedBytes, got {:?}",
invalid_token
)))
},
};

loop {
if now_sec() > args.wait_until {
return TX_PLAIN_ERR!(
"Waited too long until {} for transaction {:?} to be spent ",
args.wait_until,
tx,
);
}

let current_block = match self.current_block().compat().await {
Ok(b) => b,
Err(e) => {
error!("Error getting block number: {}", e);
Timer::sleep(5.).await;
continue;
},
};

let events = match self
.spend_events(swap_contract_address, args.from_block, current_block)
.compat()
.await
{
Ok(ev) => ev,
Err(e) => {
error!("Error getting spend events: {}", e);
Timer::sleep(5.).await;
continue;
},
};
let id = try_tx_s!(extract_id_from_tx_data(tx.unsigned().data(), &SWAP_CONTRACT, &func_name).await);

let found = events.iter().find(|event| &event.data.0[..32] == id.as_slice());

if let Some(event) = found {
if let Some(tx_hash) = event.transaction_hash {
let transaction = match self.transaction(TransactionId::Hash(tx_hash)).await {
Ok(Some(t)) => t,
Ok(None) => {
info!("Tx {} not found yet", tx_hash);
Timer::sleep(args.check_every).await;
Comment on lines -2640 to -2641
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's confusing why we use 5s sleep and in other situations we use check_every. but i see you preserved the logic as it was 👍

we can leave a todo about this (if there is no justification).
i think we should always do check_every, as that's the expected wait time when failure or no result found. using a constant like 5s might not play well with certain (check_every & wait_until) pair.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's confusing why we use 5s sleep and in other situations we use check_every. but i see you preserved the logic as it was

yes, I decided to leave time sleep in legacy as it is, as Im not sure about the reason of using check_every and 5 sec in different places. When it comes to legacy Im trying to balance between "do the refactor when we need it" and "Does it work? Dont touch it".

I used check_every everywhere in find_taker_payment_spend_tx_impl (its an new protocol alternative of legacy wait_for_htlc_tx_spend). So we can have a fresh view of this behaviour.

continue;
},
Err(e) => {
error!("Get tx {} error: {}", tx_hash, e);
Timer::sleep(args.check_every).await;
continue;
},
};

return Ok(TransactionEnum::from(try_tx_s!(signed_tx_from_web3_tx(transaction))));
}
}
let find_params = SpendTxSearchParams {
swap_contract_address,
event_name: "ReceiverSpent",
abi_contract: &SWAP_CONTRACT,
swap_id: &try_tx_s!(id.as_slice().try_into()),
from_block: args.from_block,
wait_until: args.wait_until,
check_every: args.check_every,
};
let tx_hash = self
.find_transaction_hash_by_event(find_params)
.await
.map_err(|e| TransactionErr::Plain(e.get_inner().to_string()))?;

Timer::sleep(5.).await;
}
let spend_tx = self
.wait_for_spend_transaction(tx_hash, args.wait_until, args.check_every)
.await
.map_err(|e| TransactionErr::Plain(e.get_inner().to_string()))?;
Ok(TransactionEnum::from(spend_tx))
}

fn tx_enum_from_bytes(&self, bytes: &[u8]) -> Result<TransactionEnum, MmError<TxMarshalingErr>> {
Expand Down Expand Up @@ -4537,7 +4491,9 @@ impl EthCoin {
let function = ERC20_CONTRACT.function("balanceOf")?;
let data = function.encode_input(&[Token::Address(address)])?;

let res = coin.call_request(address, *token_addr, None, Some(data.into())).await?;
let res = coin
.call_request(address, *token_addr, None, Some(data.into()), BlockNumber::Latest)
.await?;
let decoded = function.decode_output(&res.0)?;
match decoded[0] {
Token::Uint(number) => Ok(number),
Expand Down Expand Up @@ -4601,7 +4557,7 @@ impl EthCoin {
let function = ERC20_CONTRACT.function("balanceOf")?;
let data = function.encode_input(&[Token::Address(address)])?;
let res = self
.call_request(address, token_address, None, Some(data.into()))
.call_request(address, token_address, None, Some(data.into()), BlockNumber::Latest)
.await?;
let decoded = function.decode_output(&res.0)?;

Expand All @@ -4628,7 +4584,7 @@ impl EthCoin {
let my_address = self.derivation_method.single_addr_or_err().await?;
let data = function.encode_input(&[Token::Address(my_address), Token::Uint(token_id_u256)])?;
let result = self
.call_request(my_address, token_addr, None, Some(data.into()))
.call_request(my_address, token_addr, None, Some(data.into()), BlockNumber::Latest)
.await?;
let decoded = function.decode_output(&result.0)?;
match decoded[0] {
Expand Down Expand Up @@ -4659,7 +4615,7 @@ impl EthCoin {
let data = function.encode_input(&[Token::Uint(token_id_u256)])?;
let my_address = self.derivation_method.single_addr_or_err().await?;
let result = self
.call_request(my_address, token_addr, None, Some(data.into()))
.call_request(my_address, token_addr, None, Some(data.into()), BlockNumber::Latest)
.await?;
let decoded = function.decode_output(&result.0)?;
match decoded[0] {
Expand Down Expand Up @@ -4737,6 +4693,7 @@ impl EthCoin {
to: Address,
value: Option<U256>,
data: Option<Bytes>,
block_number: BlockNumber,
) -> Result<Bytes, web3::Error> {
let request = CallRequest {
from: Some(from),
Expand All @@ -4748,7 +4705,7 @@ impl EthCoin {
..CallRequest::default()
};

self.call(request, Some(BlockId::Number(BlockNumber::Latest))).await
self.call(request, Some(BlockId::Number(block_number))).await
}

pub fn allowance(&self, spender: Address) -> Web3RpcFut<U256> {
Expand All @@ -4764,7 +4721,7 @@ impl EthCoin {
let data = function.encode_input(&[Token::Address(my_address), Token::Address(spender)])?;

let res = coin
.call_request(my_address, *token_addr, None, Some(data.into()))
.call_request(my_address, *token_addr, None, Some(data.into()), BlockNumber::Latest)
.await?;
let decoded = function.decode_output(&res.0)?;

Expand Down Expand Up @@ -4864,25 +4821,30 @@ impl EthCoin {
Box::new(fut.boxed().compat())
}

/// Gets `ReceiverSpent` events from etomic swap smart contract since `from_block`
fn spend_events(
/// Returns events from `from_block` to `to_block` or current `latest` block.
/// According to ["eth_getLogs" doc](https://docs.infura.io/api/networks/ethereum/json-rpc-methods/eth_getlogs) `toBlock` is optional, default is "latest".
async fn events_from_block(
&self,
swap_contract_address: Address,
event_name: &str,
from_block: u64,
to_block: u64,
) -> Box<dyn Future<Item = Vec<Log>, Error = String> + Send> {
let contract_event = try_fus!(SWAP_CONTRACT.event("ReceiverSpent"));
let filter = FilterBuilder::default()
to_block: Option<u64>,
swap_contract: &Contract,
) -> MmResult<Vec<Log>, FindPaymentSpendError> {
let contract_event = swap_contract.event(event_name)?;
let mut filter_builder = FilterBuilder::default()
.topics(Some(vec![contract_event.signature()]), None, None, None)
.from_block(BlockNumber::Number(from_block.into()))
.to_block(BlockNumber::Number(to_block.into()))
.address(vec![swap_contract_address])
.build();

let coin = self.clone();

let fut = async move { coin.logs(filter).await.map_err(|e| ERRL!("{}", e)) };
Box::new(fut.boxed().compat())
.address(vec![swap_contract_address]);
if let Some(block) = to_block {
filter_builder = filter_builder.to_block(BlockNumber::Number(block.into()));
}
let filter = filter_builder.build();
let events_logs = self
.logs(filter)
.await
.map_err(|e| FindPaymentSpendError::Transport(e.to_string()))?;
Ok(events_logs)
}

fn validate_payment(&self, input: ValidatePaymentInput) -> ValidatePaymentFut<()> {
Expand Down Expand Up @@ -5192,9 +5154,16 @@ impl EthCoin {
.single_addr_or_err()
.await
.map_err(|e| ERRL!("{}", e))?;
coin.call_request(my_address, swap_contract_address, None, Some(data.into()))
.await
.map_err(|e| ERRL!("{}", e))
coin.call_request(
my_address,
swap_contract_address,
None,
Some(data.into()),
// TODO worth reviewing places where we could use BlockNumber::Pending
BlockNumber::Latest,
)
.await
.map_err(|e| ERRL!("{}", e))
};

Box::new(fut.boxed().compat().and_then(move |bytes| {
Expand Down Expand Up @@ -5244,10 +5213,16 @@ impl EthCoin {
let to_block = current_block.min(from_block + self.logs_block_range);

let spend_events = try_s!(
self.spend_events(swap_contract_address, from_block, to_block)
.compat()
.await
self.events_from_block(
swap_contract_address,
"ReceiverSpent",
from_block,
Some(to_block),
&SWAP_CONTRACT
)
.await
);

let found = spend_events.iter().find(|event| &event.data.0[..32] == id.as_slice());

if let Some(event) = found {
Expand Down Expand Up @@ -7005,7 +6980,10 @@ impl ParseCoinAssocTypes for EthCoin {
}
}

fn addr_to_string(&self, address: &Self::Address) -> String { eth_addr_to_hex(address) }

fn parse_address(&self, address: &str) -> Result<Self::Address, Self::AddressParseError> {
// crate `Address::from_str` supports both address variants with and without `0x` prefix
Address::from_str(address).map_to_mm(|e| EthAssocTypesError::InvalidHexString(e.to_string()))
}

Expand Down Expand Up @@ -7347,14 +7325,19 @@ impl TakerCoinSwapOpsV2 for EthCoin {
self.sign_and_broadcast_taker_payment_spend_impl(gen_args, secret).await
}

/// Wrapper for [EthCoin::wait_for_taker_payment_spend_impl]
async fn wait_for_taker_payment_spend(
/// Wrapper for [EthCoin::find_taker_payment_spend_tx_impl]
async fn find_taker_payment_spend_tx(
&self,
taker_payment: &Self::Tx,
_from_block: u64,
from_block: u64,
wait_until: u64,
) -> MmResult<Self::Tx, WaitForPaymentSpendError> {
self.wait_for_taker_payment_spend_impl(taker_payment, wait_until).await
) -> MmResult<Self::Tx, FindPaymentSpendError> {
self.find_taker_payment_spend_tx_impl(taker_payment, from_block, wait_until, 10.)
.await
}

async fn extract_secret_v2(&self, _secret_hash: &[u8], spend_tx: &Self::Tx) -> Result<[u8; 32], String> {
self.extract_secret_v2_impl(spend_tx).await
}
}

Expand Down
Loading
Loading