reth_basic_payload_builder/
stack.rs1use crate::{
2 BuildArguments, BuildOutcome, PayloadBuilder, PayloadBuilderAttributes, PayloadBuilderError,
3 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::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,
155{
156 fn block(&self) -> &SealedBlock {
157 match self {
158 Self::Left(l) => l.block(),
159 Self::Right(r) => r.block(),
160 }
161 }
162
163 fn fees(&self) -> U256 {
164 match self {
165 Self::Left(l) => l.fees(),
166 Self::Right(r) => r.fees(),
167 }
168 }
169
170 fn requests(&self) -> Option<Requests> {
171 match self {
172 Self::Left(l) => l.requests(),
173 Self::Right(r) => r.requests(),
174 }
175 }
176}
177
178impl<L, R, Pool, Client> PayloadBuilder<Pool, Client> for PayloadBuilderStack<L, R>
179where
180 L: PayloadBuilder<Pool, Client> + Unpin + 'static,
181 R: PayloadBuilder<Pool, Client> + Unpin + 'static,
182 Client: Clone,
183 Pool: Clone,
184 L::Attributes: Unpin + Clone,
185 R::Attributes: Unpin + Clone,
186 L::BuiltPayload: Unpin + Clone,
187 R::BuiltPayload: Unpin + Clone,
188 <<L as PayloadBuilder<Pool, Client>>::Attributes as PayloadBuilderAttributes>::Error: 'static,
189 <<R as PayloadBuilder<Pool, Client>>::Attributes as PayloadBuilderAttributes>::Error: 'static,
190{
191 type Attributes = Either<L::Attributes, R::Attributes>;
192 type BuiltPayload = Either<L::BuiltPayload, R::BuiltPayload>;
193
194 fn try_build(
195 &self,
196 args: BuildArguments<Pool, Client, Self::Attributes, Self::BuiltPayload>,
197 ) -> Result<BuildOutcome<Self::BuiltPayload>, PayloadBuilderError> {
198 match args.config.attributes {
199 Either::Left(ref left_attr) => {
200 let left_args: BuildArguments<Pool, Client, L::Attributes, L::BuiltPayload> =
201 BuildArguments {
202 client: args.client.clone(),
203 pool: args.pool.clone(),
204 cached_reads: args.cached_reads.clone(),
205 config: PayloadConfig {
206 parent_header: args.config.parent_header.clone(),
207 attributes: left_attr.clone(),
208 },
209 cancel: args.cancel.clone(),
210 best_payload: args.best_payload.clone().and_then(|payload| {
211 if let Either::Left(p) = payload {
212 Some(p)
213 } else {
214 None
215 }
216 }),
217 };
218
219 self.left.try_build(left_args).map(|out| out.map_payload(Either::Left))
220 }
221 Either::Right(ref right_attr) => {
222 let right_args = BuildArguments {
223 client: args.client.clone(),
224 pool: args.pool.clone(),
225 cached_reads: args.cached_reads.clone(),
226 config: PayloadConfig {
227 parent_header: args.config.parent_header.clone(),
228 attributes: right_attr.clone(),
229 },
230 cancel: args.cancel.clone(),
231 best_payload: args.best_payload.clone().and_then(|payload| {
232 if let Either::Right(p) = payload {
233 Some(p)
234 } else {
235 None
236 }
237 }),
238 };
239
240 self.right.try_build(right_args).map(|out| out.map_payload(Either::Right))
241 }
242 }
243 }
244
245 fn build_empty_payload(
246 &self,
247 client: &Client,
248 config: PayloadConfig<Self::Attributes>,
249 ) -> Result<Self::BuiltPayload, PayloadBuilderError> {
250 match config.attributes {
251 Either::Left(left_attr) => {
252 let left_config = PayloadConfig {
253 parent_header: config.parent_header.clone(),
254 attributes: left_attr,
255 };
256 self.left.build_empty_payload(client, left_config).map(Either::Left)
257 }
258 Either::Right(right_attr) => {
259 let right_config = PayloadConfig {
260 parent_header: config.parent_header.clone(),
261 attributes: right_attr,
262 };
263 self.right.build_empty_payload(client, right_config).map(Either::Right)
264 }
265 }
266 }
267}