reth_basic_payload_builder/
stack.rs
1use crate::{
2 BuildArguments, BuildOutcome, HeaderForPayload, PayloadBuilder, PayloadBuilderAttributes,
3 PayloadBuilderError, PayloadConfig,
4};
5
6use alloy_eips::eip4895::Withdrawals;
7use alloy_primitives::{Address, B256, U256};
8use reth_payload_builder::PayloadId;
9use reth_payload_primitives::BuiltPayload;
10use reth_primitives::{NodePrimitives, SealedBlock};
11
12use alloy_eips::eip7685::Requests;
13use std::{error::Error, fmt};
14
15#[derive(Debug, Clone)]
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> PayloadBuilderAttributes for Either<L, R>
51where
52 L: PayloadBuilderAttributes,
53 R: PayloadBuilderAttributes,
54 L::Error: Error + 'static,
55 R::Error: Error + 'static,
56{
57 type RpcPayloadAttributes = Either<L::RpcPayloadAttributes, R::RpcPayloadAttributes>;
58 type Error = Either<L::Error, R::Error>;
59
60 fn try_new(
61 parent: B256,
62 rpc_payload_attributes: Self::RpcPayloadAttributes,
63 version: u8,
64 ) -> Result<Self, Self::Error> {
65 match rpc_payload_attributes {
66 Either::Left(attr) => {
67 L::try_new(parent, attr, version).map(Either::Left).map_err(Either::Left)
68 }
69 Either::Right(attr) => {
70 R::try_new(parent, attr, version).map(Either::Right).map_err(Either::Right)
71 }
72 }
73 }
74
75 fn payload_id(&self) -> PayloadId {
76 match self {
77 Self::Left(l) => l.payload_id(),
78 Self::Right(r) => r.payload_id(),
79 }
80 }
81
82 fn parent(&self) -> B256 {
83 match self {
84 Self::Left(l) => l.parent(),
85 Self::Right(r) => r.parent(),
86 }
87 }
88
89 fn timestamp(&self) -> u64 {
90 match self {
91 Self::Left(l) => l.timestamp(),
92 Self::Right(r) => r.timestamp(),
93 }
94 }
95
96 fn parent_beacon_block_root(&self) -> Option<B256> {
97 match self {
98 Self::Left(l) => l.parent_beacon_block_root(),
99 Self::Right(r) => r.parent_beacon_block_root(),
100 }
101 }
102
103 fn suggested_fee_recipient(&self) -> Address {
104 match self {
105 Self::Left(l) => l.suggested_fee_recipient(),
106 Self::Right(r) => r.suggested_fee_recipient(),
107 }
108 }
109
110 fn prev_randao(&self) -> B256 {
111 match self {
112 Self::Left(l) => l.prev_randao(),
113 Self::Right(r) => r.prev_randao(),
114 }
115 }
116
117 fn withdrawals(&self) -> &Withdrawals {
118 match self {
119 Self::Left(l) => l.withdrawals(),
120 Self::Right(r) => r.withdrawals(),
121 }
122 }
123}
124
125#[derive(Debug)]
129pub struct PayloadBuilderStack<L, R> {
130 left: L,
131 right: R,
132}
133
134impl<L, R> PayloadBuilderStack<L, R> {
135 pub const fn new(left: L, right: R) -> Self {
137 Self { left, right }
138 }
139}
140
141impl<L, R> Clone for PayloadBuilderStack<L, R>
142where
143 L: Clone,
144 R: Clone,
145{
146 fn clone(&self) -> Self {
147 Self::new(self.left.clone(), self.right.clone())
148 }
149}
150
151impl<L, R> BuiltPayload for Either<L, R>
152where
153 L: BuiltPayload,
154 R: BuiltPayload<Primitives = L::Primitives>,
155{
156 type Primitives = L::Primitives;
157
158 fn block(&self) -> &SealedBlock<<L::Primitives as NodePrimitives>::Block> {
159 match self {
160 Self::Left(l) => l.block(),
161 Self::Right(r) => r.block(),
162 }
163 }
164
165 fn fees(&self) -> U256 {
166 match self {
167 Self::Left(l) => l.fees(),
168 Self::Right(r) => r.fees(),
169 }
170 }
171
172 fn requests(&self) -> Option<Requests> {
173 match self {
174 Self::Left(l) => l.requests(),
175 Self::Right(r) => r.requests(),
176 }
177 }
178}
179
180impl<L, R> PayloadBuilder for PayloadBuilderStack<L, R>
181where
182 L: PayloadBuilder + Unpin + 'static,
183 R: PayloadBuilder + Unpin + 'static,
184 L::Attributes: Unpin + Clone,
185 R::Attributes: Unpin + Clone,
186 L::BuiltPayload: Unpin + Clone,
187 R::BuiltPayload:
188 BuiltPayload<Primitives = <L::BuiltPayload as BuiltPayload>::Primitives> + Unpin + Clone,
189{
190 type Attributes = Either<L::Attributes, R::Attributes>;
191 type BuiltPayload = Either<L::BuiltPayload, R::BuiltPayload>;
192
193 fn try_build(
194 &self,
195 args: BuildArguments<Self::Attributes, Self::BuiltPayload>,
196 ) -> Result<BuildOutcome<Self::BuiltPayload>, PayloadBuilderError> {
197 match args.config.attributes {
198 Either::Left(ref left_attr) => {
199 let left_args: BuildArguments<L::Attributes, L::BuiltPayload> = BuildArguments {
200 cached_reads: args.cached_reads.clone(),
201 config: PayloadConfig {
202 parent_header: args.config.parent_header.clone(),
203 attributes: left_attr.clone(),
204 },
205 cancel: args.cancel.clone(),
206 best_payload: args.best_payload.clone().and_then(|payload| {
207 if let Either::Left(p) = payload {
208 Some(p)
209 } else {
210 None
211 }
212 }),
213 };
214
215 self.left.try_build(left_args).map(|out| out.map_payload(Either::Left))
216 }
217 Either::Right(ref right_attr) => {
218 let right_args = BuildArguments {
219 cached_reads: args.cached_reads.clone(),
220 config: PayloadConfig {
221 parent_header: args.config.parent_header.clone(),
222 attributes: right_attr.clone(),
223 },
224 cancel: args.cancel.clone(),
225 best_payload: args.best_payload.clone().and_then(|payload| {
226 if let Either::Right(p) = payload {
227 Some(p)
228 } else {
229 None
230 }
231 }),
232 };
233
234 self.right.try_build(right_args).map(|out| out.map_payload(Either::Right))
235 }
236 }
237 }
238
239 fn build_empty_payload(
240 &self,
241 config: PayloadConfig<Self::Attributes, HeaderForPayload<Self::BuiltPayload>>,
242 ) -> Result<Self::BuiltPayload, PayloadBuilderError> {
243 match config.attributes {
244 Either::Left(left_attr) => {
245 let left_config = PayloadConfig {
246 parent_header: config.parent_header.clone(),
247 attributes: left_attr,
248 };
249 self.left.build_empty_payload(left_config).map(Either::Left)
250 }
251 Either::Right(right_attr) => {
252 let right_config = PayloadConfig {
253 parent_header: config.parent_header.clone(),
254 attributes: right_attr,
255 };
256 self.right.build_empty_payload(right_config).map(Either::Right)
257 }
258 }
259 }
260}