1use crate::PayloadAttributes;
6use alloc::vec::Vec;
7use alloy_primitives::{Bytes, B256};
8
9pub const TESTING_BUILD_BLOCK_V1: &str = "testing_buildBlockV1";
11
12#[derive(Clone, Debug, Default, PartialEq, Eq)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize))]
19#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
20pub struct TestingBuildBlockRequestV1 {
21 pub parent_block_hash: B256,
23 pub payload_attributes: PayloadAttributes,
25 pub transactions: Vec<Bytes>,
27 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
29 pub extra_data: Option<Bytes>,
30}
31
32impl TestingBuildBlockRequestV1 {
33 pub fn into_params(self) -> (B256, PayloadAttributes, Vec<Bytes>, Option<Bytes>) {
35 (self.parent_block_hash, self.payload_attributes, self.transactions, self.extra_data)
36 }
37}
38
39#[cfg(feature = "serde")]
40impl<'de> serde::Deserialize<'de> for TestingBuildBlockRequestV1 {
46 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
47 where
48 D: serde::Deserializer<'de>,
49 {
50 #[derive(serde::Deserialize)]
51 #[serde(rename_all = "camelCase")]
52 struct RequestObject {
53 parent_block_hash: B256,
54 payload_attributes: PayloadAttributes,
55 #[serde(default)]
56 transactions: Option<Vec<Bytes>>,
57 #[serde(default)]
58 extra_data: Option<Bytes>,
59 }
60
61 #[derive(serde::Deserialize)]
62 #[serde(untagged)]
63 enum Request {
64 Object(RequestObject),
65 Params4(B256, PayloadAttributes, Option<Vec<Bytes>>, Option<Bytes>),
66 Params3(B256, PayloadAttributes, Option<Vec<Bytes>>),
67 Params2(B256, PayloadAttributes),
68 }
69
70 Ok(match Request::deserialize(deserializer)? {
71 Request::Object(request) => Self {
72 parent_block_hash: request.parent_block_hash,
73 payload_attributes: request.payload_attributes,
74 transactions: request.transactions.unwrap_or_default(),
75 extra_data: request.extra_data,
76 },
77 Request::Params4(parent_block_hash, payload_attributes, transactions, extra_data) => {
78 Self {
79 parent_block_hash,
80 payload_attributes,
81 transactions: transactions.unwrap_or_default(),
82 extra_data,
83 }
84 }
85 Request::Params3(parent_block_hash, payload_attributes, transactions) => Self {
86 parent_block_hash,
87 payload_attributes,
88 transactions: transactions.unwrap_or_default(),
89 extra_data: None,
90 },
91 Request::Params2(parent_block_hash, payload_attributes) => Self {
92 parent_block_hash,
93 payload_attributes,
94 transactions: Vec::new(),
95 extra_data: None,
96 },
97 })
98 }
99}
100
101#[cfg(all(test, feature = "serde"))]
102mod tests {
103 use super::*;
104 use alloy_primitives::Address;
105 use serde_json::json;
106 use similar_asserts::assert_eq;
107
108 fn parent_block_hash() -> B256 {
109 "0xaf51811799f22260e5b4e1f95504dae760505f102dcb2e9ca7d897d8a40124a1".parse().unwrap()
110 }
111
112 fn payload_attributes_json() -> serde_json::Value {
113 json!({
114 "parentBeaconBlockRoot": B256::ZERO,
115 "prevRandao": B256::ZERO,
116 "suggestedFeeRecipient": Address::ZERO,
117 "timestamp": "0x1ce",
118 "withdrawals": [],
119 })
120 }
121
122 fn payload_attributes() -> PayloadAttributes {
123 serde_json::from_value(payload_attributes_json()).unwrap()
124 }
125
126 #[test]
127 fn deserialize_testing_build_block_request_object() {
128 let expected = TestingBuildBlockRequestV1 {
129 parent_block_hash: parent_block_hash(),
130 payload_attributes: payload_attributes(),
131 transactions: vec![Bytes::from(vec![0x12, 0x34])],
132 extra_data: Some(Bytes::default()),
133 };
134 let value = serde_json::to_value(&expected).unwrap();
135
136 let actual: TestingBuildBlockRequestV1 = serde_json::from_value(value).unwrap();
137
138 assert_eq!(actual, expected);
139 }
140
141 #[test]
142 fn deserialize_testing_build_block_request_params_with_null_transactions() {
143 let value = json!([
144 "0xaf51811799f22260e5b4e1f95504dae760505f102dcb2e9ca7d897d8a40124a1",
145 payload_attributes_json(),
146 null,
147 "0x"
148 ]);
149
150 let actual: TestingBuildBlockRequestV1 = serde_json::from_value(value).unwrap();
151
152 assert_eq!(
153 actual,
154 TestingBuildBlockRequestV1 {
155 parent_block_hash: parent_block_hash(),
156 payload_attributes: payload_attributes(),
157 transactions: Vec::new(),
158 extra_data: Some(Bytes::default()),
159 }
160 );
161 }
162
163 #[test]
164 fn deserialize_testing_build_block_request_params_with_transactions() {
165 let value = json!([
166 "0xaf51811799f22260e5b4e1f95504dae760505f102dcb2e9ca7d897d8a40124a1",
167 payload_attributes_json(),
168 ["0x1234"]
169 ]);
170
171 let actual: TestingBuildBlockRequestV1 = serde_json::from_value(value).unwrap();
172
173 assert_eq!(
174 actual,
175 TestingBuildBlockRequestV1 {
176 parent_block_hash: parent_block_hash(),
177 payload_attributes: payload_attributes(),
178 transactions: vec![Bytes::from(vec![0x12, 0x34])],
179 extra_data: None,
180 }
181 );
182 }
183}