stratus/eth/primitives/
transaction_execution.rs1use alloy_consensus::Eip658Value;
2use alloy_consensus::Receipt;
3use alloy_consensus::ReceiptEnvelope;
4use alloy_consensus::ReceiptWithBloom;
5use display_json::DebugAsJson;
6
7use crate::alias::AlloyLog;
8use crate::alias::AlloyLogData;
9use crate::alias::AlloyLogPrimitive;
10use crate::alias::AlloyReceipt;
11use crate::alias::AlloyTransaction;
12use crate::eth::executor::EvmExecutionResult;
13use crate::eth::executor::EvmInput;
14use crate::eth::primitives::EvmExecutionMetrics;
15use crate::eth::primitives::ExecutionInfo;
16use crate::eth::primitives::Log;
17use crate::eth::primitives::MinedData;
18use crate::eth::primitives::Signature;
19use crate::eth::primitives::TransactionInfo;
20use crate::eth::primitives::TransactionInput;
21use crate::eth::primitives::logs_bloom::LogsBloom;
22use crate::ext::OptionExt;
23use crate::ext::RuintExt;
24
25#[derive(DebugAsJson, Clone, derive_new::new, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
26#[cfg_attr(test, derive(fake::Dummy))]
27pub struct TransactionExecution {
28 pub info: TransactionInfo,
29 pub signature: Signature,
30 pub evm_input: EvmInput,
31 pub result: EvmExecutionResult,
32}
33
34impl TransactionExecution {
35 pub fn metrics(&self) -> EvmExecutionMetrics {
37 self.result.metrics
38 }
39
40 pub fn create_alloy_logs(&self) -> Vec<AlloyLog> {
41 self.logs()
42 .iter()
43 .map(|log| AlloyLog {
44 inner: AlloyLogPrimitive {
45 address: log.address.into(),
46 data: AlloyLogData::new_unchecked(log.topics_non_empty().into_iter().map(Into::into).collect(), log.data.clone().into()),
47 },
48 block_hash: None,
49 block_number: Some(self.evm_input.block_number.as_u64()),
50 block_timestamp: Some(*self.evm_input.block_timestamp),
51 transaction_hash: Some(self.info.hash.into()),
52 transaction_index: None,
53 log_index: None,
54 removed: false,
55 })
56 .collect()
57 }
58
59 fn compute_bloom(&self) -> LogsBloom {
61 let mut bloom = LogsBloom::default();
62 for log in self.result.execution.logs.iter() {
63 bloom.accrue_log(log);
64 }
65 bloom
66 }
67
68 pub fn logs(&self) -> &Vec<Log> {
69 &self.result.execution.logs
70 }
71}
72
73impl From<TransactionExecution> for AlloyTransaction {
74 fn from(value: TransactionExecution) -> Self {
75 let tx_input: TransactionInput = value.into();
76 tx_input.into()
77 }
78}
79
80impl From<TransactionExecution> for TransactionInput {
81 fn from(value: TransactionExecution) -> Self {
82 Self {
83 transaction_info: value.info,
84 execution_info: ExecutionInfo {
85 chain_id: value.evm_input.chain_id,
86 nonce: value.evm_input.nonce.unwrap_or_default(),
87 signer: value.evm_input.from,
88 to: value.evm_input.to,
89 value: value.evm_input.value,
90 input: value.evm_input.data,
91 gas_limit: value.evm_input.gas_limit,
92 gas_price: value.evm_input.gas_price,
93 },
94 signature: value.signature,
95 }
96 }
97}
98
99pub fn _tx_to_alloy_receipt_impl(execution: TransactionExecution, alloy_logs: Vec<AlloyLog>, mined_data: Option<MinedData>) -> AlloyReceipt {
100 let receipt = Receipt {
101 status: Eip658Value::Eip658(execution.result.execution.is_success()),
102 cumulative_gas_used: execution.result.execution.gas_used.into(), logs: alloy_logs,
104 };
105
106 let receipt_with_bloom = ReceiptWithBloom {
107 receipt,
108 logs_bloom: execution.compute_bloom().into(),
109 };
110
111 let inner = match execution.info.tx_type.map(|tx| tx.as_u64()) {
112 Some(1u64) => ReceiptEnvelope::Eip2930(receipt_with_bloom),
113 Some(2u64) => ReceiptEnvelope::Eip1559(receipt_with_bloom),
114 Some(3u64) => ReceiptEnvelope::Eip4844(receipt_with_bloom),
115 Some(4u64) => ReceiptEnvelope::Eip7702(receipt_with_bloom),
116 _ => ReceiptEnvelope::Legacy(receipt_with_bloom),
117 };
118
119 AlloyReceipt {
120 inner,
121 transaction_hash: execution.info.hash.into(),
122 transaction_index: mined_data.map(|data| data.index.into()),
123 block_hash: mined_data.map(|data| data.block_hash.into()),
124 block_number: Some(execution.evm_input.block_number.as_u64()),
125 gas_used: execution.result.execution.gas_used.into(),
126 effective_gas_price: execution.evm_input.gas_price,
127 blob_gas_used: None,
128 blob_gas_price: None,
129 from: execution.evm_input.from.into(),
130 to: execution.evm_input.to.map_into(),
131 contract_address: execution.result.execution.deployed_contract_address.map_into(),
132 }
133}
134
135impl From<TransactionExecution> for AlloyReceipt {
136 fn from(value: TransactionExecution) -> Self {
137 let alloy_logs = value.create_alloy_logs();
138 _tx_to_alloy_receipt_impl(value, alloy_logs, None)
139 }
140}