44#[ cfg( with_testing) ]
55use std:: sync:: LazyLock ;
66use std:: {
7- collections:: { BTreeMap , HashSet } ,
7+ collections:: BTreeMap ,
88 env,
99 path:: { Path , PathBuf } ,
1010 sync:: Arc ,
@@ -195,9 +195,9 @@ pub struct LocalNet {
195195 num_shards : usize ,
196196 validator_keys : BTreeMap < usize , ( String , String ) > ,
197197 running_validators : BTreeMap < usize , Validator > ,
198- namespace : String ,
199- validators_with_initialized_storage : HashSet < usize > ,
200- storage_config : StorageConfig ,
198+ initialized_validator_storages : BTreeMap < usize , StorageConfigNamespace > ,
199+ common_namespace : String ,
200+ common_storage_config : StorageConfig ,
201201 cross_chain_config : CrossChainConfig ,
202202 path_provider : PathProvider ,
203203 num_block_exporters : u32 ,
@@ -379,10 +379,10 @@ impl LocalNet {
379379 fn new (
380380 network : NetworkConfig ,
381381 testing_prng_seed : Option < u64 > ,
382- namespace : String ,
382+ common_namespace : String ,
383383 num_initial_validators : usize ,
384384 num_shards : usize ,
385- storage_config : StorageConfig ,
385+ common_storage_config : StorageConfig ,
386386 cross_chain_config : CrossChainConfig ,
387387 path_provider : PathProvider ,
388388 num_block_exporters : u32 ,
@@ -395,9 +395,9 @@ impl LocalNet {
395395 num_shards,
396396 validator_keys : BTreeMap :: new ( ) ,
397397 running_validators : BTreeMap :: new ( ) ,
398- namespace ,
399- validators_with_initialized_storage : HashSet :: new ( ) ,
400- storage_config ,
398+ initialized_validator_storages : BTreeMap :: new ( ) ,
399+ common_namespace ,
400+ common_storage_config ,
401401 cross_chain_config,
402402 path_provider,
403403 num_block_exporters,
@@ -559,12 +559,15 @@ impl LocalNet {
559559 }
560560
561561 async fn run_proxy ( & mut self , validator : usize ) -> Result < Child > {
562- let storage = self . initialize_shared_storage ( validator) . await ?;
562+ let storage = self
563+ . initialized_validator_storages
564+ . get ( & validator)
565+ . expect ( "initialized storage" ) ;
563566 let child = self
564567 . command_for_binary ( "linera-proxy" )
565568 . await ?
566569 . arg ( format ! ( "server_{}.json" , validator) )
567- . args ( [ "--storage" , & storage] )
570+ . args ( [ "--storage" , & storage. to_string ( ) ] )
568571 . args ( [ "--genesis" , "genesis.json" ] )
569572 . spawn_into ( ) ?;
570573
@@ -588,14 +591,17 @@ impl LocalNet {
588591 }
589592
590593 async fn run_exporter ( & mut self , validator : usize , exporter_id : u32 ) -> Result < Child > {
591- let storage = self . initialize_shared_storage ( validator) . await ?;
592594 let config_path = format ! ( "exporter_config_{validator}:{exporter_id}.toml" ) ;
595+ let storage = self
596+ . initialized_validator_storages
597+ . get ( & validator)
598+ . expect ( "initialized storage" ) ;
593599
594600 let child = self
595601 . command_for_binary ( "linera-exporter" )
596602 . await ?
597603 . arg ( config_path)
598- . args ( [ "--storage" , & storage] )
604+ . args ( [ "--storage" , & storage. to_string ( ) ] )
599605 . args ( [ "--genesis" , "genesis.json" ] )
600606 . spawn_into ( ) ?;
601607
@@ -652,84 +658,43 @@ impl LocalNet {
652658 bail ! ( "Failed to start {nickname}" ) ;
653659 }
654660
655- async fn initialize_storage_internal ( & mut self , storage : & str , genesis : & str ) -> Result < ( ) > {
656- let max_try = 4 ;
657- let mut i_try = 0 ;
658- loop {
659- let mut command = self . command_for_binary ( "linera-server" ) . await ?;
660- if let Ok ( var) = env:: var ( SERVER_ENV ) {
661- command. args ( var. split_whitespace ( ) ) ;
662- }
663- command. arg ( "initialize" ) ;
664- let result = command
665- . args ( [ "--storage" , storage] )
666- . args ( [ "--genesis" , genesis] )
667- . spawn_and_wait_for_stdout ( )
668- . await ;
669- if result. is_ok ( ) {
670- return Ok ( ( ) ) ;
671- }
672- warn ! (
673- "Failed to initialize storage={} using linera-server, i_try={}, error={:?}" ,
674- storage, i_try, result
675- ) ;
676- i_try += 1 ;
677- if i_try == max_try {
678- bail ! ( "Failed to initialize after {} attempts" , max_try) ;
679- }
680- let one_second = linera_base:: time:: Duration :: from_secs ( 1 ) ;
681- std:: thread:: sleep ( one_second) ;
682- }
683- }
684-
685- async fn initialize_shared_storage ( & mut self , validator : usize ) -> Result < String > {
686- let namespace = format ! ( "{}_server_{}_db" , self . namespace, validator) ;
687- let storage_config = self . storage_config . get_shared_storage ( ) ;
661+ async fn initialize_storage ( & mut self , validator : usize ) -> Result < ( ) > {
662+ let namespace = format ! ( "{}_server_{}_db" , self . common_namespace, validator) ;
663+ let storage_config = self . common_storage_config . clone ( ) ;
688664 let storage = StorageConfigNamespace {
689665 storage_config,
690666 namespace,
691- }
692- . to_string ( ) ;
693- if !self
694- . validators_with_initialized_storage
695- . contains ( & validator)
696- {
697- self . initialize_storage_internal ( & storage, "genesis.json" )
698- . await ?;
699- self . validators_with_initialized_storage . insert ( validator) ;
700- }
701- Ok ( storage)
702- }
703-
704- async fn initialize_storage ( & mut self , validator : usize , shard : usize ) -> Result < String > {
705- if self . storage_config . are_chains_shared ( ) {
706- self . initialize_shared_storage ( validator) . await
707- } else {
708- let namespace = format ! ( "{}_server_{}_db" , self . namespace, validator) ;
709- let mut storage_config = self . storage_config . clone ( ) ;
710- let shard_str = format ! ( "shard_{}" , shard) ;
711- storage_config. append_shard_str ( & shard_str) ;
712- let storage = StorageConfigNamespace {
713- storage_config,
714- namespace,
715- }
716- . to_string ( ) ;
667+ } ;
717668
718- self . initialize_storage_internal ( & storage , "genesis.json" )
719- . await ? ;
720- Ok ( storage )
669+ let mut command = self . command_for_binary ( "linera-server" ) . await ? ;
670+ if let Ok ( var ) = env :: var ( SERVER_ENV ) {
671+ command . args ( var . split_whitespace ( ) ) ;
721672 }
673+ command. arg ( "initialize" ) ;
674+ command
675+ . args ( [ "--storage" , & storage. to_string ( ) ] )
676+ . args ( [ "--genesis" , "genesis.json" ] )
677+ . spawn_and_wait_for_stdout ( )
678+ . await ?;
679+
680+ self . initialized_validator_storages
681+ . insert ( validator, storage) ;
682+ Ok ( ( ) )
722683 }
723684
724685 async fn run_server ( & mut self , validator : usize , shard : usize ) -> Result < Child > {
725- let storage = self . initialize_storage ( validator, shard) . await ?;
686+ let storage = self
687+ . initialized_validator_storages
688+ . get ( & validator)
689+ . expect ( "initialized storage" ) ;
690+
726691 let mut command = self . command_for_binary ( "linera-server" ) . await ?;
727692 if let Ok ( var) = env:: var ( SERVER_ENV ) {
728693 command. args ( var. split_whitespace ( ) ) ;
729694 }
730695 command
731696 . arg ( "run" )
732- . args ( [ "--storage" , & storage] )
697+ . args ( [ "--storage" , & storage. to_string ( ) ] )
733698 . args ( [ "--server" , & format ! ( "server_{}.json" , validator) ] )
734699 . args ( [ "--shard" , & shard. to_string ( ) ] )
735700 . args ( [ "--genesis" , "genesis.json" ] )
@@ -762,28 +727,34 @@ impl LocalNet {
762727 Ok ( ( ) )
763728 }
764729
765- pub async fn start_validator ( & mut self , validator : usize ) -> Result < ( ) > {
766- let proxy = self . run_proxy ( validator) . await ?;
767- let mut validator_proxy = Validator :: new ( proxy) ;
730+ /// Start a validator.
731+ pub async fn start_validator ( & mut self , index : usize ) -> Result < ( ) > {
732+ self . initialize_storage ( index) . await ?;
733+ self . restart_validator ( index) . await
734+ }
735+
736+ /// Restart a validator. This is similar to `start_validator` except that the
737+ /// database was already initialized once.
738+ pub async fn restart_validator ( & mut self , index : usize ) -> Result < ( ) > {
739+ let proxy = self . run_proxy ( index) . await ?;
740+ let mut validator = Validator :: new ( proxy) ;
768741 for shard in 0 ..self . num_shards {
769- let server = self . run_server ( validator , shard) . await ?;
770- validator_proxy . add_server ( server) ;
742+ let server = self . run_server ( index , shard) . await ?;
743+ validator . add_server ( server) ;
771744 }
772-
773745 for block_exporter in 0 ..self . num_block_exporters {
774- let exporter = self . run_exporter ( validator , block_exporter) . await ?;
775- validator_proxy . add_block_exporter ( exporter) ;
746+ let exporter = self . run_exporter ( index , block_exporter) . await ?;
747+ validator . add_block_exporter ( exporter) ;
776748 }
777-
778- self . running_validators . insert ( validator, validator_proxy) ;
749+ self . running_validators . insert ( index, validator) ;
779750 Ok ( ( ) )
780751 }
781752
782753 /// Terminates all the processes of a given validator.
783- pub async fn stop_validator ( & mut self , validator_index : usize ) -> Result < ( ) > {
784- if let Some ( mut validator) = self . running_validators . remove ( & validator_index ) {
754+ pub async fn stop_validator ( & mut self , index : usize ) -> Result < ( ) > {
755+ if let Some ( mut validator) = self . running_validators . remove ( & index ) {
785756 if let Err ( error) = validator. terminate ( ) . await {
786- error ! ( "Failed to stop validator {validator_index }: {error}" ) ;
757+ error ! ( "Failed to stop validator {index }: {error}" ) ;
787758 return Err ( error) ;
788759 }
789760 }
@@ -857,7 +828,7 @@ impl LocalNet {
857828 let server = self . run_server ( validator, shard) . await ?;
858829 self . running_validators
859830 . get_mut ( & validator)
860- . context ( "could not find server " ) ?
831+ . context ( "could not find validator " ) ?
861832 . add_server ( server) ;
862833 Ok ( ( ) )
863834 }
0 commit comments