1
+ use alloy:: eips:: eip2718:: Eip2718Error ;
2
+ use std:: time:: { SystemTime , UNIX_EPOCH } ;
3
+ use std:: { sync:: OnceLock , time:: Duration } ;
4
+ use tokio:: { sync:: mpsc, task:: JoinHandle } ;
5
+ use tracing:: Instrument ;
6
+
1
7
use super :: bundler:: { Bundle , BundlePoller } ;
2
8
use super :: oauth:: Authenticator ;
3
9
use super :: tx_poller:: TxPoller ;
10
+
4
11
use crate :: config:: { BuilderConfig , WalletlessProvider } ;
12
+
5
13
use alloy:: providers:: Provider ;
14
+ use alloy:: rpc:: types:: mev:: EthSendBundle ;
6
15
use alloy:: {
7
16
consensus:: { SidecarBuilder , SidecarCoder , TxEnvelope } ,
8
17
eips:: eip2718:: Decodable2718 ,
9
18
} ;
10
19
use alloy_primitives:: { keccak256, Bytes , B256 } ;
11
20
use alloy_rlp:: Buf ;
12
- use std:: time:: { SystemTime , UNIX_EPOCH } ;
13
- use std:: { sync:: OnceLock , time:: Duration } ;
14
- use tokio:: { sync:: mpsc, task:: JoinHandle } ;
15
- use tracing:: Instrument ;
21
+
22
+ use zenith_types:: BundleHelper :: FillPermit2 ;
16
23
use zenith_types:: { encode_txns, Alloy2718Coder } ;
17
24
18
25
/// Ethereum's slot time in seconds.
@@ -29,7 +36,11 @@ pub struct InProgressBlock {
29
36
impl InProgressBlock {
30
37
/// Create a new `InProgressBlock`
31
38
pub fn new ( ) -> Self {
32
- Self { transactions : Vec :: new ( ) , raw_encoding : OnceLock :: new ( ) , hash : OnceLock :: new ( ) }
39
+ Self {
40
+ transactions : Vec :: new ( ) ,
41
+ raw_encoding : OnceLock :: new ( ) ,
42
+ hash : OnceLock :: new ( ) ,
43
+ }
33
44
}
34
45
35
46
/// Get the number of transactions in the block.
@@ -73,15 +84,28 @@ impl InProgressBlock {
73
84
pub fn ingest_bundle ( & mut self , bundle : Bundle ) {
74
85
tracing:: trace!( bundle = %bundle. id, "ingesting bundle" ) ;
75
86
76
- let txs = bundle
77
- . bundle
78
- . bundle
79
- . txs
80
- . into_iter ( )
81
- . map ( |tx| TxEnvelope :: decode_2718 ( & mut tx. chunk ( ) ) )
82
- . collect :: < Result < Vec < _ > , _ > > ( ) ;
87
+ // If host fills exists, then it's a Signet bundle
88
+ if let Some ( _) = bundle. bundle . host_fills {
89
+ self . process_signet_bundle ( bundle) ;
90
+ } else {
91
+ // otherwise, treat the bundle as a regular eth bundle and ingest it's tx list in order to maintain compatibility
92
+ self . process_eth_bundle ( bundle) ;
93
+ }
94
+ }
95
+
96
+ /// Process a Signet bundle by checking outputs for corresponding host fills and appending the txs in order
97
+ fn process_signet_bundle ( & mut self , bundle : Bundle ) {
98
+ let host_fills = bundle. bundle . host_fills . unwrap ( ) ; // safe because we already checked it above
99
+ let host_fill_list = host_fills. clone ( ) . outputs ;
100
+ for output in host_fill_list. iter ( ) {
101
+ tracing:: debug!( ?output, "found host fill" ) ;
102
+ // Parse the output as a FillPermit2
103
+ }
104
+ }
83
105
84
- if let Ok ( txs) = txs {
106
+ /// Processes a typical bundle of transactions, appending them in order to the in progress block.
107
+ fn process_eth_bundle ( & mut self , bundle : Bundle ) {
108
+ if let Ok ( txs) = self . decode_2718_txs ( bundle. bundle . bundle ) {
85
109
self . unseal ( ) ;
86
110
// extend the transactions with the decoded transactions.
87
111
// As this builder does not provide bundles landing "top of block", its fine to just extend.
@@ -91,6 +115,15 @@ impl InProgressBlock {
91
115
}
92
116
}
93
117
118
+ /// Extracts and decodes a list of 2718 transactions from a EthSendBundle
119
+ fn decode_2718_txs ( & mut self , bundle : EthSendBundle ) -> Result < Vec < TxEnvelope > , Eip2718Error > {
120
+ bundle
121
+ . txs
122
+ . into_iter ( )
123
+ . map ( |tx| TxEnvelope :: decode_2718 ( & mut tx. chunk ( ) ) )
124
+ . collect :: < Result < Vec < _ > , _ > > ( )
125
+ }
126
+
94
127
/// Encode the in-progress block
95
128
fn encode_raw ( & self ) -> & Bytes {
96
129
self . seal ( ) ;
@@ -125,7 +158,7 @@ pub struct BlockBuilder {
125
158
}
126
159
127
160
impl BlockBuilder {
128
- // create a new block builder with the given config.
161
+ // Creates a new block builder with the given config
129
162
pub fn new (
130
163
config : & BuilderConfig ,
131
164
authenticator : Authenticator ,
@@ -139,9 +172,10 @@ impl BlockBuilder {
139
172
}
140
173
}
141
174
175
+ /// Fetches transactions from the cache and ingests them into the current block
142
176
async fn get_transactions ( & mut self , in_progress : & mut InProgressBlock ) {
143
177
tracing:: trace!( "query transactions from cache" ) ;
144
- let txns = self . tx_poller . check_tx_cache ( ) . await ;
178
+ let txns: Result < Vec < TxEnvelope > , eyre :: Error > = self . tx_poller . check_tx_cache ( ) . await ;
145
179
match txns {
146
180
Ok ( txns) => {
147
181
tracing:: trace!( "got transactions response" ) ;
@@ -155,12 +189,16 @@ impl BlockBuilder {
155
189
}
156
190
}
157
191
192
+ /// Returns bundles from the cache and ingests them into the current block
158
193
async fn _get_bundles ( & mut self , in_progress : & mut InProgressBlock ) {
159
194
tracing:: trace!( "query bundles from cache" ) ;
195
+
196
+ // fetch latest bundles from the cache
160
197
let bundles = self . bundle_poller . check_bundle_cache ( ) . await ;
161
198
match bundles {
162
199
Ok ( bundles) => {
163
- tracing:: trace!( "got bundles response" ) ;
200
+ tracing:: trace!( ?bundles, "got bundles response" ) ;
201
+ // QUESTION: When does this need to stop attempting to ingest for the current block?
164
202
for bundle in bundles {
165
203
in_progress. ingest_bundle ( bundle) ;
166
204
}
@@ -172,6 +210,7 @@ impl BlockBuilder {
172
210
self . bundle_poller . evict ( ) ;
173
211
}
174
212
213
+ // Filters confirmed transactions from the block
175
214
async fn filter_transactions ( & self , in_progress : & mut InProgressBlock ) {
176
215
// query the rollup node to see which transaction(s) have been included
177
216
let mut confirmed_transactions = Vec :: new ( ) ;
@@ -193,14 +232,14 @@ impl BlockBuilder {
193
232
}
194
233
}
195
234
196
- // calculate the duration in seconds until the beginning of the next block slot.
235
+ // Calculate the duration in seconds until the beginning of the next block slot.
197
236
fn secs_to_next_slot ( & self ) -> u64 {
198
237
let curr_timestamp: u64 = SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) . unwrap ( ) . as_secs ( ) ;
199
238
let current_slot_time = ( curr_timestamp - self . config . chain_offset ) % ETHEREUM_SLOT_TIME ;
200
239
( ETHEREUM_SLOT_TIME - current_slot_time) % ETHEREUM_SLOT_TIME
201
240
}
202
241
203
- // add a buffer to the beginning of the block slot.
242
+ // Add a buffer to the beginning of the block slot.
204
243
fn secs_to_next_target ( & self ) -> u64 {
205
244
self . secs_to_next_slot ( ) + self . config . target_slot_time
206
245
}
@@ -219,8 +258,8 @@ impl BlockBuilder {
219
258
let mut in_progress = InProgressBlock :: default ( ) ;
220
259
self . get_transactions ( & mut in_progress) . await ;
221
260
222
- // TODO: Implement bundle ingestion #later
223
- // self.get_bundles (&mut in_progress).await;
261
+ // Ingest bundles
262
+ self . _get_bundles ( & mut in_progress) . await ;
224
263
225
264
// Filter confirmed transactions from the block
226
265
self . filter_transactions ( & mut in_progress) . await ;
0 commit comments