pathfinder_common/
receipt.rs

1use fake::{Dummy, Fake, Faker};
2use pathfinder_crypto::Felt;
3
4use crate::prelude::*;
5
6#[derive(Clone, Default, Debug, PartialEq, Eq, Dummy)]
7pub struct Receipt {
8    pub actual_fee: Fee,
9    pub execution_resources: ExecutionResources,
10    pub l2_to_l1_messages: Vec<L2ToL1Message>,
11    pub execution_status: ExecutionStatus,
12    pub transaction_hash: TransactionHash,
13    pub transaction_index: TransactionIndex,
14}
15
16impl Receipt {
17    pub fn is_reverted(&self) -> bool {
18        matches!(self.execution_status, ExecutionStatus::Reverted { .. })
19    }
20
21    pub fn revert_reason(&self) -> Option<&str> {
22        match &self.execution_status {
23            ExecutionStatus::Succeeded => None,
24            ExecutionStatus::Reverted { reason } => Some(reason.as_str()),
25        }
26    }
27}
28
29#[derive(Clone, Debug, PartialEq, Eq)]
30pub struct L2ToL1Message {
31    pub from_address: ContractAddress,
32    pub payload: Vec<L2ToL1MessagePayloadElem>,
33    // This is purposefully not EthereumAddress even though this
34    // represents an Ethereum address normally. Starknet allows this value
35    // to be Felt sized; so technically callers can send a message to a garbage
36    // address.
37    pub to_address: ContractAddress,
38}
39
40#[derive(Clone, Debug, Default, PartialEq, Eq)]
41pub struct ExecutionResources {
42    pub builtins: BuiltinCounters,
43    pub n_steps: u64,
44    pub n_memory_holes: u64,
45    pub data_availability: L1Gas,
46    pub total_gas_consumed: L1Gas,
47    pub l2_gas: L2Gas,
48}
49
50#[derive(Clone, Debug, Default, PartialEq, Eq, Dummy)]
51pub struct L1Gas {
52    pub l1_gas: u128,
53    pub l1_data_gas: u128,
54}
55
56#[derive(Clone, Debug, Default, PartialEq, Eq, Dummy, serde::Serialize)]
57#[serde(transparent)]
58pub struct L2Gas(pub u128);
59
60#[derive(Clone, Debug, Default, PartialEq, Eq)]
61pub struct BuiltinCounters {
62    pub output: u64,
63    pub pedersen: u64,
64    pub range_check: u64,
65    pub ecdsa: u64,
66    pub bitwise: u64,
67    pub ec_op: u64,
68    pub keccak: u64,
69    pub poseidon: u64,
70    pub segment_arena: u64,
71    pub add_mod: u64,
72    pub mul_mod: u64,
73    pub range_check96: u64,
74}
75
76#[derive(Clone, Default, Debug, PartialEq, Eq, Dummy)]
77pub enum ExecutionStatus {
78    // This must be the default as pre v0.12.1 receipts did not contain this value and
79    // were always success as reverted did not exist.
80    #[default]
81    Succeeded,
82    Reverted {
83        reason: String,
84    },
85}
86
87impl<T> Dummy<T> for L2ToL1Message {
88    fn dummy_with_rng<R: rand::Rng + ?Sized>(_: &T, rng: &mut R) -> Self {
89        Self {
90            from_address: Faker.fake_with_rng(rng),
91            payload: Faker.fake_with_rng(rng),
92            // P2P treats this field as an EthereumAddress
93            to_address: ContractAddress(
94                Felt::from_be_slice(Faker.fake_with_rng::<EthereumAddress, R>(rng).0.as_bytes())
95                    .unwrap(),
96            ),
97        }
98    }
99}
100
101impl<T> Dummy<T> for ExecutionResources {
102    fn dummy_with_rng<R: rand::Rng + ?Sized>(_: &T, rng: &mut R) -> Self {
103        Self {
104            builtins: Faker.fake_with_rng(rng),
105            // P2P values are capped at u32::MAX
106            n_steps: rng.next_u32() as u64,
107            n_memory_holes: rng.next_u32() as u64,
108            data_availability: Faker.fake_with_rng(rng),
109            // TODO fix this after total_gas_consumed is added to p2p messages
110            total_gas_consumed: Default::default(),
111            l2_gas: Default::default(),
112        }
113    }
114}
115
116impl<T> Dummy<T> for BuiltinCounters {
117    fn dummy_with_rng<R: rand::Rng + ?Sized>(_: &T, rng: &mut R) -> Self {
118        Self {
119            // P2P values are capped at u32::MAX
120            output: rng.next_u32() as u64,
121            pedersen: rng.next_u32() as u64,
122            range_check: rng.next_u32() as u64,
123            ecdsa: rng.next_u32() as u64,
124            bitwise: rng.next_u32() as u64,
125            ec_op: rng.next_u32() as u64,
126            keccak: rng.next_u32() as u64,
127            poseidon: rng.next_u32() as u64,
128            // This field is not used in p2p
129            segment_arena: 0,
130            add_mod: rng.next_u32() as u64,
131            mul_mod: rng.next_u32() as u64,
132            range_check96: rng.next_u32() as u64,
133        }
134    }
135}