reth_basic_payload_builder/
stack.rs1use crate::{
2 BuildArguments, BuildOutcome, HeaderForPayload, PayloadBuilder, PayloadBuilderError,
3 PayloadConfig,
4};
5
6use alloy_primitives::{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
84#[derive(Debug)]
88pub struct PayloadBuilderStack<L, R> {
89 left: L,
90 right: R,
91}
92
93impl<L, R> PayloadBuilderStack<L, R> {
94 pub const fn new(left: L, right: R) -> Self {
96 Self { left, right }
97 }
98}
99
100impl<L, R> Clone for PayloadBuilderStack<L, R>
101where
102 L: Clone,
103 R: Clone,
104{
105 fn clone(&self) -> Self {
106 Self::new(self.left.clone(), self.right.clone())
107 }
108}
109
110impl<L, R> BuiltPayload for Either<L, R>
111where
112 L: BuiltPayload,
113 R: BuiltPayload<Primitives = L::Primitives>,
114{
115 type Primitives = L::Primitives;
116
117 fn block(&self) -> &SealedBlock<<L::Primitives as NodePrimitives>::Block> {
118 match self {
119 Self::Left(l) => l.block(),
120 Self::Right(r) => r.block(),
121 }
122 }
123
124 fn fees(&self) -> U256 {
125 match self {
126 Self::Left(l) => l.fees(),
127 Self::Right(r) => r.fees(),
128 }
129 }
130
131 fn requests(&self) -> Option<Requests> {
132 match self {
133 Self::Left(l) => l.requests(),
134 Self::Right(r) => r.requests(),
135 }
136 }
137}
138
139impl<L, R> PayloadBuilder for PayloadBuilderStack<L, R>
140where
141 L: PayloadBuilder + Unpin + 'static,
142 R: PayloadBuilder + Unpin + 'static,
143 L::Attributes: Unpin + Clone,
144 R::Attributes: Unpin + Clone,
145 L::BuiltPayload: Unpin + Clone,
146 R::BuiltPayload:
147 BuiltPayload<Primitives = <L::BuiltPayload as BuiltPayload>::Primitives> + Unpin + Clone,
148{
149 type Attributes = Either<L::Attributes, R::Attributes>;
150 type BuiltPayload = Either<L::BuiltPayload, R::BuiltPayload>;
151
152 fn try_build(
153 &self,
154 args: BuildArguments<Self::Attributes, Self::BuiltPayload>,
155 ) -> Result<BuildOutcome<Self::BuiltPayload>, PayloadBuilderError> {
156 let BuildArguments { cached_reads, config, cancel, best_payload } = args;
157 let PayloadConfig { parent_header, attributes, payload_id } = config;
158
159 match attributes {
160 Either::Left(left_attr) => {
161 let left_args: BuildArguments<L::Attributes, L::BuiltPayload> = BuildArguments {
162 cached_reads,
163 config: PayloadConfig { parent_header, attributes: left_attr, payload_id },
164 cancel,
165 best_payload: best_payload.and_then(|payload| {
166 if let Either::Left(p) = payload {
167 Some(p)
168 } else {
169 None
170 }
171 }),
172 };
173 self.left.try_build(left_args).map(|out| out.map_payload(Either::Left))
174 }
175 Either::Right(right_attr) => {
176 let right_args = BuildArguments {
177 cached_reads,
178 config: PayloadConfig { parent_header, attributes: right_attr, payload_id },
179 cancel,
180 best_payload: best_payload.and_then(|payload| {
181 if let Either::Right(p) = payload {
182 Some(p)
183 } else {
184 None
185 }
186 }),
187 };
188 self.right.try_build(right_args).map(|out| out.map_payload(Either::Right))
189 }
190 }
191 }
192
193 fn build_empty_payload(
194 &self,
195 config: PayloadConfig<Self::Attributes, HeaderForPayload<Self::BuiltPayload>>,
196 ) -> Result<Self::BuiltPayload, PayloadBuilderError> {
197 match config {
198 PayloadConfig { parent_header, attributes: Either::Left(left_attr), payload_id } => {
199 let left_config =
200 PayloadConfig { parent_header, attributes: left_attr, payload_id };
201 self.left.build_empty_payload(left_config).map(Either::Left)
202 }
203 PayloadConfig { parent_header, attributes: Either::Right(right_attr), payload_id } => {
204 let right_config =
205 PayloadConfig { parent_header, attributes: right_attr, payload_id };
206 self.right.build_empty_payload(right_config).map(Either::Right)
207 }
208 }
209 }
210}