reth_bench/bench/send_invalid_payload/
invalidation.rs1use alloy_eips::eip4895::Withdrawal;
2use alloy_primitives::{Address, Bloom, Bytes, B256, U256};
3use alloy_rpc_types_engine::{ExecutionPayloadV1, ExecutionPayloadV2, ExecutionPayloadV3};
4
5#[derive(Debug, Default)]
7pub(super) struct InvalidationConfig {
8 pub(super) parent_hash: Option<B256>,
10 pub(super) fee_recipient: Option<Address>,
11 pub(super) state_root: Option<B256>,
12 pub(super) receipts_root: Option<B256>,
13 pub(super) logs_bloom: Option<Bloom>,
14 pub(super) prev_randao: Option<B256>,
15 pub(super) block_number: Option<u64>,
16 pub(super) gas_limit: Option<u64>,
17 pub(super) gas_used: Option<u64>,
18 pub(super) timestamp: Option<u64>,
19 pub(super) extra_data: Option<Bytes>,
20 pub(super) base_fee_per_gas: Option<u64>,
21 pub(super) block_hash: Option<B256>,
22 pub(super) blob_gas_used: Option<u64>,
23 pub(super) excess_blob_gas: Option<u64>,
24
25 pub(super) invalidate_parent_hash: bool,
27 pub(super) invalidate_state_root: bool,
28 pub(super) invalidate_receipts_root: bool,
29 pub(super) invalidate_gas_used: bool,
30 pub(super) invalidate_block_number: bool,
31 pub(super) invalidate_timestamp: bool,
32 pub(super) invalidate_base_fee: bool,
33 pub(super) invalidate_transactions: bool,
34 pub(super) invalidate_block_hash: bool,
35 pub(super) invalidate_withdrawals: bool,
36 pub(super) invalidate_blob_gas_used: bool,
37 pub(super) invalidate_excess_blob_gas: bool,
38}
39
40impl InvalidationConfig {
41 pub(super) const fn should_skip_hash_recalc(&self) -> bool {
44 self.block_hash.is_some() || self.invalidate_block_hash
45 }
46
47 pub(super) fn apply_to_payload_v1(&self, payload: &mut ExecutionPayloadV1) -> Vec<String> {
49 let mut changes = Vec::new();
50
51 if let Some(parent_hash) = self.parent_hash {
53 payload.parent_hash = parent_hash;
54 changes.push(format!("parent_hash = {parent_hash}"));
55 }
56
57 if let Some(fee_recipient) = self.fee_recipient {
58 payload.fee_recipient = fee_recipient;
59 changes.push(format!("fee_recipient = {fee_recipient}"));
60 }
61
62 if let Some(state_root) = self.state_root {
63 payload.state_root = state_root;
64 changes.push(format!("state_root = {state_root}"));
65 }
66
67 if let Some(receipts_root) = self.receipts_root {
68 payload.receipts_root = receipts_root;
69 changes.push(format!("receipts_root = {receipts_root}"));
70 }
71
72 if let Some(logs_bloom) = self.logs_bloom {
73 payload.logs_bloom = logs_bloom;
74 changes.push("logs_bloom = <custom>".to_string());
75 }
76
77 if let Some(prev_randao) = self.prev_randao {
78 payload.prev_randao = prev_randao;
79 changes.push(format!("prev_randao = {prev_randao}"));
80 }
81
82 if let Some(block_number) = self.block_number {
83 payload.block_number = block_number;
84 changes.push(format!("block_number = {block_number}"));
85 }
86
87 if let Some(gas_limit) = self.gas_limit {
88 payload.gas_limit = gas_limit;
89 changes.push(format!("gas_limit = {gas_limit}"));
90 }
91
92 if let Some(gas_used) = self.gas_used {
93 payload.gas_used = gas_used;
94 changes.push(format!("gas_used = {gas_used}"));
95 }
96
97 if let Some(timestamp) = self.timestamp {
98 payload.timestamp = timestamp;
99 changes.push(format!("timestamp = {timestamp}"));
100 }
101
102 if let Some(ref extra_data) = self.extra_data {
103 payload.extra_data = extra_data.clone();
104 changes.push(format!("extra_data = {} bytes", extra_data.len()));
105 }
106
107 if let Some(base_fee_per_gas) = self.base_fee_per_gas {
108 payload.base_fee_per_gas = U256::from_limbs([base_fee_per_gas, 0, 0, 0]);
109 changes.push(format!("base_fee_per_gas = {base_fee_per_gas}"));
110 }
111
112 if let Some(block_hash) = self.block_hash {
113 payload.block_hash = block_hash;
114 changes.push(format!("block_hash = {block_hash}"));
115 }
116
117 if self.invalidate_parent_hash {
119 let random_hash = B256::random();
120 payload.parent_hash = random_hash;
121 changes.push(format!("parent_hash = {random_hash} (auto-invalidated: random)"));
122 }
123
124 if self.invalidate_state_root {
125 payload.state_root = B256::ZERO;
126 changes.push("state_root = ZERO (auto-invalidated: empty trie root)".to_string());
127 }
128
129 if self.invalidate_receipts_root {
130 payload.receipts_root = B256::ZERO;
131 changes.push("receipts_root = ZERO (auto-invalidated)".to_string());
132 }
133
134 if self.invalidate_gas_used {
135 let invalid_gas = payload.gas_limit + 1;
136 payload.gas_used = invalid_gas;
137 changes.push(format!("gas_used = {invalid_gas} (auto-invalidated: exceeds gas_limit)"));
138 }
139
140 if self.invalidate_block_number {
141 let invalid_number = payload.block_number + 999;
142 payload.block_number = invalid_number;
143 changes.push(format!("block_number = {invalid_number} (auto-invalidated: huge gap)"));
144 }
145
146 if self.invalidate_timestamp {
147 payload.timestamp = 0;
148 changes.push("timestamp = 0 (auto-invalidated: impossibly old)".to_string());
149 }
150
151 if self.invalidate_base_fee {
152 payload.base_fee_per_gas = U256::ZERO;
153 changes
154 .push("base_fee_per_gas = 0 (auto-invalidated: invalid post-London)".to_string());
155 }
156
157 if self.invalidate_transactions {
158 let invalid_tx = Bytes::from_static(&[0xff, 0xff, 0xff]);
159 payload.transactions.insert(0, invalid_tx);
160 changes.push("transactions = prepended invalid RLP (auto-invalidated)".to_string());
161 }
162
163 if self.invalidate_block_hash {
164 let random_hash = B256::random();
165 payload.block_hash = random_hash;
166 changes.push(format!("block_hash = {random_hash} (auto-invalidated: random)"));
167 }
168
169 changes
170 }
171
172 pub(super) fn apply_to_payload_v2(&self, payload: &mut ExecutionPayloadV2) -> Vec<String> {
174 let mut changes = self.apply_to_payload_v1(&mut payload.payload_inner);
175
176 if self.invalidate_withdrawals {
178 let fake_withdrawal = Withdrawal {
179 index: u64::MAX,
180 validator_index: u64::MAX,
181 address: Address::ZERO,
182 amount: u64::MAX,
183 };
184 payload.withdrawals.push(fake_withdrawal);
185 changes.push("withdrawals = added fake withdrawal (auto-invalidated)".to_string());
186 }
187
188 changes
189 }
190
191 pub(super) fn apply_to_payload_v3(&self, payload: &mut ExecutionPayloadV3) -> Vec<String> {
193 let mut changes = self.apply_to_payload_v2(&mut payload.payload_inner);
194
195 if let Some(blob_gas_used) = self.blob_gas_used {
197 payload.blob_gas_used = blob_gas_used;
198 changes.push(format!("blob_gas_used = {blob_gas_used}"));
199 }
200
201 if let Some(excess_blob_gas) = self.excess_blob_gas {
202 payload.excess_blob_gas = excess_blob_gas;
203 changes.push(format!("excess_blob_gas = {excess_blob_gas}"));
204 }
205
206 if self.invalidate_blob_gas_used {
208 payload.blob_gas_used = u64::MAX;
209 changes.push("blob_gas_used = MAX (auto-invalidated)".to_string());
210 }
211
212 if self.invalidate_excess_blob_gas {
213 payload.excess_blob_gas = u64::MAX;
214 changes.push("excess_blob_gas = MAX (auto-invalidated)".to_string());
215 }
216
217 changes
218 }
219}