use std::path::PathBuf;
use anyhow::Error;
use linera_client::{client_context::ClientContext, config::GenesisConfig};
use linera_execution::WithWasmDefault as _;
use linera_service::{
cli::{command::ClientCommand, common_options::CommonCliOptions},
storage::{Runnable, RunnableWithStore, StorageConfig},
Wallet,
};
use tracing::debug;
#[derive(Clone, clap::Parser)]
#[command(
name = "linera",
version = linera_version::VersionInfo::default_clap_str(),
about = "Client implementation and command-line tool for the Linera blockchain",
)]
pub struct Options {
#[command(flatten)]
pub client_options: linera_client::Options,
#[command(flatten)]
pub common: CommonCliOptions,
#[arg(long)]
pub chrome_trace_exporter: bool,
#[arg(long, env = "LINERA_CHROME_TRACE_FILE")]
pub chrome_trace_file: Option<String>,
#[arg(long, env = "LINERA_OTLP_EXPORTER_ENDPOINT")]
pub otlp_exporter_endpoint: Option<String>,
#[cfg(feature = "jemalloc")]
#[arg(long, env = "LINERA_ENABLE_MEMORY_PROFILING")]
pub enable_memory_profiling: bool,
#[command(subcommand)]
pub command: ClientCommand,
}
impl Options {
pub fn init() -> Self {
<Options as clap::Parser>::parse()
}
pub fn enable_memory_profiling(&self) -> bool {
#[cfg(feature = "jemalloc")]
{
self.enable_memory_profiling
}
#[cfg(not(feature = "jemalloc"))]
{
false
}
}
pub async fn create_client_context<S, Si>(
&self,
storage: S,
wallet: Wallet,
signer: Si,
) -> anyhow::Result<
ClientContext<linera_core::environment::Impl<S, linera_rpc::NodeProvider, Si, Wallet>>,
>
where
S: linera_core::environment::Storage,
Si: linera_core::environment::Signer,
{
let genesis_config = wallet.genesis_config().clone();
let default_chain = wallet.default_chain();
Ok(ClientContext::new(
storage,
wallet,
signer,
&self.client_options,
default_chain,
genesis_config,
self.common.common_storage_options.block_cache_size,
self.common
.common_storage_options
.execution_state_cache_size,
)
.await?)
}
pub async fn run_with_storage<R: Runnable>(&self, job: R) -> Result<R::Output, Error> {
let storage_config = self.storage_config()?;
debug!("Running command using storage configuration: {storage_config}");
let store_config =
storage_config.add_common_storage_options(&self.common.common_storage_options)?;
let cache_sizes = self.common.common_storage_options.storage_cache_sizes();
let output = Box::pin(store_config.run_with_storage(
self.common.wasm_runtime.with_wasm_default(),
self.common.application_logs,
cache_sizes,
job,
))
.await?;
Ok(output)
}
pub async fn run_with_store<R: RunnableWithStore>(
&self,
assert_storage_v1: bool,
need_migration: bool,
job: R,
) -> Result<R::Output, Error> {
let storage_config = self.storage_config()?;
debug!("Running command using storage configuration: {storage_config}");
let store_config =
storage_config.add_common_storage_options(&self.common.common_storage_options)?;
let cache_sizes = self.common.common_storage_options.storage_cache_sizes();
if assert_storage_v1 {
store_config
.clone()
.run_with_store(cache_sizes, crate::AssertStorageV1)
.await?;
}
if need_migration {
store_config
.clone()
.run_with_store(cache_sizes, crate::StorageMigration)
.await?;
}
let output = Box::pin(store_config.run_with_store(cache_sizes, job)).await?;
Ok(output)
}
pub async fn initialize_storage(&self) -> Result<(), Error> {
let storage_config = self.storage_config()?;
debug!("Initializing storage using configuration: {storage_config}");
let store_config =
storage_config.add_common_storage_options(&self.common.common_storage_options)?;
let wallet = self.wallet()?;
let cache_sizes = self.common.common_storage_options.storage_cache_sizes();
linera_service::storage::initialize(store_config, cache_sizes, wallet.genesis_config())
.await?;
Ok(())
}
fn storage_config(&self) -> Result<StorageConfig, Error> {
self.common.storage_config()
}
pub fn wallet_path(&self) -> Result<PathBuf, Error> {
self.common.wallet_path()
}
pub fn wallet(&self) -> Result<Wallet, Error> {
self.common.wallet()
}
pub fn keystore(&self) -> Result<linera_wallet_json::Keystore, Error> {
self.common.keystore()
}
pub fn create_wallet(&self, genesis_config: GenesisConfig) -> Result<Wallet, Error> {
self.common.create_wallet(genesis_config)
}
pub fn create_keystore(
&self,
testing_prng_seed: Option<u64>,
) -> Result<linera_wallet_json::Keystore, Error> {
self.common.create_keystore(testing_prng_seed)
}
}