diff --git a/CLI.md b/CLI.md index 3998b7f390e..caea5d7022a 100644 --- a/CLI.md +++ b/CLI.md @@ -20,6 +20,7 @@ This document contains the help content for the `linera` command-line program. * [`linera query-validators`↴](#linera-query-validators) * [`linera set-validator`↴](#linera-set-validator) * [`linera remove-validator`↴](#linera-remove-validator) +* [`linera finalize-committee`↴](#linera-finalize-committee) * [`linera resource-control-policy`↴](#linera-resource-control-policy) * [`linera create-genesis-config`↴](#linera-create-genesis-config) * [`linera watch`↴](#linera-watch) @@ -71,6 +72,7 @@ A Byzantine-fault tolerant sidechain with low-latency finality and high throughp * `query-validators` — Show the current set of validators for a chain * `set-validator` — Add or modify a validator (admin only) * `remove-validator` — Remove a validator (admin only) +* `finalize-committee` — Deprecates all committees except the last one * `resource-control-policy` — View or update the resource control policy * `create-genesis-config` — Create genesis configuration for a Linera deployment. Create initial user chains and print information to be used for initialization of validator setup. This will also create an initial wallet for the owner of the initial "root" chains * `watch` — Watch the network for notifications @@ -382,6 +384,14 @@ Remove a validator (admin only) +## `linera finalize-committee` + +Deprecates all committees except the last one + +**Usage:** `linera finalize-committee` + + + ## `linera resource-control-policy` View or update the resource control policy diff --git a/linera-client/src/client_options.rs b/linera-client/src/client_options.rs index 35709ae9297..39dc4355c31 100644 --- a/linera-client/src/client_options.rs +++ b/linera-client/src/client_options.rs @@ -460,6 +460,9 @@ pub enum ClientCommand { name: ValidatorName, }, + /// Deprecates all committees except the last one. + FinalizeCommittee, + /// View or update the resource control policy ResourceControlPolicy { /// Set the base price for creating a block. diff --git a/linera-service/src/cli_wrappers/wallet.rs b/linera-service/src/cli_wrappers/wallet.rs index d9982beb128..733bcad3a1b 100644 --- a/linera-service/src/cli_wrappers/wallet.rs +++ b/linera-service/src/cli_wrappers/wallet.rs @@ -785,6 +785,15 @@ impl ClientWrapper { Ok(()) } + pub async fn finalize_committee(&self) -> Result<()> { + self.command() + .await? + .arg("finalize-committee") + .spawn_and_wait_for_stdout() + .await?; + Ok(()) + } + /// Runs `linera keygen`. pub async fn keygen(&self) -> Result { let stdout = self @@ -975,7 +984,7 @@ impl NodeService { } pub async fn query_node(&self, query: impl AsRef) -> Result { - let n_try = 15; + let n_try = 5; let query = query.as_ref(); for i in 0..n_try { tokio::time::sleep(Duration::from_secs(i)).await; diff --git a/linera-service/src/linera/main.rs b/linera-service/src/linera/main.rs index c286e895139..3c4f0686670 100644 --- a/linera-service/src/linera/main.rs +++ b/linera-service/src/linera/main.rs @@ -633,9 +633,20 @@ impl Runnable for Job { let Some(certificate) = maybe_certificate else { return Ok(()); }; + info!("Created new committee:\n{:?}", certificate); + + let time_total = time_start.elapsed(); + info!("Operations confirmed after {} ms", time_total.as_millis()); + } + + FinalizeCommittee => { + info!("Starting operations to remove old committees"); + let time_start = Instant::now(); + + let chain_client = context.make_chain_client(context.wallet.genesis_admin_chain()); // Remove the old committee. - info!("Finalizing committee:\n{:?}", certificate); + info!("Finalizing current committee"); context .apply_client_command(&chain_client, |chain_client| { let chain_client = chain_client.clone(); diff --git a/linera-service/tests/local_net_tests.rs b/linera-service/tests/local_net_tests.rs index 7cfe5619898..807d1f6d891 100644 --- a/linera-service/tests/local_net_tests.rs +++ b/linera-service/tests/local_net_tests.rs @@ -138,6 +138,7 @@ async fn test_end_to_end_reconfiguration(config: LocalNetConfig) -> Result<()> { client .set_validator(net.validator_name(4).unwrap(), LocalNet::proxy_port(4), 100) .await?; + client.finalize_committee().await?; client.query_validators(None).await?; client.query_validators(Some(chain_1)).await?; @@ -150,6 +151,7 @@ async fn test_end_to_end_reconfiguration(config: LocalNetConfig) -> Result<()> { client .set_validator(net.validator_name(5).unwrap(), LocalNet::proxy_port(5), 100) .await?; + client.finalize_committee().await?; if matches!(network, Network::Grpc) { assert_eq!(faucet.current_validators().await?.len(), 6); } @@ -158,6 +160,7 @@ async fn test_end_to_end_reconfiguration(config: LocalNetConfig) -> Result<()> { client .remove_validator(net.validator_name(4).unwrap()) .await?; + client.finalize_committee().await?; net.remove_validator(4)?; if matches!(network, Network::Grpc) { assert_eq!(faucet.current_validators().await?.len(), 5); @@ -174,6 +177,7 @@ async fn test_end_to_end_reconfiguration(config: LocalNetConfig) -> Result<()> { for i in 0..4 { let name = net.validator_name(i).unwrap(); client.remove_validator(name).await?; + client.finalize_committee().await?; if let Some(service) = &node_service_2 { service.process_inbox(&chain_2).await?; } else { @@ -203,6 +207,16 @@ async fn test_end_to_end_reconfiguration(config: LocalNetConfig) -> Result<()> { let response = node_service_2.query_node(query.clone()).await?; let balances = &response["chain"]["executionState"]["system"]["balances"]; assert_eq!(balances["entry"]["value"].as_str(), Some("5.")); + + let query = format!( + "query {{ chain(chainId:\"{chain_2}\") {{ + executionState {{ system {{ committees }} }} + }} }}" + ); + let response = node_service_2.query_node(query.clone()).await?; + let committees = &response["chain"]["executionState"]["system"]["committees"]; + let epochs = committees.as_object().unwrap().keys().collect::>(); + assert_eq!(&epochs, &["7"]); } else { client_2.sync(chain_2).await?; client_2.process_inbox(chain_2).await?;