@@ -45,6 +45,9 @@ pub struct ScrollRollupNodeConfig {
4545 /// Whether the rollup node should be run in test mode.
4646 #[ arg( long) ]
4747 pub test : bool ,
48+ /// Consensus args
49+ #[ command( flatten) ]
50+ pub consensus_args : ConsensusArgs ,
4851 /// Database args
4952 #[ command( flatten) ]
5053 pub database_args : DatabaseArgs ,
@@ -74,14 +77,32 @@ pub struct ScrollRollupNodeConfig {
7477impl ScrollRollupNodeConfig {
7578 /// Validate that either signer key file or AWS KMS key ID is provided when sequencer is enabled
7679 pub fn validate ( & self ) -> Result < ( ) , String > {
77- if !self . test && self . sequencer_args . sequencer_enabled {
78- if self . signer_args . key_file . is_none ( ) && self . signer_args . aws_kms_key_id . is_none ( ) {
79- return Err ( "Either signer key file or AWS KMS key ID is required when sequencer is enabled" . to_string ( ) ) ;
80+ if self . sequencer_args . sequencer_enabled &
81+ !matches ! ( self . consensus_args. algorithm, ConsensusAlgorithm :: Noop )
82+ {
83+ if self . signer_args . key_file . is_none ( ) &&
84+ self . signer_args . aws_kms_key_id . is_none ( ) &&
85+ self . signer_args . private_key . is_none ( )
86+ {
87+ return Err ( "Either signer key file, AWS KMS key ID or private key is required when sequencer is enabled" . to_string ( ) ) ;
8088 }
81- if self . signer_args . key_file . is_some ( ) && self . signer_args . aws_kms_key_id . is_some ( ) {
82- return Err ( "Cannot specify both signer key file and AWS KMS key ID" . to_string ( ) ) ;
89+
90+ if ( self . signer_args . key_file . is_some ( ) as u8 +
91+ self . signer_args . aws_kms_key_id . is_some ( ) as u8 +
92+ self . signer_args . private_key . is_some ( ) as u8 ) >
93+ 1
94+ {
95+ return Err ( "Cannot specify more than one signer key source" . to_string ( ) ) ;
8396 }
8497 }
98+
99+ if self . consensus_args . algorithm == ConsensusAlgorithm :: SystemContract &&
100+ self . consensus_args . authorized_signer . is_none ( ) &&
101+ self . l1_provider_args . url . is_none ( )
102+ {
103+ return Err ( "System contract consensus requires either an authorized signer or a L1 provider URL" . to_string ( ) ) ;
104+ }
105+
85106 Ok ( ( ) )
86107 }
87108}
@@ -202,13 +223,23 @@ impl ScrollRollupNodeConfig {
202223 ) ;
203224
204225 // Create the consensus.
205- let consensus: Box < dyn Consensus > = if let Some ( ref provider) = l1_provider {
206- let signer = provider
207- . authorized_signer ( node_config. address_book . system_contract_address )
208- . await ?;
209- Box :: new ( SystemContractConsensus :: new ( signer) )
210- } else {
211- Box :: new ( NoopConsensus :: default ( ) )
226+ let consensus: Box < dyn Consensus > = match self . consensus_args . algorithm {
227+ ConsensusAlgorithm :: Noop => Box :: new ( NoopConsensus :: default ( ) ) ,
228+ ConsensusAlgorithm :: SystemContract => {
229+ let authorized_signer = if let Some ( address) = self . consensus_args . authorized_signer
230+ {
231+ address
232+ } else if let Some ( provider) = l1_provider. as_ref ( ) {
233+ provider
234+ . authorized_signer ( node_config. address_book . system_contract_address )
235+ . await ?
236+ } else {
237+ return Err ( eyre:: eyre!(
238+ "System contract consensus requires either an authorized signer or a L1 provider URL"
239+ ) ) ;
240+ } ;
241+ Box :: new ( SystemContractConsensus :: new ( authorized_signer) )
242+ }
212243 } ;
213244
214245 let ( l1_notification_tx, l1_notification_rx) : ( Option < Sender < Arc < L1Notification > > > , _ ) =
@@ -297,6 +328,45 @@ pub struct DatabaseArgs {
297328 pub path : Option < PathBuf > ,
298329}
299330
331+ /// The database arguments.
332+ #[ derive( Debug , Default , Clone , clap:: Args ) ]
333+ pub struct ConsensusArgs {
334+ /// The type of consensus to use.
335+ #[ arg(
336+ long = "consensus.algorithm" ,
337+ value_name = "CONSENSUS_ALGORITHM" ,
338+ default_value = "system-contract"
339+ ) ]
340+ pub algorithm : ConsensusAlgorithm ,
341+
342+ /// The optional authorized signer for system contract consensus.
343+ #[ arg( long = "consensus.authorized-signer" , value_name = "ADDRESS" ) ]
344+ pub authorized_signer : Option < Address > ,
345+ }
346+
347+ impl ConsensusArgs {
348+ /// Create a new [`ConsensusArgs`] with the no-op consensus algorithm.
349+ pub const fn noop ( ) -> Self {
350+ Self { algorithm : ConsensusAlgorithm :: Noop , authorized_signer : None }
351+ }
352+ }
353+
354+ /// The consensus algorithm to use.
355+ #[ derive( Debug , clap:: ValueEnum , Clone , PartialEq , Eq ) ]
356+ pub enum ConsensusAlgorithm {
357+ /// System contract consensus with an optional authorized signer. If the authorized signer is
358+ /// not provided the system will use the L1 provider to query the authorized signer from L1.
359+ SystemContract ,
360+ /// No-op consensus that does not validate blocks.
361+ Noop ,
362+ }
363+
364+ impl Default for ConsensusAlgorithm {
365+ fn default ( ) -> Self {
366+ Self :: SystemContract
367+ }
368+ }
369+
300370/// The engine driver args.
301371#[ derive( Debug , Default , Clone , clap:: Args ) ]
302372pub struct EngineDriverArgs {
@@ -424,6 +494,9 @@ pub struct SignerArgs {
424494 help = "AWS KMS Key ID for signing transactions. Mutually exclusive with --signer.key-file"
425495 ) ]
426496 pub aws_kms_key_id : Option < String > ,
497+
498+ /// The private key signer, if any.
499+ pub private_key : Option < PrivateKeySigner > ,
427500}
428501
429502impl SignerArgs {
@@ -455,7 +528,7 @@ impl SignerArgs {
455528 . map_err ( |e| eyre:: eyre!( "Failed to create signer from key file: {}" , e) ) ?
456529 . with_chain_id ( Some ( chain_id) ) ;
457530
458- tracing:: info!(
531+ tracing:: info!( target : "scroll::node::args" ,
459532 "Created private key signer with address: {} for chain ID: {}" ,
460533 private_key_signer. address( ) ,
461534 chain_id
@@ -474,12 +547,17 @@ impl SignerArgs {
474547 . map_err ( |e| eyre:: eyre!( "Failed to initialize AWS KMS signer: {}" , e) ) ?;
475548
476549 tracing:: info!(
550+ target: "scroll::node::args" ,
477551 "Created AWS KMS signer with address: {} for chain ID: {}" ,
478552 aws_signer. address( ) ,
479553 chain_id
480554 ) ;
481555
482556 Ok ( Some ( Box :: new ( aws_signer) ) )
557+ } else if let Some ( private_key) = & self . private_key {
558+ tracing:: info!( target: "scroll::node::args" , "Created private key signer with address: {} for chain ID: {}" , private_key. address( ) , chain_id) ;
559+ let signer = private_key. clone ( ) . with_chain_id ( Some ( chain_id) ) ;
560+ Ok ( Some ( Box :: new ( signer) ) )
483561 } else {
484562 Ok ( None )
485563 }
@@ -505,19 +583,23 @@ mod tests {
505583 let config = ScrollRollupNodeConfig {
506584 test : false ,
507585 sequencer_args : SequencerArgs { sequencer_enabled : true , ..Default :: default ( ) } ,
508- signer_args : SignerArgs { key_file : None , aws_kms_key_id : None } ,
586+ signer_args : SignerArgs { key_file : None , aws_kms_key_id : None , private_key : None } ,
509587 database_args : DatabaseArgs :: default ( ) ,
510588 engine_driver_args : EngineDriverArgs :: default ( ) ,
511589 l1_provider_args : L1ProviderArgs :: default ( ) ,
512590 beacon_provider_args : BeaconProviderArgs :: default ( ) ,
513591 network_args : NetworkArgs :: default ( ) ,
514592 gas_price_oracle_args : GasPriceOracleArgs :: default ( ) ,
593+ consensus_args : ConsensusArgs {
594+ algorithm : ConsensusAlgorithm :: SystemContract ,
595+ authorized_signer : None ,
596+ } ,
515597 } ;
516598
517599 let result = config. validate ( ) ;
518600 assert ! ( result. is_err( ) ) ;
519601 assert ! ( result. unwrap_err( ) . contains(
520- "Either signer key file or AWS KMS key ID is required when sequencer is enabled"
602+ "Either signer key file, AWS KMS key ID or private key is required when sequencer is enabled"
521603 ) ) ;
522604 }
523605
@@ -529,20 +611,23 @@ mod tests {
529611 signer_args : SignerArgs {
530612 key_file : Some ( PathBuf :: from ( "/path/to/key" ) ) ,
531613 aws_kms_key_id : Some ( "key-id" . to_string ( ) ) ,
614+ private_key : None ,
532615 } ,
533616 database_args : DatabaseArgs :: default ( ) ,
534617 engine_driver_args : EngineDriverArgs :: default ( ) ,
535618 l1_provider_args : L1ProviderArgs :: default ( ) ,
536619 beacon_provider_args : BeaconProviderArgs :: default ( ) ,
537620 network_args : NetworkArgs :: default ( ) ,
538621 gas_price_oracle_args : GasPriceOracleArgs :: default ( ) ,
622+ consensus_args : ConsensusArgs {
623+ algorithm : ConsensusAlgorithm :: SystemContract ,
624+ authorized_signer : None ,
625+ } ,
539626 } ;
540627
541628 let result = config. validate ( ) ;
542629 assert ! ( result. is_err( ) ) ;
543- assert ! ( result
544- . unwrap_err( )
545- . contains( "Cannot specify both signer key file and AWS KMS key ID" ) ) ;
630+ assert ! ( result. unwrap_err( ) . contains( "Cannot specify more than one signer key source" ) ) ;
546631 }
547632
548633 #[ test]
@@ -553,13 +638,15 @@ mod tests {
553638 signer_args : SignerArgs {
554639 key_file : Some ( PathBuf :: from ( "/path/to/key" ) ) ,
555640 aws_kms_key_id : None ,
641+ private_key : None ,
556642 } ,
557643 database_args : DatabaseArgs :: default ( ) ,
558644 engine_driver_args : EngineDriverArgs :: default ( ) ,
559645 l1_provider_args : L1ProviderArgs :: default ( ) ,
560646 beacon_provider_args : BeaconProviderArgs :: default ( ) ,
561647 network_args : NetworkArgs :: default ( ) ,
562648 gas_price_oracle_args : GasPriceOracleArgs :: default ( ) ,
649+ consensus_args : ConsensusArgs :: noop ( ) ,
563650 } ;
564651
565652 assert ! ( config. validate( ) . is_ok( ) ) ;
@@ -570,30 +657,18 @@ mod tests {
570657 let config = ScrollRollupNodeConfig {
571658 test : false ,
572659 sequencer_args : SequencerArgs { sequencer_enabled : true , ..Default :: default ( ) } ,
573- signer_args : SignerArgs { key_file : None , aws_kms_key_id : Some ( "key-id" . to_string ( ) ) } ,
574- database_args : DatabaseArgs :: default ( ) ,
575- engine_driver_args : EngineDriverArgs :: default ( ) ,
576- l1_provider_args : L1ProviderArgs :: default ( ) ,
577- beacon_provider_args : BeaconProviderArgs :: default ( ) ,
578- network_args : NetworkArgs :: default ( ) ,
579- gas_price_oracle_args : GasPriceOracleArgs :: default ( ) ,
580- } ;
581-
582- assert ! ( config. validate( ) . is_ok( ) ) ;
583- }
584-
585- #[ test]
586- fn test_validate_test_mode_without_any_signer_succeeds ( ) {
587- let config = ScrollRollupNodeConfig {
588- test : true ,
589- sequencer_args : SequencerArgs { sequencer_enabled : true , ..Default :: default ( ) } ,
590- signer_args : SignerArgs { key_file : None , aws_kms_key_id : None } ,
660+ signer_args : SignerArgs {
661+ key_file : None ,
662+ aws_kms_key_id : Some ( "key-id" . to_string ( ) ) ,
663+ private_key : None ,
664+ } ,
591665 database_args : DatabaseArgs :: default ( ) ,
592666 engine_driver_args : EngineDriverArgs :: default ( ) ,
593667 l1_provider_args : L1ProviderArgs :: default ( ) ,
594668 beacon_provider_args : BeaconProviderArgs :: default ( ) ,
595669 network_args : NetworkArgs :: default ( ) ,
596670 gas_price_oracle_args : GasPriceOracleArgs :: default ( ) ,
671+ consensus_args : ConsensusArgs :: noop ( ) ,
597672 } ;
598673
599674 assert ! ( config. validate( ) . is_ok( ) ) ;
@@ -604,13 +679,14 @@ mod tests {
604679 let config = ScrollRollupNodeConfig {
605680 test : false ,
606681 sequencer_args : SequencerArgs { sequencer_enabled : false , ..Default :: default ( ) } ,
607- signer_args : SignerArgs { key_file : None , aws_kms_key_id : None } ,
682+ signer_args : SignerArgs { key_file : None , aws_kms_key_id : None , private_key : None } ,
608683 database_args : DatabaseArgs :: default ( ) ,
609684 engine_driver_args : EngineDriverArgs :: default ( ) ,
610685 l1_provider_args : L1ProviderArgs :: default ( ) ,
611686 beacon_provider_args : BeaconProviderArgs :: default ( ) ,
612687 network_args : NetworkArgs :: default ( ) ,
613688 gas_price_oracle_args : GasPriceOracleArgs :: default ( ) ,
689+ consensus_args : ConsensusArgs :: noop ( ) ,
614690 } ;
615691
616692 assert ! ( config. validate( ) . is_ok( ) ) ;
0 commit comments