From fd340a8cdbc065e1a16d0b2474ff80c348f8c276 Mon Sep 17 00:00:00 2001 From: Dori Medini Date: Thu, 30 Apr 2026 16:47:35 +0300 Subject: [PATCH] central_systest_blobs: deploy operator account --- Cargo.lock | 3 + crates/central_systest_blobs/Cargo.toml | 3 + .../resources/blob_file_generation | 2 +- .../resources/preconfirmed_block.json | 60 +++++++++------ .../src/cende_blob_regression_test.rs | 73 ++++++++++++++++++- 5 files changed, 117 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 140880ec5bf..94799622639 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4883,6 +4883,9 @@ dependencies = [ "mockall", "serde", "serde_json", + "starknet-core", + "starknet-crypto 0.8.1", + "starknet-types-core", "starknet_api", "starknet_committer", "starknet_patricia_storage", diff --git a/crates/central_systest_blobs/Cargo.toml b/crates/central_systest_blobs/Cargo.toml index e689a770e66..d9a277b6966 100644 --- a/crates/central_systest_blobs/Cargo.toml +++ b/crates/central_systest_blobs/Cargo.toml @@ -21,6 +21,9 @@ http.workspace = true mockall.workspace = true serde.workspace = true serde_json.workspace = true +starknet-core.workspace = true +starknet-crypto.workspace = true +starknet-types-core.workspace = true starknet_api = { workspace = true, features = ["testing"] } starknet_committer = { workspace = true, features = ["testing"] } starknet_patricia_storage = { workspace = true, features = ["testing"] } diff --git a/crates/central_systest_blobs/resources/blob_file_generation b/crates/central_systest_blobs/resources/blob_file_generation index 62f9457511f..c7930257dfe 100644 --- a/crates/central_systest_blobs/resources/blob_file_generation +++ b/crates/central_systest_blobs/resources/blob_file_generation @@ -1 +1 @@ -6 \ No newline at end of file +7 \ No newline at end of file diff --git a/crates/central_systest_blobs/resources/preconfirmed_block.json b/crates/central_systest_blobs/resources/preconfirmed_block.json index daa375f8112..683d4d0d346 100644 --- a/crates/central_systest_blobs/resources/preconfirmed_block.json +++ b/crates/central_systest_blobs/resources/preconfirmed_block.json @@ -1,5 +1,5 @@ { - "block_number": 1, + "block_number": 2, "pre_confirmed_block": { "l1_da_mode": "CALLDATA", "l1_data_gas_price": { @@ -17,53 +17,68 @@ "sequencer_address": "0x1000", "starknet_version": "0.14.3", "status": "PRE_CONFIRMED", - "timestamp": 1001, + "timestamp": 1002, "transaction_receipts": [ { - "actual_fee": "0x0", + "actual_fee": "0xf8a7b", "events": [], "execution_resources": { - "builtin_instance_counter": {}, + "builtin_instance_counter": { + "pedersen_builtin": 12, + "poseidon_builtin": 12, + "range_check_builtin": 93 + }, "data_availability": { "l1_data_gas": 0, - "l1_gas": 0, + "l1_gas": 3305, "l2_gas": 0 }, "n_memory_holes": 0, - "n_steps": 0, + "n_steps": 4602, "total_gas_consumed": { "l1_data_gas": 0, - "l1_gas": 0, - "l2_gas": 0 + "l1_gas": 3856, + "l2_gas": 1014635 } }, "execution_status": "SUCCEEDED", "l2_to_l1_messages": [], - "transaction_hash": "0x2bd201c1de8711bc3748efdbba3b2e997d44792dee9b4a8c598cf8663f99824", + "transaction_hash": "0x3eb7b9db643a241dbb7bb6fcef605d767e2cd3acd626284587afac4507e52de", "transaction_index": 0 } ], "transaction_state_diffs": [ { - "declared_classes": [ + "declared_classes": [], + "deployed_contracts": [ { - "class_hash": "0x77fcf11f339d18db724aa522729b4c0e4e04aa85a6f104c10b469c020207dc1", - "compiled_class_hash": "0x1738a9f4a4bb3f014041cdb569087473d4ee4428328dc507cdac7da2df39b12" + "address": "0xf99e7cdfbcce0bf14ce17e4c57fd2d12ad1bca5fc8e46a9fbafc36b59a9955", + "class_hash": "0x77fcf11f339d18db724aa522729b4c0e4e04aa85a6f104c10b469c020207dc1" } ], - "deployed_contracts": [], "migrated_compiled_classes": [], - "nonces": {}, + "nonces": { + "0xf99e7cdfbcce0bf14ce17e4c57fd2d12ad1bca5fc8e46a9fbafc36b59a9955": "0x1" + }, "old_declared_contracts": [], "replaced_classes": [], - "storage_diffs": {} + "storage_diffs": { + "0xf99e7cdfbcce0bf14ce17e4c57fd2d12ad1bca5fc8e46a9fbafc36b59a9955": [ + { + "key": "0x3b28019ccfdbd30ffc65951d94bb85c9e2b8434111a000b5afd533ce65f57a4", + "value": "0x411494b501a98abd8262b0da1351e17899a0c4ef23dd2f96fec5ba847310b20" + } + ] + } } ], "transactions": [ { - "account_deployment_data": [], "class_hash": "0x77fcf11f339d18db724aa522729b4c0e4e04aa85a6f104c10b469c020207dc1", - "compiled_class_hash": "0x1738a9f4a4bb3f014041cdb569087473d4ee4428328dc507cdac7da2df39b12", + "constructor_calldata": [ + "0x411494b501a98abd8262b0da1351e17899a0c4ef23dd2f96fec5ba847310b20" + ], + "contract_address_salt": "0x0", "fee_data_availability_mode": 0, "nonce": "0x0", "nonce_data_availability_mode": 0, @@ -82,11 +97,14 @@ "max_price_per_unit": "0x0" } }, - "sender_address": "0x424f4f545354524150", - "signature": [], + "sender_address": "0xf99e7cdfbcce0bf14ce17e4c57fd2d12ad1bca5fc8e46a9fbafc36b59a9955", + "signature": [ + "0x4bf92970c40634da1a0452af752326723ae810809c676aa06fa5ef76e77cc26", + "0x715137c17ff9a873f7d05def6648c93ee7fe0715ad3f21fbb1b59ed76bb1193" + ], "tip": "0x0", - "transaction_hash": "0x2bd201c1de8711bc3748efdbba3b2e997d44792dee9b4a8c598cf8663f99824", - "type": "DECLARE", + "transaction_hash": "0x3eb7b9db643a241dbb7bb6fcef605d767e2cd3acd626284587afac4507e52de", + "type": "DEPLOY_ACCOUNT", "version": "0x3" } ] diff --git a/crates/central_systest_blobs/src/cende_blob_regression_test.rs b/crates/central_systest_blobs/src/cende_blob_regression_test.rs index 12aa74dcb08..bc7d1f9c96c 100644 --- a/crates/central_systest_blobs/src/cende_blob_regression_test.rs +++ b/crates/central_systest_blobs/src/cende_blob_regression_test.rs @@ -52,41 +52,52 @@ use starknet_api::block_hash::block_hash_calculator::{ TransactionHashingData, }; use starknet_api::consensus_transaction::InternalConsensusTransaction; -use starknet_api::contract_address; use starknet_api::contract_class::compiled_class_hash::HashVersion; use starknet_api::core::{ChainId, Nonce, OsChainInfo}; use starknet_api::data_availability::{DataAvailabilityMode, L1DataAvailabilityMode}; use starknet_api::executable_transaction::{ AccountTransaction as ExecutableAccountTx, DeclareTransaction as ExecutableDeclareTx, + DeployAccountTransaction as ExecutableDeployAccountTx, Transaction as ExecutableTx, }; use starknet_api::hash::StateRoots; use starknet_api::rpc_transaction::{ InternalRpcDeclareTransactionV3, + InternalRpcDeployAccountTransaction, InternalRpcTransaction, InternalRpcTransactionWithoutTxHash, + RpcDeployAccountTransaction, + RpcDeployAccountTransactionV3, }; use starknet_api::state::ThinStateDiff; use starknet_api::test_utils::TEST_SEQUENCER_ADDRESS; use starknet_api::transaction::fields::{ AccountDeploymentData, AllResourceBounds, + ContractAddressSalt, PaymasterData, Tip, TransactionSignature, }; use starknet_api::transaction::{ + CalculateContractAddress, DeclareTransaction, + DeployAccountTransaction, + TransactionHash, TransactionHasher, TransactionOffsetInBlock, TransactionVersion, }; +use starknet_api::{calldata, contract_address}; use starknet_committer::block_committer::input::StateDiff; use starknet_committer::db::facts_db::FactsDb; use starknet_committer::db::forest_trait::StorageInitializer; +use starknet_core::crypto::ecdsa_sign; +use starknet_crypto::get_public_key; use starknet_patricia_storage::map_storage::MapStorage; use starknet_transaction_prover::running::committer_utils::commit_state_diff; +use starknet_types_core::felt::Felt; const GCS_ERROR_CODE_NOT_FOUND: u16 = 404; @@ -201,6 +212,8 @@ struct BlobFactory { } impl BlobFactory { + const OPERATOR_PRIVATE_KEY: Felt = Felt::THREE; + pub fn new() -> Self { let chain_info = ChainInfo { chain_id: CHAIN_ID.clone(), ..ChainInfo::create_for_testing() }; @@ -362,6 +375,11 @@ impl BlobFactory { // Tx generation // ===================== + fn sign_tx(tx_hash: TransactionHash) -> TransactionSignature { + let sig = ecdsa_sign(&Self::OPERATOR_PRIVATE_KEY, &tx_hash.0).unwrap(); + TransactionSignature(Arc::new(vec![sig.r, sig.s])) + } + fn boostrap_declare_tx(&mut self, contract: FeatureContract) { let sender_address = ExecutableDeclareTx::bootstrap_address(); let sierra = contract.get_sierra(); @@ -417,6 +435,55 @@ impl BlobFactory { self.next_txs.push((executable.into(), internal_tx)); } + fn make_free_deploy_account_tx(&mut self, account: FeatureContract) { + let class_hash = account.get_sierra().calculate_class_hash(); + let public_key = get_public_key(&Self::OPERATOR_PRIVATE_KEY); + let constructor_calldata = calldata![public_key]; + let contract_address_salt = ContractAddressSalt::default(); + // Build with placeholder signature to compute the hash (signature excluded from hash). + let rpc_tx_unsigned = RpcDeployAccountTransactionV3 { + signature: TransactionSignature::default(), + resource_bounds: AllResourceBounds::new_unlimited_gas_no_fee_enforcement(), + tip: Tip::default(), + contract_address_salt, + class_hash, + constructor_calldata: constructor_calldata.clone(), + nonce: Nonce::default(), + nonce_data_availability_mode: DataAvailabilityMode::L1, + fee_data_availability_mode: DataAvailabilityMode::L1, + paymaster_data: PaymasterData::default(), + }; + let contract_address = rpc_tx_unsigned.calculate_contract_address().unwrap(); + let without_hash_unsigned = InternalRpcTransactionWithoutTxHash::DeployAccount( + InternalRpcDeployAccountTransaction { + tx: RpcDeployAccountTransaction::V3(rpc_tx_unsigned.clone()), + contract_address, + }, + ); + let tx_hash = without_hash_unsigned.calculate_transaction_hash(&CHAIN_ID).unwrap(); + let signature = Self::sign_tx(tx_hash); + + let mut rpc_tx_signed = rpc_tx_unsigned; + rpc_tx_signed.signature = signature; + let without_hash = InternalRpcTransactionWithoutTxHash::DeployAccount( + InternalRpcDeployAccountTransaction { + tx: RpcDeployAccountTransaction::V3(rpc_tx_signed.clone()), + contract_address, + }, + ); + + let executable = ExecutableDeployAccountTx::create( + DeployAccountTransaction::V3(rpc_tx_signed.into()), + &CHAIN_ID, + ) + .unwrap(); + let internal = InternalConsensusTransaction::RpcTransaction(InternalRpcTransaction { + tx: without_hash, + tx_hash, + }); + self.next_txs.push((executable.into(), internal)); + } + // ===================== // Data generation // ===================== @@ -606,8 +673,8 @@ async fn test_make_data() { // Create the list of transactions to be included in the blobs: // 1. bootstrap declare of an ERC20 contract. // 2. bootstrap declare of an account with real validate. - // TODO(Dori): the rest of the txs. // 3. deploy account (with zero fees). + // TODO(Dori): the rest of the txs. // 4. deploy ERC20 contract from the account (with zero fees), while minting some tokens to the // sender account. // (from this point - all txs include non-zero fees, and no more bootstrap declares) @@ -621,6 +688,8 @@ async fn test_make_data() { blob_factory.boostrap_declare_tx(erc20_contract); blob_factory.close_block().await; blob_factory.boostrap_declare_tx(account_with_real_validate); + blob_factory.close_block().await; + blob_factory.make_free_deploy_account_tx(account_with_real_validate); let (blobs, preconfirmed_block) = blob_factory.finalize().await; expect_file![CHAIN_INFO_PATH].assert_eq(&serde_json::to_string_pretty(&chain_info).unwrap());