diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index b4416f9..55b7d77 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -3,13 +3,10 @@ on: pull_request: branches: - '**' - concurrency: group: "integration-tests" cancel-in-progress: true - permissions: read-all - jobs: integration-tests: name: Setup Toolchain and Test diff --git a/.github/workflows/update-cachix.yml b/.github/workflows/update-cachix.yml index d90049c..47f5111 100644 --- a/.github/workflows/update-cachix.yml +++ b/.github/workflows/update-cachix.yml @@ -2,7 +2,6 @@ # # substituter: https://bonsol.cachix.org # public-key: bonsol.cachix.org-1:yz7vi1rCPW1BpqoszdJvf08HZxQ/5gPTPxft4NnT74A= - name: Update Cachix on: push: @@ -22,22 +21,18 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 - - name: Install Nix uses: DeterminateSystems/nix-installer-action@main with: extra-conf: | extra-substituters = https://bonsol.cachix.org extra-trusted-public-keys = bonsol.cachix.org-1:yz7vi1rCPW1BpqoszdJvf08HZxQ/5gPTPxft4NnT74A= - - name: Install and configure Cachix uses: cachix/cachix-action@v15 with: name: bonsol authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' - - name: Run nix flake check run: nix flake check - - name: Enter development shell run: nix develop diff --git a/CHANGELOG.md b/CHANGELOG.md index b6848b1..18995ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Changed * `bonsol` cli option requirements and error messages updated for added clarity +* **Breaking**: `bonsol deploy` cli subcommand requirements updated. Please refer to the docs, or use `bonsol deploy --help` for more info. ### Added * `bonsol estimate` for estimating execution cost of bonsol programs. diff --git a/charts/templates/deployment-tester.yaml b/charts/templates/deployment-tester.yaml index a344623..7aa9b22 100644 --- a/charts/templates/deployment-tester.yaml +++ b/charts/templates/deployment-tester.yaml @@ -59,7 +59,7 @@ spec: - -c - | solana config set --keypair {{ .Values.signer.path }} -u $RPC_ENDPOINT - bonsol deploy -y -m {{ include "bonsol-tester.manifestPath" . }} -t url --url $SIMPLE_IMAGE + bonsol deploy url -y -m {{ include "bonsol-tester.manifestPath" . }} --url $SIMPLE_IMAGE while : do date '+%Y/%m/%d %H:%M:%S' diff --git a/cli/README.md b/cli/README.md index 36c93f1..2e1e4df 100644 --- a/cli/README.md +++ b/cli/README.md @@ -43,12 +43,12 @@ The output of the build command is a manifest.json file which is placed in the r You can deploy a bonsol program with the following command ``` -bonsol -k ./keypair.json -u http://localhost:8899 deploy -m {path to manifest.json} -y {auto confirm} -t {s3|shadow-drive|url} ... {upload type specific options} +bonsol -k ./keypair.json -u http://localhost:8899 deploy {s3|shadow-drive|url} -m {path to manifest.json} -y {auto confirm} ... {upload type specific options} ``` There will be many options for how to upload the program, the default is s3. Here is an example of how to deploy a program to s3 ``` -bonsol -k ./keypair.json -u http://localhost:8899 deploy -m program/manifest.json -t s3 --bucket bonsol-public-images --region us-east-1 --access-key {your key} --secret-key {your secret key} +bonsol -k ./keypair.json -u http://localhost:8899 deploy s3 -m program/manifest.json --bucket bonsol-public-images --region us-east-1 --access-key {your key} --secret-key {your secret key} ``` In the above example the manifest.json file is the file that was created by the build command. This will try to upload the binary to the s3 bucket and create a deployment account for the program. Programs are indexed by the image id, which is a kind of checksum of the program elf file. This means that if you change the elf file, the image id will change and the program will be deployed again under a new deployment account. Programs are immutable and can only be changed by redeploying the program. When a node downloads a program it will check the image id and if it doesnt match the deployment account it will reject the program. Furthermore when bonsol checks the proof, it will check the image id and if it doesnt match the deployment account and desired image id from execution request it will reject the proof. diff --git a/cli/src/command.rs b/cli/src/command.rs index 7ff85a2..3cc33af 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -1,4 +1,4 @@ -use clap::{command, ArgGroup, Args, Parser, Subcommand, ValueEnum}; +use clap::{command, ArgGroup, Args, Parser, Subcommand}; #[derive(Parser, Debug)] #[command(version)] @@ -39,29 +39,6 @@ pub struct BonsolCli { pub command: Command, } -pub struct ParsedBonsolCli { - pub config: Option, - - pub keypair: Option, - - pub rpc_url: Option, - - pub command: ParsedCommand, -} - -impl TryFrom for ParsedBonsolCli { - type Error = anyhow::Error; - - fn try_from(value: BonsolCli) -> Result { - Ok(Self { - config: value.config, - keypair: value.keypair, - rpc_url: value.rpc_url, - command: value.command.try_into()?, - }) - } -} - #[derive(Debug, Clone, Args)] pub struct S3UploadArgs { #[arg( @@ -108,6 +85,9 @@ pub struct S3UploadArgs { env = "AWS_S3_ENDPOINT" )] pub endpoint: Option, + + #[command(flatten)] + pub shared_args: SharedDeployArgs, } #[derive(Debug, Clone, Args)] @@ -139,63 +119,58 @@ pub struct ShadowDriveUploadArgs { #[arg(help = "Create a new Shadow Drive storage account", long)] pub create: bool, + + #[command(flatten)] + pub shared_args: SharedDeployArgs, } #[derive(Debug, Clone, Args)] pub struct UrlUploadArgs { #[arg(help = "Specify a URL endpoint to deploy to", long, required = true)] pub url: String, -} -#[derive(Debug, Clone, ValueEnum)] -pub enum DeployType { - S3, - ShadowDrive, - Url, + #[command(flatten)] + pub shared_args: SharedDeployArgs, } -#[derive(Debug, Clone)] -pub enum DeployDestination { +#[derive(Debug, Clone, Subcommand)] +pub enum DeployArgs { + #[command(about = "Deploy a program using an AWS S3 bucket")] S3(S3UploadArgs), + + #[command(about = "Deploy a program using ShadowDrive")] ShadowDrive(ShadowDriveUploadArgs), + + #[command(about = "Deploy a program manually with a URL")] Url(UrlUploadArgs), } -impl DeployDestination { - pub fn try_parse( - deploy_type: DeployType, - s3: Option, - sd: Option, - url: Option, - ) -> anyhow::Result { - match deploy_type { - // Because we are not supporting a direct mapping (eg, subcommand), - // it's possible for a user to specify a deployment type and provide the wrong - // arguments. If we support subcommands in the future this will be - // much clearer, otherwise we would need to do more validation here - // to provide better error messages when the wrong args are present. - DeployType::S3 if s3.is_some() => Ok(Self::S3(s3.unwrap())), - DeployType::ShadowDrive if sd.is_some() => Ok(Self::ShadowDrive(sd.unwrap())), - DeployType::Url if url.is_some() => Ok(Self::Url(url.unwrap())), - _ => anyhow::bail!("The deployment type and its corresponding args do not match, expected args for deployment type '{:?}'", deploy_type), + +impl DeployArgs { + pub fn shared_args(&self) -> SharedDeployArgs { + match self { + Self::S3(s3) => s3.shared_args.clone(), + Self::ShadowDrive(sd) => sd.shared_args.clone(), + Self::Url(url) => url.shared_args.clone(), } } } -#[derive(Debug, Clone)] -pub struct DeployArgs { - pub dest: DeployDestination, +#[derive(Debug, Clone, Args)] +pub struct SharedDeployArgs { + #[arg( + help = "The path to the program's manifest file (manifest.json)", + short = 'm', + long + )] pub manifest_path: String, + + #[arg( + help = "Whether to automatically confirm deployment", + short = 'y', + long + )] pub auto_confirm: bool, } -impl DeployArgs { - pub fn parse(dest: DeployDestination, manifest_path: String, auto_confirm: bool) -> Self { - Self { - dest, - manifest_path, - auto_confirm, - } - } -} #[derive(Subcommand, Debug)] pub enum Command { @@ -203,38 +178,10 @@ pub enum Command { about = "Deploy a program with various storage options, such as S3, ShadowDrive, or manually with a URL" )] Deploy { - #[arg( - help = "Specify the deployment type", - short = 't', - long, - value_enum, - required = true - )] - deploy_type: DeployType, - - #[command(flatten)] - s3: Option, - - #[command(flatten)] - shadow_drive: Option, - - #[command(flatten)] - url: Option, - - #[arg( - help = "The path to the program's manifest file (manifest.json)", - short = 'm', - long - )] - manifest_path: String, - - #[arg( - help = "Whether to automatically confirm deployment", - short = 'y', - long - )] - auto_confirm: bool, + #[clap(subcommand)] + deploy_args: DeployArgs, }, + #[command(about = "Build a ZK program")] Build { #[arg( @@ -244,6 +191,7 @@ pub enum Command { )] zk_program_path: String, }, + #[command(about = "Estimate the execution cost of a ZK RISC0 program")] Estimate { #[arg( @@ -263,6 +211,7 @@ pub enum Command { )] max_cycles: Option, }, + Execute { #[arg(short = 'f', long)] execution_request_file: Option, @@ -280,17 +229,18 @@ pub enum Command { #[arg(short = 'm', long)] tip: Option, - #[arg(short = 'i')] - input_file: Option, // overrides inputs in execution request file + #[arg(short = 'i', long, help = "override inputs in execution request file")] + input_file: Option, /// wait for execution to be proven - #[arg(short = 'w', long)] + #[arg(short = 'w', long, help = "wait for execution to be proven")] wait: bool, /// timeout in seconds - #[arg(short = 't', long)] + #[arg(short = 't', long, help = "timeout in seconds")] timeout: Option, }, + Prove { #[arg(short = 'm', long)] manifest_path: Option, @@ -307,6 +257,8 @@ pub enum Command { #[arg(short = 'o')] output_location: Option, }, + + #[command(about = "Initialize a new project")] Init { #[arg(short = 'd', long)] dir: Option, @@ -315,117 +267,3 @@ pub enum Command { project_name: String, }, } - -#[derive(Debug)] -pub enum ParsedCommand { - Deploy { - deploy_args: DeployArgs, - }, - Build { - zk_program_path: String, - }, - Estimate { - manifest_path: String, - input_file: Option, - max_cycles: Option, - }, - Execute { - execution_request_file: Option, - - program_id: Option, - - execution_id: Option, - - expiry: Option, - - tip: Option, - - input_file: Option, - - wait: bool, - - timeout: Option, - }, - Prove { - manifest_path: Option, - - program_id: Option, - - input_file: Option, - - execution_id: String, - - output_location: Option, - }, - Init { - dir: Option, - - project_name: String, - }, -} - -impl TryFrom for ParsedCommand { - type Error = anyhow::Error; - - fn try_from(value: Command) -> Result { - match value { - Command::Deploy { - deploy_type, - s3, - shadow_drive, - url, - manifest_path, - auto_confirm, - } => Ok(ParsedCommand::Deploy { - deploy_args: DeployArgs::parse( - DeployDestination::try_parse(deploy_type, s3, shadow_drive, url)?, - manifest_path, - auto_confirm, - ), - }), - Command::Build { zk_program_path } => Ok(ParsedCommand::Build { zk_program_path }), - Command::Estimate { - manifest_path, - input_file, - max_cycles, - } => Ok(ParsedCommand::Estimate { - manifest_path, - input_file, - max_cycles, - }), - Command::Execute { - execution_request_file, - program_id, - execution_id, - expiry, - tip, - input_file, - wait, - timeout, - } => Ok(ParsedCommand::Execute { - execution_request_file, - program_id, - execution_id, - expiry, - tip, - input_file, - wait, - timeout, - }), - Command::Prove { - manifest_path, - program_id, - input_file, - execution_id, - output_location, - } => Ok(ParsedCommand::Prove { - manifest_path, - program_id, - input_file, - execution_id, - output_location, - }), - Command::Init { dir, project_name } => Ok(ParsedCommand::Init { dir, project_name }), - } - } -} diff --git a/cli/src/common.rs b/cli/src/common.rs index 625726e..67dc2e1 100644 --- a/cli/src/common.rs +++ b/cli/src/common.rs @@ -215,6 +215,26 @@ pub(crate) fn try_load_from_config(config: Option) -> anyhow::Result<(St Ok((config.json_rpc_url, config.keypair_path)) } +pub(crate) fn load_solana_config( + config: Option, + rpc_url: Option, + keypair: Option, +) -> anyhow::Result<(String, solana_sdk::signer::keypair::Keypair)> { + let (rpc_url, keypair_file) = match rpc_url.zip(keypair) { + Some(config) => config, + None => try_load_from_config(config)?, + }; + Ok(( + rpc_url, + solana_sdk::signature::read_keypair_file(std::path::Path::new(&keypair_file)).map_err( + |err| BonsolCliError::FailedToReadKeypair { + file: keypair_file, + err: format!("{err:?}"), + }, + )?, + )) +} + pub async fn sol_check(rpc_client: String, pubkey: Pubkey) -> bool { let rpc_client = rpc_client::RpcClient::new(rpc_client); if let Ok(account) = rpc_client.get_account(&pubkey).await { diff --git a/cli/src/deploy.rs b/cli/src/deploy.rs index 7d0981b..54b471c 100644 --- a/cli/src/deploy.rs +++ b/cli/src/deploy.rs @@ -15,18 +15,17 @@ use solana_sdk::commitment_config::CommitmentConfig; use solana_sdk::pubkey::Pubkey; use solana_sdk::signature::read_keypair_file; -use crate::command::{DeployArgs, DeployDestination, S3UploadArgs, ShadowDriveUploadArgs}; +use crate::command::{DeployArgs, S3UploadArgs, ShadowDriveUploadArgs, SharedDeployArgs}; use crate::common::ZkProgramManifest; use crate::error::{BonsolCliError, S3ClientError, ShadowDriveClientError, ZkManifestError}; pub async fn deploy(rpc_url: String, signer: Keypair, deploy_args: DeployArgs) -> Result<()> { let bar = ProgressBar::new_spinner(); let rpc_client = RpcClient::new_with_commitment(rpc_url.clone(), CommitmentConfig::confirmed()); - let DeployArgs { - dest, + let SharedDeployArgs { manifest_path, auto_confirm, - } = deploy_args; + } = deploy_args.shared_args(); let manifest_file = File::open(Path::new(&manifest_path)).map_err(|err| { BonsolCliError::ZkManifestError(ZkManifestError::FailedToOpen { @@ -46,8 +45,8 @@ pub async fn deploy(rpc_url: String, signer: Keypair, deploy_args: DeployArgs) - err, }) })?; - let url: String = match dest { - DeployDestination::S3(s3_upload) => { + let url: String = match deploy_args { + DeployArgs::S3(s3_upload) => { let S3UploadArgs { bucket, access_key, @@ -58,10 +57,12 @@ pub async fn deploy(rpc_url: String, signer: Keypair, deploy_args: DeployArgs) - } = s3_upload; let dest = - object_store::path::Path::from(format!("{}-{}", manifest.name, manifest.image_id)); + object_store::path::Path::from(format!("{}-{}", manifest.name, manifest.image_id)); - let url = endpoint.unwrap_or( - format!("https://{}.s3.{}.amazonaws.com/{}", bucket, region, dest)); + let url = endpoint.unwrap_or(format!( + "https://{}.s3.{}.amazonaws.com/{}", + bucket, region, dest + )); let s3_client = AmazonS3Builder::new() .with_bucket_name(&bucket) @@ -102,7 +103,7 @@ pub async fn deploy(rpc_url: String, signer: Keypair, deploy_args: DeployArgs) - println!("Uploaded to S3 url {}", url); url } - DeployDestination::ShadowDrive(shadow_drive_upload) => { + DeployArgs::ShadowDrive(shadow_drive_upload) => { let ShadowDriveUploadArgs { storage_account, storage_account_size_mb, @@ -198,7 +199,7 @@ pub async fn deploy(rpc_url: String, signer: Keypair, deploy_args: DeployArgs) - println!("Uploaded to shadow drive"); resp.message } - DeployDestination::Url(url_upload) => { + DeployArgs::Url(url_upload) => { let req = reqwest::get(&url_upload.url).await?; let bytes = req.bytes().await?; if bytes != loaded_binary { diff --git a/cli/src/error.rs b/cli/src/error.rs index 345d709..053a0c0 100644 --- a/cli/src/error.rs +++ b/cli/src/error.rs @@ -21,7 +21,7 @@ pub enum BonsolCliError { FailedToReadKeypair { file: String, err: String }, #[error("Account '{0}' does not have any SOL to pay for the transaction(s)")] - InsufficientFundsForTransactions(String), + InsufficientFunds(String), #[error(transparent)] ZkManifestError(#[from] ZkManifestError), diff --git a/cli/src/main.rs b/cli/src/main.rs index 11cdea1..2108c5e 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -5,15 +5,13 @@ use std::path::Path; use atty::Stream; use bonsol_sdk::BonsolClient; use clap::Parser; -use common::{execute_get_inputs, ZkProgramManifest}; use risc0_circuit_rv32im::prove::emu::exec::DEFAULT_SEGMENT_LIMIT_PO2; use risc0_circuit_rv32im::prove::emu::testutil::DEFAULT_SESSION_LIMIT; use risc0_zkvm::ExecutorEnv; -use solana_sdk::signature::read_keypair_file; use solana_sdk::signer::Signer; -use crate::command::{BonsolCli, ParsedBonsolCli, ParsedCommand}; -use crate::common::{sol_check, try_load_from_config}; +use crate::command::{BonsolCli, Command}; +use crate::common::{execute_get_inputs, load_solana_config, sol_check, ZkProgramManifest}; use crate::error::{BonsolCliError, ZkManifestError}; mod build; @@ -32,43 +30,27 @@ pub(crate) mod error; #[tokio::main] async fn main() -> anyhow::Result<()> { - let ParsedBonsolCli { + let BonsolCli { config, keypair, rpc_url, command, - } = BonsolCli::parse().try_into()?; - - let (rpc, kpp) = match rpc_url.zip(keypair) { - Some(conf) => conf, - None => try_load_from_config(config)?, - }; - let keypair = - read_keypair_file(Path::new(&kpp)).map_err(|err| BonsolCliError::FailedToReadKeypair { - file: kpp, - err: format!("{err:?}"), - })?; - let stdin = atty::isnt(Stream::Stdin) - .then(|| { - let mut buffer = String::new(); - io::stdin().read_to_string(&mut buffer).ok()?; - (!buffer.trim().is_empty()).then_some(buffer) - }) - .flatten(); - let sdk = BonsolClient::new(rpc.clone()); + } = BonsolCli::parse(); match command { - ParsedCommand::Build { zk_program_path } => build::build(&keypair, zk_program_path), - ParsedCommand::Deploy { deploy_args } => { - if !sol_check(rpc.clone(), keypair.pubkey()).await { - return Err(BonsolCliError::InsufficientFundsForTransactions( - keypair.pubkey().to_string(), - ) - .into()); + Command::Build { zk_program_path } => build::build( + &load_solana_config(config, rpc_url, keypair)?.1, + zk_program_path, + ), + Command::Deploy { deploy_args } => { + let (rpc_url, keypair) = load_solana_config(config, rpc_url, keypair)?; + if !sol_check(rpc_url.clone(), keypair.pubkey()).await { + return Err(BonsolCliError::InsufficientFunds(keypair.pubkey().to_string()).into()); } - deploy::deploy(rpc, keypair, deploy_args).await + + deploy::deploy(rpc_url, keypair, deploy_args).await } - ParsedCommand::Estimate { + Command::Estimate { manifest_path, input_file, max_cycles, @@ -92,19 +74,20 @@ async fn main() -> anyhow::Result<()> { err, }) })?; + let mut env = &mut ExecutorEnv::builder(); env = env .segment_limit_po2(DEFAULT_SEGMENT_LIMIT_PO2 as u32) .session_limit(max_cycles.or(DEFAULT_SESSION_LIMIT)); - if input_file.is_some() { let inputs = execute_get_inputs(input_file, None)?; let inputs: Vec<&str> = inputs.iter().map(|i| i.data.as_str()).collect(); env = env.write(&inputs.as_slice())?; } + estimate::estimate(elf.as_slice(), env.build()?) } - ParsedCommand::Execute { + Command::Execute { execution_request_file, program_id, execution_id, @@ -114,15 +97,22 @@ async fn main() -> anyhow::Result<()> { tip, timeout, } => { - if !sol_check(rpc.clone(), keypair.pubkey()).await { - return Err(BonsolCliError::InsufficientFundsForTransactions( - keypair.pubkey().to_string(), - ) - .into()); + let (rpc_url, keypair) = load_solana_config(config, rpc_url, keypair)?; + if !sol_check(rpc_url.clone(), keypair.pubkey()).await { + return Err(BonsolCliError::InsufficientFunds(keypair.pubkey().to_string()).into()); } + let stdin = atty::isnt(Stream::Stdin) + .then(|| { + let mut buffer = String::new(); + io::stdin().read_to_string(&mut buffer).ok()?; + (!buffer.trim().is_empty()).then_some(buffer) + }) + .flatten(); + let sdk = BonsolClient::new(rpc_url.clone()); + execute::execute( &sdk, - rpc, + rpc_url, &keypair, execution_request_file, program_id, @@ -136,13 +126,23 @@ async fn main() -> anyhow::Result<()> { ) .await } - ParsedCommand::Prove { + Command::Prove { manifest_path, program_id, input_file, execution_id, output_location, } => { + let rpc_url = load_solana_config(config, rpc_url, keypair)?.0; + let stdin = atty::isnt(Stream::Stdin) + .then(|| { + let mut buffer = String::new(); + io::stdin().read_to_string(&mut buffer).ok()?; + (!buffer.trim().is_empty()).then_some(buffer) + }) + .flatten(); + let sdk = BonsolClient::new(rpc_url.clone()); + prove::prove( &sdk, execution_id, @@ -154,6 +154,6 @@ async fn main() -> anyhow::Result<()> { ) .await } - ParsedCommand::Init { project_name, dir } => init::init_project(&project_name, dir), + Command::Init { project_name, dir } => init::init_project(&project_name, dir), } } diff --git a/cli/src/tests/estimate.rs b/cli/src/tests/estimate.rs index 9a782ae..108f5fc 100644 --- a/cli/src/tests/estimate.rs +++ b/cli/src/tests/estimate.rs @@ -7,21 +7,7 @@ use crate::tests::bonsol_cmd; fn bonsol_estimate() -> Command { let mut cmd = bonsol_cmd(); - let keypair = cmd - .get_current_dir() - .unwrap() - .join("cli") - .join("src") - .join("tests") - .join("test_data") - .join("test_id.json"); - cmd.args(&[ - "--keypair", - keypair.to_str().unwrap(), - "--rpc-url", - "http://localhost:8899", - ]) - .arg("estimate"); + cmd.arg("estimate"); cmd } diff --git a/docs/docs/contributing/contributing.mdx b/docs/docs/contributing/contributing.mdx index 4399ead..9a4efee 100644 --- a/docs/docs/contributing/contributing.mdx +++ b/docs/docs/contributing/contributing.mdx @@ -70,7 +70,7 @@ cargo run -p bonsol-cli build -z images/simple ``` 5. Use the bonsol cli to deploy a zkprogram (here is a example already uploaded for you) ```bash -cargo run -p bonsol-cli deploy -m images/simple/manifest.json -t url --url https://bonsol-public-images.s3.us-east-1.amazonaws.com/simple-68f4b0c5f9ce034aa60ceb264a18d6c410a3af68fafd931bcfd9ebe7c1e42960 +cargo run -p bonsol-cli deploy url -m images/simple/manifest.json --url https://bonsol-public-images.s3.us-east-1.amazonaws.com/simple-68f4b0c5f9ce034aa60ceb264a18d6c410a3af68fafd931bcfd9ebe7c1e42960 ``` 6. Use the bonsol cli to execute a zkprogram ```bash diff --git a/docs/docs/shared/deploy.mdx b/docs/docs/shared/deploy.mdx index 4e14ded..b848b33 100644 --- a/docs/docs/shared/deploy.mdx +++ b/docs/docs/shared/deploy.mdx @@ -16,7 +16,7 @@ Manual deployment can be a cause of bugs and mismatches in this regard so we don To deploy manually you can use the following command. ```bash -bonsol deploy -m ./path-to-your-manifest.json -t {s3|shadow-drive|url} +bonsol deploy {s3|shadow-drive|url} -m ./path-to-your-manifest.json ``` #### S3 @@ -31,8 +31,7 @@ aws s3api create-bucket \ ``` ```bash -bonsol deploy \ - --deploy-type s3 \ +bonsol deploy s3 \ --bucket {bucket_name} \ --access-key {access-key} \ --secret-key {secret-key} \ @@ -46,9 +45,9 @@ ShadowDrive is a decentralized storage network that allows you to upload your pr If you have not already created a storage account you can create and upload in one command. ```bash -bonsol deploy -m ./path-to-your-manifest.json -t shadow-drive --storage-account-name {your storage account} --storage-account-size-mb {your storage account size in mb} --storage-account-name {your storage account name} --alternate-keypair {path to your alternate keypair} +bonsol deploy shadow-drive -m ./path-to-your-manifest.json --storage-account-name {your storage account} --storage-account-size-mb {your storage account size in mb} --storage-account-name {your storage account name} --alternate-keypair {path to your alternate keypair} ``` Once you have created your storage account you can upload your program to it for the future versions of your program. ```bash -bonsol deploy -m ./path-to-your-manifest.json -t shadow-drive --storage-account {your storage account} +bonsol deploy shadow-drive -m ./path-to-your-manifest.json --storage-account {your storage account} ```