Skip to content

Commit

Permalink
feat: support skip_validate in mempool
Browse files Browse the repository at this point in the history
  • Loading branch information
Yael-Starkware committed Jul 15, 2024
1 parent 06cc71b commit 41fb6a8
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 8 deletions.
1 change: 1 addition & 0 deletions crates/mempool/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ derive_more.workspace = true
starknet_mempool_infra = { path = "../mempool_infra", version = "0.0" }
starknet_api.workspace = true
starknet_mempool_types = { path = "../mempool_types", version = "0.0" }
starknet-types-core.workspace = true
tokio.workspace = true

[dev-dependencies]
Expand Down
24 changes: 24 additions & 0 deletions crates/mempool/src/mempool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ use std::collections::HashMap;

use starknet_api::core::{ContractAddress, Nonce};
use starknet_api::transaction::{Tip, TransactionHash};
use starknet_mempool_types::errors::MempoolError;
use starknet_mempool_types::mempool_types::{
Account, AccountState, MempoolInput, MempoolResult, ThinTransaction,
};
use starknet_types_core::felt::Felt;

use crate::transaction_pool::TransactionPool;
use crate::transaction_queue::TransactionQueue;
Expand Down Expand Up @@ -61,6 +63,9 @@ impl Mempool {
/// TODO: support fee escalation and transactions with future nonces.
/// TODO: check Account nonce and balance.
pub fn add_tx(&mut self, input: MempoolInput) -> MempoolResult<()> {
// TODO(Yael 8/7/2024): Consider removing this check and instead add an API for the gateway
// to check if the deploy_account tx exists.
self.should_insert(&input)?;
self.insert_tx(input)
}

Expand Down Expand Up @@ -88,6 +93,25 @@ impl Mempool {
Ok(())
}

pub fn should_insert(&self, input: &MempoolInput) -> MempoolResult<()> {
// If the tx nonce is 1 and the account nonce is 0, the account was not deployed yet and the
// gateway has skipped validations. In this case, we need to verify that a deploy_account
// transaction exists for this account. It is suficient to check if the account exists in
// the mempool since it means that either it has a deploy_account transaction or
// transactions with future nonces that passed validations.
// TODO(Yael 8/7/2024): Consider instead of checking the nonces, get a value from the
// gateway that indicates that the mempool needs to check the deploy_account existence.
if input.tx.nonce == Nonce(Felt::ONE)
&& input.account.state.nonce == Nonce(Felt::ZERO)
&& !self.tx_pool.contains_address(input.tx.sender_address)
{
return Err(MempoolError::UndeployedAccount {
sender_address: input.tx.sender_address,
});
}
Ok(())
}

#[cfg(test)]
pub(crate) fn _tx_pool(&self) -> &TransactionPool {
&self.tx_pool
Expand Down
29 changes: 29 additions & 0 deletions crates/mempool/src/mempool_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ impl FromIterator<TransactionReference> for TransactionQueue {
}
}

const TEST_SENDER_ADDRESS: u8 = 0x1;

#[track_caller]
fn add_tx(mempool: &mut Mempool, input: &MempoolInput) {
assert_eq!(mempool.add_tx(input.clone()), Ok(()));
Expand Down Expand Up @@ -264,3 +266,30 @@ fn test_tip_priority_over_tx_hash(mut mempool: Mempool) {
add_tx(&mut mempool, &input_small_tip_big_hash);
assert_eq_mempool_queue(&mempool, &[input_big_tip_small_hash.tx, input_small_tip_big_hash.tx])
}

#[rstest]
#[case::empty_mempool(Mempool::empty())]
#[case::mempool_contains_another_address(Mempool::new([
add_tx_input!(tip: 0, tx_hash: 1, sender_address: 0x2345_u16, tx_nonce: 2_u8, account_nonce: 0_u8),])
.unwrap()
)]
// TODO(Yael 7/7/2024) - add case for mempool that contains a transaction with nonce 0, and no error
// is received. This case is not available now since the mempool doesn't supoprt multiple nonces per
// account.
fn test_undeployed_account(#[case] mut mempool: Mempool) {
let input = add_tx_input!(
tip: 0,
tx_hash: 0,
sender_address: TEST_SENDER_ADDRESS,
tx_nonce: 1_u8,
account_nonce: 0_u8
);
let result = mempool.add_tx(input.clone());

assert_eq!(
result,
Err(MempoolError::UndeployedAccount {
sender_address: contract_address!(TEST_SENDER_ADDRESS)
})
);
}
12 changes: 4 additions & 8 deletions crates/mempool/src/transaction_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,8 @@ impl TransactionPool {
self.tx_pool.get(&tx_hash).ok_or(MempoolError::TransactionNotFound { tx_hash })
}

pub fn get_by_address_and_nonce(
&self,
address: ContractAddress,
nonce: Nonce,
) -> Option<&TransactionReference> {
self.txs_by_account.get(address, nonce)
pub fn contains_address(&self, address: ContractAddress) -> bool {
self.txs_by_account.contains(address)
}

#[cfg(test)]
Expand Down Expand Up @@ -101,7 +97,7 @@ impl AccountTransactionIndex {
removed_tx
}

fn get(&self, address: ContractAddress, nonce: Nonce) -> Option<&TransactionReference> {
self.0.get(&address)?.get(&nonce)
fn contains(&self, address: ContractAddress) -> bool {
self.0.contains_key(&address)
}
}
3 changes: 3 additions & 0 deletions crates/mempool_types/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use starknet_api::core::ContractAddress;
use starknet_api::transaction::TransactionHash;
use thiserror::Error;

#[derive(Clone, Debug, Error, PartialEq, Eq)]
pub enum MempoolError {
#[error("Duplicate transaction, with hash: {tx_hash}")]
DuplicateTransaction { tx_hash: TransactionHash },
#[error("Undeployed account {:?}", sender_address)]
UndeployedAccount { sender_address: ContractAddress },
#[error("Transaction with hash: {tx_hash} not found")]
TransactionNotFound { tx_hash: TransactionHash },
}

0 comments on commit 41fb6a8

Please sign in to comment.