From 06cfd122e4a62c1fb6de6f463afc32fb53569da8 Mon Sep 17 00:00:00 2001 From: Thomas Coratger Date: Mon, 28 Oct 2024 23:30:15 +0100 Subject: [PATCH 1/4] nonce management: query nonce on-chain before relaying tx --- src/bin/hive_chain.rs | 14 +- src/main.rs | 2 +- src/pool/mempool.rs | 136 ++++++------------ .../eth_provider/starknet/relayer.rs | 29 ++-- src/test_utils/eoa.rs | 17 +-- tests/tests/eth_provider.rs | 24 +--- 6 files changed, 74 insertions(+), 148 deletions(-) diff --git a/src/bin/hive_chain.rs b/src/bin/hive_chain.rs index 1c8ce0798..a808d14c0 100644 --- a/src/bin/hive_chain.rs +++ b/src/bin/hive_chain.rs @@ -6,7 +6,7 @@ use clap::Parser; use kakarot_rpc::{ constants::STARKNET_CHAIN_ID, into_via_try_wrapper, - providers::{eth_provider::starknet::relayer::LockedRelayer, sn_provider::StarknetProvider}, + providers::{eth_provider::starknet::relayer::Relayer, sn_provider::StarknetProvider}, }; use reth_primitives::{Block, BlockBody}; use starknet::{ @@ -14,7 +14,7 @@ use starknet::{ providers::{jsonrpc::HttpTransport, JsonRpcClient, Provider}, }; use std::{path::PathBuf, str::FromStr}; -use tokio::{fs::File, io::AsyncReadExt, sync::Mutex}; +use tokio::{fs::File, io::AsyncReadExt}; use tokio_stream::StreamExt; use tokio_util::codec::{Decoder, FramedRead}; use url::Url; @@ -72,9 +72,8 @@ async fn main() -> eyre::Result<()> { let relayer_balance = starknet_provider.balance_at(args.relayer_address, BlockId::Tag(BlockTag::Latest)).await?; let relayer_balance = into_via_try_wrapper!(relayer_balance)?; - let current_nonce = Mutex::new(Felt::ZERO); - let mut relayer = LockedRelayer::new( - current_nonce.lock().await, + let mut current_nonce = Felt::ZERO; + let relayer = Relayer::new( args.relayer_address, relayer_balance, JsonRpcClient::new(HttpTransport::new(Url::from_str(STARKNET_RPC_URL)?)), @@ -105,12 +104,11 @@ async fn main() -> eyre::Result<()> { } for transaction in &body.transactions { - relayer.relay_transaction(transaction).await?; + relayer.relay_transaction(transaction, current_nonce).await?; tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; // Increase the relayer's nonce - let nonce = relayer.nonce_mut(); - *nonce += Felt::ONE; + current_nonce += Felt::ONE; } } diff --git a/src/main.rs b/src/main.rs index f5342c21a..fe7915cd9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -63,7 +63,7 @@ async fn main() -> Result<()> { // Start the relayer manager let addresses = var("RELAYERS_ADDRESSES")?.split(',').filter_map(|addr| Felt::from_str(addr).ok()).collect::>(); - AccountManager::from_addresses(addresses, Arc::clone(ð_client)).await?.start(); + AccountManager::from_addresses(addresses, Arc::clone(ð_client))?.start(); // Start the maintenance of the mempool maintain_transaction_pool(Arc::clone(ð_client), PRUNE_DURATION); diff --git a/src/pool/mempool.rs b/src/pool/mempool.rs index 468fe7d0a..e528639c0 100644 --- a/src/pool/mempool.rs +++ b/src/pool/mempool.rs @@ -6,10 +6,9 @@ use crate::{ constants::KAKAROT_RPC_CONFIG, into_via_try_wrapper, pool::constants::ONE_TENTH_ETH, - providers::eth_provider::{database::state::EthDatabase, starknet::relayer::LockedRelayer, BlockProvider}, + providers::eth_provider::{database::state::EthDatabase, starknet::relayer::Relayer, BlockProvider}, }; use alloy_primitives::{Address, U256}; -use futures::future::select_all; use rand::{seq::SliceRandom, SeedableRng}; use reth_chainspec::ChainSpec; use reth_execution_types::ChangedAccount; @@ -20,11 +19,11 @@ use reth_transaction_pool::{ TransactionOrigin, TransactionPool, TransactionPoolExt, }; use starknet::{ - core::types::{requests::GetNonceRequest, BlockId, BlockTag, Felt}, - providers::{jsonrpc::HttpTransport, JsonRpcClient, ProviderRequestData, ProviderResponseData}, + core::types::{BlockTag, Felt}, + providers::{jsonrpc::HttpTransport, JsonRpcClient}, }; use std::{collections::HashMap, sync::Arc, time::Duration}; -use tokio::{sync::Mutex, time::Instant}; +use tokio::time::Instant; use tracing::instrument; /// A type alias for the Kakarot Transaction Validator. @@ -38,31 +37,25 @@ pub type TransactionOrdering = CoinbaseTipOrdering; /// A type alias for the Kakarot Sequencer Mempool. pub type KakarotPool = Pool, TransactionOrdering, NoopBlobStore>; -/// Manages a collection of accounts and their associated nonces, interfacing with an Ethereum client. +/// Manages a collection of accounts addresses, interfacing with an Ethereum client. /// /// This struct provides functionality to initialize account data from a file, monitor account balances, /// and process transactions for accounts with sufficient balance. #[derive(Debug)] pub struct AccountManager { - /// A shared, mutable collection of accounts and their nonces. - accounts: HashMap>>, + /// A collection of account addresses. + accounts: Vec, /// The Ethereum client used to interact with the blockchain. eth_client: Arc>, } impl AccountManager { /// Initialize the account manager with a set of passed accounts. - pub async fn from_addresses(addresses: Vec, eth_client: Arc>) -> eyre::Result { - let mut accounts = HashMap::new(); + pub fn from_addresses(addresses: Vec, eth_client: Arc>) -> eyre::Result { + let mut accounts = Vec::new(); for add in addresses { - // Query the initial account_nonce for the account from the provider - let nonce = eth_client - .starknet_provider() - .get_nonce(starknet::core::types::BlockId::Tag(BlockTag::Pending), add) - .await - .unwrap_or_default(); - accounts.insert(add, Arc::new(Mutex::new(nonce))); + accounts.push(add); } Ok(Self { accounts, eth_client }) @@ -73,9 +66,6 @@ impl AccountM pub fn start(self) { let this = Arc::new(self); - // Start the nonce updater in a separate task - this.clone().start_nonce_updater(); - tokio::spawn(async move { loop { // TODO: add a listener on the pool and only try to call [`best_transaction`] @@ -99,7 +89,7 @@ impl AccountM let manager = this.clone(); tokio::spawn(async move { // Lock the relayer account - let maybe_relayer = manager.lock_account().await; + let maybe_relayer = manager.get_relayer().await; if maybe_relayer.is_err() { // If we fail to fetch a relayer, we need to re-insert the transaction in the pool tracing::error!(target: "account_manager", err = ?maybe_relayer.unwrap_err(), "failed to fetch relayer"); @@ -110,11 +100,21 @@ impl AccountM .await; return; } - let mut relayer = maybe_relayer.expect("maybe_lock is not error"); + let relayer = maybe_relayer.expect("maybe_lock is not error"); // Send the Ethereum transaction using the relayer let transaction_signed = transaction.to_recovered_transaction().into_signed(); - let res = relayer.relay_transaction(&transaction_signed).await; + + // Query the updated nonce for the account from the provider. + // Via on chain query we have the most up-to-date nonce. + let relayer_nonce = manager + .eth_client + .starknet_provider() + .get_nonce(starknet::core::types::BlockId::Tag(BlockTag::Pending), relayer.address()) + .await + .unwrap_or_default(); + + let res = relayer.relay_transaction(&transaction_signed, relayer_nonce).await; if res.is_err() { // If the relayer failed to relay the transaction, we need to reposition it in the mempool tracing::error!(target: "account_manager", err = ?res.unwrap_err(), "failed to relay transaction"); @@ -127,10 +127,6 @@ impl AccountM } tracing::info!(target: "account_manager", starknet_hash = ?res.expect("not error"), ethereum_hash = ?transaction_signed.hash()); - - // Increment account_nonce after sending a transaction - let nonce = relayer.nonce_mut(); - *nonce = *nonce + 1; }); } @@ -140,58 +136,45 @@ impl AccountM } /// Returns the next available account from the manager. - pub async fn lock_account(&self) -> eyre::Result>> + pub async fn get_relayer(&self) -> eyre::Result>> where SP: starknet::providers::Provider + Send + Sync + Clone + 'static, { // Use `StdRng` instead of `ThreadRng` as it is `Send` let mut rng = rand::rngs::StdRng::from_entropy(); - // Collect the accounts into a vector for shuffling - let mut accounts: Vec<_> = self.accounts.iter().collect(); + // Shuffle indices of accounts randomly + let mut account_indices: Vec<_> = (0..self.accounts.len()).collect(); + account_indices.shuffle(&mut rng); - // Shuffle the accounts randomly before iterating - accounts.shuffle(&mut rng); + for index in account_indices { + let account_address = self.accounts[index]; - loop { - if accounts.is_empty() { - return Err(eyre::eyre!("failed to fetch funded account")); - } + // Retrieve the balance of the selected account + let balance = self.get_balance(account_address).await?; - // Create the future locks with indices for more efficient removal - // use [`select_all`] to poll an iterator over impl Future)> - // We use Box::pin because this Future doesn't implement `Unpin`. - let fut_locks = accounts - .iter() - .enumerate() - .map(|(index, (address, nonce))| Box::pin(async move { (index, *address, nonce.lock().await) })); - - // Select the first account that gets unlocked - let ((index, account_address, guard), _, _) = select_all(fut_locks).await; - - // Fetch the balance of the selected account - let balance = self.get_balance(*account_address).await?; - - // If the balance is lower than the threshold, remove the account using swap_remove + // Skip accounts with insufficient balance if balance < U256::from(ONE_TENTH_ETH) { - accounts.swap_remove(index); continue; } - let balance = into_via_try_wrapper!(balance)?; + // Retrieve chain ID for the Ethereum context let chain_id = self.eth_client.starknet_provider().chain_id().await?; + let balance = into_via_try_wrapper!(balance)?; - let account = LockedRelayer::new( - guard, - *account_address, + // Construct the `Relayer` with the account address and other relevant data + let account = Relayer::new( + account_address, balance, JsonRpcClient::new(HttpTransport::new(KAKAROT_RPC_CONFIG.network_url.clone())), chain_id, ); - // Return the account address and the guard on the nonce + // Return the locked relayer instance return Ok(account); } + + Err(eyre::eyre!("failed to fetch funded account")) } /// Retrieves the balance of the specified account address for the [`BlockTag::Pending`] @@ -203,45 +186,6 @@ impl AccountM .await .map_err(Into::into) } - - /// Update the nonces for all accounts every minute. - pub fn start_nonce_updater(self: Arc) { - tokio::spawn(async move { - loop { - // Convert the account addresses into batch requests - let requests = self - .accounts - .keys() - .map(|add| { - ProviderRequestData::GetNonce(GetNonceRequest { - contract_address: *add, - block_id: BlockId::Tag(BlockTag::Pending), - }) - }) - .collect::>(); - - // Try to make the request to the provider. If it fails, display error and retry 1 minute later. - let maybe_new_nonces = self.eth_client.starknet_provider().batch_requests(requests).await; - if maybe_new_nonces.is_err() { - tracing::error!(target: "account_manager", err = ?maybe_new_nonces.unwrap_err(), "failed to get nonces"); - // Sleep for 1 minute before the next update - tokio::time::sleep(Duration::from_secs(60)).await; - continue; - } - let new_nonces = maybe_new_nonces.expect("not error"); - - for ((address, old_nonce), new_nonce) in self.accounts.iter().zip(new_nonces) { - if let ProviderResponseData::GetNonce(new_nonce) = new_nonce { - *old_nonce.lock().await = new_nonce; - tracing::info!(target: "account_manager", ?address, ?new_nonce); - }; - } - - // Sleep for 1 minute before the next update - tokio::time::sleep(Duration::from_secs(60)).await; - } - }); - } } #[derive(Default)] diff --git a/src/providers/eth_provider/starknet/relayer.rs b/src/providers/eth_provider/starknet/relayer.rs index 6b797607b..db0655d81 100644 --- a/src/providers/eth_provider/starknet/relayer.rs +++ b/src/providers/eth_provider/starknet/relayer.rs @@ -14,7 +14,6 @@ use starknet::{ signers::{LocalWallet, SigningKey}, }; use std::{env::var, ops::Deref, str::FromStr, sync::LazyLock}; -use tokio::sync::MutexGuard; /// Signer for all relayers static RELAYER_SIGNER: LazyLock = LazyLock::new(|| { @@ -24,33 +23,35 @@ static RELAYER_SIGNER: LazyLock = LazyLock::new(|| { )) }); -/// A relayer holding a lock on a mutex on an account and connected to the Starknet network. +/// A relayer holding an account and a balance. +/// /// The relayer is used to sign transactions and broadcast them on the network. #[derive(Debug)] -pub struct LockedRelayer<'a, SP: Provider + Send + Sync> { +pub struct Relayer { /// The account used to sign and broadcast the transaction account: SingleOwnerAccount, /// The balance of the relayer balance: Felt, - /// The locked nonce held by the relayer - nonce: MutexGuard<'a, Felt>, } -impl<'a, SP> LockedRelayer<'a, SP> +impl Relayer where SP: Provider + Send + Sync, { - /// Create a new relayer with the provided Starknet provider, address, balance and nonce. - pub fn new(lock: MutexGuard<'a, Felt>, address: Felt, balance: Felt, provider: SP, chain_id: Felt) -> Self { + /// Create a new relayer with the provided Starknet provider, address, balance. + pub fn new(address: Felt, balance: Felt, provider: SP, chain_id: Felt) -> Self { let relayer = SingleOwnerAccount::new(provider, RELAYER_SIGNER.clone(), address, chain_id, ExecutionEncoding::New); - Self { account: relayer, balance, nonce: lock } + Self { account: relayer, balance } } /// Relay the provided Ethereum transaction on the Starknet network. + /// The relayer nonce is directly fetched from the chain to have the most up-to-date value. + /// This is a way to avoid nonce issues. + /// /// Returns the corresponding Starknet transaction hash. - pub async fn relay_transaction(&self, transaction: &TransactionSigned) -> EthApiResult { + pub async fn relay_transaction(&self, transaction: &TransactionSigned, relayer_nonce: Felt) -> EthApiResult { // Transform the transaction's data to Starknet calldata let relayer_address = self.account.address(); let calldata = transaction_data_to_starknet_calldata(transaction, relayer_address)?; @@ -62,7 +63,7 @@ where // Construct the call let call = starknet::core::types::Call { to: eoa_address, selector: *EXECUTE_FROM_OUTSIDE, calldata }; let mut execution = ExecutionV1::new(vec![call], &self.account); - execution = execution.nonce(*self.nonce); + execution = execution.nonce(relayer_nonce); // We set the max fee to the balance of the account / 5. This means that the account could // send up to 5 transactions before hitting a feeder gateway error. @@ -74,12 +75,12 @@ where Ok(res.transaction_hash) } - pub fn nonce_mut(&mut self) -> &mut Felt { - &mut self.nonce + pub fn address(&self) -> Felt { + self.account.address() } } -impl<'a, SP> Deref for LockedRelayer<'a, SP> +impl Deref for Relayer where SP: Provider + Send + Sync, { diff --git a/src/test_utils/eoa.rs b/src/test_utils/eoa.rs index f1592c0ea..52d31dd9f 100644 --- a/src/test_utils/eoa.rs +++ b/src/test_utils/eoa.rs @@ -2,7 +2,7 @@ use crate::{ client::{EthClient, KakarotTransactions}, into_via_try_wrapper, providers::eth_provider::{ - starknet::{kakarot_core::starknet_address, relayer::LockedRelayer}, + starknet::{kakarot_core::starknet_address, relayer::Relayer}, ChainProvider, TransactionProvider, }, test_utils::{ @@ -28,7 +28,6 @@ use starknet::{ signers::LocalWallet, }; use std::sync::Arc; -use tokio::sync::Mutex; pub const TX_GAS_LIMIT: u64 = 5_000_000; pub const TX_GAS_PRICE: u64 = 10; @@ -164,17 +163,14 @@ impl KakarotEOA

{ .await .unwrap_or_default(); - let current_nonce = Mutex::new(nonce); - // Relay the transaction - let starknet_transaction_hash = LockedRelayer::new( - current_nonce.lock().await, + let starknet_transaction_hash = Relayer::new( self.relayer.address(), relayer_balance, self.starknet_provider(), self.starknet_provider().chain_id().await.expect("Failed to get chain id"), ) - .relay_transaction(&tx_signed) + .relay_transaction(&tx_signed, nonce) .await .expect("Failed to relay transaction"); @@ -248,17 +244,14 @@ impl KakarotEOA

{ .await .unwrap_or_default(); - let current_nonce = Mutex::new(nonce); - // Relay the transaction - let starknet_transaction_hash = LockedRelayer::new( - current_nonce.lock().await, + let starknet_transaction_hash = Relayer::new( self.relayer.address(), relayer_balance, self.starknet_provider(), self.starknet_provider().chain_id().await.expect("Failed to get chain id"), ) - .relay_transaction(&tx_signed) + .relay_transaction(&tx_signed, nonce) .await .expect("Failed to relay transaction"); diff --git a/tests/tests/eth_provider.rs b/tests/tests/eth_provider.rs index ec4934850..20fd19181 100644 --- a/tests/tests/eth_provider.rs +++ b/tests/tests/eth_provider.rs @@ -20,7 +20,7 @@ use kakarot_rpc::{ constant::{MAX_LOGS, STARKNET_MODULUS}, database::{ethereum::EthereumTransactionStore, types::transaction::StoredTransaction}, provider::EthereumProvider, - starknet::relayer::LockedRelayer, + starknet::relayer::Relayer, BlockProvider, ChainProvider, GasProvider, LogProvider, ReceiptProvider, StateProvider, TransactionProvider, }, test_utils::{ @@ -41,7 +41,6 @@ use starknet::{ providers::Provider, }; use std::sync::Arc; -use tokio::sync::Mutex; #[rstest] #[awt] @@ -754,17 +753,14 @@ async fn test_send_raw_transaction(#[future] katana_empty: Katana, _setup: ()) { .await .unwrap_or_default(); - let current_nonce = Mutex::new(nonce); - // Relay the transaction - let _ = LockedRelayer::new( - current_nonce.lock().await, + let _ = Relayer::new( katana.eoa.relayer.address(), relayer_balance, &(*(*eth_client.starknet_provider())), eth_client.starknet_provider().chain_id().await.expect("Failed to get chain id"), ) - .relay_transaction(&transaction_signed) + .relay_transaction(&transaction_signed, nonce) .await .expect("Failed to relay transaction"); @@ -1012,17 +1008,14 @@ async fn test_send_raw_transaction_pre_eip_155(#[future] katana_empty: Katana, _ .await .unwrap_or_default(); - let current_nonce = Mutex::new(nonce); - // Relay the transaction - let starknet_transaction_hash = LockedRelayer::new( - current_nonce.lock().await, + let starknet_transaction_hash = Relayer::new( katana.eoa.relayer.address(), relayer_balance, &(*(*katana.eth_client.starknet_provider())), katana.eth_client.starknet_provider().chain_id().await.expect("Failed to get chain id"), ) - .relay_transaction(&transaction_signed) + .relay_transaction(&transaction_signed, nonce) .await .expect("Failed to relay transaction"); @@ -1374,17 +1367,14 @@ async fn test_transaction_by_hash(#[future] katana_empty: Katana, _setup: ()) { .await .unwrap_or_default(); - let current_nonce = Mutex::new(nonce); - // Relay the transaction - let _ = LockedRelayer::new( - current_nonce.lock().await, + let _ = Relayer::new( katana_empty.eoa.relayer.address(), relayer_balance, &(*(*katana_empty.eth_client.starknet_provider())), katana_empty.eth_client.starknet_provider().chain_id().await.expect("Failed to get chain id"), ) - .relay_transaction(&transaction_signed) + .relay_transaction(&transaction_signed, nonce) .await .expect("Failed to relay transaction"); From b7260658db3f295b46bbfcf888c67016d7b39bf7 Mon Sep 17 00:00:00 2001 From: Thomas Coratger Date: Tue, 29 Oct 2024 09:02:13 +0100 Subject: [PATCH 2/4] fix comments --- src/bin/hive_chain.rs | 2 -- src/main.rs | 2 +- src/pool/mempool.rs | 16 ++++------------ src/providers/eth_provider/starknet/relayer.rs | 6 +++--- src/test_utils/eoa.rs | 2 -- tests/tests/eth_provider.rs | 3 --- 6 files changed, 8 insertions(+), 23 deletions(-) diff --git a/src/bin/hive_chain.rs b/src/bin/hive_chain.rs index a808d14c0..e405e2655 100644 --- a/src/bin/hive_chain.rs +++ b/src/bin/hive_chain.rs @@ -4,7 +4,6 @@ use alloy_primitives::bytes::{Buf, BytesMut}; use alloy_rlp::Decodable; use clap::Parser; use kakarot_rpc::{ - constants::STARKNET_CHAIN_ID, into_via_try_wrapper, providers::{eth_provider::starknet::relayer::Relayer, sn_provider::StarknetProvider}, }; @@ -77,7 +76,6 @@ async fn main() -> eyre::Result<()> { args.relayer_address, relayer_balance, JsonRpcClient::new(HttpTransport::new(Url::from_str(STARKNET_RPC_URL)?)), - *STARKNET_CHAIN_ID, ); // Read the rlp file diff --git a/src/main.rs b/src/main.rs index fe7915cd9..6ccf61e5f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -63,7 +63,7 @@ async fn main() -> Result<()> { // Start the relayer manager let addresses = var("RELAYERS_ADDRESSES")?.split(',').filter_map(|addr| Felt::from_str(addr).ok()).collect::>(); - AccountManager::from_addresses(addresses, Arc::clone(ð_client))?.start(); + AccountManager::new(addresses, Arc::clone(ð_client)).start(); // Start the maintenance of the mempool maintain_transaction_pool(Arc::clone(ð_client), PRUNE_DURATION); diff --git a/src/pool/mempool.rs b/src/pool/mempool.rs index e528639c0..33495231a 100644 --- a/src/pool/mempool.rs +++ b/src/pool/mempool.rs @@ -51,14 +51,8 @@ pub struct AccountManager AccountManager { /// Initialize the account manager with a set of passed accounts. - pub fn from_addresses(addresses: Vec, eth_client: Arc>) -> eyre::Result { - let mut accounts = Vec::new(); - - for add in addresses { - accounts.push(add); - } - - Ok(Self { accounts, eth_client }) + pub const fn new(accounts: Vec, eth_client: Arc>) -> Self { + Self { accounts, eth_client } } /// Starts the account manager task that periodically checks account balances and processes transactions. @@ -100,7 +94,7 @@ impl AccountM .await; return; } - let relayer = maybe_relayer.expect("maybe_lock is not error"); + let relayer = maybe_relayer.expect("not error"); // Send the Ethereum transaction using the relayer let transaction_signed = transaction.to_recovered_transaction().into_signed(); @@ -158,8 +152,7 @@ impl AccountM continue; } - // Retrieve chain ID for the Ethereum context - let chain_id = self.eth_client.starknet_provider().chain_id().await?; + // Convert the balance to `Felt` let balance = into_via_try_wrapper!(balance)?; // Construct the `Relayer` with the account address and other relevant data @@ -167,7 +160,6 @@ impl AccountM account_address, balance, JsonRpcClient::new(HttpTransport::new(KAKAROT_RPC_CONFIG.network_url.clone())), - chain_id, ); // Return the locked relayer instance diff --git a/src/providers/eth_provider/starknet/relayer.rs b/src/providers/eth_provider/starknet/relayer.rs index db0655d81..2ac391176 100644 --- a/src/providers/eth_provider/starknet/relayer.rs +++ b/src/providers/eth_provider/starknet/relayer.rs @@ -5,7 +5,7 @@ use crate::{ provider::EthApiResult, starknet::kakarot_core::{starknet_address, EXECUTE_FROM_OUTSIDE}, }, -}; +};use crate::constants::STARKNET_CHAIN_ID; use reth_primitives::TransactionSigned; use starknet::{ accounts::{Account, ExecutionEncoding, ExecutionV1, SingleOwnerAccount}, @@ -39,9 +39,9 @@ where SP: Provider + Send + Sync, { /// Create a new relayer with the provided Starknet provider, address, balance. - pub fn new(address: Felt, balance: Felt, provider: SP, chain_id: Felt) -> Self { + pub fn new(address: Felt, balance: Felt, provider: SP) -> Self { let relayer = - SingleOwnerAccount::new(provider, RELAYER_SIGNER.clone(), address, chain_id, ExecutionEncoding::New); + SingleOwnerAccount::new(provider, RELAYER_SIGNER.clone(), address, *STARKNET_CHAIN_ID, ExecutionEncoding::New); Self { account: relayer, balance } } diff --git a/src/test_utils/eoa.rs b/src/test_utils/eoa.rs index 52d31dd9f..00b8a28fd 100644 --- a/src/test_utils/eoa.rs +++ b/src/test_utils/eoa.rs @@ -168,7 +168,6 @@ impl KakarotEOA

{ self.relayer.address(), relayer_balance, self.starknet_provider(), - self.starknet_provider().chain_id().await.expect("Failed to get chain id"), ) .relay_transaction(&tx_signed, nonce) .await @@ -249,7 +248,6 @@ impl KakarotEOA

{ self.relayer.address(), relayer_balance, self.starknet_provider(), - self.starknet_provider().chain_id().await.expect("Failed to get chain id"), ) .relay_transaction(&tx_signed, nonce) .await diff --git a/tests/tests/eth_provider.rs b/tests/tests/eth_provider.rs index 20fd19181..47447dcaa 100644 --- a/tests/tests/eth_provider.rs +++ b/tests/tests/eth_provider.rs @@ -758,7 +758,6 @@ async fn test_send_raw_transaction(#[future] katana_empty: Katana, _setup: ()) { katana.eoa.relayer.address(), relayer_balance, &(*(*eth_client.starknet_provider())), - eth_client.starknet_provider().chain_id().await.expect("Failed to get chain id"), ) .relay_transaction(&transaction_signed, nonce) .await @@ -1013,7 +1012,6 @@ async fn test_send_raw_transaction_pre_eip_155(#[future] katana_empty: Katana, _ katana.eoa.relayer.address(), relayer_balance, &(*(*katana.eth_client.starknet_provider())), - katana.eth_client.starknet_provider().chain_id().await.expect("Failed to get chain id"), ) .relay_transaction(&transaction_signed, nonce) .await @@ -1372,7 +1370,6 @@ async fn test_transaction_by_hash(#[future] katana_empty: Katana, _setup: ()) { katana_empty.eoa.relayer.address(), relayer_balance, &(*(*katana_empty.eth_client.starknet_provider())), - katana_empty.eth_client.starknet_provider().chain_id().await.expect("Failed to get chain id"), ) .relay_transaction(&transaction_signed, nonce) .await From 3f38e5350237949018e29686d504b1f4dc28bbdd Mon Sep 17 00:00:00 2001 From: Thomas Coratger Date: Tue, 29 Oct 2024 09:04:29 +0100 Subject: [PATCH 3/4] fmt --- src/pool/mempool.rs | 2 +- .../eth_provider/starknet/relayer.rs | 12 ++++++--- src/test_utils/eoa.rs | 24 ++++++------------ tests/tests/eth_provider.rs | 25 +++++++------------ 4 files changed, 27 insertions(+), 36 deletions(-) diff --git a/src/pool/mempool.rs b/src/pool/mempool.rs index 33495231a..36536758e 100644 --- a/src/pool/mempool.rs +++ b/src/pool/mempool.rs @@ -52,7 +52,7 @@ pub struct AccountManager AccountManager { /// Initialize the account manager with a set of passed accounts. pub const fn new(accounts: Vec, eth_client: Arc>) -> Self { - Self { accounts, eth_client } + Self { accounts, eth_client } } /// Starts the account manager task that periodically checks account balances and processes transactions. diff --git a/src/providers/eth_provider/starknet/relayer.rs b/src/providers/eth_provider/starknet/relayer.rs index 2ac391176..841361150 100644 --- a/src/providers/eth_provider/starknet/relayer.rs +++ b/src/providers/eth_provider/starknet/relayer.rs @@ -1,11 +1,12 @@ use crate::{ + constants::STARKNET_CHAIN_ID, models::transaction::transaction_data_to_starknet_calldata, providers::eth_provider::{ error::{SignatureError, TransactionError}, provider::EthApiResult, starknet::kakarot_core::{starknet_address, EXECUTE_FROM_OUTSIDE}, }, -};use crate::constants::STARKNET_CHAIN_ID; +}; use reth_primitives::TransactionSigned; use starknet::{ accounts::{Account, ExecutionEncoding, ExecutionV1, SingleOwnerAccount}, @@ -40,8 +41,13 @@ where { /// Create a new relayer with the provided Starknet provider, address, balance. pub fn new(address: Felt, balance: Felt, provider: SP) -> Self { - let relayer = - SingleOwnerAccount::new(provider, RELAYER_SIGNER.clone(), address, *STARKNET_CHAIN_ID, ExecutionEncoding::New); + let relayer = SingleOwnerAccount::new( + provider, + RELAYER_SIGNER.clone(), + address, + *STARKNET_CHAIN_ID, + ExecutionEncoding::New, + ); Self { account: relayer, balance } } diff --git a/src/test_utils/eoa.rs b/src/test_utils/eoa.rs index 00b8a28fd..a3ba26a7e 100644 --- a/src/test_utils/eoa.rs +++ b/src/test_utils/eoa.rs @@ -164,14 +164,10 @@ impl KakarotEOA

{ .unwrap_or_default(); // Relay the transaction - let starknet_transaction_hash = Relayer::new( - self.relayer.address(), - relayer_balance, - self.starknet_provider(), - ) - .relay_transaction(&tx_signed, nonce) - .await - .expect("Failed to relay transaction"); + let starknet_transaction_hash = Relayer::new(self.relayer.address(), relayer_balance, self.starknet_provider()) + .relay_transaction(&tx_signed, nonce) + .await + .expect("Failed to relay transaction"); watch_tx( self.eth_client.eth_provider().starknet_provider_inner(), @@ -244,14 +240,10 @@ impl KakarotEOA

{ .unwrap_or_default(); // Relay the transaction - let starknet_transaction_hash = Relayer::new( - self.relayer.address(), - relayer_balance, - self.starknet_provider(), - ) - .relay_transaction(&tx_signed, nonce) - .await - .expect("Failed to relay transaction"); + let starknet_transaction_hash = Relayer::new(self.relayer.address(), relayer_balance, self.starknet_provider()) + .relay_transaction(&tx_signed, nonce) + .await + .expect("Failed to relay transaction"); watch_tx( self.eth_client.eth_provider().starknet_provider_inner(), diff --git a/tests/tests/eth_provider.rs b/tests/tests/eth_provider.rs index 47447dcaa..ba5bbf737 100644 --- a/tests/tests/eth_provider.rs +++ b/tests/tests/eth_provider.rs @@ -754,14 +754,10 @@ async fn test_send_raw_transaction(#[future] katana_empty: Katana, _setup: ()) { .unwrap_or_default(); // Relay the transaction - let _ = Relayer::new( - katana.eoa.relayer.address(), - relayer_balance, - &(*(*eth_client.starknet_provider())), - ) - .relay_transaction(&transaction_signed, nonce) - .await - .expect("Failed to relay transaction"); + let _ = Relayer::new(katana.eoa.relayer.address(), relayer_balance, &(*(*eth_client.starknet_provider()))) + .relay_transaction(&transaction_signed, nonce) + .await + .expect("Failed to relay transaction"); // Retrieve the current size of the mempool let mempool_size_after_send = eth_client.mempool().pool_size(); @@ -1008,14 +1004,11 @@ async fn test_send_raw_transaction_pre_eip_155(#[future] katana_empty: Katana, _ .unwrap_or_default(); // Relay the transaction - let starknet_transaction_hash = Relayer::new( - katana.eoa.relayer.address(), - relayer_balance, - &(*(*katana.eth_client.starknet_provider())), - ) - .relay_transaction(&transaction_signed, nonce) - .await - .expect("Failed to relay transaction"); + let starknet_transaction_hash = + Relayer::new(katana.eoa.relayer.address(), relayer_balance, &(*(*katana.eth_client.starknet_provider()))) + .relay_transaction(&transaction_signed, nonce) + .await + .expect("Failed to relay transaction"); watch_tx( eth_provider.starknet_provider_inner(), From cf494bb471afe667c8d045a30f39f860e5138d47 Mon Sep 17 00:00:00 2001 From: Thomas Coratger Date: Tue, 29 Oct 2024 12:15:49 +0100 Subject: [PATCH 4/4] fix comment --- src/bin/hive_chain.rs | 6 +---- src/pool/mempool.rs | 11 +------- .../eth_provider/starknet/relayer.rs | 15 ++++++++--- src/test_utils/eoa.rs | 18 ++----------- tests/tests/eth_provider.rs | 27 +++---------------- 5 files changed, 19 insertions(+), 58 deletions(-) diff --git a/src/bin/hive_chain.rs b/src/bin/hive_chain.rs index e405e2655..859ae257c 100644 --- a/src/bin/hive_chain.rs +++ b/src/bin/hive_chain.rs @@ -71,7 +71,6 @@ async fn main() -> eyre::Result<()> { let relayer_balance = starknet_provider.balance_at(args.relayer_address, BlockId::Tag(BlockTag::Latest)).await?; let relayer_balance = into_via_try_wrapper!(relayer_balance)?; - let mut current_nonce = Felt::ZERO; let relayer = Relayer::new( args.relayer_address, relayer_balance, @@ -102,11 +101,8 @@ async fn main() -> eyre::Result<()> { } for transaction in &body.transactions { - relayer.relay_transaction(transaction, current_nonce).await?; + relayer.relay_transaction(transaction).await?; tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; - - // Increase the relayer's nonce - current_nonce += Felt::ONE; } } diff --git a/src/pool/mempool.rs b/src/pool/mempool.rs index 36536758e..4e42bfff2 100644 --- a/src/pool/mempool.rs +++ b/src/pool/mempool.rs @@ -99,16 +99,7 @@ impl AccountM // Send the Ethereum transaction using the relayer let transaction_signed = transaction.to_recovered_transaction().into_signed(); - // Query the updated nonce for the account from the provider. - // Via on chain query we have the most up-to-date nonce. - let relayer_nonce = manager - .eth_client - .starknet_provider() - .get_nonce(starknet::core::types::BlockId::Tag(BlockTag::Pending), relayer.address()) - .await - .unwrap_or_default(); - - let res = relayer.relay_transaction(&transaction_signed, relayer_nonce).await; + let res = relayer.relay_transaction(&transaction_signed).await; if res.is_err() { // If the relayer failed to relay the transaction, we need to reposition it in the mempool tracing::error!(target: "account_manager", err = ?res.unwrap_err(), "failed to relay transaction"); diff --git a/src/providers/eth_provider/starknet/relayer.rs b/src/providers/eth_provider/starknet/relayer.rs index 841361150..b090bc237 100644 --- a/src/providers/eth_provider/starknet/relayer.rs +++ b/src/providers/eth_provider/starknet/relayer.rs @@ -9,8 +9,8 @@ use crate::{ }; use reth_primitives::TransactionSigned; use starknet::{ - accounts::{Account, ExecutionEncoding, ExecutionV1, SingleOwnerAccount}, - core::types::{Felt, NonZeroFelt}, + accounts::{Account, ConnectedAccount, ExecutionEncoding, ExecutionV1, SingleOwnerAccount}, + core::types::{BlockTag, Felt, NonZeroFelt}, providers::Provider, signers::{LocalWallet, SigningKey}, }; @@ -57,7 +57,7 @@ where /// This is a way to avoid nonce issues. /// /// Returns the corresponding Starknet transaction hash. - pub async fn relay_transaction(&self, transaction: &TransactionSigned, relayer_nonce: Felt) -> EthApiResult { + pub async fn relay_transaction(&self, transaction: &TransactionSigned) -> EthApiResult { // Transform the transaction's data to Starknet calldata let relayer_address = self.account.address(); let calldata = transaction_data_to_starknet_calldata(transaction, relayer_address)?; @@ -69,6 +69,15 @@ where // Construct the call let call = starknet::core::types::Call { to: eoa_address, selector: *EXECUTE_FROM_OUTSIDE, calldata }; let mut execution = ExecutionV1::new(vec![call], &self.account); + + // Fetch the relayer nonce from the Starknet provider + let relayer_nonce = self + .account + .provider() + .get_nonce(starknet::core::types::BlockId::Tag(BlockTag::Pending), relayer_address) + .await + .unwrap_or_default(); + execution = execution.nonce(relayer_nonce); // We set the max fee to the balance of the account / 5. This means that the account could diff --git a/src/test_utils/eoa.rs b/src/test_utils/eoa.rs index a3ba26a7e..6ff87a814 100644 --- a/src/test_utils/eoa.rs +++ b/src/test_utils/eoa.rs @@ -156,16 +156,9 @@ impl KakarotEOA

{ .await?; let relayer_balance = into_via_try_wrapper!(relayer_balance)?; - let nonce = self - .eth_client - .starknet_provider() - .get_nonce(BlockId::Tag(BlockTag::Latest), self.relayer.address()) - .await - .unwrap_or_default(); - // Relay the transaction let starknet_transaction_hash = Relayer::new(self.relayer.address(), relayer_balance, self.starknet_provider()) - .relay_transaction(&tx_signed, nonce) + .relay_transaction(&tx_signed) .await .expect("Failed to relay transaction"); @@ -232,16 +225,9 @@ impl KakarotEOA

{ .await?; let relayer_balance = into_via_try_wrapper!(relayer_balance)?; - let nonce = self - .eth_client - .starknet_provider() - .get_nonce(BlockId::Tag(BlockTag::Latest), self.relayer.address()) - .await - .unwrap_or_default(); - // Relay the transaction let starknet_transaction_hash = Relayer::new(self.relayer.address(), relayer_balance, self.starknet_provider()) - .relay_transaction(&tx_signed, nonce) + .relay_transaction(&tx_signed) .await .expect("Failed to relay transaction"); diff --git a/tests/tests/eth_provider.rs b/tests/tests/eth_provider.rs index ba5bbf737..a4754fbfe 100644 --- a/tests/tests/eth_provider.rs +++ b/tests/tests/eth_provider.rs @@ -38,7 +38,6 @@ use rstest::*; use starknet::{ accounts::Account, core::types::{BlockId, BlockTag, Felt}, - providers::Provider, }; use std::sync::Arc; @@ -747,15 +746,9 @@ async fn test_send_raw_transaction(#[future] katana_empty: Katana, _setup: ()) { .expect("Failed to get relayer balance"); let relayer_balance = into_via_try_wrapper!(relayer_balance).expect("Failed to convert balance"); - let nonce = eth_client - .starknet_provider() - .get_nonce(BlockId::Tag(BlockTag::Latest), katana.eoa.relayer.address()) - .await - .unwrap_or_default(); - // Relay the transaction let _ = Relayer::new(katana.eoa.relayer.address(), relayer_balance, &(*(*eth_client.starknet_provider()))) - .relay_transaction(&transaction_signed, nonce) + .relay_transaction(&transaction_signed) .await .expect("Failed to relay transaction"); @@ -996,17 +989,10 @@ async fn test_send_raw_transaction_pre_eip_155(#[future] katana_empty: Katana, _ .expect("Failed to get relayer balance"); let relayer_balance = into_via_try_wrapper!(relayer_balance).expect("Failed to convert balance"); - let nonce = katana - .eth_client - .starknet_provider() - .get_nonce(BlockId::Tag(BlockTag::Latest), katana.eoa.relayer.address()) - .await - .unwrap_or_default(); - // Relay the transaction let starknet_transaction_hash = Relayer::new(katana.eoa.relayer.address(), relayer_balance, &(*(*katana.eth_client.starknet_provider()))) - .relay_transaction(&transaction_signed, nonce) + .relay_transaction(&transaction_signed) .await .expect("Failed to relay transaction"); @@ -1351,20 +1337,13 @@ async fn test_transaction_by_hash(#[future] katana_empty: Katana, _setup: ()) { .expect("Failed to get relayer balance"); let relayer_balance = into_via_try_wrapper!(relayer_balance).expect("Failed to convert balance"); - let nonce = katana_empty - .eth_client - .starknet_provider() - .get_nonce(BlockId::Tag(BlockTag::Latest), katana_empty.eoa.relayer.address()) - .await - .unwrap_or_default(); - // Relay the transaction let _ = Relayer::new( katana_empty.eoa.relayer.address(), relayer_balance, &(*(*katana_empty.eth_client.starknet_provider())), ) - .relay_transaction(&transaction_signed, nonce) + .relay_transaction(&transaction_signed) .await .expect("Failed to relay transaction");