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 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 requests(&self) -> Option<Requests> {
139 match self {
140 Self::Left(l) => l.requests(),
141 Self::Right(r) => r.requests(),
142 }
143 }
144}
145
146impl<L, R> PayloadBuilder for PayloadBuilderStack<L, R>
147where
148 L: PayloadBuilder + Unpin + 'static,
149 R: PayloadBuilder + Unpin + 'static,
150 L::Attributes: Unpin + Clone,
151 R::Attributes: Unpin + Clone,
152 L::BuiltPayload: Unpin + Clone,
153 R::BuiltPayload:
154 BuiltPayload<Primitives = <L::BuiltPayload as BuiltPayload>::Primitives> + Unpin + Clone,
155{
156 type Attributes = Either<L::Attributes, R::Attributes>;
157 type BuiltPayload = Either<L::BuiltPayload, R::BuiltPayload>;
158
159 fn try_build(
160 &self,
161 args: BuildArguments<Self::Attributes, Self::BuiltPayload>,
162 ) -> Result<BuildOutcome<Self::BuiltPayload>, PayloadBuilderError> {
163 let BuildArguments {
164 cached_reads,
165 execution_cache,
166 trie_handle,
167 config,
168 cancel,
169 best_payload,
170 } = args;
171 let PayloadConfig { parent_header, attributes, payload_id } = config;
172
173 match attributes {
174 Either::Left(left_attr) => {
175 let left_args: BuildArguments<L::Attributes, L::BuiltPayload> = BuildArguments {
176 cached_reads,
177 execution_cache,
178 trie_handle,
179 config: PayloadConfig { parent_header, attributes: left_attr, payload_id },
180 cancel,
181 best_payload: best_payload.and_then(|payload| {
182 if let Either::Left(p) = payload {
183 Some(p)
184 } else {
185 None
186 }
187 }),
188 };
189 self.left.try_build(left_args).map(|out| out.map_payload(Either::Left))
190 }
191 Either::Right(right_attr) => {
192 let right_args = BuildArguments {
193 cached_reads,
194 execution_cache,
195 trie_handle,
196 config: PayloadConfig { parent_header, attributes: right_attr, payload_id },
197 cancel,
198 best_payload: best_payload.and_then(|payload| {
199 if let Either::Right(p) = payload {
200 Some(p)
201 } else {
202 None
203 }
204 }),
205 };
206 self.right.try_build(right_args).map(|out| out.map_payload(Either::Right))
207 }
208 }
209 }
210
211 fn build_empty_payload(
212 &self,
213 config: PayloadConfig<Self::Attributes, HeaderForPayload<Self::BuiltPayload>>,
214 ) -> Result<Self::BuiltPayload, PayloadBuilderError> {
215 match config {
216 PayloadConfig { parent_header, attributes: Either::Left(left_attr), payload_id } => {
217 let left_config =
218 PayloadConfig { parent_header, attributes: left_attr, payload_id };
219 self.left.build_empty_payload(left_config).map(Either::Left)
220 }
221 PayloadConfig { parent_header, attributes: Either::Right(right_attr), payload_id } => {
222 let right_config =
223 PayloadConfig { parent_header, attributes: right_attr, payload_id };
224 self.right.build_empty_payload(right_config).map(Either::Right)
225 }
226 }
227 }
228}