From df8169b543e5ffd13a993c22fb20702d6b7dc410 Mon Sep 17 00:00:00 2001 From: Shahak Shama Date: Tue, 17 Oct 2023 18:03:18 +0300 Subject: [PATCH] feat(JSON-RPC): get_transaction_receipt supports pending --- .../V0_4_0/starknet_api_openrpc.json | 165 ++++++++++++++---- crates/papyrus_rpc/src/v0_4_0/api/api_impl.rs | 118 ++++++++----- crates/papyrus_rpc/src/v0_4_0/api/mod.rs | 6 +- crates/papyrus_rpc/src/v0_4_0/api/test.rs | 102 +++++++++-- crates/papyrus_rpc/src/v0_4_0/transaction.rs | 66 +++++++ .../src/reader/objects/test_utils.rs | 49 ++++++ .../src/reader/objects/transaction.rs | 10 ++ crates/test_utils/src/lib.rs | 4 + 8 files changed, 425 insertions(+), 95 deletions(-) diff --git a/crates/papyrus_rpc/resources/V0_4_0/starknet_api_openrpc.json b/crates/papyrus_rpc/resources/V0_4_0/starknet_api_openrpc.json index b9b5b27384..c4f33fbfe8 100644 --- a/crates/papyrus_rpc/resources/V0_4_0/starknet_api_openrpc.json +++ b/crates/papyrus_rpc/resources/V0_4_0/starknet_api_openrpc.json @@ -2199,6 +2199,31 @@ } ] }, + "PENDING_INVOKE_TXN_RECEIPT": { + "title": "Invoke Transaction Receipt", + "allOf": [ + { + "title": "Type", + "type": "object", + "properties": { + "type": { + "title": "Type", + "type": "string", + "enum": [ + "INVOKE" + ] + } + }, + "required": [ + "type" + ] + }, + { + "title": "Common receipt properties", + "$ref": "#/components/schemas/PENDING_COMMON_RECEIPT_PROPERTIES" + } + ] + }, "DECLARE_TXN_RECEIPT": { "title": "Declare Transaction Receipt", "allOf": [ @@ -2224,6 +2249,31 @@ } ] }, + "PENDING_DECLARE_TXN_RECEIPT": { + "title": "Declare Transaction Receipt", + "allOf": [ + { + "title": "Declare txn receipt", + "type": "object", + "properties": { + "type": { + "title": "Declare", + "type": "string", + "enum": [ + "DECLARE" + ] + } + }, + "required": [ + "type" + ] + }, + { + "title": "Common receipt properties", + "$ref": "#/components/schemas/PENDING_COMMON_RECEIPT_PROPERTIES" + } + ] + }, "DEPLOY_ACCOUNT_TXN_RECEIPT": { "title": "Deploy Account Transaction Receipt", "allOf": [ @@ -2255,6 +2305,37 @@ } ] }, + "PENDING_DEPLOY_ACCOUNT_TXN_RECEIPT": { + "title": "Deploy Account Transaction Receipt", + "allOf": [ + { + "title": "Common receipt properties", + "$ref": "#/components/schemas/PENDING_COMMON_RECEIPT_PROPERTIES" + }, + { + "title": "DeployAccount txn receipt", + "type": "object", + "properties": { + "type": { + "title": "Deploy account", + "type": "string", + "enum": [ + "DEPLOY_ACCOUNT" + ] + }, + "contract_address": { + "title": "Contract address", + "description": "The address of the deployed contract", + "$ref": "#/components/schemas/FELT" + } + }, + "required": [ + "type", + "contract_address" + ] + } + ] + }, "DEPLOY_TXN_RECEIPT": { "title": "Deploy Transaction Receipt", "allOf": [ @@ -2312,6 +2393,32 @@ } ] }, + "PENDING_L1_HANDLER_TXN_RECEIPT": { + "title": "L1 Handler Transaction Receipt", + "description": "receipt for l1 handler transaction", + "allOf": [ + { + "title": "Transaction type", + "type": "object", + "properties": { + "type": { + "title": "type", + "type": "string", + "enum": [ + "L1_HANDLER" + ] + } + }, + "required": [ + "type" + ] + }, + { + "title": "Common receipt properties", + "$ref": "#/components/schemas/PENDING_COMMON_RECEIPT_PROPERTIES" + } + ] + }, "TXN_RECEIPT": { "title": "Transaction Receipt", "oneOf": [ @@ -2341,6 +2448,27 @@ } ] }, + "PENDING_TXN_RECEIPT": { + "title": "Transaction Receipt", + "oneOf": [ + { + "title": "Pending Invoke transaction receipt", + "$ref": "#/components/schemas/PENDING_INVOKE_TXN_RECEIPT" + }, + { + "title": "Pending L1 handler transaction receipt", + "$ref": "#/components/schemas/PENDING_L1_HANDLER_TXN_RECEIPT" + }, + { + "title": "Pending Declare transaction receipt", + "$ref": "#/components/schemas/PENDING_DECLARE_TXN_RECEIPT" + }, + { + "title": "Pending Deploy account transaction receipt", + "$ref": "#/components/schemas/PENDING_DEPLOY_ACCOUNT_TXN_RECEIPT" + } + ] + }, "PENDING_COMMON_RECEIPT_PROPERTIES": { "title": "Pending common receipt properties", "description": "Common properties for a pending transaction receipt", @@ -2402,41 +2530,8 @@ "events", "finality_status", "execution_status" - ] - }, - "PENDING_DEPLOY_TXN_RECEIPT": { - "title": "Pending deploy Transaction Receipt", - "allOf": [ - { - "title": "Common receipt properties", - "$ref": "#/components/schemas/PENDING_COMMON_RECEIPT_PROPERTIES" - }, - { - "type": "object", - "title": "Contract address", - "properties": { - "contract_address": { - "title": "Contract address", - "description": "The address of the deployed contract", - "$ref": "#/components/schemas/FELT" - } - } - } - ] - }, - "PENDING_TXN_RECEIPT": { - "title": "Pending Transaction Receipt", - "oneOf": [ - { - "title": "Pending deploy transaction receipt", - "$ref": "#/components/schemas/PENDING_DEPLOY_TXN_RECEIPT" - }, - { - "title": "Pending common receipt properties", - "$comment": "Used for pending invoke and declare transaction receipts", - "$ref": "#/components/schemas/PENDING_COMMON_RECEIPT_PROPERTIES" - } - ] + ], + "additionalProperties": false }, "MSG_TO_L1": { "title": "Message to L1", diff --git a/crates/papyrus_rpc/src/v0_4_0/api/api_impl.rs b/crates/papyrus_rpc/src/v0_4_0/api/api_impl.rs index e22b679155..88320ea363 100644 --- a/crates/papyrus_rpc/src/v0_4_0/api/api_impl.rs +++ b/crates/papyrus_rpc/src/v0_4_0/api/api_impl.rs @@ -51,6 +51,10 @@ use super::super::broadcasted_transaction::{ use super::super::state::{AcceptedStateUpdate, PendingStateUpdate, StateUpdate}; use super::super::transaction::{ Event, + GeneralTransactionReceipt, + PendingTransactionFinalityStatus, + PendingTransactionOutput, + PendingTransactionReceipt, Transaction, TransactionOutput, TransactionReceipt, @@ -234,9 +238,16 @@ impl JsonRpcV0_4Server for JsonRpcServerV0_4Impl { ) -> RpcResult { let txn = self.storage_reader.begin_ro_txn().map_err(internal_server_error)?; - let Some(transaction_index) = + if let Some(transaction_index) = txn.get_transaction_idx_by_hash(&transaction_hash).map_err(internal_server_error)? - else { + { + let transaction = txn + .get_transaction(transaction_index) + .map_err(internal_server_error)? + .ok_or_else(|| ErrorObjectOwned::from(TRANSACTION_HASH_NOT_FOUND))?; + + Ok(TransactionWithHash { transaction: transaction.try_into()?, transaction_hash }) + } else { // The transaction is not in any non-pending block. Search for it in the pending block // and if it's not found, return error. let client_transaction = self @@ -256,14 +267,7 @@ impl JsonRpcV0_4Server for JsonRpcServerV0_4Impl { transaction: starknet_api_transaction.try_into()?, transaction_hash, }); - }; - - let transaction = txn - .get_transaction(transaction_index) - .map_err(internal_server_error)? - .ok_or_else(|| ErrorObjectOwned::from(TRANSACTION_HASH_NOT_FOUND))?; - - Ok(TransactionWithHash { transaction: transaction.try_into()?, transaction_hash }) + } } #[instrument(skip(self), level = "debug", err, ret)] @@ -361,50 +365,78 @@ impl JsonRpcV0_4Server for JsonRpcServerV0_4Impl { } #[instrument(skip(self), level = "debug", err, ret)] - fn get_transaction_receipt( + async fn get_transaction_receipt( &self, transaction_hash: TransactionHash, - ) -> RpcResult { + ) -> RpcResult { let txn = self.storage_reader.begin_ro_txn().map_err(internal_server_error)?; - let transaction_index = txn - .get_transaction_idx_by_hash(&transaction_hash) - .map_err(internal_server_error)? - .ok_or_else(|| ErrorObjectOwned::from(TRANSACTION_HASH_NOT_FOUND))?; + if let Some(transaction_index) = + txn.get_transaction_idx_by_hash(&transaction_hash).map_err(internal_server_error)? + { + let block_number = transaction_index.0; + let status = get_block_status(&txn, block_number)?; + + // rejected blocks should not be a part of the API so we early return here. + // this assumption also holds for the conversion from block status to transaction + // finality status where we set rejected blocks to unreachable. + if status == BlockStatus::Rejected { + return Err(ErrorObjectOwned::from(BLOCK_NOT_FOUND))?; + } - let block_number = transaction_index.0; - let status = get_block_status(&txn, block_number)?; + let block_hash = get_block_header_by_number::<_, BlockHeader>(&txn, block_number) + .map_err(internal_server_error)? + .block_hash; - // rejected blocks should not be a part of the API so we early return here. - // this assumption also holds for the conversion from block status to transaction finality - // status where we set rejected blocks to unreachable. - if status == BlockStatus::Rejected { - return Err(ErrorObjectOwned::from(BLOCK_NOT_FOUND))?; - } + let thin_tx_output = txn + .get_transaction_output(transaction_index) + .map_err(internal_server_error)? + .ok_or_else(|| ErrorObjectOwned::from(TRANSACTION_HASH_NOT_FOUND))?; - let block_hash = get_block_header_by_number::<_, BlockHeader>(&txn, block_number) - .map_err(internal_server_error)? - .block_hash; + let events = txn + .get_transaction_events(transaction_index) + .map_err(internal_server_error)? + .ok_or_else(|| ErrorObjectOwned::from(TRANSACTION_HASH_NOT_FOUND))?; - let thin_tx_output = txn - .get_transaction_output(transaction_index) - .map_err(internal_server_error)? - .ok_or_else(|| ErrorObjectOwned::from(TRANSACTION_HASH_NOT_FOUND))?; + let output = TransactionOutput::from_thin_transaction_output(thin_tx_output, events); - let events = txn - .get_transaction_events(transaction_index) - .map_err(internal_server_error)? - .ok_or_else(|| ErrorObjectOwned::from(TRANSACTION_HASH_NOT_FOUND))?; + Ok(GeneralTransactionReceipt::TransactionReceipt(TransactionReceipt { + finality_status: status.into(), + transaction_hash, + block_hash, + block_number, + output, + })) + } else { + // The transaction is not in any non-pending block. Search for it in the pending block + // and if it's not found, return error. - let output = TransactionOutput::from_thin_transaction_output(thin_tx_output, events); + // TODO(shahak): Consider cloning the transactions and the receipts in order to free + // the lock sooner (Check which is better). + let pending_block = &self.pending_data.read().await.block; - Ok(TransactionReceipt { - finality_status: status.into(), - transaction_hash, - block_hash, - block_number, - output, - }) + let client_transaction_receipt = pending_block + .transaction_receipts + .iter() + .find(|receipt| receipt.transaction_hash == transaction_hash) + .ok_or_else(|| ErrorObjectOwned::from(TRANSACTION_HASH_NOT_FOUND))? + .clone(); + let client_transaction = &pending_block + .transactions + .iter() + .find(|transaction| transaction.transaction_hash() == transaction_hash) + .ok_or_else(|| ErrorObjectOwned::from(TRANSACTION_HASH_NOT_FOUND))?; + let starknet_api_output = + client_transaction_receipt.into_starknet_api_transaction_output(client_transaction); + let output = + PendingTransactionOutput::try_from(TransactionOutput::from(starknet_api_output))?; + Ok(GeneralTransactionReceipt::PendingTransactionReceipt(PendingTransactionReceipt { + // ACCEPTED_ON_L2 is the only finality status of a pending transaction. + finality_status: PendingTransactionFinalityStatus::AcceptedOnL2, + transaction_hash, + output, + })) + } } #[instrument(skip(self), level = "debug", err, ret)] diff --git a/crates/papyrus_rpc/src/v0_4_0/api/mod.rs b/crates/papyrus_rpc/src/v0_4_0/api/mod.rs index 25d34c812a..11a3afe3d5 100644 --- a/crates/papyrus_rpc/src/v0_4_0/api/mod.rs +++ b/crates/papyrus_rpc/src/v0_4_0/api/mod.rs @@ -42,10 +42,10 @@ use super::transaction::{ DeployAccountTransaction, DeployAccountTransactionV1, Event, + GeneralTransactionReceipt, InvokeTransaction, InvokeTransactionV0, InvokeTransactionV1, - TransactionReceipt, TransactionWithHash, }; use super::write_api_result::{AddDeclareOkResult, AddDeployAccountOkResult, AddInvokeOkResult}; @@ -111,10 +111,10 @@ pub trait JsonRpc { /// Gets the transaction receipt by the transaction hash. #[method(name = "getTransactionReceipt")] - fn get_transaction_receipt( + async fn get_transaction_receipt( &self, transaction_hash: TransactionHash, - ) -> RpcResult; + ) -> RpcResult; /// Gets the contract class definition associated with the given hash. #[method(name = "getClass")] diff --git a/crates/papyrus_rpc/src/v0_4_0/api/test.rs b/crates/papyrus_rpc/src/v0_4_0/api/test.rs index 15f2fb57a4..8f3dc49375 100644 --- a/crates/papyrus_rpc/src/v0_4_0/api/test.rs +++ b/crates/papyrus_rpc/src/v0_4_0/api/test.rs @@ -22,7 +22,8 @@ use papyrus_storage::state::StateStorageWriter; use papyrus_storage::test_utils::get_test_storage; use papyrus_storage::StorageScope; use pretty_assertions::assert_eq; -use rand::random; +use rand::{random, RngCore}; +use rand_chacha::ChaCha8Rng; use reqwest::StatusCode; use serde::{Deserialize, Serialize}; use starknet_api::block::{BlockHash, BlockHeader, BlockNumber, BlockStatus}; @@ -51,7 +52,10 @@ use starknet_client::reader::objects::state::{ StateDiff as ClientStateDiff, StorageEntry as ClientStorageEntry, }; -use starknet_client::reader::objects::transaction::Transaction as ClientTransaction; +use starknet_client::reader::objects::transaction::{ + Transaction as ClientTransaction, + TransactionReceipt as ClientTransactionReceipt, +}; use starknet_client::starknet_error::{KnownStarknetErrorCode, StarknetError, StarknetErrorCode}; use starknet_client::writer::objects::response::{ DeclareResponse, @@ -94,7 +98,11 @@ use super::super::state::{ use super::super::transaction::{ DeployAccountTransaction, Event, + GeneralTransactionReceipt, InvokeTransactionV1, + PendingTransactionFinalityStatus, + PendingTransactionOutput, + PendingTransactionReceipt, TransactionFinalityStatus, TransactionOutput, TransactionReceipt, @@ -699,8 +707,10 @@ async fn get_class() { #[tokio::test] async fn get_transaction_receipt() { let method_name = "starknet_V0_4_getTransactionReceipt"; - let (module, mut storage_writer) = - get_test_rpc_server_and_storage_writer::(); + let pending_data = get_test_pending_data(); + let (module, mut storage_writer) = get_test_rpc_server_and_storage_writer_from_params::< + JsonRpcServerV0_4Impl, + >(None, None, Some(pending_data.clone()), None, None); let block = get_test_block(1, None, None, None); storage_writer .begin_rw_txn() @@ -731,7 +741,7 @@ async fn get_transaction_receipt() { // struct in the TransactionOutput enum that matches the json is chosen. To not depend here // on the order of structs we compare the serialized data. assert_eq!( - serde_json::to_string(&res.clone().unwrap()).unwrap(), + serde_json::to_string(&res.unwrap()).unwrap(), serde_json::to_string(&expected_receipt).unwrap(), ); assert!(validate_schema( @@ -757,6 +767,41 @@ async fn get_transaction_receipt() { assert_eq!(res.finality_status, TransactionFinalityStatus::AcceptedOnL1); assert_eq!(res.output.execution_status(), &TransactionExecutionStatus::Succeeded); + // Add a pneding transaction and ask for its receipt. + let mut rng = get_rng(); + let (client_transaction, client_transaction_receipt, expected_receipt) = + generate_client_transaction_client_receipt_and_rpc_receipt(&mut rng); + + { + let pending_block = &mut pending_data.write().await.block; + pending_block.transactions.push(client_transaction.clone()); + pending_block.transaction_receipts.push(client_transaction_receipt.clone()); + } + + let expected_result = GeneralTransactionReceipt::PendingTransactionReceipt(expected_receipt); + let (json_response, result) = raw_call::<_, TransactionHash, PendingTransactionReceipt>( + &module, + method_name, + &Some(client_transaction_receipt.transaction_hash), + ) + .await; + // See above for explanation why we compare the json strings. + assert_eq!( + serde_json::to_string(&result.unwrap()).unwrap(), + serde_json::to_string(&expected_result).unwrap(), + ); + // Validating schema again since pending has a different schema + assert!(validate_schema( + &get_starknet_spec_api_schema_for_method_results( + &[( + SpecFile::StarknetApiOpenrpc, + &[method_name_to_spec_method_name(method_name).as_str()] + )], + &VERSION_0_4, + ), + &json_response["result"], + )); + // Ask for an invalid transaction. call_api_then_assert_and_validate_schema_for_err::<_, TransactionHash, TransactionReceipt>( &module, @@ -1216,12 +1261,45 @@ async fn get_storage_at() { assert_matches!(err, Error::Call(err) if err == BLOCK_NOT_FOUND.into()); } -fn generate_client_transaction_and_rpc_transaction() -> (ClientTransaction, TransactionWithHash) { - let mut rng = get_rng(); +fn generate_client_transaction_client_receipt_and_rpc_receipt( + rng: &mut ChaCha8Rng, +) -> (ClientTransaction, ClientTransactionReceipt, PendingTransactionReceipt) { + let pending_transaction_hash = TransactionHash(StarkHash::from(rng.next_u64())); + let mut client_transaction_receipt = ClientTransactionReceipt::get_test_instance(rng); + client_transaction_receipt.transaction_hash = pending_transaction_hash; + // Generating a transaction until we receive a transaction that can have pending output (i.e a + // non-deploy transaction). + let (mut client_transaction, output) = loop { + let (client_transaction, _) = generate_client_transaction_and_rpc_transaction(rng); + let starknet_api_output = client_transaction_receipt + .clone() + .into_starknet_api_transaction_output(&client_transaction); + let maybe_output = + PendingTransactionOutput::try_from(TransactionOutput::from(starknet_api_output)); + let Ok(output) = maybe_output else { + continue; + }; + break (client_transaction, output); + }; + *client_transaction.transaction_hash_mut() = pending_transaction_hash; + ( + client_transaction, + client_transaction_receipt, + PendingTransactionReceipt { + finality_status: PendingTransactionFinalityStatus::AcceptedOnL2, + transaction_hash: pending_transaction_hash, + output, + }, + ) +} + +fn generate_client_transaction_and_rpc_transaction( + rng: &mut ChaCha8Rng, +) -> (ClientTransaction, TransactionWithHash) { // TODO(shahak): Remove retry once v3 transactions are supported and the impl of TryInto will // become impl of Into. loop { - let client_transaction = ClientTransaction::get_test_instance(&mut rng); + let client_transaction = ClientTransaction::get_test_instance(rng); let Ok(starknet_api_transaction): Result = client_transaction.clone().try_into() else { @@ -1272,16 +1350,12 @@ async fn get_transaction_by_hash() { // Ask for a transaction in the pending block. let (client_transaction, expected_transaction_with_hash) = - generate_client_transaction_and_rpc_transaction(); + generate_client_transaction_and_rpc_transaction(&mut get_rng()); pending_data.write().await.block.transactions.push(client_transaction.clone()); let res = module .call::<_, TransactionWithHash>(method_name, (client_transaction.transaction_hash(), 0)) .await .unwrap(); - println!( - "{:?}, {:?}", - expected_transaction_with_hash.transaction_hash, expected_transaction.transaction_hash - ); assert_eq!(res, expected_transaction_with_hash); // Ask for an invalid transaction. @@ -1364,7 +1438,7 @@ async fn get_transaction_by_block_id_and_index() { // Get transaction of pending block. let (client_transaction, expected_transaction_with_hash) = - generate_client_transaction_and_rpc_transaction(); + generate_client_transaction_and_rpc_transaction(&mut get_rng()); pending_data.write().await.block.transactions.push(client_transaction); let res = module .call::<_, TransactionWithHash>(method_name, (BlockId::Tag(Tag::Pending), 0)) diff --git a/crates/papyrus_rpc/src/v0_4_0/transaction.rs b/crates/papyrus_rpc/src/v0_4_0/transaction.rs index 90bb2e69ba..66a18b8bb8 100644 --- a/crates/papyrus_rpc/src/v0_4_0/transaction.rs +++ b/crates/papyrus_rpc/src/v0_4_0/transaction.rs @@ -367,6 +367,16 @@ pub enum TransactionFinalityStatus { AcceptedOnL1, } +/// Transaction Finality status on starknet for transactions in the pending block. +#[derive( + Debug, Copy, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord, Default, +)] +pub enum PendingTransactionFinalityStatus { + #[serde(rename = "ACCEPTED_ON_L2")] + #[default] + AcceptedOnL2, +} + impl From for TransactionFinalityStatus { fn from(status: BlockStatus) -> Self { match status { @@ -381,6 +391,13 @@ impl From for TransactionFinalityStatus { } } +#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord)] +#[serde(untagged)] +pub enum GeneralTransactionReceipt { + TransactionReceipt(TransactionReceipt), + PendingTransactionReceipt(PendingTransactionReceipt), +} + #[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord)] pub struct TransactionReceipt { pub finality_status: TransactionFinalityStatus, @@ -391,6 +408,14 @@ pub struct TransactionReceipt { pub output: TransactionOutput, } +#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord)] +pub struct PendingTransactionReceipt { + pub finality_status: PendingTransactionFinalityStatus, + pub transaction_hash: TransactionHash, + #[serde(flatten)] + pub output: PendingTransactionOutput, +} + #[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord)] #[serde(tag = "type")] pub enum TransactionOutput { @@ -406,6 +431,23 @@ pub enum TransactionOutput { L1Handler(L1HandlerTransactionOutput), } +#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord)] +#[serde(tag = "type")] +// Applying deny_unknown_fields on the inner type instead of on PendingTransactionReceipt because +// of a bug that makes deny_unknown_fields not work well with flatten: +// https://github.com/serde-rs/serde/issues/1358 +#[serde(deny_unknown_fields)] +pub enum PendingTransactionOutput { + #[serde(rename = "DECLARE")] + Declare(DeclareTransactionOutput), + #[serde(rename = "DEPLOY_ACCOUNT")] + DeployAccount(DeployAccountTransactionOutput), + #[serde(rename = "INVOKE")] + Invoke(InvokeTransactionOutput), + #[serde(rename = "L1_HANDLER")] + L1Handler(L1HandlerTransactionOutput), +} + impl TransactionOutput { #[cfg(test)] pub fn execution_status(&self) -> &TransactionExecutionStatus { @@ -492,6 +534,30 @@ impl From for TransactionOutput { } } +impl TryFrom for PendingTransactionOutput { + type Error = ErrorObjectOwned; + + fn try_from(tx_output: TransactionOutput) -> Result { + match tx_output { + TransactionOutput::Declare(declare_tx_output) => { + Ok(PendingTransactionOutput::Declare(declare_tx_output)) + } + TransactionOutput::Deploy(_) => { + Err(internal_server_error("Got a pending deploy transaction.")) + } + TransactionOutput::DeployAccount(deploy_tx_output) => { + Ok(PendingTransactionOutput::DeployAccount(deploy_tx_output)) + } + TransactionOutput::Invoke(invoke_tx_output) => { + Ok(PendingTransactionOutput::Invoke(invoke_tx_output)) + } + TransactionOutput::L1Handler(l1_handler_tx_output) => { + Ok(PendingTransactionOutput::L1Handler(l1_handler_tx_output)) + } + } + } +} + #[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)] pub struct Event { pub block_hash: BlockHash, diff --git a/crates/starknet_client/src/reader/objects/test_utils.rs b/crates/starknet_client/src/reader/objects/test_utils.rs index 56dc066d04..16b9a1ac90 100644 --- a/crates/starknet_client/src/reader/objects/test_utils.rs +++ b/crates/starknet_client/src/reader/objects/test_utils.rs @@ -1,32 +1,48 @@ +use std::collections::HashMap; + use starknet_api::core::{ ClassHash, CompiledClassHash, ContractAddress, EntryPointSelector, + EthAddress, Nonce, }; use starknet_api::data_availability::DataAvailabilityMode; +use starknet_api::hash::StarkHash; use starknet_api::transaction::{ AccountDeploymentData, Calldata, ContractAddressSalt, + Event, Fee, + L1ToL2Payload, + L2ToL1Payload, PaymasterData, ResourceBoundsMapping, Tip, + TransactionExecutionStatus, TransactionHash, + TransactionOffsetInBlock, TransactionSignature, TransactionVersion, }; use test_utils::{auto_impl_get_test_instance, get_number_of_variants, GetTestInstance}; use crate::reader::objects::transaction::{ + BuiltinInstanceCounter, DeployTransaction, + EmptyBuiltinInstanceCounter, + ExecutionResources, IntermediateDeclareTransaction, IntermediateDeployAccountTransaction, IntermediateInvokeTransaction, L1HandlerTransaction, + L1ToL2Message, + L1ToL2Nonce, + L2ToL1Message, Transaction, + TransactionReceipt, }; auto_impl_get_test_instance! { @@ -101,4 +117,37 @@ auto_impl_get_test_instance! { pub entry_point_selector: EntryPointSelector, pub calldata: Calldata, } + pub struct TransactionReceipt { + pub transaction_index: TransactionOffsetInBlock, + pub transaction_hash: TransactionHash, + pub l1_to_l2_consumed_message: L1ToL2Message, + pub l2_to_l1_messages: Vec, + pub events: Vec, + pub execution_resources: ExecutionResources, + pub actual_fee: Fee, + pub execution_status: TransactionExecutionStatus, + } + pub struct L1ToL2Message { + pub from_address: EthAddress, + pub to_address: ContractAddress, + pub selector: EntryPointSelector, + pub payload: L1ToL2Payload, + pub nonce: L1ToL2Nonce, + } + pub struct L1ToL2Nonce(pub StarkHash); + pub struct ExecutionResources { + pub n_steps: u64, + pub builtin_instance_counter: BuiltinInstanceCounter, + pub n_memory_holes: u64, + } + pub enum BuiltinInstanceCounter { + NonEmpty(HashMap) = 0, + Empty(EmptyBuiltinInstanceCounter) = 1, + } + pub struct EmptyBuiltinInstanceCounter {} + pub struct L2ToL1Message { + pub from_address: ContractAddress, + pub to_address: EthAddress, + pub payload: L2ToL1Payload, + } } diff --git a/crates/starknet_client/src/reader/objects/transaction.rs b/crates/starknet_client/src/reader/objects/transaction.rs index e35022ef7a..e54c29ec74 100644 --- a/crates/starknet_client/src/reader/objects/transaction.rs +++ b/crates/starknet_client/src/reader/objects/transaction.rs @@ -92,6 +92,16 @@ impl Transaction { } } + pub fn transaction_hash_mut(&mut self) -> &mut TransactionHash { + match self { + Transaction::Declare(tx) => &mut tx.transaction_hash, + Transaction::Deploy(tx) => &mut tx.transaction_hash, + Transaction::DeployAccount(tx) => &mut tx.transaction_hash, + Transaction::Invoke(tx) => &mut tx.transaction_hash, + Transaction::L1Handler(tx) => &mut tx.transaction_hash, + } + } + pub fn transaction_type(&self) -> TransactionType { match self { Transaction::Declare(_) => TransactionType::Declare, diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index 90c9908a4a..dccb10e047 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs @@ -503,6 +503,10 @@ auto_impl_get_test_instance! { pub function_idx: FunctionIndex, pub selector: EntryPointSelector, } + pub struct Event { + pub from_address: ContractAddress, + pub content: EventContent, + } pub struct FunctionIndex(pub usize); pub struct EntryPointOffset(pub usize); pub struct EntryPointSelector(pub StarkHash);