1
1
//! App to benchmark/test the tx block execution.
2
2
//! This only works when reth node is stopped and the chain moved forward from its synced state
3
3
//! It downloads block after the last one synced and re-executes all the txs in it.
4
+ use alloy_consensus:: TxEnvelope ;
5
+ use alloy_eips:: Decodable2718 ;
4
6
use alloy_provider:: Provider ;
5
7
use clap:: Parser ;
6
8
use eyre:: Context ;
@@ -11,9 +13,11 @@ use rbuilder::{
11
13
ThreadBlockBuildingContext ,
12
14
} ,
13
15
live_builder:: { base_config:: load_config_toml_and_env, cli:: LiveBuilderConfig , config:: Config } ,
16
+ mev_boost:: submission:: SubmitBlockRequest ,
14
17
provider:: StateProviderFactory ,
15
18
utils:: { extract_onchain_block_txs, find_suggested_fee_recipient, http_provider, Signer } ,
16
19
} ;
20
+ use reth_primitives_traits:: SignerRecoverable ;
17
21
use reth_provider:: StateProvider ;
18
22
use std:: { path:: PathBuf , sync:: Arc , time:: Instant } ;
19
23
use tracing:: { debug, info} ;
@@ -31,6 +35,11 @@ struct Cli {
31
35
rpc_url : String ,
32
36
#[ clap( long, help = "Config file path" , env = "RBUILDER_CONFIG" ) ]
33
37
config : PathBuf ,
38
+ #[ clap(
39
+ long,
40
+ help = "Path to submit block request to replay to use instead of the onchain block"
41
+ ) ]
42
+ submit_block_request_json : Option < PathBuf > ,
34
43
}
35
44
36
45
#[ tokio:: main]
@@ -54,6 +63,15 @@ async fn main() -> eyre::Result<()> {
54
63
. await ?
55
64
. ok_or_else ( || eyre:: eyre!( "block not found on rpc" ) ) ?;
56
65
66
+ let onchain_block = if let Some ( submit_block_request_json) = cli. submit_block_request_json {
67
+ let mut block = read_execution_payload_from_json ( submit_block_request_json) ?;
68
+ // without parent_beacon_block_root we can't build block and its not available in submit_block_request_json
69
+ block. header . parent_beacon_block_root = onchain_block. header . parent_beacon_block_root ;
70
+ block
71
+ } else {
72
+ onchain_block
73
+ } ;
74
+
57
75
let txs = extract_onchain_block_txs ( & onchain_block) ?;
58
76
let suggested_fee_recipient = find_suggested_fee_recipient ( & onchain_block, & txs) ;
59
77
info ! (
@@ -91,21 +109,25 @@ async fn main() -> eyre::Result<()> {
91
109
let state_provider = state_provider. clone ( ) ;
92
110
let ( build_time, finalize_time) =
93
111
tokio:: task:: spawn_blocking ( move || -> eyre:: Result < _ > {
94
- let partial_block = PartialBlock :: new ( true ) ;
112
+ let mut partial_block = PartialBlock :: new ( true ) ;
95
113
let mut state = BlockState :: new_arc ( state_provider) ;
96
114
let mut local_ctx = ThreadBlockBuildingContext :: default ( ) ;
97
115
98
116
let build_time = Instant :: now ( ) ;
99
117
118
+ partial_block. pre_block_call ( & ctx, & mut local_ctx, & mut state) ?;
119
+
100
120
let mut space_state = BlockBuildingSpaceState :: ZERO ;
101
121
for ( idx, tx) in txs. into_iter ( ) . enumerate ( ) {
102
122
let result = {
103
123
let mut fork = PartialBlockFork :: new ( & mut state, & ctx, & mut local_ctx) ;
124
+
104
125
fork. commit_tx ( & tx, space_state) ?. with_context ( || {
105
126
format ! ( "Failed to commit tx: {} {:?}" , idx, tx. hash( ) )
106
127
} ) ?
107
128
} ;
108
129
space_state. use_space ( result. space_used ( ) , result. blob_gas_used ) ;
130
+ partial_block. executed_tx_infos . push ( result. tx_info ) ;
109
131
}
110
132
111
133
let build_time = build_time. elapsed ( ) ;
@@ -132,6 +154,27 @@ async fn main() -> eyre::Result<()> {
132
154
Ok ( ( ) )
133
155
}
134
156
157
+ fn read_execution_payload_from_json ( path : PathBuf ) -> eyre:: Result < alloy_rpc_types:: Block > {
158
+ let req = std:: fs:: read_to_string ( & path) ?;
159
+ let req: SubmitBlockRequest = serde_json:: from_str ( & req) ?;
160
+ let block_raw = match req {
161
+ SubmitBlockRequest :: Capella ( req) => req. execution_payload . clone ( ) . into_block_raw ( ) ?,
162
+ SubmitBlockRequest :: Fulu ( req) => req. execution_payload . clone ( ) . into_block_raw ( ) ?,
163
+ SubmitBlockRequest :: Deneb ( req) => req. execution_payload . clone ( ) . into_block_raw ( ) ?,
164
+ SubmitBlockRequest :: Electra ( req) => req. execution_payload . clone ( ) . into_block_raw ( ) ?,
165
+ } ;
166
+ let rpc_block = alloy_rpc_types:: Block :: from_consensus ( block_raw, None ) ;
167
+ let rpc_block = rpc_block. try_map_transactions ( |bytes| -> eyre:: Result < _ > {
168
+ let envelope = TxEnvelope :: decode_2718 ( & mut bytes. as_ref ( ) ) ?;
169
+ let recovered = envelope. try_into_recovered ( ) ?;
170
+ Ok ( alloy_rpc_types:: Transaction :: from_transaction (
171
+ recovered,
172
+ alloy_rpc_types:: TransactionInfo :: default ( ) ,
173
+ ) )
174
+ } ) ?;
175
+ Ok ( rpc_block)
176
+ }
177
+
135
178
fn report_time_data ( action : & str , data : & [ u128 ] ) {
136
179
let mean = data. iter ( ) . sum :: < u128 > ( ) as f64 / data. len ( ) as f64 ;
137
180
let median = * data. iter ( ) . sorted ( ) . nth ( data. len ( ) / 2 ) . unwrap ( ) ;
0 commit comments