Skip to content

Commit

Permalink
fix(ethexe): problem with too fast request to rpc after transaction c…
Browse files Browse the repository at this point in the history
…onfirmation (#4221)
  • Loading branch information
grishasobol authored Sep 5, 2024
1 parent 6b4608a commit 6016672
Show file tree
Hide file tree
Showing 12 changed files with 66 additions and 47 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.

2 changes: 1 addition & 1 deletion ethexe/cli/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ async fn ping() {
}

#[tokio::test(flavor = "multi_thread")]
#[ntest::timeout(60_000)]
#[ntest::timeout(120_000)]
async fn ping_reorg() {
gear_utils::init_default_logger();

Expand Down
1 change: 1 addition & 0 deletions ethexe/ethereum/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ alloy = { workspace = true, features = [
futures.workspace = true
log.workspace = true
parity-scale-codec = { workspace = true, features = ["std", "derive"] }
tokio.workspace = true

[dev-dependencies]
rand.workspace = true
2 changes: 1 addition & 1 deletion ethexe/ethereum/Mirror.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ethexe/ethereum/MirrorProxy.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ethexe/ethereum/Router.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ethexe/ethereum/TransparentUpgradeableProxy.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ethexe/ethereum/WrappedVara.json

Large diffs are not rendered by default.

48 changes: 43 additions & 5 deletions ethexe/ethereum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,26 +26,27 @@ use abi::{
};
use alloy::{
consensus::{self as alloy_consensus, SignableTransaction},
network::{Ethereum as AlloyEthereum, EthereumWallet, TxSigner},
network::{Ethereum as AlloyEthereum, EthereumWallet, Network, TxSigner},
primitives::{Address, Bytes, ChainId, Signature, B256, U256},
providers::{
fillers::{FillProvider, JoinFill, RecommendedFiller, WalletFiller},
Provider, ProviderBuilder, RootProvider,
PendingTransactionBuilder, PendingTransactionError, Provider, ProviderBuilder,
RootProvider,
},
rpc::types::eth::Log,
signers::{
self as alloy_signer, sign_transaction_with_chain_id, Error as SignerError,
Result as SignerResult, Signer, SignerSync,
},
sol_types::{SolCall, SolEvent},
transports::BoxTransport,
transports::{BoxTransport, RpcError, Transport},
};
use anyhow::{anyhow, Result};
use async_trait::async_trait;
use ethexe_signer::{Address as LocalAddress, PublicKey, Signer as LocalSigner};
use mirror::Mirror;
use router::{Router, RouterQuery};
use std::sync::Arc;
use std::{sync::Arc, time::Duration};

mod abi;
mod eip1167;
Expand Down Expand Up @@ -157,7 +158,7 @@ impl Ethereum {
let mirror_proxy = IMirrorProxy::deploy(provider.clone(), router_address).await?;

let builder = wrapped_vara.approve(router_address, U256::MAX);
builder.send().await?.get_receipt().await?;
builder.send().await?.try_get_receipt().await?;

assert_eq!(router.mirror().call().await?._0, *mirror.address());
assert_eq!(
Expand Down Expand Up @@ -270,3 +271,40 @@ impl SignerSync for Sender {
self.chain_id
}
}

// TODO: Maybe better to append solution like this to alloy.
trait TryGetReceipt<T: Transport + Clone, N: Network> {
/// Works like `self.get_receipt().await`, but retries a few times if rpc returns a null response.
async fn try_get_receipt(self) -> Result<N::ReceiptResponse>;
}

impl<T: Transport + Clone, N: Network> TryGetReceipt<T, N> for PendingTransactionBuilder<'_, T, N> {
async fn try_get_receipt(self) -> Result<N::ReceiptResponse> {
let tx_hash = *self.tx_hash();
let provider = self.provider().clone();

let mut err = match self.get_receipt().await {
Ok(r) => return Ok(r),
Err(err) => err,
};

for _ in 0..3 {
match err {
PendingTransactionError::TransportError(RpcError::NullResp) => {}
_ => break,
}

tokio::time::sleep(Duration::from_millis(100)).await;

match provider.get_transaction_receipt(tx_hash).await {
Ok(Some(r)) => return Ok(r),
Ok(None) => {}
Err(e) => err = e.into(),
}
}

Err(anyhow!(
"Failed to get transaction receipt for {tx_hash}: {err}"
))
}
}
13 changes: 4 additions & 9 deletions ethexe/ethereum/src/mirror/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use crate::{abi::IMirror, AlloyProvider, AlloyTransport};
use crate::{abi::IMirror, AlloyProvider, AlloyTransport, TryGetReceipt};
use alloy::{
primitives::Address,
providers::{Provider, ProviderBuilder, RootProvider},
Expand Down Expand Up @@ -59,9 +59,7 @@ impl Mirror {
value: u128,
) -> Result<(H256, MessageId)> {
let builder = self.0.sendMessage(payload.as_ref().to_vec().into(), value);
let tx = builder.send().await?;

let receipt = tx.get_receipt().await?;
let receipt = builder.send().await?.try_get_receipt().await?;

let tx_hash = (*receipt.transaction_hash).into();
let mut message_id = None;
Expand Down Expand Up @@ -95,17 +93,14 @@ impl Mirror {
payload.as_ref().to_vec().into(),
value,
);
let tx = builder.send().await?;
let receipt = builder.send().await?.try_get_receipt().await?;

let receipt = tx.get_receipt().await?;
Ok((*receipt.transaction_hash).into())
}

pub async fn claim_value(&self, claimed_id: MessageId) -> Result<H256> {
let builder = self.0.claimValue(claimed_id.into_bytes().into());
let tx = builder.send().await?;

let receipt = tx.get_receipt().await?;
let receipt = builder.send().await?.try_get_receipt().await?;

Ok((*receipt.transaction_hash).into())
}
Expand Down
24 changes: 7 additions & 17 deletions ethexe/ethereum/src/router/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use crate::{abi::IRouter, wvara::WVara, AlloyProvider, AlloyTransport};
use crate::{abi::IRouter, wvara::WVara, AlloyProvider, AlloyTransport, TryGetReceipt};
use alloy::{
consensus::{SidecarBuilder, SimpleCoder},
primitives::{Address, Bytes, B256},
Expand Down Expand Up @@ -81,9 +81,7 @@ impl Router {
.collect();

let builder = self.instance.updateValidators(validators);
let tx = builder.send().await?;

let receipt = tx.get_receipt().await?;
let receipt = builder.send().await?.try_get_receipt().await?;

Ok((*receipt.transaction_hash).into())
}
Expand All @@ -97,9 +95,7 @@ impl Router {
code_id.into_bytes().into(),
blob_tx_hash.to_fixed_bytes().into(),
);
let tx = builder.send().await?;

let receipt = tx.get_receipt().await?;
let receipt = builder.send().await?.try_get_receipt().await?;

Ok((*receipt.transaction_hash).into())
}
Expand All @@ -114,9 +110,7 @@ impl Router {
.instance
.requestCodeValidation(code_id.into_bytes().into(), B256::ZERO)
.sidecar(SidecarBuilder::<SimpleCoder>::from_slice(code).build()?);
let tx = builder.send().await?;

let receipt = tx.get_receipt().await?;
let receipt = builder.send().await?.try_get_receipt().await?;

Ok(((*receipt.transaction_hash).into(), code_id))
}
Expand Down Expand Up @@ -161,9 +155,7 @@ impl Router {
payload.as_ref().to_vec().into(),
value,
);
let tx = builder.send().await?;

let receipt = tx.get_receipt().await?;
let receipt = builder.send().await?.try_get_receipt().await?;

let tx_hash = (*receipt.transaction_hash).into();
let mut actor_id = None;
Expand Down Expand Up @@ -195,8 +187,7 @@ impl Router {
.map(|signature| Bytes::copy_from_slice(signature.as_ref()))
.collect(),
);
let tx = builder.send().await?;
let receipt = tx.get_receipt().await?;
let receipt = builder.send().await?.try_get_receipt().await?;
Ok(H256(receipt.transaction_hash.0))
}

Expand All @@ -215,8 +206,7 @@ impl Router {
.collect(),
)
.gas(10_000_000);
let tx = builder.send().await?;
let receipt = tx.get_receipt().await?;
let receipt = builder.send().await?.try_get_receipt().await?;
Ok(H256(receipt.transaction_hash.0))
}
}
Expand Down
14 changes: 4 additions & 10 deletions ethexe/ethereum/src/wvara/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

use crate::{
abi::{self, IWrappedVara},
AlloyProvider, AlloyTransport,
AlloyProvider, AlloyTransport, TryGetReceipt,
};
use alloy::{
primitives::{Address, U256 as AlloyU256},
Expand Down Expand Up @@ -58,9 +58,7 @@ impl WVara {

pub async fn transfer(&self, to: Address, value: u128) -> Result<H256> {
let builder = self.0.transfer(to, AlloyU256::from(value));
let tx = builder.send().await?;

let receipt = tx.get_receipt().await?;
let receipt = builder.send().await?.try_get_receipt().await?;

let tx_hash = (*receipt.transaction_hash).into();

Expand All @@ -69,9 +67,7 @@ impl WVara {

pub async fn transfer_from(&self, from: Address, to: Address, value: u128) -> Result<H256> {
let builder = self.0.transferFrom(from, to, AlloyU256::from(value));
let tx = builder.send().await?;

let receipt = tx.get_receipt().await?;
let receipt = builder.send().await?.try_get_receipt().await?;

let tx_hash = (*receipt.transaction_hash).into();

Expand All @@ -88,9 +84,7 @@ impl WVara {

async fn _approve(&self, address: Address, value: AlloyU256) -> Result<H256> {
let builder = self.0.approve(address, value);
let tx = builder.send().await?;

let receipt = tx.get_receipt().await?;
let receipt = builder.send().await?.try_get_receipt().await?;

let tx_hash = (*receipt.transaction_hash).into();

Expand Down

0 comments on commit 6016672

Please sign in to comment.