From 1388cd2183f4606bee80ec894621aa6858725be8 Mon Sep 17 00:00:00 2001 From: Karel Moravec Date: Thu, 7 Nov 2024 11:04:21 +0100 Subject: [PATCH] fix: use eth_getTransactionCount(pending) to get nonce (#1194) --- Cargo.lock | 25 +++++++++++ ipc/provider/src/manager/evm/manager.rs | 55 +++++++++++++------------ 2 files changed, 54 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2fbe3e919..5bcddd643 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7482,6 +7482,29 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "procfs" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4" +dependencies = [ + "bitflags 2.6.0", + "hex", + "lazy_static", + "procfs-core", + "rustix 0.38.34", +] + +[[package]] +name = "procfs-core" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" +dependencies = [ + "bitflags 2.6.0", + "hex", +] + [[package]] name = "prometheus" version = "0.13.4" @@ -7491,8 +7514,10 @@ dependencies = [ "cfg-if", "fnv", "lazy_static", + "libc", "memchr", "parking_lot", + "procfs", "protobuf", "thiserror", ] diff --git a/ipc/provider/src/manager/evm/manager.rs b/ipc/provider/src/manager/evm/manager.rs index 2cd9efc43..ac9b0766f 100644 --- a/ipc/provider/src/manager/evm/manager.rs +++ b/ipc/provider/src/manager/evm/manager.rs @@ -289,8 +289,9 @@ impl SubnetManager for EthSubnetManager { signer.clone(), ); - let call = call_with_premium_estimation(signer, registry_contract.new_subnet_actor(params)) - .await?; + let call = + call_with_premium_and_pending_block(signer, registry_contract.new_subnet_actor(params)) + .await?; // TODO: Edit call to get estimate premium let pending_tx = call.send().await?; // We need the retry to parse the deployment event. At the time of this writing, it's a bug @@ -348,7 +349,7 @@ impl SubnetManager for EthSubnetManager { let mut txn = contract.join(ethers::types::Bytes::from(pub_key), U256::from(collateral)); txn = self.handle_txn_token(&subnet, txn, collateral, 0).await?; - let txn = call_with_premium_estimation(signer, txn).await?; + let txn = call_with_premium_and_pending_block(signer, txn).await?; // Use the pending state to get the nonce because there could have been a pre-fund. Best would be to use this for everything. let txn = txn.block(BlockId::Number(ethers::types::BlockNumber::Pending)); @@ -374,7 +375,7 @@ impl SubnetManager for EthSubnetManager { let mut txn = contract.pre_fund(U256::from(balance)); txn = self.handle_txn_token(&subnet, txn, 0, balance).await?; - let txn = call_with_premium_estimation(signer, txn).await?; + let txn = call_with_premium_and_pending_block(signer, txn).await?; txn.send().await?; Ok(()) @@ -398,7 +399,7 @@ impl SubnetManager for EthSubnetManager { let contract = subnet_actor_manager_facet::SubnetActorManagerFacet::new(address, signer.clone()); - call_with_premium_estimation(signer, contract.pre_release(amount.into())) + call_with_premium_and_pending_block(signer, contract.pre_release(amount.into())) .await? .send() .await? @@ -425,7 +426,7 @@ impl SubnetManager for EthSubnetManager { let mut txn = contract.stake(U256::from(collateral)); txn = self.handle_txn_token(&subnet, txn, collateral, 0).await?; - let txn = call_with_premium_estimation(signer, txn).await?; + let txn = call_with_premium_and_pending_block(signer, txn).await?; txn.send().await?.await?; @@ -452,7 +453,8 @@ impl SubnetManager for EthSubnetManager { let contract = subnet_actor_manager_facet::SubnetActorManagerFacet::new(address, signer.clone()); - let txn = call_with_premium_estimation(signer, contract.unstake(collateral.into())).await?; + let txn = call_with_premium_and_pending_block(signer, contract.unstake(collateral.into())) + .await?; txn.send().await?.await?; Ok(()) @@ -466,7 +468,7 @@ impl SubnetManager for EthSubnetManager { let contract = subnet_actor_manager_facet::SubnetActorManagerFacet::new(address, signer.clone()); - call_with_premium_estimation(signer, contract.leave()) + call_with_premium_and_pending_block(signer, contract.leave()) .await? .send() .await? @@ -483,7 +485,7 @@ impl SubnetManager for EthSubnetManager { let contract = subnet_actor_manager_facet::SubnetActorManagerFacet::new(address, signer.clone()); - call_with_premium_estimation(signer, contract.kill()) + call_with_premium_and_pending_block(signer, contract.kill()) .await? .send() .await? @@ -524,7 +526,7 @@ impl SubnetManager for EthSubnetManager { let contract = subnet_actor_reward_facet::SubnetActorRewardFacet::new(address, signer.clone()); - call_with_premium_estimation(signer, contract.claim()) + call_with_premium_and_pending_block(signer, contract.claim()) .await? .send() .await? @@ -564,7 +566,7 @@ impl SubnetManager for EthSubnetManager { gateway_manager_facet::FvmAddress::try_from(to)?, ); txn.tx.set_value(value); - let txn = call_with_premium_estimation(signer, txn).await?; + let txn = call_with_premium_and_pending_block(signer, txn).await?; let pending_tx = txn.send().await?; let receipt = pending_tx.retries(TRANSACTION_RECEIPT_RETRIES).await?; @@ -598,7 +600,7 @@ impl SubnetManager for EthSubnetManager { let token_contract = IERC20::new(token_address, signer.clone()); let txn = token_contract.approve(self.ipc_contract_info.gateway_addr, value); - let txn = call_with_premium_estimation(signer, txn).await?; + let txn = call_with_premium_and_pending_block(signer, txn).await?; let pending_tx = txn.send().await?; let receipt = pending_tx.retries(TRANSACTION_RECEIPT_RETRIES).await?; @@ -630,7 +632,7 @@ impl SubnetManager for EthSubnetManager { gateway_manager_facet::FvmAddress::try_from(to)?, value, ); - let txn = call_with_premium_estimation(signer, txn).await?; + let txn = call_with_premium_and_pending_block(signer, txn).await?; let pending_tx = txn.send().await?; let receipt = pending_tx.retries(TRANSACTION_RECEIPT_RETRIES).await?; @@ -660,7 +662,7 @@ impl SubnetManager for EthSubnetManager { ); let mut txn = gateway_contract.release(gateway_manager_facet::FvmAddress::try_from(to)?); txn.tx.set_value(value); - let txn = call_with_premium_estimation(signer, txn).await?; + let txn = call_with_premium_and_pending_block(signer, txn).await?; let pending_tx = txn.send().await?; let receipt = pending_tx.retries(TRANSACTION_RECEIPT_RETRIES).await?; @@ -695,7 +697,7 @@ impl SubnetManager for EthSubnetManager { let mut key = [0u8; 32]; key.copy_from_slice(&postbox_msg_key); - call_with_premium_estimation(signer, gateway_contract.propagate(key)) + call_with_premium_and_pending_block(signer, gateway_contract.propagate(key)) .await? .send() .await?; @@ -834,7 +836,7 @@ impl SubnetManager for EthSubnetManager { let contract = subnet_actor_manager_facet::SubnetActorManagerFacet::new(address, signer.clone()); - call_with_premium_estimation(signer, contract.add_bootstrap_node(endpoint)) + call_with_premium_and_pending_block(signer, contract.add_bootstrap_node(endpoint)) .await? .send() .await? @@ -911,7 +913,7 @@ impl SubnetManager for EthSubnetManager { tracing::debug!("from address: {:?}", from); let call = contract.set_federated_power(addresses, pubkeys, power_u256); - let txn = call_with_premium_estimation(signer, call).await?; + let txn = call_with_premium_and_pending_block(signer, call).await?; let pending_tx = txn.send().await?; let receipt = pending_tx.retries(TRANSACTION_RECEIPT_RETRIES).await?; block_number_from_receipt(receipt) @@ -1092,10 +1094,8 @@ impl EthSubnetManager { let wallet = LocalWallet::from_bytes(private_key.private_key())? .with_chain_id(self.ipc_contract_info.chain_id); - Ok(SignerMiddleware::new( - self.ipc_contract_info.provider.clone(), - wallet, - )) + let signer = SignerMiddleware::new(self.ipc_contract_info.provider.clone(), wallet); + Ok(signer) } pub fn from_subnet_with_wallet_store( @@ -1178,7 +1178,7 @@ impl BottomUpCheckpointRelayer for EthSubnetManager { signer.clone(), ); let call = contract.submit_checkpoint(checkpoint, signatories, signatures); - let call = call_with_premium_estimation(signer, call).await?; + let call = call_with_premium_and_pending_block(signer, call).await?; let pending_tx = call.send().await?; let receipt = pending_tx.retries(TRANSACTION_RECEIPT_RETRIES).await?; @@ -1278,9 +1278,10 @@ impl BottomUpCheckpointRelayer for EthSubnetManager { } } -/// Receives an input `FunctionCall` and returns a new instance -/// after estimating an optimal `gas_premium` for the transaction -pub(crate) async fn call_with_premium_estimation( +/// Takes a `FunctionCall` input and returns a new instance with an estimated optimal `gas_premium`. +/// The function also uses the pending block number to help retrieve the latest nonce +/// via `get_transaction_count` with the `pending` parameter. +pub(crate) async fn call_with_premium_and_pending_block( signer: Arc, call: ethers_contract::FunctionCall, ) -> Result> @@ -1289,7 +1290,9 @@ where M: ethers::abi::Detokenize, { let (max_priority_fee_per_gas, _) = premium_estimation(signer).await?; - Ok(call.gas_price(max_priority_fee_per_gas)) + Ok(call + .gas_price(max_priority_fee_per_gas) + .block(ethers::types::BlockNumber::Pending)) } /// Returns an estimation of an optimal `gas_premium` and `gas_fee_cap`