Skip to content

Commit

Permalink
SimulateTransactions integration tests (#628)
Browse files Browse the repository at this point in the history
* remove handle_transaction_result, refactor errors

* integration tests

* added new error type

* typo

* fixed unit tests

* fixed integration test

* remove fully qualified names in errors file

* changed test name

* reuse variable

* replace declare_deploy_v1 with declare_v3_deploy_v3

* add simulate transaction validation check

* add functionality

* refactor if else with match 

* remove trait implementation

* changed error variant

* commment
  • Loading branch information
marioiordanov authored Oct 22, 2024
1 parent 093add7 commit 79e288c
Show file tree
Hide file tree
Showing 19 changed files with 1,202 additions and 350 deletions.
66 changes: 58 additions & 8 deletions crates/starknet-devnet-core/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
use blockifier::fee::fee_checks::FeeCheckError;
use blockifier::transaction::errors::{
TransactionExecutionError, TransactionFeeError, TransactionPreValidationError,
};
use starknet_rs_core::types::{BlockId, Felt};
use starknet_types;
use starknet_types::contract_address::ContractAddress;
Expand All @@ -13,11 +17,11 @@ pub enum Error {
#[error(transparent)]
BlockifierStateError(#[from] blockifier::state::errors::StateError),
#[error(transparent)]
BlockifierTransactionError(#[from] blockifier::transaction::errors::TransactionExecutionError),
BlockifierTransactionError(TransactionExecutionError),
#[error(transparent)]
BlockifierExecutionError(#[from] blockifier::execution::errors::EntryPointExecutionError),
#[error("{revert_error}")]
ExecutionError { revert_error: String },
#[error("{execution_error}")]
ExecutionError { execution_error: String, index: usize },
#[error("Types error: {0}")]
TypesError(#[from] starknet_types::error::Error),
#[error("I/O error: {0}")]
Expand Down Expand Up @@ -56,14 +60,10 @@ pub enum Error {
SerializationError { origin: String },
#[error("Serialization not supported: {obj_name}")]
SerializationNotSupported { obj_name: String },
#[error(
"{tx_type}: max_fee cannot be zero (exception is v3 transaction where l2 gas must be zero)"
)]
MaxFeeZeroError { tx_type: String },
#[error(transparent)]
TransactionValidationError(#[from] TransactionValidationError),
#[error(transparent)]
TransactionFeeError(#[from] blockifier::transaction::errors::TransactionFeeError),
TransactionFeeError(blockifier::transaction::errors::TransactionFeeError),
#[error(transparent)]
MessagingError(#[from] MessagingError),
#[error("Transaction has no trace")]
Expand Down Expand Up @@ -104,6 +104,56 @@ pub enum TransactionValidationError {
ValidationFailure { reason: String },
}

impl From<TransactionExecutionError> for Error {
fn from(value: TransactionExecutionError) -> Self {
match value {
TransactionExecutionError::TransactionPreValidationError(
TransactionPreValidationError::InvalidNonce { .. },
) => TransactionValidationError::InvalidTransactionNonce.into(),
TransactionExecutionError::FeeCheckError(err) => err.into(),
TransactionExecutionError::TransactionPreValidationError(
TransactionPreValidationError::TransactionFeeError(err),
) => err.into(),
TransactionExecutionError::TransactionFeeError(err) => err.into(),
TransactionExecutionError::ValidateTransactionError { .. } => {
TransactionValidationError::ValidationFailure { reason: value.to_string() }.into()
}
other => Self::BlockifierTransactionError(other),
}
}
}

impl From<FeeCheckError> for Error {
fn from(value: FeeCheckError) -> Self {
match value {
FeeCheckError::MaxL1GasAmountExceeded { .. } | FeeCheckError::MaxFeeExceeded { .. } => {
TransactionValidationError::InsufficientMaxFee.into()
}
FeeCheckError::InsufficientFeeTokenBalance { .. } => {
TransactionValidationError::InsufficientAccountBalance.into()
}
}
}
}

impl From<TransactionFeeError> for Error {
fn from(value: TransactionFeeError) -> Self {
match value {
TransactionFeeError::FeeTransferError { .. }
| TransactionFeeError::MaxFeeTooLow { .. }
| TransactionFeeError::MaxL1GasPriceTooLow { .. }
| TransactionFeeError::MaxL1GasAmountTooLow { .. } => {
TransactionValidationError::InsufficientMaxFee.into()
}
TransactionFeeError::MaxFeeExceedsBalance { .. }
| TransactionFeeError::L1GasBoundsExceedBalance { .. } => {
TransactionValidationError::InsufficientAccountBalance.into()
}
err => Error::TransactionFeeError(err),
}
}
}

#[derive(Debug, Error)]
pub enum MessagingError {
#[error(
Expand Down
40 changes: 10 additions & 30 deletions crates/starknet-devnet-core/src/starknet/add_declare_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use starknet_types::rpc::transactions::{
BroadcastedDeclareTransaction, DeclareTransaction, Transaction, TransactionWithHash,
};

use crate::error::{DevnetResult, Error};
use crate::error::{DevnetResult, Error, TransactionValidationError};
use crate::starknet::Starknet;
use crate::state::CustomState;
use crate::utils::calculate_casm_hash;
Expand All @@ -18,9 +18,7 @@ pub fn add_declare_transaction(
broadcasted_declare_transaction: BroadcastedDeclareTransaction,
) -> DevnetResult<(TransactionHash, ClassHash)> {
if broadcasted_declare_transaction.is_max_fee_zero_value() {
return Err(Error::MaxFeeZeroError {
tx_type: broadcasted_declare_transaction.to_string(),
});
return Err(TransactionValidationError::InsufficientMaxFee.into());
}

if broadcasted_declare_transaction.is_only_query() {
Expand Down Expand Up @@ -79,7 +77,7 @@ pub fn add_declare_transaction(
)?);

let transaction = TransactionWithHash::new(transaction_hash, declare_transaction);
let blockifier_execution_result =
let blockifier_execution_info =
blockifier::transaction::account_transaction::AccountTransaction::Declare(
blockifier_declare_transaction,
)
Expand All @@ -88,16 +86,15 @@ pub fn add_declare_transaction(
&starknet.block_context,
true,
validate,
);
)?;

// if tx successful, store the class
if blockifier_execution_result.as_ref().is_ok_and(|res| !res.is_reverted()) {
if !blockifier_execution_info.is_reverted() {
let state = starknet.get_state();
state.declare_contract_class(class_hash, casm_hash, contract_class)?;
}

// do the steps required in all transactions
starknet.handle_transaction_result(transaction, blockifier_execution_result)?;
starknet.handle_accepted_transaction(transaction, blockifier_execution_info)?;

Ok((transaction_hash, class_hash))
}
Expand Down Expand Up @@ -149,6 +146,7 @@ mod tests {
use starknet_types::rpc::transactions::BroadcastedDeclareTransaction;
use starknet_types::traits::HashProducer;

use crate::error::{Error, TransactionValidationError};
use crate::starknet::tests::setup_starknet_with_no_signature_check_account;
use crate::starknet::Starknet;
use crate::state::{BlockNumberOrPending, CustomStateReader};
Expand Down Expand Up @@ -221,13 +219,7 @@ mod tests {

assert!(result.is_err());
match result.err().unwrap() {
err @ crate::error::Error::MaxFeeZeroError { .. } => {
assert_eq!(
err.to_string(),
"Declare transaction V3: max_fee cannot be zero (exception is v3 transaction \
where l2 gas must be zero)"
)
}
Error::TransactionValidationError(TransactionValidationError::InsufficientMaxFee) => {}
_ => panic!("Wrong error type"),
}
}
Expand All @@ -250,13 +242,7 @@ mod tests {

assert!(result.is_err());
match result.err().unwrap() {
err @ crate::error::Error::MaxFeeZeroError { .. } => {
assert_eq!(
err.to_string(),
"Declare transaction V2: max_fee cannot be zero (exception is v3 transaction \
where l2 gas must be zero)"
)
}
Error::TransactionValidationError(TransactionValidationError::InsufficientMaxFee) => {}
_ => panic!("Wrong error type"),
}
}
Expand Down Expand Up @@ -397,13 +383,7 @@ mod tests {

assert!(result.is_err());
match result.err().unwrap() {
err @ crate::error::Error::MaxFeeZeroError { .. } => {
assert_eq!(
err.to_string(),
"Declare transaction V1: max_fee cannot be zero (exception is v3 transaction \
where l2 gas must be zero)"
)
}
Error::TransactionValidationError(TransactionValidationError::InsufficientMaxFee) => {}
_ => panic!("Wrong error type"),
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,15 @@ use starknet_types::rpc::transactions::{
};

use super::Starknet;
use crate::error::{DevnetResult, Error};
use crate::error::{DevnetResult, Error, TransactionValidationError};
use crate::state::CustomStateReader;

pub fn add_deploy_account_transaction(
starknet: &mut Starknet,
broadcasted_deploy_account_transaction: BroadcastedDeployAccountTransaction,
) -> DevnetResult<(TransactionHash, ContractAddress)> {
if broadcasted_deploy_account_transaction.is_max_fee_zero_value() {
return Err(Error::MaxFeeZeroError {
tx_type: broadcasted_deploy_account_transaction.to_string(),
});
return Err(TransactionValidationError::InsufficientMaxFee.into());
}

if broadcasted_deploy_account_transaction.is_only_query() {
Expand Down Expand Up @@ -57,13 +55,13 @@ pub fn add_deploy_account_transaction(
let transaction_hash = blockifier_deploy_account_transaction.tx_hash.0;
let transaction = TransactionWithHash::new(transaction_hash, deploy_account_transaction);

let blockifier_execution_result =
let blockifier_execution_info =
blockifier::transaction::account_transaction::AccountTransaction::DeployAccount(
blockifier_deploy_account_transaction,
)
.execute(&mut starknet.pending_state.state, &starknet.block_context, true, true);
.execute(&mut starknet.pending_state.state, &starknet.block_context, true, true)?;

starknet.handle_transaction_result(transaction, blockifier_execution_result)?;
starknet.handle_accepted_transaction(transaction, blockifier_execution_info)?;

Ok((transaction_hash, address))
}
Expand All @@ -90,7 +88,7 @@ mod tests {
self, DEVNET_DEFAULT_CHAIN_ID, DEVNET_DEFAULT_STARTING_BLOCK_NUMBER,
ETH_ERC20_CONTRACT_ADDRESS, STRK_ERC20_CONTRACT_ADDRESS,
};
use crate::error::Error;
use crate::error::{Error, TransactionValidationError};
use crate::starknet::{predeployed, Starknet};
use crate::state::CustomState;
use crate::traits::{Deployed, HashIdentifiedMut};
Expand Down Expand Up @@ -157,13 +155,7 @@ mod tests {

assert!(result.is_err());
match result.err().unwrap() {
err @ crate::error::Error::MaxFeeZeroError { .. } => {
assert_eq!(
err.to_string(),
"Deploy account transaction V1: max_fee cannot be zero (exception is v3 \
transaction where l2 gas must be zero)"
)
}
Error::TransactionValidationError(TransactionValidationError::InsufficientMaxFee) => {}
_ => panic!("Wrong error type"),
}
}
Expand All @@ -180,13 +172,7 @@ mod tests {
))
.unwrap_err();
match txn_err {
err @ crate::error::Error::MaxFeeZeroError { .. } => {
assert_eq!(
err.to_string(),
"Deploy account transaction V3: max_fee cannot be zero (exception is v3 \
transaction where l2 gas must be zero)"
)
}
Error::TransactionValidationError(TransactionValidationError::InsufficientMaxFee) => {}
_ => panic!("Wrong error type"),
}
}
Expand Down
38 changes: 11 additions & 27 deletions crates/starknet-devnet-core/src/starknet/add_invoke_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ use starknet_types::rpc::transactions::{
};

use super::Starknet;
use crate::error::{DevnetResult, Error};
use crate::error::{DevnetResult, Error, TransactionValidationError};

pub fn add_invoke_transaction(
starknet: &mut Starknet,
broadcasted_invoke_transaction: BroadcastedInvokeTransaction,
) -> DevnetResult<TransactionHash> {
if broadcasted_invoke_transaction.is_max_fee_zero_value() {
return Err(Error::MaxFeeZeroError { tx_type: broadcasted_invoke_transaction.to_string() });
return Err(TransactionValidationError::InsufficientMaxFee.into());
}

if broadcasted_invoke_transaction.is_only_query() {
Expand Down Expand Up @@ -48,15 +48,15 @@ pub fn add_invoke_transaction(

let state = &mut starknet.get_state().state;

let blockifier_execution_result =
let blockifier_execution_info =
blockifier::transaction::account_transaction::AccountTransaction::Invoke(
blockifier_invoke_transaction,
)
.execute(state, &block_context, true, validate);
.execute(state, &block_context, true, validate)?;

let transaction = TransactionWithHash::new(transaction_hash, invoke_transaction);

starknet.handle_transaction_result(transaction, blockifier_execution_result)?;
starknet.handle_accepted_transaction(transaction, blockifier_execution_info)?;

Ok(transaction_hash)
}
Expand Down Expand Up @@ -89,6 +89,7 @@ mod tests {
self, DEVNET_DEFAULT_CHAIN_ID, DEVNET_DEFAULT_STARTING_BLOCK_NUMBER,
ETH_ERC20_CONTRACT_ADDRESS,
};
use crate::error::{Error, TransactionValidationError};
use crate::starknet::{predeployed, Starknet};
use crate::state::CustomState;
use crate::traits::{Accounted, Deployed, HashIdentifiedMut};
Expand Down Expand Up @@ -206,14 +207,7 @@ mod tests {
.expect_err("Expected MaxFeeZeroError");

match invoke_v3_txn_error {
err @ crate::error::Error::MaxFeeZeroError { .. } => {
assert_eq!(
err.to_string(),
"Invoke transaction V3: max_fee cannot be zero (exception is v3 transaction \
where l2 gas must be zero)"
.to_string()
);
}
Error::TransactionValidationError(TransactionValidationError::InsufficientMaxFee) => {}
_ => panic!("Wrong error type"),
}
}
Expand Down Expand Up @@ -282,13 +276,9 @@ mod tests {

assert!(transaction.is_err());
match transaction.err().unwrap() {
err @ crate::error::Error::MaxFeeZeroError { .. } => {
assert_eq!(
err.to_string(),
"Invoke transaction V3: max_fee cannot be zero (exception is v3 \
transaction where l2 gas must be zero)"
)
}
Error::TransactionValidationError(
TransactionValidationError::InsufficientMaxFee,
) => {}
_ => {
panic!("Wrong error type")
}
Expand Down Expand Up @@ -389,13 +379,7 @@ mod tests {

assert!(result.is_err());
match result.err().unwrap() {
err @ crate::error::Error::MaxFeeZeroError { .. } => {
assert_eq!(
err.to_string(),
"Invoke transaction V1: max_fee cannot be zero (exception is v3 transaction \
where l2 gas must be zero)"
)
}
Error::TransactionValidationError(TransactionValidationError::InsufficientMaxFee) => {}
_ => panic!("Wrong error type"),
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ pub fn add_l1_handler_transaction(
let charge_fee = false;
let validate = true;

let blockifier_execution_result = blockifier_transaction.execute(
let blockifier_execution_info = blockifier_transaction.execute(
&mut starknet.pending_state.state,
&starknet.block_context,
charge_fee,
validate,
);
)?;

starknet.handle_transaction_result(
starknet.handle_accepted_transaction(
TransactionWithHash::new(transaction_hash, Transaction::L1Handler(transaction.clone())),
blockifier_execution_result,
blockifier_execution_info,
)?;

Ok(transaction_hash)
Expand Down
Loading

0 comments on commit 79e288c

Please sign in to comment.