1
1
//! This module contains all CLI-specific code for the host binary.
2
2
3
- use crate :: {
4
- blobs:: OnlineBlobProvider ,
5
- kv:: {
6
- DiskKeyValueStore , LocalKeyValueStore , MemoryKeyValueStore , SharedKeyValueStore ,
7
- SplitKeyValueStore ,
8
- } ,
9
- } ;
10
- use alloy_primitives:: B256 ;
11
- use alloy_provider:: ReqwestProvider ;
12
- use alloy_rpc_client:: RpcClient ;
13
- use alloy_transport_http:: Http ;
14
- use anyhow:: { anyhow, Result } ;
3
+ use crate :: single:: SingleChainHostCli ;
15
4
use clap:: {
16
5
builder:: styling:: { AnsiColor , Color , Style } ,
17
- ArgAction , Parser ,
6
+ ArgAction , Parser , Subcommand ,
18
7
} ;
19
- use op_alloy_genesis:: RollupConfig ;
20
- use reqwest:: Client ;
21
8
use serde:: Serialize ;
22
- use std:: { path:: PathBuf , sync:: Arc } ;
23
- use tokio:: sync:: RwLock ;
24
9
25
10
mod parser;
26
11
pub ( crate ) use parser:: parse_b256;
@@ -37,164 +22,22 @@ primary thread.
37
22
" ;
38
23
39
24
/// The host binary CLI application arguments.
40
- #[ derive( Default , Parser , Serialize , Clone , Debug ) ]
25
+ #[ derive( Parser , Serialize , Clone , Debug ) ]
41
26
#[ command( about = ABOUT , version, styles = cli_styles( ) ) ]
42
27
pub struct HostCli {
43
28
/// Verbosity level (0-2)
44
29
#[ arg( long, short, action = ArgAction :: Count ) ]
45
30
pub v : u8 ,
46
- /// Hash of the L1 head block. Derivation stops after this block is processed.
47
- #[ clap( long, value_parser = parse_b256, env) ]
48
- pub l1_head : B256 ,
49
- /// Hash of the agreed upon safe L2 block committed to by `--agreed-l2-output-root`.
50
- #[ clap( long, visible_alias = "l2-head" , value_parser = parse_b256, env) ]
51
- pub agreed_l2_head_hash : B256 ,
52
- /// Agreed safe L2 Output Root to start derivation from.
53
- #[ clap( long, visible_alias = "l2-output-root" , value_parser = parse_b256, env) ]
54
- pub agreed_l2_output_root : B256 ,
55
- /// Claimed L2 output root at block # `--claimed-l2-block-number` to validate.
56
- #[ clap( long, visible_alias = "l2-claim" , value_parser = parse_b256, env) ]
57
- pub claimed_l2_output_root : B256 ,
58
- /// Number of the L2 block that the claimed output root commits to.
59
- #[ clap( long, visible_alias = "l2-block-number" , env) ]
60
- pub claimed_l2_block_number : u64 ,
61
- /// Address of L2 JSON-RPC endpoint to use (eth and debug namespace required).
62
- #[ clap(
63
- long,
64
- visible_alias = "l2" ,
65
- requires = "l1_node_address" ,
66
- requires = "l1_beacon_address" ,
67
- env
68
- ) ]
69
- pub l2_node_address : Option < String > ,
70
- /// Address of L1 JSON-RPC endpoint to use (eth and debug namespace required)
71
- #[ clap(
72
- long,
73
- visible_alias = "l1" ,
74
- requires = "l2_node_address" ,
75
- requires = "l1_beacon_address" ,
76
- env
77
- ) ]
78
- pub l1_node_address : Option < String > ,
79
- /// Address of the L1 Beacon API endpoint to use.
80
- #[ clap(
81
- long,
82
- visible_alias = "beacon" ,
83
- requires = "l1_node_address" ,
84
- requires = "l2_node_address" ,
85
- env
86
- ) ]
87
- pub l1_beacon_address : Option < String > ,
88
- /// The Data Directory for preimage data storage. Optional if running in online mode,
89
- /// required if running in offline mode.
90
- #[ clap(
91
- long,
92
- visible_alias = "db" ,
93
- required_unless_present_all = [ "l2_node_address" , "l1_node_address" , "l1_beacon_address" ] ,
94
- env
95
- ) ]
96
- pub data_dir : Option < PathBuf > ,
97
- /// Run the client program natively.
98
- #[ clap( long, conflicts_with = "server" , required_unless_present = "server" ) ]
99
- pub native : bool ,
100
- /// Run in pre-image server mode without executing any client program. If not provided, the
101
- /// host will run the client program in the host process.
102
- #[ clap( long, conflicts_with = "native" , required_unless_present = "native" ) ]
103
- pub server : bool ,
104
- /// The L2 chain ID of a supported chain. If provided, the host will look for the corresponding
105
- /// rollup config in the superchain registry.
106
- #[ clap(
107
- long,
108
- conflicts_with = "rollup_config_path" ,
109
- required_unless_present = "rollup_config_path" ,
110
- env
111
- ) ]
112
- pub l2_chain_id : Option < u64 > ,
113
- /// Path to rollup config. If provided, the host will use this config instead of attempting to
114
- /// look up the config in the superchain registry.
115
- #[ clap(
116
- long,
117
- alias = "rollup-cfg" ,
118
- conflicts_with = "l2_chain_id" ,
119
- required_unless_present = "l2_chain_id" ,
120
- env
121
- ) ]
122
- pub rollup_config_path : Option < PathBuf > ,
31
+ /// Host mode
32
+ #[ clap( subcommand) ]
33
+ pub mode : HostMode ,
123
34
}
124
35
125
- impl HostCli {
126
- /// Returns `true` if the host is running in offline mode.
127
- pub const fn is_offline ( & self ) -> bool {
128
- self . l1_node_address . is_none ( ) &&
129
- self . l2_node_address . is_none ( ) &&
130
- self . l1_beacon_address . is_none ( )
131
- }
132
-
133
- /// Returns an HTTP provider for the given URL.
134
- fn http_provider ( url : & str ) -> ReqwestProvider {
135
- let url = url. parse ( ) . unwrap ( ) ;
136
- let http = Http :: < Client > :: new ( url) ;
137
- ReqwestProvider :: new ( RpcClient :: new ( http, true ) )
138
- }
139
-
140
- /// Creates the providers associated with the [HostCli] configuration.
141
- ///
142
- /// ## Returns
143
- /// - A [ReqwestProvider] for the L1 node.
144
- /// - An [OnlineBlobProvider] for the L1 beacon node.
145
- /// - A [ReqwestProvider] for the L2 node.
146
- pub async fn create_providers (
147
- & self ,
148
- ) -> Result < ( ReqwestProvider , OnlineBlobProvider , ReqwestProvider ) > {
149
- let blob_provider = OnlineBlobProvider :: new_http (
150
- self . l1_beacon_address . clone ( ) . ok_or ( anyhow ! ( "Beacon API URL must be set" ) ) ?,
151
- )
152
- . await
153
- . map_err ( |e| anyhow ! ( "Failed to load blob provider configuration: {e}" ) ) ?;
154
- let l1_provider = Self :: http_provider (
155
- self . l1_node_address . as_ref ( ) . ok_or ( anyhow ! ( "Provider must be set" ) ) ?,
156
- ) ;
157
- let l2_provider = Self :: http_provider (
158
- self . l2_node_address . as_ref ( ) . ok_or ( anyhow ! ( "L2 node address must be set" ) ) ?,
159
- ) ;
160
-
161
- Ok ( ( l1_provider, blob_provider, l2_provider) )
162
- }
163
-
164
- /// Parses the CLI arguments and returns a new instance of a [SharedKeyValueStore], as it is
165
- /// configured to be created.
166
- pub fn construct_kv_store ( & self ) -> SharedKeyValueStore {
167
- let local_kv_store = LocalKeyValueStore :: new ( self . clone ( ) ) ;
168
-
169
- let kv_store: SharedKeyValueStore = if let Some ( ref data_dir) = self . data_dir {
170
- let disk_kv_store = DiskKeyValueStore :: new ( data_dir. clone ( ) ) ;
171
- let split_kv_store = SplitKeyValueStore :: new ( local_kv_store, disk_kv_store) ;
172
- Arc :: new ( RwLock :: new ( split_kv_store) )
173
- } else {
174
- let mem_kv_store = MemoryKeyValueStore :: new ( ) ;
175
- let split_kv_store = SplitKeyValueStore :: new ( local_kv_store, mem_kv_store) ;
176
- Arc :: new ( RwLock :: new ( split_kv_store) )
177
- } ;
178
-
179
- kv_store
180
- }
181
-
182
- /// Reads the [RollupConfig] from the file system and returns it as a string.
183
- pub fn read_rollup_config ( & self ) -> Result < RollupConfig > {
184
- let path = self . rollup_config_path . as_ref ( ) . ok_or_else ( || {
185
- anyhow:: anyhow!(
186
- "No rollup config path provided. Please provide a path to the rollup config."
187
- )
188
- } ) ?;
189
-
190
- // Read the serialized config from the file system.
191
- let ser_config = std:: fs:: read_to_string ( path)
192
- . map_err ( |e| anyhow ! ( "Error reading RollupConfig file: {e}" ) ) ?;
193
-
194
- // Deserialize the config and return it.
195
- serde_json:: from_str ( & ser_config)
196
- . map_err ( |e| anyhow ! ( "Error deserializing RollupConfig: {e}" ) )
197
- }
36
+ /// Operation modes for the host binary.
37
+ #[ derive( Subcommand , Serialize , Clone , Debug ) ]
38
+ pub enum HostMode {
39
+ /// Run the host in single-chain mode.
40
+ Single ( SingleChainHostCli ) ,
198
41
}
199
42
200
43
/// Styles for the CLI application.
@@ -208,69 +51,3 @@ const fn cli_styles() -> clap::builder::Styles {
208
51
. valid ( Style :: new ( ) . bold ( ) . underline ( ) . fg_color ( Some ( Color :: Ansi ( AnsiColor :: Green ) ) ) )
209
52
. placeholder ( Style :: new ( ) . fg_color ( Some ( Color :: Ansi ( AnsiColor :: White ) ) ) )
210
53
}
211
-
212
- #[ cfg( test) ]
213
- mod test {
214
- use crate :: HostCli ;
215
- use alloy_primitives:: B256 ;
216
- use clap:: Parser ;
217
-
218
- #[ test]
219
- fn test_flags ( ) {
220
- let zero_hash_str = & B256 :: ZERO . to_string ( ) ;
221
- let default_flags = [
222
- "host" ,
223
- "--l1-head" ,
224
- zero_hash_str,
225
- "--l2-head" ,
226
- zero_hash_str,
227
- "--l2-output-root" ,
228
- zero_hash_str,
229
- "--l2-claim" ,
230
- zero_hash_str,
231
- "--l2-block-number" ,
232
- "0" ,
233
- ] ;
234
-
235
- let cases = [
236
- // valid
237
- ( [ "--server" , "--l2-chain-id" , "0" , "--data-dir" , "dummy" ] . as_slice ( ) , true ) ,
238
- ( [ "--server" , "--rollup-config-path" , "dummy" , "--data-dir" , "dummy" ] . as_slice ( ) , true ) ,
239
- ( [ "--native" , "--l2-chain-id" , "0" , "--data-dir" , "dummy" ] . as_slice ( ) , true ) ,
240
- ( [ "--native" , "--rollup-config-path" , "dummy" , "--data-dir" , "dummy" ] . as_slice ( ) , true ) ,
241
- (
242
- [
243
- "--l1-node-address" ,
244
- "dummy" ,
245
- "--l2-node-address" ,
246
- "dummy" ,
247
- "--l1-beacon-address" ,
248
- "dummy" ,
249
- "--server" ,
250
- "--l2-chain-id" ,
251
- "0" ,
252
- ]
253
- . as_slice ( ) ,
254
- true ,
255
- ) ,
256
- // invalid
257
- ( [ "--server" , "--native" , "--l2-chain-id" , "0" ] . as_slice ( ) , false ) ,
258
- ( [ "--l2-chain-id" , "0" , "--rollup-config-path" , "dummy" , "--server" ] . as_slice ( ) , false ) ,
259
- ( [ "--server" ] . as_slice ( ) , false ) ,
260
- ( [ "--native" ] . as_slice ( ) , false ) ,
261
- ( [ "--rollup-config-path" , "dummy" ] . as_slice ( ) , false ) ,
262
- ( [ "--l2-chain-id" , "0" ] . as_slice ( ) , false ) ,
263
- ( [ "--l1-node-address" , "dummy" , "--server" , "--l2-chain-id" , "0" ] . as_slice ( ) , false ) ,
264
- ( [ "--l2-node-address" , "dummy" , "--server" , "--l2-chain-id" , "0" ] . as_slice ( ) , false ) ,
265
- ( [ "--l1-beacon-address" , "dummy" , "--server" , "--l2-chain-id" , "0" ] . as_slice ( ) , false ) ,
266
- ( [ ] . as_slice ( ) , false ) ,
267
- ] ;
268
-
269
- for ( args_ext, valid) in cases. into_iter ( ) {
270
- let args = default_flags. iter ( ) . chain ( args_ext. iter ( ) ) . cloned ( ) . collect :: < Vec < _ > > ( ) ;
271
-
272
- let parsed = HostCli :: try_parse_from ( args) ;
273
- assert_eq ! ( parsed. is_ok( ) , valid) ;
274
- }
275
- }
276
- }
0 commit comments