From 4ac868924f9ff63b61084fcf7a1a9ecf17c48b50 Mon Sep 17 00:00:00 2001
From: jb caron <jbcaron.dev@gmail.com>
Date: Sun, 11 Feb 2024 19:57:54 +0100
Subject: [PATCH 1/5] feat: :sparkles: compute transaction

reexecution of transactions from the block to the requested transaction, retrieval of state, resources, events and messages from l2 to l1
---
 crates/client/rpc/src/lib.rs | 428 ++++++++++++++++++++++++-----------
 1 file changed, 294 insertions(+), 134 deletions(-)

diff --git a/crates/client/rpc/src/lib.rs b/crates/client/rpc/src/lib.rs
index 3c4e790ce5..80cf6353af 100644
--- a/crates/client/rpc/src/lib.rs
+++ b/crates/client/rpc/src/lib.rs
@@ -11,10 +11,13 @@ mod types;
 use std::marker::PhantomData;
 use std::sync::Arc;
 
+use blockifier::execution::contract_class::{ContractClass as ContractClassBf, ContractClassV1 as ContractClassV1Bf};
+use blockifier::execution::entry_point::CallInfo;
 use errors::StarknetRpcApiError;
 use jsonrpsee::core::{async_trait, RpcResult};
 use jsonrpsee::types::error::CallError;
 use log::error;
+use mc_deoxys::commitments::transactions;
 use mc_deoxys::utility::get_highest_block_hash_and_number;
 use mc_genesis_data_provider::GenesisProvider;
 pub use mc_rpc_core::utils::*;
@@ -27,7 +30,9 @@ use mp_felt::{Felt252Wrapper, Felt252WrapperError};
 use mp_hashers::HasherT;
 use mp_transactions::compute_hash::ComputeTransactionHash;
 use mp_transactions::to_starknet_core_transaction::to_starknet_core_tx;
-use mp_transactions::{TransactionStatus, UserTransaction};
+use mp_transactions::{
+    DeclareTransaction, Transaction as TransactionMp, TransactionStatus, UserOrL1HandlerTransaction, UserTransaction,
+};
 use pallet_starknet_runtime_api::{ConvertTransactionRuntimeApi, StarknetRuntimeApi};
 use sc_client_api::backend::{Backend, StorageProvider};
 use sc_client_api::BlockBackend;
@@ -42,6 +47,7 @@ use sp_core::H256;
 use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
 use sp_runtime::transaction_validity::InvalidTransaction;
 use sp_runtime::DispatchError;
+use starknet_api::api_core::ClassHash;
 use starknet_api::block::BlockHash;
 use starknet_api::hash::StarkHash;
 use starknet_api::transaction::Calldata;
@@ -49,11 +55,11 @@ use starknet_core::types::{
     BlockHashAndNumber, BlockId, BlockTag, BlockWithTxHashes, BlockWithTxs, BroadcastedDeclareTransaction,
     BroadcastedDeployAccountTransaction, BroadcastedInvokeTransaction, BroadcastedTransaction, ContractClass,
     DeclareTransactionReceipt, DeclareTransactionResult, DeployAccountTransactionReceipt,
-    DeployAccountTransactionResult, DeployTransactionReceipt, EventFilterWithPage, EventsPage, ExecutionResources,
-    ExecutionResult, FeeEstimate, FieldElement, FunctionCall, Hash256, InvokeTransactionReceipt,
+    DeployAccountTransactionResult, DeployTransactionReceipt, Event, EventFilterWithPage, EventsPage,
+    ExecutionResources, ExecutionResult, FeeEstimate, FieldElement, FunctionCall, Hash256, InvokeTransactionReceipt,
     InvokeTransactionResult, L1HandlerTransactionReceipt, MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs,
-    MaybePendingTransactionReceipt, MsgFromL1, StateDiff, StateUpdate, SyncStatus, SyncStatusType, Transaction,
-    TransactionExecutionStatus, TransactionFinalityStatus, TransactionReceipt,
+    MaybePendingTransactionReceipt, MsgFromL1, MsgToL1, StateDiff, StateUpdate, SyncStatus, SyncStatusType,
+    Transaction, TransactionExecutionStatus, TransactionFinalityStatus, TransactionReceipt,
 };
 
 use crate::constants::{MAX_EVENTS_CHUNK_SIZE, MAX_EVENTS_KEYS};
@@ -1453,26 +1459,26 @@ where
             .mapping()
             .block_hash_from_transaction_hash(Felt252Wrapper::from(transaction_hash).into())
             .map_err(|e| {
-                error!("Failed to interact with db backend error: {e}");
+                log::error!("Failed to retrieve substrate block hash: {e}");
                 StarknetRpcApiError::InternalServerError
             })?
             .ok_or(StarknetRpcApiError::TxnHashNotFound)?;
 
-        let starknet_block: mp_block::Block = get_block_by_block_hash(self.client.as_ref(), substrate_block_hash)?;
-
-        let block_header = starknet_block.header();
-        let block_hash: Felt252Wrapper = block_header.hash::<H>().into();
+        let block = get_block_by_block_hash(self.client.as_ref(), substrate_block_hash)?;
+        let block_header = block.header();
         let block_number = block_header.block_number;
+        let block_hash: Felt252Wrapper = block_header.hash::<H>().into();
+        let starknet_version = block_header.protocol_version;
 
         let chain_id = self.chain_id()?.0;
 
-        let starknet_version = starknet_block.header().protocol_version;
-
-        let fee_disabled =
-            self.client.runtime_api().is_transaction_fee_disabled(substrate_block_hash).map_err(|e| {
-                error!("Failed to get check fee disabled. Substrate block hash: {substrate_block_hash}, error: {e}");
+        let previous_substrate_block_hash = {
+            let previous_block_number = block_number - 1;
+            self.substrate_block_hash_from_starknet_block(BlockId::Number(previous_block_number)).map_err(|e| {
+                log::error!("Failed to retrieve previous substrate block hash: {e}");
                 StarknetRpcApiError::InternalServerError
-            })?;
+            })
+        }?;
 
         let block_txs_hashes: Vec<_> = if let Some(tx_hashes) = self.get_cached_transaction_hashes(block_hash.into()) {
             tx_hashes
@@ -1489,8 +1495,8 @@ where
                 })
                 .collect()
         } else {
-            starknet_block
-                .transactions_hashes::<H>(chain_id.into(), Some(starknet_block.header().block_number))
+            block
+                .transactions_hashes::<H>(chain_id.into(), Some(block_header.block_number))
                 .map(FieldElement::from)
                 .collect()
         };
@@ -1498,74 +1504,172 @@ where
         let (tx_index, _) =
             block_txs_hashes.into_iter().enumerate().find(|(_, hash)| hash == &transaction_hash.into()).unwrap().into();
 
-        let transaction = starknet_block.transactions().get(tx_index).unwrap();
-
-        let events = starknet_block
-            .events()
-            .into_iter()
-            .filter(|event| event.index == tx_index as u128)
-            .flat_map(|event| event.events.clone())
-            .map(event_conversion)
-            .collect();
-
-        let execution_result = {
-            let revert_error = self
-                .client
-                .runtime_api()
-                .get_tx_execution_outcome(substrate_block_hash, Felt252Wrapper(transaction_hash).into())
-                .map_err(|e| {
-                    error!(
-                        "Failed to get transaction execution outcome. Substrate block hash: {substrate_block_hash}, \
-                         transaction hash: {transaction_hash}, error: {e}"
-                    );
-                    StarknetRpcApiError::InternalServerError
-                })?;
+        let transaction = block.transactions().get(tx_index).ok_or_else(|| {
+            log::error!("Failed to retrieve transaction at index {tx_index} from block with hash {block_hash:?}");
+            StarknetRpcApiError::InternalServerError
+        })?;
 
-            match revert_error {
-                None => ExecutionResult::Succeeded,
-                // This is safe because the message is a Vec<u8> build from a String
-                Some(message) => ExecutionResult::Reverted { reason: unsafe { String::from_utf8_unchecked(message) } },
+        block.transactions().iter().take(tx_index + 1).enumerate().for_each(|(i, tx)| match tx {
+            TransactionMp::Declare(_) => {
+                println!("transaction {i}: declare_tx");
             }
-        };
+            TransactionMp::DeployAccount(_) => {
+                println!("transaction {i}: deploy_account_tx");
+            }
+            TransactionMp::Deploy(_) => {
+                println!("transaction {i}: deploy_tx");
+            }
+            TransactionMp::Invoke(_) => {
+                println!("transaction {i}: invoke_tx");
+            }
+            TransactionMp::L1Handler(_) => {
+                println!("transaction {i}: l1_handler_tx");
+            }
+        });
+
+        let transactions = block
+            .transactions()
+            .iter()
+            .take(tx_index + 1)
+            .map(|tx| match tx {
+                TransactionMp::Invoke(invoke_tx) => {
+                    RpcResult::Ok(UserOrL1HandlerTransaction::User(UserTransaction::Invoke(invoke_tx.clone())))
+                }
+                TransactionMp::DeployAccount(deploy_account_tx) => {
+                    Ok(UserOrL1HandlerTransaction::User(UserTransaction::DeployAccount(deploy_account_tx.clone())))
+                }
+                TransactionMp::Declare(declare_tx) => {
+                    let class_hash = ClassHash::from(*declare_tx.class_hash());
+
+                    match declare_tx {
+                        DeclareTransaction::V0(_) | DeclareTransaction::V1(_) => {
+                            let contract_class = self
+                                .overrides
+                                .for_block_hash(self.client.as_ref(), substrate_block_hash)
+                                .contract_class_by_class_hash(substrate_block_hash, class_hash)
+                                .ok_or_else(|| {
+                                    log::error!("Failed to retrieve contract class from hash '{class_hash}'");
+                                    StarknetRpcApiError::InternalServerError
+                                })?;
+
+                            Ok(UserOrL1HandlerTransaction::User(UserTransaction::Declare(
+                                declare_tx.clone(),
+                                contract_class,
+                            )))
+                        }
+                        DeclareTransaction::V2(tx) => {
+                            let contract_class = self
+                                .backend
+                                .sierra_classes()
+                                .get_sierra_class(class_hash)
+                                .map_err(|e| {
+                                    log::error!("Failed to fetch sierra class with hash {class_hash}: {e}");
+                                    StarknetRpcApiError::InternalServerError
+                                })?
+                                .ok_or_else(|| {
+                                    log::error!("The sierra class with hash {class_hash} is not present in db backend");
+                                    StarknetRpcApiError::InternalServerError
+                                })?;
+                            let contract_class = mp_transactions::utils::sierra_to_casm_contract_class(contract_class)
+                                .map_err(|e| {
+                                    log::error!("Failed to convert the SierraContractClass to CasmContractClass: {e}");
+                                    StarknetRpcApiError::InternalServerError
+                                })?;
+                            let contract_class =
+                                ContractClassBf::V1(ContractClassV1Bf::try_from(contract_class).map_err(|e| {
+                                    log::error!(
+                                        "Failed to convert the compiler CasmContractClass to blockifier \
+                                         CasmContractClass: {e}"
+                                    );
+                                    StarknetRpcApiError::InternalServerError
+                                })?);
+
+                            Ok(UserOrL1HandlerTransaction::User(UserTransaction::Declare(
+                                declare_tx.clone(),
+                                contract_class,
+                            )))
+                        }
+                    }
+                }
+                TransactionMp::L1Handler(handle_l1_message_tx) => {
+                    let chain_id = self.chain_id()?.0.into();
+                    let tx_hash = handle_l1_message_tx.compute_hash::<H>(chain_id, false, Some(block_number));
+                    let paid_fee =
+                        self.backend.l1_handler_paid_fee().get_fee_paid_for_l1_handler_tx(tx_hash.into()).map_err(
+                            |e| {
+                                log::error!("Failed to retrieve fee paid on l1 for tx with hash `{tx_hash:?}`: {e}");
+                                StarknetRpcApiError::InternalServerError
+                            },
+                        )?;
+
+                    Ok(UserOrL1HandlerTransaction::L1Handler(handle_l1_message_tx.clone(), paid_fee))
+                }
+                TransactionMp::Deploy(_) => todo!(),
+            })
+            .collect::<Result<Vec<_>, _>>()?;
+
+        let execution_infos = self
+            .client
+            .runtime_api()
+            .re_execute_transactions(previous_substrate_block_hash, transactions.clone())
+            .map_err(|e| {
+                log::error!("Failed to execute runtime API call: {e}");
+                StarknetRpcApiError::InternalServerError
+            })?
+            .map_err(|e| {
+                log::error!("Failed to reexecute the transactions: {e:?}");
+                StarknetRpcApiError::InternalServerError
+            })?
+            .map_err(|_| {
+                log::error!("One of the transaction failed during it's reexecution");
+                StarknetRpcApiError::InternalServerError
+            })?
+            .pop() // get only the last transaction execution info
+            .ok_or_else(|| {
+                log::error!("No execution info returned for the last transaction");
+                StarknetRpcApiError::InternalServerError
+            })?;
 
         // TODO(#1291): compute message hash correctly to L1HandlerTransactionReceipt
         let message_hash: Hash256 = Hash256::from_felt(&FieldElement::default());
 
-        fn event_conversion(event: starknet_api::transaction::Event) -> starknet_core::types::Event {
-            starknet_core::types::Event {
-                from_address: Felt252Wrapper::from(event.from_address).0,
-                keys: event.content.keys.into_iter().map(|felt| Felt252Wrapper::from(felt).0).collect(),
-                data: event.content.data.0.into_iter().map(|felt| Felt252Wrapper::from(felt).0).collect(),
-            }
-        }
-
-        let actual_fee = FieldElement::ZERO;
+        let actual_fee = execution_infos.actual_fee.0.into();
 
-        let actual_status = if starknet_block.header().block_number
-            <= mc_deoxys::l1::ETHEREUM_STATE_UPDATE.lock().unwrap().block_number.0
-        {
+        let actual_status = if block_number <= mc_deoxys::l1::ETHEREUM_STATE_UPDATE.lock().unwrap().block_number.0 {
             TransactionFinalityStatus::AcceptedOnL1.into()
         } else {
             TransactionFinalityStatus::AcceptedOnL2.into()
         };
-        let messages = self
-            .client
-            .runtime_api()
-            .get_tx_messages_to_l1(substrate_block_hash, Felt252Wrapper(transaction_hash).into())
-            .map_err(|e| {
-                error!("'{e}'");
-                StarknetRpcApiError::InternalServerError
-            })?;
 
-        fn message_conversion(message: starknet_api::transaction::MessageToL1) -> starknet_core::types::MsgToL1 {
-            let mut to_address = [0u8; 32];
-            to_address[12..32].copy_from_slice(message.to_address.0.as_bytes());
-            starknet_core::types::MsgToL1 {
-                from_address: Felt252Wrapper::from(message.from_address).0,
-                to_address: FieldElement::from_bytes_be(&to_address).unwrap(),
-                payload: message.payload.0.into_iter().map(|felt| Felt252Wrapper::from(felt).0).collect(),
-            }
-        }
+        let execution_result = match execution_infos.revert_error.clone() {
+            Some(err) => ExecutionResult::Reverted { reason: err },
+            None => ExecutionResult::Succeeded,
+        };
+
+        let execution_resources = match execution_infos.execute_call_info {
+            Some(ref call_info) => blockifier_call_info_to_starknet_resources(call_info),
+            None => ExecutionResources {
+                steps: 0,
+                memory_holes: None,
+                range_check_builtin_applications: 0,
+                pedersen_builtin_applications: 0,
+                poseidon_builtin_applications: 0,
+                ec_op_builtin_applications: 0,
+                ecdsa_builtin_applications: 0,
+                bitwise_builtin_applications: 0,
+                keccak_builtin_applications: 0,
+            },
+        };
+
+        let events = match execution_infos.execute_call_info {
+            Some(ref call_info) => extract_events_from_call_info(call_info),
+            None => vec![],
+        };
+
+        let messages_sent = match execution_infos.execute_call_info {
+            Some(ref call_info) => extract_messages_from_call_info(call_info),
+            None => vec![],
+        };
 
         // TODO: use actual execution ressources
         let receipt = match transaction {
@@ -1575,20 +1679,10 @@ where
                 finality_status: actual_status,
                 block_hash: block_hash.into(),
                 block_number,
-                messages_sent: messages.into_iter().map(message_conversion).collect(),
+                messages_sent,
                 events,
                 execution_result,
-                execution_resources: ExecutionResources {
-                    steps: 0,
-                    memory_holes: None,
-                    range_check_builtin_applications: 0,
-                    pedersen_builtin_applications: 0,
-                    poseidon_builtin_applications: 0,
-                    ec_op_builtin_applications: 0,
-                    ecdsa_builtin_applications: 0,
-                    bitwise_builtin_applications: 0,
-                    keccak_builtin_applications: 0,
-                },
+                execution_resources,
             }),
             mp_transactions::Transaction::DeployAccount(tx) => {
                 TransactionReceipt::DeployAccount(DeployAccountTransactionReceipt {
@@ -1597,21 +1691,11 @@ where
                     finality_status: actual_status,
                     block_hash: block_hash.into(),
                     block_number,
-                    messages_sent: messages.into_iter().map(message_conversion).collect(),
+                    messages_sent,
                     events,
                     contract_address: tx.get_account_address(),
                     execution_result,
-                    execution_resources: ExecutionResources {
-                        steps: 0,
-                        memory_holes: None,
-                        range_check_builtin_applications: 0,
-                        pedersen_builtin_applications: 0,
-                        poseidon_builtin_applications: 0,
-                        ec_op_builtin_applications: 0,
-                        ecdsa_builtin_applications: 0,
-                        bitwise_builtin_applications: 0,
-                        keccak_builtin_applications: 0,
-                    },
+                    execution_resources,
                 })
             }
             mp_transactions::Transaction::Deploy(tx) => TransactionReceipt::Deploy(DeployTransactionReceipt {
@@ -1620,21 +1704,11 @@ where
                 finality_status: actual_status,
                 block_hash: block_hash.into(),
                 block_number,
-                messages_sent: Default::default(),
+                messages_sent,
                 events,
                 contract_address: tx.get_account_address(),
                 execution_result,
-                execution_resources: ExecutionResources {
-                    steps: 0,
-                    memory_holes: None,
-                    range_check_builtin_applications: 0,
-                    pedersen_builtin_applications: 0,
-                    poseidon_builtin_applications: 0,
-                    ec_op_builtin_applications: 0,
-                    ecdsa_builtin_applications: 0,
-                    bitwise_builtin_applications: 0,
-                    keccak_builtin_applications: 0,
-                },
+                execution_resources,
             }),
             mp_transactions::Transaction::Invoke(_) => TransactionReceipt::Invoke(InvokeTransactionReceipt {
                 transaction_hash,
@@ -1642,20 +1716,10 @@ where
                 finality_status: actual_status,
                 block_hash: block_hash.into(),
                 block_number,
-                messages_sent: messages.into_iter().map(message_conversion).collect(),
+                messages_sent,
                 events,
                 execution_result,
-                execution_resources: ExecutionResources {
-                    steps: 0,
-                    memory_holes: None,
-                    range_check_builtin_applications: 0,
-                    pedersen_builtin_applications: 0,
-                    poseidon_builtin_applications: 0,
-                    ec_op_builtin_applications: 0,
-                    ecdsa_builtin_applications: 0,
-                    bitwise_builtin_applications: 0,
-                    keccak_builtin_applications: 0,
-                },
+                execution_resources,
             }),
             mp_transactions::Transaction::L1Handler(_) => TransactionReceipt::L1Handler(L1HandlerTransactionReceipt {
                 message_hash,
@@ -1664,20 +1728,10 @@ where
                 finality_status: actual_status,
                 block_hash: block_hash.into(),
                 block_number,
-                messages_sent: messages.into_iter().map(message_conversion).collect(),
+                messages_sent,
                 events,
                 execution_result,
-                execution_resources: ExecutionResources {
-                    steps: 0,
-                    memory_holes: None,
-                    range_check_builtin_applications: 0,
-                    pedersen_builtin_applications: 0,
-                    poseidon_builtin_applications: 0,
-                    ec_op_builtin_applications: 0,
-                    ecdsa_builtin_applications: 0,
-                    bitwise_builtin_applications: 0,
-                    keccak_builtin_applications: 0,
-                },
+                execution_resources,
             }),
         };
 
@@ -1744,3 +1798,109 @@ where
 fn h256_to_felt(h256: H256) -> Result<FieldElement, Felt252WrapperError> {
     Felt252Wrapper::try_from(h256).map(|f| f.0)
 }
+
+fn blockifier_to_starknet_rs_ordered_events(
+    ordered_events: &[blockifier::execution::entry_point::OrderedEvent],
+) -> Vec<starknet_core::types::OrderedEvent> {
+    ordered_events
+        .iter()
+        .map(|event| starknet_core::types::OrderedEvent {
+            order: event.order as u64, // Convert usize to u64
+            keys: event.event.keys.iter().map(|key| FieldElement::from_byte_slice_be(key.0.bytes()).unwrap()).collect(),
+            data: event
+                .event
+                .data
+                .0
+                .iter()
+                .map(|data_item| FieldElement::from_byte_slice_be(data_item.bytes()).unwrap())
+                .collect(),
+        })
+        .collect()
+}
+
+fn blockifier_call_info_to_starknet_resources(callinfo: &CallInfo) -> ExecutionResources {
+    let vm_ressources = &callinfo.vm_resources;
+
+    let steps = vm_ressources.n_steps as u64;
+    let memory_holes = match vm_ressources.n_memory_holes as u64 {
+        0 => None,
+        n => Some(n),
+    };
+
+    let builtin_insstance = &vm_ressources.builtin_instance_counter;
+
+    let range_check_builtin_applications = *builtin_insstance.get("range_check_builtin").unwrap_or(&0) as u64;
+    let pedersen_builtin_applications = *builtin_insstance.get("pedersen_builtin").unwrap_or(&0) as u64;
+    let poseidon_builtin_applications = *builtin_insstance.get("poseidon_builtin").unwrap_or(&0) as u64;
+    let ec_op_builtin_applications = *builtin_insstance.get("ec_op_builtin").unwrap_or(&0) as u64;
+    let ecdsa_builtin_applications = *builtin_insstance.get("ecdsa_builtin").unwrap_or(&0) as u64;
+    let bitwise_builtin_applications = *builtin_insstance.get("bitwise_builtin").unwrap_or(&0) as u64;
+    let keccak_builtin_applications = *builtin_insstance.get("keccak_builtin").unwrap_or(&0) as u64;
+
+    ExecutionResources {
+        steps,
+        memory_holes,
+        range_check_builtin_applications,
+        pedersen_builtin_applications,
+        poseidon_builtin_applications,
+        ec_op_builtin_applications,
+        ecdsa_builtin_applications,
+        bitwise_builtin_applications,
+        keccak_builtin_applications,
+    }
+}
+
+fn extract_events_from_call_info(call_info: &CallInfo) -> Vec<Event> {
+    let address = call_info.call.storage_address;
+    let events: Vec<_> = call_info
+        .execution
+        .events
+        .iter()
+        .map(|ordered_event| Event {
+            from_address: FieldElement::from_byte_slice_be(address.0.0.bytes()).unwrap(),
+            keys: ordered_event
+                .event
+                .keys
+                .iter()
+                .map(|key| FieldElement::from_byte_slice_be(key.0.bytes()).unwrap())
+                .collect(),
+            data: ordered_event
+                .event
+                .data
+                .0
+                .iter()
+                .map(|data_item| FieldElement::from_byte_slice_be(data_item.bytes()).unwrap())
+                .collect(),
+        })
+        .collect();
+
+    let inner_events: Vec<_> =
+        call_info.inner_calls.iter().flat_map(|inner_call| extract_events_from_call_info(inner_call)).collect();
+
+    events.into_iter().chain(inner_events).collect()
+}
+
+fn extract_messages_from_call_info(call_info: &CallInfo) -> Vec<MsgToL1> {
+    let address = call_info.call.storage_address;
+    let events: Vec<_> = call_info
+        .execution
+        .l2_to_l1_messages
+        .iter()
+        .map(|msg| MsgToL1 {
+            from_address: FieldElement::from_byte_slice_be(address.0.0.bytes()).unwrap(),
+            to_address: FieldElement::from_byte_slice_be(msg.message.to_address.0.to_fixed_bytes().as_slice()).unwrap(),
+            payload: msg
+                .message
+                .payload
+                .0
+                .iter()
+                .map(|data_item| FieldElement::from_byte_slice_be(data_item.bytes()).unwrap())
+                .collect(),
+        })
+        .collect();
+
+    let inner_messages: Vec<_> =
+        call_info.inner_calls.iter().flat_map(|inner_call| extract_messages_from_call_info(inner_call)).collect();
+
+    events.into_iter().chain(inner_messages).collect()
+}

From 3607fbf62567f14a41216effd61ed260e05ef806 Mon Sep 17 00:00:00 2001
From: jb caron <jbcaron.dev@gmail.com>
Date: Tue, 20 Feb 2024 12:46:01 +0100
Subject: [PATCH 2/5] refactor: :recycle: create utils for rpc functions

---
 crates/client/rpc/src/lib.rs   | 134 +++------------------------------
 crates/client/rpc/src/utils.rs | 109 +++++++++++++++++++++++++++
 2 files changed, 120 insertions(+), 123 deletions(-)
 create mode 100644 crates/client/rpc/src/utils.rs

diff --git a/crates/client/rpc/src/lib.rs b/crates/client/rpc/src/lib.rs
index 80cf6353af..577a7698c2 100644
--- a/crates/client/rpc/src/lib.rs
+++ b/crates/client/rpc/src/lib.rs
@@ -8,6 +8,8 @@ mod events;
 mod madara_backend_client;
 mod trace_api;
 mod types;
+mod utils;
+
 use std::marker::PhantomData;
 use std::sync::Arc;
 
@@ -64,6 +66,9 @@ use starknet_core::types::{
 
 use crate::constants::{MAX_EVENTS_CHUNK_SIZE, MAX_EVENTS_KEYS};
 use crate::types::RpcEventFilter;
+use crate::utils::{
+    blockifier_call_info_to_starknet_resources, extract_events_from_call_info, extract_messages_from_call_info,
+};
 
 /// A Starknet RPC server for Madara
 pub struct Starknet<A: ChainApi, B: BlockT, BE, G, C, P, H> {
@@ -1509,28 +1514,17 @@ where
             StarknetRpcApiError::InternalServerError
         })?;
 
-        block.transactions().iter().take(tx_index + 1).enumerate().for_each(|(i, tx)| match tx {
-            TransactionMp::Declare(_) => {
-                println!("transaction {i}: declare_tx");
-            }
-            TransactionMp::DeployAccount(_) => {
-                println!("transaction {i}: deploy_account_tx");
-            }
-            TransactionMp::Deploy(_) => {
-                println!("transaction {i}: deploy_tx");
-            }
-            TransactionMp::Invoke(_) => {
-                println!("transaction {i}: invoke_tx");
-            }
-            TransactionMp::L1Handler(_) => {
-                println!("transaction {i}: l1_handler_tx");
-            }
-        });
+        // TODO: remove this line when deploy is supported
+        if let TransactionMp::Deploy(..) = transaction {
+            log::error!("re executing a deploy transaction is not supported yet");
+            return Err(StarknetRpcApiError::InternalServerError.into());
+        }
 
         let transactions = block
             .transactions()
             .iter()
             .take(tx_index + 1)
+            .filter(|tx| matches!(tx, TransactionMp::Invoke(_) | TransactionMp::DeployAccount(_) | TransactionMp::Declare(_) | TransactionMp::L1Handler(_)))// TODO: remove this line when deploy is supported
             .map(|tx| match tx {
                 TransactionMp::Invoke(invoke_tx) => {
                     RpcResult::Ok(UserOrL1HandlerTransaction::User(UserTransaction::Invoke(invoke_tx.clone())))
@@ -1798,109 +1792,3 @@ where
 fn h256_to_felt(h256: H256) -> Result<FieldElement, Felt252WrapperError> {
     Felt252Wrapper::try_from(h256).map(|f| f.0)
 }
-
-fn blockifier_to_starknet_rs_ordered_events(
-    ordered_events: &[blockifier::execution::entry_point::OrderedEvent],
-) -> Vec<starknet_core::types::OrderedEvent> {
-    ordered_events
-        .iter()
-        .map(|event| starknet_core::types::OrderedEvent {
-            order: event.order as u64, // Convert usize to u64
-            keys: event.event.keys.iter().map(|key| FieldElement::from_byte_slice_be(key.0.bytes()).unwrap()).collect(),
-            data: event
-                .event
-                .data
-                .0
-                .iter()
-                .map(|data_item| FieldElement::from_byte_slice_be(data_item.bytes()).unwrap())
-                .collect(),
-        })
-        .collect()
-}
-
-fn blockifier_call_info_to_starknet_resources(callinfo: &CallInfo) -> ExecutionResources {
-    let vm_ressources = &callinfo.vm_resources;
-
-    let steps = vm_ressources.n_steps as u64;
-    let memory_holes = match vm_ressources.n_memory_holes as u64 {
-        0 => None,
-        n => Some(n),
-    };
-
-    let builtin_insstance = &vm_ressources.builtin_instance_counter;
-
-    let range_check_builtin_applications = *builtin_insstance.get("range_check_builtin").unwrap_or(&0) as u64;
-    let pedersen_builtin_applications = *builtin_insstance.get("pedersen_builtin").unwrap_or(&0) as u64;
-    let poseidon_builtin_applications = *builtin_insstance.get("poseidon_builtin").unwrap_or(&0) as u64;
-    let ec_op_builtin_applications = *builtin_insstance.get("ec_op_builtin").unwrap_or(&0) as u64;
-    let ecdsa_builtin_applications = *builtin_insstance.get("ecdsa_builtin").unwrap_or(&0) as u64;
-    let bitwise_builtin_applications = *builtin_insstance.get("bitwise_builtin").unwrap_or(&0) as u64;
-    let keccak_builtin_applications = *builtin_insstance.get("keccak_builtin").unwrap_or(&0) as u64;
-
-    ExecutionResources {
-        steps,
-        memory_holes,
-        range_check_builtin_applications,
-        pedersen_builtin_applications,
-        poseidon_builtin_applications,
-        ec_op_builtin_applications,
-        ecdsa_builtin_applications,
-        bitwise_builtin_applications,
-        keccak_builtin_applications,
-    }
-}
-
-fn extract_events_from_call_info(call_info: &CallInfo) -> Vec<Event> {
-    let address = call_info.call.storage_address;
-    let events: Vec<_> = call_info
-        .execution
-        .events
-        .iter()
-        .map(|ordered_event| Event {
-            from_address: FieldElement::from_byte_slice_be(address.0.0.bytes()).unwrap(),
-            keys: ordered_event
-                .event
-                .keys
-                .iter()
-                .map(|key| FieldElement::from_byte_slice_be(key.0.bytes()).unwrap())
-                .collect(),
-            data: ordered_event
-                .event
-                .data
-                .0
-                .iter()
-                .map(|data_item| FieldElement::from_byte_slice_be(data_item.bytes()).unwrap())
-                .collect(),
-        })
-        .collect();
-
-    let inner_events: Vec<_> =
-        call_info.inner_calls.iter().flat_map(|inner_call| extract_events_from_call_info(inner_call)).collect();
-
-    events.into_iter().chain(inner_events).collect()
-}
-
-fn extract_messages_from_call_info(call_info: &CallInfo) -> Vec<MsgToL1> {
-    let address = call_info.call.storage_address;
-    let events: Vec<_> = call_info
-        .execution
-        .l2_to_l1_messages
-        .iter()
-        .map(|msg| MsgToL1 {
-            from_address: FieldElement::from_byte_slice_be(address.0.0.bytes()).unwrap(),
-            to_address: FieldElement::from_byte_slice_be(msg.message.to_address.0.to_fixed_bytes().as_slice()).unwrap(),
-            payload: msg
-                .message
-                .payload
-                .0
-                .iter()
-                .map(|data_item| FieldElement::from_byte_slice_be(data_item.bytes()).unwrap())
-                .collect(),
-        })
-        .collect();
-
-    let inner_messages: Vec<_> =
-        call_info.inner_calls.iter().flat_map(|inner_call| extract_messages_from_call_info(inner_call)).collect();
-
-    events.into_iter().chain(inner_messages).collect()
-}
diff --git a/crates/client/rpc/src/utils.rs b/crates/client/rpc/src/utils.rs
new file mode 100644
index 0000000000..6132b440f0
--- /dev/null
+++ b/crates/client/rpc/src/utils.rs
@@ -0,0 +1,109 @@
+use blockifier::execution::entry_point::CallInfo;
+pub use mc_rpc_core::{Felt, StarknetReadRpcApiServer, StarknetTraceRpcApiServer, StarknetWriteRpcApiServer};
+use starknet_core::types::{Event, ExecutionResources, FieldElement, MsgToL1};
+
+pub fn extract_events_from_call_info(call_info: &CallInfo) -> Vec<Event> {
+    let address = call_info.call.storage_address;
+    let events: Vec<_> = call_info
+        .execution
+        .events
+        .iter()
+        .map(|ordered_event| Event {
+            from_address: FieldElement::from_byte_slice_be(address.0.0.bytes()).unwrap(),
+            keys: ordered_event
+                .event
+                .keys
+                .iter()
+                .map(|key| FieldElement::from_byte_slice_be(key.0.bytes()).unwrap())
+                .collect(),
+            data: ordered_event
+                .event
+                .data
+                .0
+                .iter()
+                .map(|data_item| FieldElement::from_byte_slice_be(data_item.bytes()).unwrap())
+                .collect(),
+        })
+        .collect();
+
+    let inner_events: Vec<_> =
+        call_info.inner_calls.iter().flat_map(|inner_call| extract_events_from_call_info(inner_call)).collect();
+
+    events.into_iter().chain(inner_events).collect()
+}
+
+pub fn extract_messages_from_call_info(call_info: &CallInfo) -> Vec<MsgToL1> {
+    let address = call_info.call.storage_address;
+    let events: Vec<_> = call_info
+        .execution
+        .l2_to_l1_messages
+        .iter()
+        .map(|msg| MsgToL1 {
+            from_address: FieldElement::from_byte_slice_be(address.0.0.bytes()).unwrap(),
+            to_address: FieldElement::from_byte_slice_be(msg.message.to_address.0.to_fixed_bytes().as_slice()).unwrap(),
+            payload: msg
+                .message
+                .payload
+                .0
+                .iter()
+                .map(|data_item| FieldElement::from_byte_slice_be(data_item.bytes()).unwrap())
+                .collect(),
+        })
+        .collect();
+
+    let inner_messages: Vec<_> =
+        call_info.inner_calls.iter().flat_map(|inner_call| extract_messages_from_call_info(inner_call)).collect();
+
+    events.into_iter().chain(inner_messages).collect()
+}
+
+pub fn blockifier_call_info_to_starknet_resources(callinfo: &CallInfo) -> ExecutionResources {
+    let vm_ressources = &callinfo.vm_resources;
+
+    let steps = vm_ressources.n_steps as u64;
+    let memory_holes = match vm_ressources.n_memory_holes as u64 {
+        0 => None,
+        n => Some(n),
+    };
+
+    let builtin_insstance = &vm_ressources.builtin_instance_counter;
+
+    let range_check_builtin_applications = *builtin_insstance.get("range_check_builtin").unwrap_or(&0) as u64;
+    let pedersen_builtin_applications = *builtin_insstance.get("pedersen_builtin").unwrap_or(&0) as u64;
+    let poseidon_builtin_applications = *builtin_insstance.get("poseidon_builtin").unwrap_or(&0) as u64;
+    let ec_op_builtin_applications = *builtin_insstance.get("ec_op_builtin").unwrap_or(&0) as u64;
+    let ecdsa_builtin_applications = *builtin_insstance.get("ecdsa_builtin").unwrap_or(&0) as u64;
+    let bitwise_builtin_applications = *builtin_insstance.get("bitwise_builtin").unwrap_or(&0) as u64;
+    let keccak_builtin_applications = *builtin_insstance.get("keccak_builtin").unwrap_or(&0) as u64;
+
+    ExecutionResources {
+        steps,
+        memory_holes,
+        range_check_builtin_applications,
+        pedersen_builtin_applications,
+        poseidon_builtin_applications,
+        ec_op_builtin_applications,
+        ecdsa_builtin_applications,
+        bitwise_builtin_applications,
+        keccak_builtin_applications,
+    }
+}
+
+pub fn blockifier_to_starknet_rs_ordered_events(
+    ordered_events: &[blockifier::execution::entry_point::OrderedEvent],
+) -> Vec<starknet_core::types::OrderedEvent> {
+    ordered_events
+        .iter()
+        .map(|event| starknet_core::types::OrderedEvent {
+            order: event.order as u64, // Convert usize to u64
+            keys: event.event.keys.iter().map(|key| FieldElement::from_byte_slice_be(key.0.bytes()).unwrap()).collect(),
+            data: event
+                .event
+                .data
+                .0
+                .iter()
+                .map(|data_item| FieldElement::from_byte_slice_be(data_item.bytes()).unwrap())
+                .collect(),
+        })
+        .collect()
+}

From ea3fd7e263b52280d03ce7ea6073f5c48d3fc7ba Mon Sep 17 00:00:00 2001
From: jb caron <jbcaron.dev@gmail.com>
Date: Tue, 20 Feb 2024 20:21:24 +0100
Subject: [PATCH 3/5] fix: :bug: block_number as u64

---
 crates/client/rpc/src/lib.rs | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/crates/client/rpc/src/lib.rs b/crates/client/rpc/src/lib.rs
index 80a4f4b9bd..96121d9988 100644
--- a/crates/client/rpc/src/lib.rs
+++ b/crates/client/rpc/src/lib.rs
@@ -19,8 +19,8 @@ use errors::StarknetRpcApiError;
 use jsonrpsee::core::{async_trait, RpcResult};
 use jsonrpsee::types::error::CallError;
 use log::error;
-use mc_deoxys::l2::get_config;
 use mc_deoxys::commitments::transactions;
+use mc_deoxys::l2::get_config;
 use mc_deoxys::utility::get_highest_block_hash_and_number;
 use mc_genesis_data_provider::GenesisProvider;
 pub use mc_rpc_core::utils::*;
@@ -1621,14 +1621,13 @@ where
                 log::error!("No execution info returned for the last transaction");
                 StarknetRpcApiError::InternalServerError
             })?;
-            
 
         // TODO(#1291): compute message hash correctly to L1HandlerTransactionReceipt
         let message_hash: Hash256 = Hash256::from_felt(&FieldElement::default());
 
         let actual_fee = execution_infos.actual_fee.0.into();
 
-        let actual_status = if block_number <= mc_deoxys::l1::ETHEREUM_STATE_UPDATE.lock().unwrap().block_number.0 {
+        let actual_status = if block_number <= mc_deoxys::l1::ETHEREUM_STATE_UPDATE.lock().unwrap().block_number {
             TransactionFinalityStatus::AcceptedOnL1.into()
         } else {
             TransactionFinalityStatus::AcceptedOnL2.into()

From da8ed06e37f5bad428892f8ca063359b52da42b7 Mon Sep 17 00:00:00 2001
From: jb caron <jbcaron.dev@gmail.com>
Date: Tue, 27 Feb 2024 12:08:13 +0100
Subject: [PATCH 4/5] refactor: :goal_net: change kind of error

---
 crates/client/rpc/src/lib.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/crates/client/rpc/src/lib.rs b/crates/client/rpc/src/lib.rs
index 96121d9988..91d3239803 100644
--- a/crates/client/rpc/src/lib.rs
+++ b/crates/client/rpc/src/lib.rs
@@ -1515,14 +1515,14 @@ where
         // TODO: remove this line when deploy is supported
         if let TransactionMp::Deploy(..) = transaction {
             log::error!("re executing a deploy transaction is not supported yet");
-            return Err(StarknetRpcApiError::InternalServerError.into());
+            return Err(StarknetRpcApiError::UnimplementedMethod.into());
         }
 
         let transactions = block
             .transactions()
             .iter()
             .take(tx_index + 1)
-            .filter(|tx| matches!(tx, TransactionMp::Invoke(_) | TransactionMp::DeployAccount(_) | TransactionMp::Declare(_) | TransactionMp::L1Handler(_)))// TODO: remove this line when deploy is supported
+            .filter(|tx| !matches!(tx, TransactionMp::Deploy(_))) // TODO: remove this line when deploy is supported
             .map(|tx| match tx {
                 TransactionMp::Invoke(invoke_tx) => {
                     RpcResult::Ok(UserOrL1HandlerTransaction::User(UserTransaction::Invoke(invoke_tx.clone())))

From 80539cb805db6030f33890f41c699071a0c3015a Mon Sep 17 00:00:00 2001
From: jb caron <jbcaron.dev@gmail.com>
Date: Tue, 27 Feb 2024 15:56:59 +0100
Subject: [PATCH 5/5] docs: :memo: update changelog

---
 CHANGELOG.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8c18579816..62dd25554f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@ git # Madara Changelog
 
 ## Next release
 
+- feat(rpc): tx_receipt, re-execute tx
 - perf(verify_l2): parallelized l2 state root update
 - perf(state_commitment): parallelized state commitment hash computations
 - fix(L1): fix l1 thread with battle tested implementation + removed l1-l2