diff --git a/CLI.md b/CLI.md index c0a2703395a4..0e1ae73d0b4f 100644 --- a/CLI.md +++ b/CLI.md @@ -603,9 +603,6 @@ Run a GraphQL service that exposes a faucet where users can claim tokens. This g Default value: `8080` * `--amount ` — The number of tokens to send to each new chain * `--limit-rate-until ` — The end timestamp: The faucet will rate-limit the token supply so it runs out of money no earlier than this -* `--max-chain-length ` — The maximum number of blocks in the faucet chain, before a new one is created - - Default value: `500` * `--listener-skip-process-inbox` — Do not create blocks automatically to receive incoming messages. Instead, wait for an explicit mutation `processInbox` * `--listener-delay-before-ms ` — Wait before processing any notification (useful for testing) diff --git a/Cargo.lock b/Cargo.lock index f3e87d97d416..3d2095a84bb0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4759,7 +4759,6 @@ dependencies = [ "linera-base", "linera-client", "linera-core", - "linera-execution", "linera-storage", "linera-version", "linera-views", diff --git a/linera-faucet/server/Cargo.toml b/linera-faucet/server/Cargo.toml index 9d567e311ccd..4a99983956d6 100644 --- a/linera-faucet/server/Cargo.toml +++ b/linera-faucet/server/Cargo.toml @@ -20,7 +20,6 @@ futures.workspace = true linera-base.workspace = true linera-client.workspace = true linera-core.workspace = true -linera-execution.workspace = true linera-storage.workspace = true linera-version.workspace = true serde.workspace = true diff --git a/linera-faucet/server/src/lib.rs b/linera-faucet/server/src/lib.rs index 099ce6f4e890..433f85e17613 100644 --- a/linera-faucet/server/src/lib.rs +++ b/linera-faucet/server/src/lib.rs @@ -11,7 +11,7 @@ use axum::{Extension, Router}; use futures::lock::Mutex; use linera_base::{ crypto::{CryptoHash, ValidatorPublicKey}, - data_types::{Amount, ApplicationPermissions, ArithmeticError, BlockHeight, Timestamp}, + data_types::{Amount, ApplicationPermissions, Timestamp}, identifiers::{AccountOwner, ChainId, MessageId}, ownership::ChainOwnership, }; @@ -20,7 +20,6 @@ use linera_client::{ config::GenesisConfig, }; use linera_core::data_types::ClientOutcome; -use linera_execution::SystemMessage; use linera_storage::{Clock as _, Storage}; use serde::Deserialize; use tower_http::cors::CorsLayer; @@ -43,15 +42,14 @@ mod tests; pub struct QueryRoot { context: Arc>, genesis_config: Arc, - chain_id: Arc>, + chain_id: ChainId, } /// The root GraphQL mutation type. pub struct MutationRoot { - chain_id: Arc>, + chain_id: ChainId, context: Arc>, amount: Amount, - end_block_height: BlockHeight, end_timestamp: Timestamp, start_timestamp: Timestamp, start_balance: Amount, @@ -91,8 +89,7 @@ where /// Returns the current committee's validators. async fn current_validators(&self) -> Result, Error> { - let chain_id = *self.chain_id.lock().await; - let client = self.context.lock().await.make_chain_client(chain_id)?; + let client = self.context.lock().await.make_chain_client(self.chain_id)?; let committee = client.local_committee().await?; Ok(committee .validators() @@ -121,8 +118,7 @@ where C: ClientContext, { async fn do_claim(&self, owner: AccountOwner) -> Result { - let chain_id = *self.chain_id.lock().await; - let client = self.context.lock().await.make_chain_client(chain_id)?; + let client = self.context.lock().await.make_chain_client(self.chain_id)?; if self.start_timestamp < self.end_timestamp { let local_time = client.storage_client().clock().current_time(); @@ -153,32 +149,16 @@ where .open_chain(ownership, ApplicationPermissions::default(), self.amount) .await; self.context.lock().await.update_wallet(&client).await?; - let (message_id, certificate) = result?.try_unwrap()?; - - if client.next_block_height() >= self.end_block_height { - let key_pair = client.key_pair().await?; - let balance = client.local_balance().await?.try_sub(Amount::ONE)?; - let ownership = client.chain_state_view().await?.ownership().clone(); - let (message_id, certificate) = client - .open_chain(ownership, ApplicationPermissions::default(), balance) - .await? - .try_unwrap()?; - // TODO(#1795): Move the remaining tokens to the new chain. - client.close_chain().await?.try_unwrap()?; - let chain_id = ChainId::child(message_id); - info!("Switching to a new faucet chain {chain_id:8}; remaining balance: {balance}"); - self.context - .lock() - .await - .update_wallet_for_new_chain( - chain_id, - Some(key_pair), - certificate.block().header.timestamp, - ) - .await?; - *self.chain_id.lock().await = chain_id; - } - + let (message_id, certificate) = match result? { + ClientOutcome::Committed(result) => result, + ClientOutcome::WaitForTimeout(timeout) => { + return Err(Error::new(format!( + "This faucet is using a multi-owner chain and is not the leader right now. \ + Try again at {}", + timeout.timestamp, + ))); + } + }; let chain_id = ChainId::child(message_id); Ok(ClaimOutcome { message_id, @@ -205,7 +185,7 @@ pub struct FaucetService where C: ClientContext, { - chain_id: Arc>, + chain_id: ChainId, context: Arc>, genesis_config: Arc, config: ChainListenerConfig, @@ -213,7 +193,6 @@ where port: NonZeroU16, amount: Amount, end_timestamp: Timestamp, - end_block_height: BlockHeight, start_timestamp: Timestamp, start_balance: Amount, } @@ -224,14 +203,13 @@ where { fn clone(&self) -> Self { Self { - chain_id: self.chain_id.clone(), + chain_id: self.chain_id, context: Arc::clone(&self.context), genesis_config: Arc::clone(&self.genesis_config), config: self.config.clone(), storage: self.storage.clone(), port: self.port, amount: self.amount, - end_block_height: self.end_block_height, end_timestamp: self.end_timestamp, start_timestamp: self.start_timestamp, start_balance: self.start_balance, @@ -250,7 +228,6 @@ where chain_id: ChainId, context: C, amount: Amount, - end_block_height: BlockHeight, end_timestamp: Timestamp, genesis_config: Arc, config: ChainListenerConfig, @@ -262,14 +239,13 @@ where client.process_inbox().await?; let start_balance = client.local_balance().await?; Ok(Self { - chain_id: Arc::new(Mutex::new(chain_id)), + chain_id, context, genesis_config, config, storage, port, amount, - end_block_height, end_timestamp, start_timestamp, start_balance, @@ -278,10 +254,9 @@ where pub fn schema(&self) -> Schema, MutationRoot, EmptySubscription> { let mutation_root = MutationRoot { - chain_id: self.chain_id.clone(), + chain_id: self.chain_id, context: Arc::clone(&self.context), amount: self.amount, - end_block_height: self.end_block_height, end_timestamp: self.end_timestamp, start_timestamp: self.start_timestamp, start_balance: self.start_balance, @@ -289,7 +264,7 @@ where let query_root = QueryRoot { genesis_config: Arc::clone(&self.genesis_config), context: Arc::clone(&self.context), - chain_id: self.chain_id.clone(), + chain_id: self.chain_id, }; Schema::build(query_root, mutation_root, EmptySubscription).finish() } @@ -297,8 +272,6 @@ where /// Runs the faucet. #[tracing::instrument(name = "FaucetService::run", skip_all, fields(port = self.port, chain_id = ?self.chain_id))] pub async fn run(self) -> anyhow::Result<()> { - self.find_current_chain().await?; - let port = self.port.get(); let index_handler = axum::routing::get(graphiql).post(Self::index_handler); @@ -329,74 +302,4 @@ where let schema = service.0.schema(); schema.execute(request.into_inner()).await.into() } - - /// Finds the current chain ID, even if the configured chain has been closed and the tokens - /// moved to a new one. - async fn find_current_chain(&self) -> anyhow::Result<()> { - let mut chain_id = *self.chain_id.lock().await; - let mut client = self.context.lock().await.make_chain_client(chain_id)?; - client.synchronize_from_validators().await?; - loop { - let chain = client.chain_state_view().await?; - if !chain.execution_state.system.closed.get() { - break; // This is the current chain; it has not been closed yet. - } - // The faucet closes each chain in the last block; the next-to-last block opens the - // new chain. - let index = chain - .confirmed_log - .count() - .checked_sub(2) - .ok_or(ArithmeticError::Underflow)?; - let hash = chain - .confirmed_log - .get(index) - .await? - .ok_or_else(|| anyhow::anyhow!("Missing confirmed_log entry"))?; - let certificate = client.storage_client().read_certificate(hash).await?; - chain_id = certificate - .block() - .messages() - .iter() - .flatten() - .find_map(|message| { - if let linera_execution::Message::System(SystemMessage::OpenChain(_)) = - &message.message - { - Some(message.destination.recipient()?) - } else { - None - } - }) - .ok_or_else(|| anyhow::anyhow!("No OpenChain message found"))?; - client = self.context.lock().await.make_chain_client(chain_id)?; - client.synchronize_from_validators().await?; - } - *self.chain_id.lock().await = chain_id; - Ok(()) - } -} - -trait ClientOutcomeExt { - type Output; - - /// Returns the committed result or an error if we are not the leader. - /// - /// It is recommended to use single-owner chains for the faucet to avoid this error. - fn try_unwrap(self) -> Result; -} - -impl ClientOutcomeExt for ClientOutcome { - type Output = T; - - fn try_unwrap(self) -> Result { - match self { - ClientOutcome::Committed(result) => Ok(result), - ClientOutcome::WaitForTimeout(timeout) => Err(Error::new(format!( - "This faucet is using a multi-owner chain and is not the leader right now. \ - Try again at {}", - timeout.timestamp, - ))), - } - } } diff --git a/linera-faucet/server/src/tests.rs b/linera-faucet/server/src/tests.rs index ed682df0a3ef..b4c007cee53c 100644 --- a/linera-faucet/server/src/tests.rs +++ b/linera-faucet/server/src/tests.rs @@ -9,7 +9,7 @@ use async_trait::async_trait; use futures::lock::Mutex; use linera_base::{ crypto::{AccountPublicKey, AccountSecretKey}, - data_types::{Amount, BlockHeight, Timestamp}, + data_types::{Amount, Timestamp}, identifiers::ChainId, }; use linera_client::{chain_listener, wallet::Wallet}; @@ -83,10 +83,9 @@ async fn test_faucet_rate_limiting() { }; let context = Arc::new(Mutex::new(context)); let root = MutationRoot { - chain_id: Arc::new(Mutex::new(chain_id)), + chain_id, context: context.clone(), amount: Amount::from_tokens(1), - end_block_height: BlockHeight::from(10), end_timestamp: Timestamp::from(6000), start_timestamp: Timestamp::from(0), start_balance: Amount::from_tokens(6), diff --git a/linera-service/src/cli_wrappers/wallet.rs b/linera-service/src/cli_wrappers/wallet.rs index 7597fba33ead..eaac0b0a569a 100644 --- a/linera-service/src/cli_wrappers/wallet.rs +++ b/linera-service/src/cli_wrappers/wallet.rs @@ -517,22 +517,15 @@ impl ClientWrapper { port: impl Into>, chain_id: ChainId, amount: Amount, - max_chain_length: Option, ) -> Result { let port = port.into().unwrap_or(8080); let mut command = self.command().await?; - command + let child = command .arg("faucet") .arg(chain_id.to_string()) .args(["--port".to_string(), port.to_string()]) - .args(["--amount".to_string(), amount.to_string()]); - if let Some(max_chain_length) = max_chain_length { - command.args([ - "--max-chain-length".to_string(), - max_chain_length.to_string(), - ]); - } - let child = command.spawn_into()?; + .args(["--amount".to_string(), amount.to_string()]) + .spawn_into()?; let client = reqwest_client(); for i in 0..10 { linera_base::time::timer::sleep(Duration::from_secs(i)).await; diff --git a/linera-service/src/linera/command.rs b/linera-service/src/linera/command.rs index 74f8c733e726..326fc9ccd93f 100644 --- a/linera-service/src/linera/command.rs +++ b/linera-service/src/linera/command.rs @@ -614,10 +614,6 @@ pub enum ClientCommand { #[arg(long)] limit_rate_until: Option>, - /// The maximum number of blocks in the faucet chain, before a new one is created. - #[arg(long, default_value = "500")] - max_chain_length: u64, - /// Configuration for the faucet chain listener. #[command(flatten)] config: ChainListenerConfig, diff --git a/linera-service/src/linera/main.rs b/linera-service/src/linera/main.rs index 972a811ef80a..3b81a35869f0 100644 --- a/linera-service/src/linera/main.rs +++ b/linera-service/src/linera/main.rs @@ -22,7 +22,7 @@ use command::{ClientCommand, DatabaseToolCommand, NetCommand, ProjectCommand, Wa use futures::{lock::Mutex, FutureExt as _, StreamExt}; use linera_base::{ crypto::{AccountSecretKey, CryptoHash, CryptoRng, Ed25519SecretKey}, - data_types::{ApplicationPermissions, BlockHeight, Timestamp}, + data_types::{ApplicationPermissions, Timestamp}, identifiers::{AccountOwner, ChainDescription, ChainId}, ownership::ChainOwnership, }; @@ -849,7 +849,6 @@ impl Runnable for Job { port, amount, limit_rate_until, - max_chain_length, config, } => { let chain_id = chain_id.unwrap_or_else(|| context.default_chain()); @@ -867,7 +866,6 @@ impl Runnable for Job { chain_id, context, amount, - BlockHeight(max_chain_length), end_timestamp, genesis_config, config, diff --git a/linera-service/src/linera/net_up_utils.rs b/linera-service/src/linera/net_up_utils.rs index 1a2a933e6426..25744bea84e8 100644 --- a/linera-service/src/linera/net_up_utils.rs +++ b/linera-service/src/linera/net_up_utils.rs @@ -290,7 +290,7 @@ async fn print_messages_and_create_faucet( ChainId::root(1) }; let service = client - .run_faucet(Some(faucet_port.into()), faucet_chain, faucet_amount, None) + .run_faucet(Some(faucet_port.into()), faucet_chain, faucet_amount) .await?; Some(service) } else { diff --git a/linera-service/tests/linera_net_tests.rs b/linera-service/tests/linera_net_tests.rs index 594ceb71f1c8..0c22bee42beb 100644 --- a/linera-service/tests/linera_net_tests.rs +++ b/linera-service/tests/linera_net_tests.rs @@ -2862,7 +2862,7 @@ async fn test_end_to_end_faucet(config: impl LineraNetConfig) -> Result<()> { let owner2 = client2.keygen().await?; let mut faucet_service = client1 - .run_faucet(None, chain1, Amount::from_tokens(2), None) + .run_faucet(None, chain1, Amount::from_tokens(2)) .await?; let faucet = faucet_service.instance(); let outcome = faucet.claim(&owner2).await?; @@ -2955,59 +2955,28 @@ async fn test_end_to_end_faucet_with_long_chains(config: impl LineraNetConfig) - } let amount = Amount::ONE; - let mut faucet_service = faucet_client - .run_faucet(None, faucet_chain, amount, Some(chain_count as u64)) - .await?; + let mut faucet_service = faucet_client.run_faucet(None, faucet_chain, amount).await?; let faucet = faucet_service.instance(); // Create a new wallet using the faucet - let client1 = net.make_client().await; - let (outcome1, _) = client1 - .wallet_init(&[], FaucetOption::NewChain(&faucet)) - .await? - .unwrap(); - - // Create a new wallet using the faucet - let client2 = net.make_client().await; - let (outcome2, _) = client2 - .wallet_init(&[], FaucetOption::NewChain(&faucet)) - .await? - .unwrap(); - - // Since the faucet chain exceeds the configured maximum length, the faucet should have - // switched after the first new chain. - assert_ne!(outcome1.message_id.chain_id, outcome2.message_id.chain_id); - - faucet_service.ensure_is_running()?; - faucet_service.terminate().await?; - - let mut faucet_service = faucet_client - .run_faucet(None, faucet_chain, amount, Some(chain_count as u64)) - .await?; - - // Create a new wallet using the faucet - let client3 = net.make_client().await; - let (outcome3, _) = client3 + let client = net.make_client().await; + let (outcome, _) = client .wallet_init(&[], FaucetOption::NewChain(&faucet)) .await? .unwrap(); - // After restarting, the faucet found its second chain, even though it was not initialized - // with it. - assert_eq!(outcome2.message_id.chain_id, outcome3.message_id.chain_id); + let chain = outcome.chain_id; + assert_eq!(chain, client.load_wallet()?.default_chain().unwrap()); - let chain = outcome3.chain_id; - assert_eq!(chain, client3.load_wallet()?.default_chain().unwrap()); - - let initial_balance = client3.query_balance(Account::chain(chain)).await?; + let initial_balance = client.query_balance(Account::chain(chain)).await?; let fees_paid = amount - initial_balance; assert!(initial_balance > Amount::ZERO); - client3 + client .transfer(initial_balance - fees_paid, chain, faucet_chain) .await?; - let final_balance = client3.query_balance(Account::chain(chain)).await?; + let final_balance = client.query_balance(Account::chain(chain)).await?; assert_eq!(final_balance, Amount::ZERO); faucet_service.ensure_is_running()?; @@ -3038,7 +3007,7 @@ async fn test_end_to_end_fungible_client_benchmark(config: impl LineraNetConfig) let chain1 = client1.load_wallet()?.default_chain().unwrap(); - let mut faucet_service = client1.run_faucet(None, chain1, Amount::ONE, None).await?; + let mut faucet_service = client1.run_faucet(None, chain1, Amount::ONE).await?; let faucet = faucet_service.instance(); let path = diff --git a/linera-service/tests/local_net_tests.rs b/linera-service/tests/local_net_tests.rs index ec60d13d4e09..ae9bfa23ca54 100644 --- a/linera-service/tests/local_net_tests.rs +++ b/linera-service/tests/local_net_tests.rs @@ -70,7 +70,7 @@ async fn test_end_to_end_reconfiguration(config: LocalNetConfig) -> Result<()> { .await?; let mut faucet_service = faucet_client - .run_faucet(None, faucet_chain, Amount::from_tokens(2), None) + .run_faucet(None, faucet_chain, Amount::from_tokens(2)) .await?; faucet_service.ensure_is_running()?; @@ -247,7 +247,7 @@ async fn test_end_to_end_receipt_of_old_create_committee_messages( if matches!(network, Network::Grpc) { let mut faucet_service = faucet_client - .run_faucet(None, faucet_chain, Amount::from_tokens(2), None) + .run_faucet(None, faucet_chain, Amount::from_tokens(2)) .await?; faucet_service.ensure_is_running()?; @@ -281,7 +281,7 @@ async fn test_end_to_end_receipt_of_old_create_committee_messages( faucet_client.process_inbox(faucet_chain).await?; let mut faucet_service = faucet_client - .run_faucet(None, faucet_chain, Amount::from_tokens(2), None) + .run_faucet(None, faucet_chain, Amount::from_tokens(2)) .await?; faucet_service.ensure_is_running()?; @@ -339,7 +339,7 @@ async fn test_end_to_end_receipt_of_old_remove_committee_messages( if matches!(network, Network::Grpc) { let mut faucet_service = faucet_client - .run_faucet(None, faucet_chain, Amount::from_tokens(2), None) + .run_faucet(None, faucet_chain, Amount::from_tokens(2)) .await?; faucet_service.ensure_is_running()?; @@ -375,7 +375,7 @@ async fn test_end_to_end_receipt_of_old_remove_committee_messages( if matches!(network, Network::Grpc) { let mut faucet_service = faucet_client - .run_faucet(None, faucet_chain, Amount::from_tokens(2), None) + .run_faucet(None, faucet_chain, Amount::from_tokens(2)) .await?; faucet_service.ensure_is_running()?; @@ -411,7 +411,7 @@ async fn test_end_to_end_receipt_of_old_remove_committee_messages( faucet_client.process_inbox(faucet_chain).await?; let mut faucet_service = faucet_client - .run_faucet(None, faucet_chain, Amount::from_tokens(2), None) + .run_faucet(None, faucet_chain, Amount::from_tokens(2)) .await?; faucet_service.ensure_is_running()?;