alloy_eip7547/
summary.rs

1//! Contains types related to the Inclusion lists that will be used by in the engine API RPC
2//! definitions.
3
4use alloy_primitives::{Address, B256};
5use alloy_rpc_types_engine::PayloadStatusEnum;
6use serde::{ser::SerializeMap, Deserialize, Serialize, Serializer};
7use std::fmt;
8
9/// This structure contains the result of processing an `engine_newInclusionListV1` RPC call.
10///
11/// From the spec:
12///
13/// ### InclusionListStatusV1
14///
15/// This structure contains the result of processing an inclusion list. The fields are encoded as
16/// follows:
17/// - `status`: `enum` - `"VALID" | "INVALID" | "SYNCING" | "ACCEPTED"`
18/// - `validationError`: `String|null` - a message providing additional details on the validation
19///   error if the payload is classified as `INVALID`.
20#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
21#[serde(rename_all = "camelCase")]
22pub struct InclusionListStatusV1 {
23    /// The status of the payload.
24    #[serde(flatten)]
25    pub status: PayloadStatusEnum,
26}
27
28impl InclusionListStatusV1 {
29    /// Initializes a new inclusion list status.
30    pub const fn new(status: PayloadStatusEnum) -> Self {
31        Self { status }
32    }
33
34    /// Returns true if the payload status is syncing.
35    pub const fn is_syncing(&self) -> bool {
36        self.status.is_syncing()
37    }
38
39    /// Returns true if the payload status is valid.
40    pub const fn is_valid(&self) -> bool {
41        self.status.is_valid()
42    }
43
44    /// Returns true if the payload status is invalid.
45    pub const fn is_invalid(&self) -> bool {
46        self.status.is_invalid()
47    }
48}
49
50impl fmt::Display for InclusionListStatusV1 {
51    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52        write!(f, "InclusionListStatusV1 {{ status: {} }}", self.status)
53    }
54}
55
56impl Serialize for InclusionListStatusV1 {
57    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
58    where
59        S: Serializer,
60    {
61        let mut map = serializer.serialize_map(Some(2))?;
62        map.serialize_entry("status", self.status.as_str())?;
63        map.serialize_entry("validationError", &self.status.validation_error())?;
64        map.end()
65    }
66}
67
68/// This is an individual entry in the inclusion list summary, representing a transaction that
69/// should be included in this block or the next block.
70///
71/// From the spec:
72///
73/// ### InclusionListSummaryEntryV1
74///
75/// This structure contains the details of each inclusion list entry.
76///
77/// - `address` : `DATA`, 20 Bytes
78/// - `nonce` : `QUANTITY`, 64 Bits
79#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
80#[serde(rename_all = "camelCase")]
81pub struct InclusionListSummaryEntryV1 {
82    /// The address of the inclusion list entry.
83    pub address: Address,
84    /// The nonce of the inclusion list entry.
85    #[serde(with = "alloy_serde::quantity")]
86    pub nonce: u64,
87}
88
89impl fmt::Display for InclusionListSummaryEntryV1 {
90    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91        write!(
92            f,
93            "InclusionListSummaryEntryV1 {{ address: {}, nonce: {} }}",
94            self.address, self.nonce
95        )
96    }
97}
98
99/// This structure contains the inclusion list summary input to the `engine_newInclusionListV1` RPC
100/// call.
101///
102/// ### InclusionListSummaryV1
103///
104/// This structure contains the inclusion list summary.
105///
106/// - `slot` : `QUANTITY`, 64 Bits
107/// - `proposer_index`: `QUANTITY`, 64 Bits
108/// - `parent_hash`: `DATA`, 32 Bytes
109/// - `summary`: `Array of InclusionListSummaryEntryV1`, Array of entries that must be satisfied.
110#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
111#[serde(rename_all = "camelCase")]
112pub struct InclusionListSummaryV1 {
113    /// The slot of the inclusion list summary.
114    #[serde(with = "alloy_serde::quantity")]
115    pub slot: u64,
116    /// The proposer index of the inclusion list summary.
117    #[serde(with = "alloy_serde::quantity")]
118    pub proposer_index: u64,
119    /// The parent hash of the inclusion list summary.
120    pub parent_hash: B256,
121    /// The summary of the inclusion list summary.
122    pub summary: Vec<InclusionListSummaryEntryV1>,
123}
124
125#[cfg(test)]
126mod tests {
127    use super::*;
128    use alloy_primitives::hex::FromHex;
129    use serde_json::json;
130
131    #[test]
132    fn inclusion_list_status_v1_serialization() {
133        let status = InclusionListStatusV1::new(PayloadStatusEnum::Valid);
134        let json = json!({
135            "status": "VALID",
136            "validationError": null,
137        });
138        assert_eq!(serde_json::to_value(status).unwrap(), json);
139    }
140
141    #[test]
142    fn inclusion_list_entry_v1_serialization() {
143        let entry = InclusionListSummaryEntryV1 {
144            address: Address::from_hex("0x0000000000000000000000000000000000000042").unwrap(),
145            nonce: 42,
146        };
147        let json = json!({
148            "address": "0x0000000000000000000000000000000000000042",
149            "nonce": "0x2a",
150        });
151        assert_eq!(serde_json::to_value(entry).unwrap(), json);
152    }
153
154    #[test]
155    fn inclusion_list_summary_v1_serialization() {
156        let summary = InclusionListSummaryV1 {
157            slot: 42,
158            proposer_index: 42,
159            parent_hash: B256::from_hex(
160                "0x2222222222222222222222222222222222222222222222222222222222222222",
161            )
162            .unwrap(),
163            summary: vec![
164                InclusionListSummaryEntryV1 {
165                    address: Address::from_hex("0x0000000000000000000000000000000000000042")
166                        .unwrap(),
167                    nonce: 42,
168                },
169                InclusionListSummaryEntryV1 {
170                    address: Address::from_hex("0x0000000000000000000000000000000000000043")
171                        .unwrap(),
172                    nonce: 43,
173                },
174            ],
175        };
176        let json = json!({
177            "slot": "0x2a",
178            "proposerIndex": "0x2a",
179            "parentHash": "0x2222222222222222222222222222222222222222222222222222222222222222",
180            "summary": [
181                {
182                    "address": "0x0000000000000000000000000000000000000042",
183                    "nonce": "0x2a",
184                },
185                {
186                    "address": "0x0000000000000000000000000000000000000043",
187                    "nonce": "0x2b",
188                },
189            ],
190        });
191        assert_eq!(serde_json::to_value(summary).unwrap(), json);
192    }
193}