Skip to content

Commit

Permalink
refactor: replace invoke json file with macro creation (#131)
Browse files Browse the repository at this point in the history
  • Loading branch information
ayeletstarkware authored May 23, 2024
1 parent b11fc8f commit af7eab1
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 86 deletions.
14 changes: 9 additions & 5 deletions crates/gateway/src/gateway_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,19 @@ use tokio::sync::mpsc::channel;

use crate::config::{StatefulTransactionValidatorConfig, StatelessTransactionValidatorConfig};
use crate::gateway::{add_tx, AppState};
use crate::starknet_api_test_utils::invoke_tx;
use crate::starknet_api_test_utils::{external_invoke_tx_to_json, invoke_tx};
use crate::state_reader_test_utils::test_state_reader_factory;
use crate::stateful_transaction_validator::StatefulTransactionValidator;
use crate::stateless_transaction_validator::StatelessTransactionValidator;

// TODO(Ayelet): Replace the use of the JSON files with generated instances, then serialize these
// into JSON for testing.
// TODO(Ayelet): add test cases for declare and deploy account transactions.
#[rstest]
// TODO (Yael 19/5/2024): Add declare and deploy_account in the next milestone
#[case::invoke(invoke_tx(), "INVOKE")]
#[tokio::test]
async fn test_add_tx(#[case] tx: ExternalTransaction, #[case] expected_response: &str) {
async fn test_add_tx(
#[case] external_invoke_tx: ExternalTransaction,
#[case] expected_response: &str,
) {
// The `_rx_gateway_to_mempool` is retained to keep the channel open, as dropping it would
// prevent the sender from transmitting messages.
let (tx_gateway_to_mempool, _rx_gateway_to_mempool) = channel::<GatewayToMempoolMessage>(1);
Expand All @@ -35,6 +36,9 @@ async fn test_add_tx(#[case] tx: ExternalTransaction, #[case] expected_response:
let network_component =
Arc::new(GatewayNetworkComponent::new(tx_gateway_to_mempool, rx_mempool_to_gateway));

let json_string = external_invoke_tx_to_json(external_invoke_tx);
let tx: ExternalTransaction = serde_json::from_str(&json_string).unwrap();

let mut app_state = AppState {
stateless_transaction_validator: StatelessTransactionValidator {
config: StatelessTransactionValidatorConfig {
Expand Down
165 changes: 108 additions & 57 deletions crates/gateway/src/starknet_api_test_utils.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use blockifier::test_utils::contracts::FeatureContract;
use blockifier::test_utils::{create_trivial_calldata, CairoVersion, NonceManager};
use serde_json::to_string_pretty;
use starknet_api::calldata;
use starknet_api::core::{ContractAddress, Nonce};
use starknet_api::data_availability::DataAvailabilityMode;
use starknet_api::external_transaction::{
Expand All @@ -10,10 +12,12 @@ use starknet_api::external_transaction::{
use starknet_api::hash::StarkFelt;
use starknet_api::internal_transaction::{InternalInvokeTransaction, InternalTransaction};
use starknet_api::transaction::{
Calldata, InvokeTransaction, InvokeTransactionV3, ResourceBounds, ResourceBoundsMapping,
TransactionSignature,
AccountDeploymentData, Calldata, InvokeTransaction, InvokeTransactionV3, PaymasterData,
ResourceBounds, ResourceBoundsMapping, Tip, TransactionSignature, TransactionVersion,
};

use crate::invoke_tx_args;

pub const VALID_L1_GAS_MAX_AMOUNT: u64 = 2214;
pub const VALID_L1_GAS_MAX_PRICE_PER_UNIT: u128 = 100000000000;

Expand Down Expand Up @@ -63,21 +67,17 @@ pub fn create_internal_tx_for_testing() -> InternalTransaction {
pub fn external_tx_for_testing(
transaction_type: TransactionType,
resource_bounds: ResourceBoundsMapping,
calldata: Option<Calldata>,
calldata: Calldata,
signature: TransactionSignature,
) -> ExternalTransaction {
match transaction_type {
TransactionType::Declare => external_declare_tx_for_testing(resource_bounds, signature),
TransactionType::DeployAccount => external_deploy_account_tx_for_testing(
resource_bounds,
calldata.expect("Calldata is missing."),
signature,
),
TransactionType::Invoke => external_invoke_tx_for_testing(
resource_bounds,
calldata.expect("Calldata is missing."),
signature,
),
TransactionType::DeployAccount => {
external_deploy_account_tx_for_testing(resource_bounds, calldata, signature)
}
TransactionType::Invoke => {
external_invoke_tx(invoke_tx_args!(signature, resource_bounds, calldata))
}
}
}

Expand Down Expand Up @@ -121,43 +121,6 @@ fn external_deploy_account_tx_for_testing(
))
}

fn external_invoke_tx_for_testing(
resource_bounds: ResourceBoundsMapping,
calldata: Calldata,
signature: TransactionSignature,
) -> ExternalTransaction {
executable_external_invoke_tx_for_testing(
resource_bounds,
Nonce::default(),
ContractAddress::default(),
calldata,
signature,
)
}

// TODO(yael 24/4/24): remove this function and generalize the external_tx_for_testing function.
// and add a struct for default args (ExteranlTransactionForTestingArgs)
pub fn executable_external_invoke_tx_for_testing(
resource_bounds: ResourceBoundsMapping,
nonce: Nonce,
sender_address: ContractAddress,
calldata: Calldata,
signature: TransactionSignature,
) -> ExternalTransaction {
ExternalTransaction::Invoke(ExternalInvokeTransaction::V3(ExternalInvokeTransactionV3 {
resource_bounds,
tip: Default::default(),
signature,
nonce,
sender_address,
calldata,
nonce_data_availability_mode: DataAvailabilityMode::L1,
fee_data_availability_mode: DataAvailabilityMode::L1,
paymaster_data: Default::default(),
account_deployment_data: Default::default(),
}))
}

pub const NON_EMPTY_RESOURCE_BOUNDS: ResourceBounds =
ResourceBounds { max_amount: 1, max_price_per_unit: 1 };

Expand Down Expand Up @@ -203,11 +166,99 @@ pub fn invoke_tx() -> ExternalTransaction {
let calldata = create_trivial_calldata(test_contract_address);
let mut nonce_manager = NonceManager::default();
let nonce = nonce_manager.next(account_address);
executable_external_invoke_tx_for_testing(
executable_resource_bounds_mapping(),
nonce,
account_address,
calldata,
TransactionSignature(vec![StarkFelt::ZERO]),
)
external_invoke_tx(invoke_tx_args! {
signature: TransactionSignature(vec![StarkFelt::ZERO]),
contract_address: account_address,
resource_bounds: executable_resource_bounds_mapping(),
nonce,
calldata
})
}

#[derive(Clone)]
pub struct InvokeTxArgs {
pub signature: TransactionSignature,
pub contract_address: ContractAddress,
pub calldata: Calldata,
pub version: TransactionVersion,
pub resource_bounds: ResourceBoundsMapping,
pub tip: Tip,
pub nonce_data_availability_mode: DataAvailabilityMode,
pub fee_data_availability_mode: DataAvailabilityMode,
pub paymaster_data: PaymasterData,
pub account_deployment_data: AccountDeploymentData,
pub nonce: Nonce,
}
impl Default for InvokeTxArgs {
fn default() -> Self {
InvokeTxArgs {
signature: TransactionSignature::default(),
contract_address: ContractAddress::default(),
calldata: calldata![],
version: TransactionVersion::THREE,
resource_bounds: zero_resource_bounds_mapping(),
tip: Tip::default(),
nonce_data_availability_mode: DataAvailabilityMode::L1,
fee_data_availability_mode: DataAvailabilityMode::L1,
paymaster_data: PaymasterData::default(),
account_deployment_data: AccountDeploymentData::default(),
nonce: Nonce::default(),
}
}
}

// TODO(Ayelet, 15/5/2025): Consider moving this to StarkNet API.
#[macro_export]
macro_rules! invoke_tx_args {
($($field:ident $(: $value:expr)?),* $(,)?) => {
$crate::starknet_api_test_utils::InvokeTxArgs {
$($field $(: $value)?,)*
..Default::default()
}
};
($($field:ident $(: $value:expr)?),* , ..$defaults:expr) => {
$crate::starknet_api_test_utils::InvokeTxArgs {
$($field $(: $value)?,)*
..$defaults
}
};
}

pub fn external_invoke_tx(invoke_args: InvokeTxArgs) -> ExternalTransaction {
match invoke_args.version {
TransactionVersion::THREE => {
starknet_api::external_transaction::ExternalTransaction::Invoke(
starknet_api::external_transaction::ExternalInvokeTransaction::V3(
ExternalInvokeTransactionV3 {
resource_bounds: invoke_args.resource_bounds,
tip: invoke_args.tip,
calldata: invoke_args.calldata,
sender_address: invoke_args.contract_address,
nonce: invoke_args.nonce,
signature: invoke_args.signature,
nonce_data_availability_mode: invoke_args.nonce_data_availability_mode,
fee_data_availability_mode: invoke_args.fee_data_availability_mode,
paymaster_data: invoke_args.paymaster_data,
account_deployment_data: invoke_args.account_deployment_data,
},
),
)
}
_ => panic!("Unsupported transaction version: {:?}.", invoke_args.version),
}
}

pub fn external_invoke_tx_to_json(tx: ExternalTransaction) -> String {
// Serialize to JSON
let mut tx_json = serde_json::to_value(&tx)
.unwrap_or_else(|_| panic!("Failed to serialize transaction: {tx:?}"));

// Add type and version manually
tx_json.as_object_mut().unwrap().extend([
("type".to_string(), "INVOKE_FUNCTION".into()),
("version".to_string(), "0x3".into()),
]);

// Serialize back to pretty JSON string
to_string_pretty(&tx_json).expect("Failed to serialize transaction")
}
19 changes: 9 additions & 10 deletions crates/gateway/src/stateful_transaction_validator_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ use starknet_api::transaction::TransactionHash;

use crate::config::StatefulTransactionValidatorConfig;
use crate::errors::{StatefulTransactionValidatorError, StatefulTransactionValidatorResult};
use crate::invoke_tx_args;
use crate::starknet_api_test_utils::{
executable_external_invoke_tx_for_testing, executable_resource_bounds_mapping,
VALID_L1_GAS_MAX_AMOUNT, VALID_L1_GAS_MAX_PRICE_PER_UNIT,
executable_resource_bounds_mapping, external_invoke_tx, VALID_L1_GAS_MAX_AMOUNT,
VALID_L1_GAS_MAX_PRICE_PER_UNIT,
};
use crate::state_reader_test_utils::{TestStateReader, TestStateReaderFactory};
use crate::stateful_transaction_validator::StatefulTransactionValidator;
Expand Down Expand Up @@ -46,7 +47,7 @@ fn test_stateful_transaction_validator(
let cairo_version = CairoVersion::Cairo1;
let block_context = &BlockContext::create_for_testing();
let account_contract = FeatureContract::AccountWithoutValidations(cairo_version);
let account_address = account_contract.get_instance_address(0);
let contract_address = account_contract.get_instance_address(0);
let test_contract = FeatureContract::TestContract(cairo_version);
let test_contract_address = test_contract.get_instance_address(0);

Expand Down Expand Up @@ -74,14 +75,12 @@ fn test_stateful_transaction_validator(

let calldata = create_trivial_calldata(test_contract_address);
let mut nonce_manager = NonceManager::default();
let nonce = nonce_manager.next(account_address);
let external_tx = executable_external_invoke_tx_for_testing(
executable_resource_bounds_mapping(),
let nonce = nonce_manager.next(contract_address);
let external_tx = external_invoke_tx(invoke_tx_args!(
resource_bounds: executable_resource_bounds_mapping(),
nonce,
account_address,
calldata,
Default::default(),
);
contract_address,
calldata));

let result = stateful_validator.run_validate(&state_reader_factory, &external_tx, None, None);
assert_eq!(format!("{:?}", result), format!("{:?}", expected_result));
Expand Down
8 changes: 4 additions & 4 deletions crates/gateway/src/stateless_transaction_validator_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ fn test_positive_flow(
tx_type: TransactionType,
) {
let tx_validator = StatelessTransactionValidator { config };
let tx = external_tx_for_testing(tx_type, resource_bounds, Some(tx_calldata), signature);
let tx = external_tx_for_testing(tx_type, resource_bounds, tx_calldata, signature);

assert!(tx_validator.validate(&tx).is_ok());
}
Expand Down Expand Up @@ -120,7 +120,7 @@ fn test_invalid_resource_bounds(
let tx = external_tx_for_testing(
tx_type,
resource_bounds,
Some(calldata![]),
calldata![],
TransactionSignature::default(),
);

Expand All @@ -136,7 +136,7 @@ fn test_calldata_too_long(
let tx = external_tx_for_testing(
tx_type,
non_zero_resource_bounds_mapping(),
Some(calldata![StarkFelt::from_u128(1), StarkFelt::from_u128(2)]),
calldata![StarkFelt::from_u128(1), StarkFelt::from_u128(2)],
TransactionSignature::default(),
);

Expand All @@ -159,7 +159,7 @@ fn test_signature_too_long(
let tx = external_tx_for_testing(
tx_type,
non_zero_resource_bounds_mapping(),
Some(calldata![]),
calldata![],
TransactionSignature(vec![StarkFelt::from_u128(1), StarkFelt::from_u128(2)]),
);

Expand Down
10 changes: 6 additions & 4 deletions crates/gateway/tests/end_to_end_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ use axum::http::{Request, StatusCode};
use hyper::{Client, Response};
use mempool_infra::network_component::CommunicationInterface;
use rstest::rstest;
use starknet_api::external_transaction::ExternalTransaction;
use starknet_api::transaction::{Tip, TransactionHash};
use starknet_gateway::config::{
GatewayConfig, GatewayNetworkConfig, StatefulTransactionValidatorConfig,
StatelessTransactionValidatorConfig,
};
use starknet_gateway::gateway::Gateway;
use starknet_gateway::starknet_api_test_utils::invoke_tx;
use starknet_gateway::starknet_api_test_utils::{external_invoke_tx_to_json, invoke_tx};
use starknet_gateway::state_reader_test_utils::test_state_reader_factory;
use starknet_mempool::mempool::Mempool;
use starknet_mempool_types::mempool_types::{
Expand Down Expand Up @@ -97,9 +98,10 @@ async fn set_up_gateway(network_component: GatewayNetworkComponent) -> (IpAddr,
async fn send_and_verify_transaction(
ip: IpAddr,
port: u16,
tx_json: String,
tx: ExternalTransaction,
expected_response: &str,
) {
let tx_json = external_invoke_tx_to_json(tx);
let request = Request::builder()
.method("POST")
.uri(format!("http://{}", SocketAddr::from((ip, port))) + "/add_tx")
Expand Down Expand Up @@ -136,8 +138,8 @@ async fn test_end_to_end() {
let (ip, port) = set_up_gateway(gateway_to_mempool_network).await;

// Send a transaction.
let invoke_json = serde_json::to_string(&invoke_tx()).unwrap();
send_and_verify_transaction(ip, port, invoke_json, "INVOKE").await;
let external_tx = invoke_tx();
send_and_verify_transaction(ip, port, external_tx, "INVOKE").await;

// Initialize Mempool.
let mut mempool = Mempool::empty(mempool_to_gateway_network, batcher_channels);
Expand Down
13 changes: 7 additions & 6 deletions crates/gateway/tests/routing_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,23 @@ use starknet_gateway::config::{
StatelessTransactionValidatorConfig,
};
use starknet_gateway::gateway::Gateway;
use starknet_gateway::starknet_api_test_utils::invoke_tx;
use starknet_gateway::starknet_api_test_utils::{external_invoke_tx_to_json, invoke_tx};
use starknet_gateway::state_reader_test_utils::test_state_reader_factory;
use starknet_mempool_types::mempool_types::{
GatewayNetworkComponent, GatewayToMempoolMessage, MempoolToGatewayMessage,
};
use tokio::sync::mpsc::channel;
use tower::ServiceExt;

// TODO(Ayelet): Replace the use of the JSON files with generated instances, then serialize these
// into JSON for testing.
// TODO(Ayelet): add test cases for declare and deploy account transactions.
#[rstest]
// TODO (Yael 19/5/2024): Add declare and deploy_account in the next milestone
#[case::invoke(invoke_tx(), "INVOKE")]
#[tokio::test]
async fn test_routes(#[case] tx: ExternalTransaction, #[case] expected_response: &str) {
let tx_json = serde_json::to_string(&tx).unwrap();
async fn test_routes(
#[case] external_invoke_tx: ExternalTransaction,
#[case] expected_response: &str,
) {
let tx_json = external_invoke_tx_to_json(external_invoke_tx);
let request = Request::post("/add_tx")
.header("content-type", "application/json")
.body(Body::from(tx_json))
Expand Down

0 comments on commit af7eab1

Please sign in to comment.