Skip to content

Commit 2d9ae1a

Browse files
committed
wip
1 parent 3c0500c commit 2d9ae1a

File tree

7 files changed

+692
-78
lines changed

7 files changed

+692
-78
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/gateway/gateway-types/src/receipt.rs

Lines changed: 376 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,379 @@ pub struct L1ToL2Message {
5858
pub payload: Vec<Felt>,
5959
pub nonce: Option<Nonce>,
6060
}
61+
62+
////////////////////////////////////////////////////////////////////////////////
63+
// Conversion to Katana RPC types.
64+
////////////////////////////////////////////////////////////////////////////////
65+
66+
impl From<ExecutionStatus> for katana_rpc_types::ExecutionResult {
67+
fn from(value: ExecutionStatus) -> Self {
68+
match value {
69+
ExecutionStatus::Succeeded => katana_rpc_types::ExecutionResult::Succeeded,
70+
ExecutionStatus::Reverted => {
71+
// When converting from gateway ExecutionStatus::Reverted, we don't have the
72+
// revert reason here. The caller should use the revert_error field from
73+
// ReceiptBody if available.
74+
katana_rpc_types::ExecutionResult::Reverted {
75+
reason: String::from("Transaction reverted"),
76+
}
77+
}
78+
}
79+
}
80+
}
81+
82+
impl From<ExecutionResources> for katana_rpc_types::ExecutionResources {
83+
fn from(value: ExecutionResources) -> Self {
84+
let gas = value.total_gas_consumed.unwrap_or_default();
85+
katana_rpc_types::ExecutionResources {
86+
l1_gas: gas.l1_gas,
87+
l1_data_gas: gas.l1_data_gas,
88+
l2_gas: gas.l2_gas,
89+
}
90+
}
91+
}
92+
93+
impl ReceiptBody {
94+
/// Convert the receipt body to an RPC execution result.
95+
///
96+
/// This uses the `execution_status` field if available, otherwise falls back to checking
97+
/// the `revert_error` field. If `revert_error` is present, the result is `Reverted`.
98+
pub fn to_execution_result(&self) -> katana_rpc_types::ExecutionResult {
99+
if let Some(revert_error) = &self.revert_error {
100+
katana_rpc_types::ExecutionResult::Reverted { reason: revert_error.clone() }
101+
} else if let Some(status) = &self.execution_status {
102+
match status {
103+
ExecutionStatus::Succeeded => katana_rpc_types::ExecutionResult::Succeeded,
104+
ExecutionStatus::Reverted => {
105+
// Reverted status without error message
106+
katana_rpc_types::ExecutionResult::Reverted {
107+
reason: String::from("Transaction reverted"),
108+
}
109+
}
110+
}
111+
} else {
112+
// If no status is provided, assume success
113+
katana_rpc_types::ExecutionResult::Succeeded
114+
}
115+
}
116+
117+
/// Convert to an RPC FeePayment with the given price unit.
118+
pub fn to_fee_payment(
119+
&self,
120+
unit: katana_primitives::fee::PriceUnit,
121+
) -> katana_rpc_types::FeePayment {
122+
katana_rpc_types::FeePayment { amount: self.actual_fee, unit }
123+
}
124+
}
125+
126+
impl ConfirmedReceipt {
127+
/// Create an RPC Invoke receipt from this gateway receipt.
128+
///
129+
/// # Arguments
130+
/// * `finality_status` - The finality status of the transaction
131+
/// * `fee_unit` - The price unit for the fee
132+
pub fn to_rpc_invoke_receipt(
133+
self,
134+
finality_status: katana_primitives::block::FinalityStatus,
135+
fee_unit: katana_primitives::fee::PriceUnit,
136+
) -> katana_rpc_types::RpcInvokeTxReceipt {
137+
let execution_result = self.body.to_execution_result();
138+
let actual_fee = self.body.to_fee_payment(fee_unit);
139+
140+
katana_rpc_types::RpcInvokeTxReceipt {
141+
actual_fee,
142+
finality_status,
143+
messages_sent: self.body.l2_to_l1_messages,
144+
events: self.body.events,
145+
execution_resources: self.body.execution_resources.unwrap_or_default().into(),
146+
execution_result,
147+
}
148+
}
149+
150+
/// Create an RPC Declare receipt from this gateway receipt.
151+
///
152+
/// # Arguments
153+
/// * `finality_status` - The finality status of the transaction
154+
/// * `fee_unit` - The price unit for the fee
155+
pub fn to_rpc_declare_receipt(
156+
self,
157+
finality_status: katana_primitives::block::FinalityStatus,
158+
fee_unit: katana_primitives::fee::PriceUnit,
159+
) -> katana_rpc_types::RpcDeclareTxReceipt {
160+
let execution_result = self.body.to_execution_result();
161+
let actual_fee = self.body.to_fee_payment(fee_unit);
162+
163+
katana_rpc_types::RpcDeclareTxReceipt {
164+
actual_fee,
165+
finality_status,
166+
messages_sent: self.body.l2_to_l1_messages,
167+
events: self.body.events,
168+
execution_resources: self.body.execution_resources.unwrap_or_default().into(),
169+
execution_result,
170+
}
171+
}
172+
173+
/// Create an RPC Deploy receipt from this gateway receipt.
174+
///
175+
/// # Arguments
176+
/// * `finality_status` - The finality status of the transaction
177+
/// * `fee_unit` - The price unit for the fee
178+
/// * `contract_address` - The deployed contract address
179+
pub fn to_rpc_deploy_receipt(
180+
self,
181+
finality_status: katana_primitives::block::FinalityStatus,
182+
fee_unit: katana_primitives::fee::PriceUnit,
183+
contract_address: ContractAddress,
184+
) -> katana_rpc_types::RpcDeployTxReceipt {
185+
let execution_result = self.body.to_execution_result();
186+
let actual_fee = self.body.to_fee_payment(fee_unit);
187+
188+
katana_rpc_types::RpcDeployTxReceipt {
189+
actual_fee,
190+
finality_status,
191+
messages_sent: self.body.l2_to_l1_messages,
192+
events: self.body.events,
193+
execution_resources: self.body.execution_resources.unwrap_or_default().into(),
194+
contract_address,
195+
execution_result,
196+
}
197+
}
198+
199+
/// Create an RPC DeployAccount receipt from this gateway receipt.
200+
///
201+
/// # Arguments
202+
/// * `finality_status` - The finality status of the transaction
203+
/// * `fee_unit` - The price unit for the fee
204+
/// * `contract_address` - The deployed account contract address
205+
pub fn to_rpc_deploy_account_receipt(
206+
self,
207+
finality_status: katana_primitives::block::FinalityStatus,
208+
fee_unit: katana_primitives::fee::PriceUnit,
209+
contract_address: ContractAddress,
210+
) -> katana_rpc_types::RpcDeployAccountTxReceipt {
211+
let execution_result = self.body.to_execution_result();
212+
let actual_fee = self.body.to_fee_payment(fee_unit);
213+
214+
katana_rpc_types::RpcDeployAccountTxReceipt {
215+
actual_fee,
216+
finality_status,
217+
messages_sent: self.body.l2_to_l1_messages,
218+
events: self.body.events,
219+
execution_resources: self.body.execution_resources.unwrap_or_default().into(),
220+
contract_address,
221+
execution_result,
222+
}
223+
}
224+
225+
/// Create an RPC L1Handler receipt from this gateway receipt.
226+
///
227+
/// # Arguments
228+
/// * `finality_status` - The finality status of the transaction
229+
/// * `fee_unit` - The price unit for the fee
230+
/// * `message_hash` - The L1 to L2 message hash
231+
pub fn to_rpc_l1_handler_receipt(
232+
self,
233+
finality_status: katana_primitives::block::FinalityStatus,
234+
fee_unit: katana_primitives::fee::PriceUnit,
235+
message_hash: katana_primitives::B256,
236+
) -> katana_rpc_types::RpcL1HandlerTxReceipt {
237+
let execution_result = self.body.to_execution_result();
238+
let actual_fee = self.body.to_fee_payment(fee_unit);
239+
240+
katana_rpc_types::RpcL1HandlerTxReceipt {
241+
actual_fee,
242+
finality_status,
243+
messages_sent: self.body.l2_to_l1_messages,
244+
events: self.body.events,
245+
execution_resources: self.body.execution_resources.unwrap_or_default().into(),
246+
message_hash,
247+
execution_result,
248+
}
249+
}
250+
}
251+
252+
impl Default for ExecutionResources {
253+
fn default() -> Self {
254+
Self {
255+
vm_resources: Default::default(),
256+
data_availability: None,
257+
total_gas_consumed: Some(Default::default()),
258+
}
259+
}
260+
}
261+
262+
#[cfg(test)]
263+
mod tests {
264+
use katana_primitives::block::FinalityStatus;
265+
use katana_primitives::fee::PriceUnit;
266+
use katana_primitives::receipt::GasUsed;
267+
use katana_primitives::{address, felt};
268+
269+
use super::*;
270+
271+
fn create_test_receipt_body() -> ReceiptBody {
272+
ReceiptBody {
273+
execution_resources: Some(ExecutionResources {
274+
vm_resources: Default::default(),
275+
data_availability: None,
276+
total_gas_consumed: Some(GasUsed { l1_gas: 100, l1_data_gas: 50, l2_gas: 200 }),
277+
}),
278+
l1_to_l2_consumed_message: None,
279+
l2_to_l1_messages: vec![],
280+
events: vec![],
281+
actual_fee: felt!("0x1234"),
282+
execution_status: Some(ExecutionStatus::Succeeded),
283+
revert_error: None,
284+
}
285+
}
286+
287+
#[test]
288+
fn test_execution_status_to_execution_result() {
289+
let succeeded: katana_rpc_types::ExecutionResult = ExecutionStatus::Succeeded.into();
290+
assert_eq!(succeeded, katana_rpc_types::ExecutionResult::Succeeded);
291+
292+
let reverted: katana_rpc_types::ExecutionResult = ExecutionStatus::Reverted.into();
293+
match reverted {
294+
katana_rpc_types::ExecutionResult::Reverted { reason } => {
295+
assert_eq!(reason, "Transaction reverted");
296+
}
297+
_ => panic!("Expected Reverted result"),
298+
}
299+
}
300+
301+
#[test]
302+
fn test_execution_resources_conversion() {
303+
let gateway_resources = ExecutionResources {
304+
vm_resources: Default::default(),
305+
data_availability: None,
306+
total_gas_consumed: Some(GasUsed { l1_gas: 100, l1_data_gas: 50, l2_gas: 200 }),
307+
};
308+
309+
let rpc_resources: katana_rpc_types::ExecutionResources = gateway_resources.into();
310+
assert_eq!(rpc_resources.l1_gas, 100);
311+
assert_eq!(rpc_resources.l1_data_gas, 50);
312+
assert_eq!(rpc_resources.l2_gas, 200);
313+
}
314+
315+
#[test]
316+
fn test_receipt_body_to_execution_result_with_revert_error() {
317+
let body = ReceiptBody {
318+
execution_resources: None,
319+
l1_to_l2_consumed_message: None,
320+
l2_to_l1_messages: vec![],
321+
events: vec![],
322+
actual_fee: felt!("0x0"),
323+
execution_status: Some(ExecutionStatus::Succeeded),
324+
revert_error: Some("Out of gas".to_string()),
325+
};
326+
327+
let result = body.to_execution_result();
328+
match result {
329+
katana_rpc_types::ExecutionResult::Reverted { reason } => {
330+
assert_eq!(reason, "Out of gas");
331+
}
332+
_ => panic!("Expected Reverted result"),
333+
}
334+
}
335+
336+
#[test]
337+
fn test_receipt_body_to_execution_result_succeeded() {
338+
let body = create_test_receipt_body();
339+
let result = body.to_execution_result();
340+
assert_eq!(result, katana_rpc_types::ExecutionResult::Succeeded);
341+
}
342+
343+
#[test]
344+
fn test_to_rpc_invoke_receipt() {
345+
let gateway_receipt = ConfirmedReceipt {
346+
transaction_hash: felt!("0xabc"),
347+
transaction_index: 5,
348+
body: create_test_receipt_body(),
349+
};
350+
351+
let rpc_receipt = gateway_receipt
352+
.clone()
353+
.to_rpc_invoke_receipt(FinalityStatus::AcceptedOnL2, PriceUnit::Wei);
354+
355+
assert_eq!(rpc_receipt.actual_fee.amount, felt!("0x1234"));
356+
assert_eq!(rpc_receipt.actual_fee.unit, PriceUnit::Wei);
357+
assert_eq!(rpc_receipt.finality_status, FinalityStatus::AcceptedOnL2);
358+
assert_eq!(rpc_receipt.execution_resources.l1_gas, 100);
359+
assert_eq!(rpc_receipt.execution_resources.l2_gas, 200);
360+
assert_eq!(rpc_receipt.execution_result, katana_rpc_types::ExecutionResult::Succeeded);
361+
}
362+
363+
#[test]
364+
fn test_to_rpc_declare_receipt() {
365+
let gateway_receipt = ConfirmedReceipt {
366+
transaction_hash: felt!("0xdef"),
367+
transaction_index: 10,
368+
body: create_test_receipt_body(),
369+
};
370+
371+
let rpc_receipt = gateway_receipt
372+
.clone()
373+
.to_rpc_declare_receipt(FinalityStatus::AcceptedOnL1, PriceUnit::Fri);
374+
375+
assert_eq!(rpc_receipt.actual_fee.amount, felt!("0x1234"));
376+
assert_eq!(rpc_receipt.actual_fee.unit, PriceUnit::Fri);
377+
assert_eq!(rpc_receipt.finality_status, FinalityStatus::AcceptedOnL1);
378+
}
379+
380+
#[test]
381+
fn test_to_rpc_deploy_receipt() {
382+
let gateway_receipt = ConfirmedReceipt {
383+
transaction_hash: felt!("0x123"),
384+
transaction_index: 1,
385+
body: create_test_receipt_body(),
386+
};
387+
388+
let contract_address = address!("0x456");
389+
let rpc_receipt = gateway_receipt.clone().to_rpc_deploy_receipt(
390+
FinalityStatus::AcceptedOnL2,
391+
PriceUnit::Wei,
392+
contract_address,
393+
);
394+
395+
assert_eq!(rpc_receipt.contract_address, contract_address);
396+
assert_eq!(rpc_receipt.actual_fee.amount, felt!("0x1234"));
397+
}
398+
399+
#[test]
400+
fn test_to_rpc_deploy_account_receipt() {
401+
let gateway_receipt = ConfirmedReceipt {
402+
transaction_hash: felt!("0x789"),
403+
transaction_index: 2,
404+
body: create_test_receipt_body(),
405+
};
406+
407+
let contract_address = address!("0xabc");
408+
let rpc_receipt = gateway_receipt.clone().to_rpc_deploy_account_receipt(
409+
FinalityStatus::AcceptedOnL2,
410+
PriceUnit::Wei,
411+
contract_address,
412+
);
413+
414+
assert_eq!(rpc_receipt.contract_address, contract_address);
415+
assert_eq!(rpc_receipt.execution_result, katana_rpc_types::ExecutionResult::Succeeded);
416+
}
417+
418+
#[test]
419+
fn test_to_rpc_l1_handler_receipt() {
420+
let gateway_receipt = ConfirmedReceipt {
421+
transaction_hash: felt!("0xfff"),
422+
transaction_index: 3,
423+
body: create_test_receipt_body(),
424+
};
425+
426+
let message_hash = katana_primitives::B256::from([1u8; 32]);
427+
let rpc_receipt = gateway_receipt.clone().to_rpc_l1_handler_receipt(
428+
FinalityStatus::AcceptedOnL2,
429+
PriceUnit::Wei,
430+
message_hash,
431+
);
432+
433+
assert_eq!(rpc_receipt.message_hash, message_hash);
434+
assert_eq!(rpc_receipt.actual_fee.amount, felt!("0x1234"));
435+
}
436+
}

0 commit comments

Comments
 (0)