reth_basic_payload_builder/
stack.rs1use crate::{
2 BuildArguments, BuildOutcome, HeaderForPayload, PayloadBuilder, PayloadBuilderError,
3 PayloadConfig,
4};
5
6use alloy_primitives::{Bytes, B256, U256};
7use reth_payload_builder::PayloadId;
8use reth_payload_primitives::{BuiltPayload, PayloadAttributes};
9use reth_primitives_traits::{NodePrimitives, SealedBlock};
10
11use alloy_eips::eip7685::Requests;
12use std::{error::Error, fmt};
13
14#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
16#[serde(untagged)]
17pub enum Either<L, R> {
18 Left(L),
20 Right(R),
22}
23
24impl<L, R> fmt::Display for Either<L, R>
25where
26 L: fmt::Display,
27 R: fmt::Display,
28{
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 match self {
31 Self::Left(l) => write!(f, "Left: {l}"),
32 Self::Right(r) => write!(f, "Right: {r}"),
33 }
34 }
35}
36
37impl<L, R> Error for Either<L, R>
38where
39 L: Error + 'static,
40 R: Error + 'static,
41{
42 fn source(&self) -> Option<&(dyn Error + 'static)> {
43 match self {
44 Self::Left(l) => Some(l),
45 Self::Right(r) => Some(r),
46 }
47 }
48}
49
50impl<L, R> PayloadAttributes for Either<L, R>
51where
52 L: PayloadAttributes,
53 R: PayloadAttributes,
54{
55 fn payload_id(&self, parent_hash: &B256) -> PayloadId {
56 match self {
57 Self::Left(l) => l.payload_id(parent_hash),
58 Self::Right(r) => r.payload_id(parent_hash),
59 }
60 }
61
62 fn timestamp(&self) -> u64 {
63 match self {
64 Self::Left(l) => l.timestamp(),
65 Self::Right(r) => r.timestamp(),
66 }
67 }
68
69 fn parent_beacon_block_root(&self) -> Option<B256> {
70 match self {
71 Self::Left(l) => l.parent_beacon_block_root(),
72 Self::Right(r) => r.parent_beacon_block_root(),
73 }
74 }
75
76 fn withdrawals(&self) -> Option<&Vec<alloy_eips::eip4895::Withdrawal>> {
77 match self {
78 Self::Left(l) => l.withdrawals(),
79 Self::Right(r) => r.withdrawals(),
80 }
81 }
82
83 fn slot_number(&self) -> Option<u64> {
84 match self {
85 Self::Left(l) => l.slot_number(),
86 Self::Right(r) => r.slot_number(),
87 }
88 }
89}
90
91#[derive(Debug)]
95pub struct PayloadBuilderStack<L, R> {
96 left: L,
97 right: R,
98}
99
100impl<L, R> PayloadBuilderStack<L, R> {
101 pub const fn new(left: L, right: R) -> Self {
103 Self { left, right }
104 }
105}
106
107impl<L, R> Clone for PayloadBuilderStack<L, R>
108where
109 L: Clone,
110 R: Clone,
111{
112 fn clone(&self) -> Self {
113 Self::new(self.left.clone(), self.right.clone())
114 }
115}
116
117impl<L, R> BuiltPayload for Either<L, R>
118where
119 L: BuiltPayload,
120 R: BuiltPayload<Primitives = L::Primitives>,
121{
122 type Primitives = L::Primitives;
123
124 fn block(&self) -> &SealedBlock<<L::Primitives as NodePrimitives>::Block> {
125 match self {
126 Self::Left(l) => l.block(),
127 Self::Right(r) => r.block(),
128 }
129 }
130
131 fn fees(&self) -> U256 {
132 match self {
133 Self::Left(l) => l.fees(),
134 Self::Right(r) => r.fees(),
135 }
136 }
137
138 fn block_access_list(&self) -> Option<&Bytes> {
139 match self {
140 Self::Left(l) => l.block_access_list(),
141 Self::Right(r) => r.block_access_list(),
142 }
143 }
144
145 fn requests(&self) -> Option<Requests> {
146 match self {
147 Self::Left(l) => l.requests(),
148 Self::Right(r) => r.requests(),
149 }
150 }
151}
152
153impl<L, R> PayloadBuilder for PayloadBuilderStack<L, R>
154where
155 L: PayloadBuilder + Unpin + 'static,
156 R: PayloadBuilder + Unpin + 'static,
157 L::Attributes: Unpin + Clone,
158 R::Attributes: Unpin + Clone,
159 L::BuiltPayload: Unpin + Clone,
160 R::BuiltPayload:
161 BuiltPayload<Primitives = <L::BuiltPayload as BuiltPayload>::Primitives> + Unpin + Clone,
162{
163 type Attributes = Either<L::Attributes, R::Attributes>;
164 type BuiltPayload = Either<L::BuiltPayload, R::BuiltPayload>;
165
166 fn try_build(
167 &self,
168 args: BuildArguments<Self::Attributes, Self::BuiltPayload>,
169 ) -> Result<BuildOutcome<Self::BuiltPayload>, PayloadBuilderError> {
170 let BuildArguments {
171 cached_reads,
172 execution_cache,
173 trie_handle,
174 config,
175 cancel,
176 best_payload,
177 } = args;
178 let PayloadConfig { parent_header, attributes, payload_id } = config;
179
180 match attributes {
181 Either::Left(left_attr) => {
182 let left_args: BuildArguments<L::Attributes, L::BuiltPayload> = BuildArguments {
183 cached_reads,
184 execution_cache,
185 trie_handle,
186 config: PayloadConfig { parent_header, attributes: left_attr, payload_id },
187 cancel,
188 best_payload: best_payload.and_then(|payload| {
189 if let Either::Left(p) = payload {
190 Some(p)
191 } else {
192 None
193 }
194 }),
195 };
196 self.left.try_build(left_args).map(|out| out.map_payload(Either::Left))
197 }
198 Either::Right(right_attr) => {
199 let right_args = BuildArguments {
200 cached_reads,
201 execution_cache,
202 trie_handle,
203 config: PayloadConfig { parent_header, attributes: right_attr, payload_id },
204 cancel,
205 best_payload: best_payload.and_then(|payload| {
206 if let Either::Right(p) = payload {
207 Some(p)
208 } else {
209 None
210 }
211 }),
212 };
213 self.right.try_build(right_args).map(|out| out.map_payload(Either::Right))
214 }
215 }
216 }
217
218 fn build_empty_payload(
219 &self,
220 config: PayloadConfig<Self::Attributes, HeaderForPayload<Self::BuiltPayload>>,
221 ) -> Result<Self::BuiltPayload, PayloadBuilderError> {
222 match config {
223 PayloadConfig { parent_header, attributes: Either::Left(left_attr), payload_id } => {
224 let left_config =
225 PayloadConfig { parent_header, attributes: left_attr, payload_id };
226 self.left.build_empty_payload(left_config).map(Either::Left)
227 }
228 PayloadConfig { parent_header, attributes: Either::Right(right_attr), payload_id } => {
229 let right_config =
230 PayloadConfig { parent_header, attributes: right_attr, payload_id };
231 self.right.build_empty_payload(right_config).map(Either::Right)
232 }
233 }
234 }
235}