Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for contract id alias name when deploying and invoking contracts. #1356

Merged
merged 26 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
689887e
Optimistically save contract id alias name to local soroban directory.
fnando Jun 4, 2024
0ae1aeb
Update docs.
fnando Jun 4, 2024
58a35e4
Merge branch 'main' into alias
fnando Jun 4, 2024
da28bdf
Use config_dir() instead.
fnando Jun 4, 2024
1c21fc5
Read contract id from alias.
fnando Jun 4, 2024
a26290b
Merge branch 'main' into alias
fnando Jun 4, 2024
cce8aca
Update cmd/soroban-cli/src/commands/contract/deploy/wasm.rs
fnando Jun 5, 2024
1e678fd
Apply pr feedback.
fnando Jun 5, 2024
c25ed7e
Do not make alias_path() return an optional.
fnando Jun 5, 2024
93b8b61
Add network name as part of the alias file path.
fnando Jun 5, 2024
7c59ee4
Merge branch 'main' into alias
fnando Jun 5, 2024
983b514
Validate alias format.
fnando Jun 5, 2024
c659ac6
Use json to store the contract id alias.
fnando Jun 5, 2024
ab9961c
Merge branch 'main' into alias
fnando Jun 5, 2024
a1664c5
Rename due to language semantics.
fnando Jun 6, 2024
f1dca79
Update cmd/soroban-cli/src/commands/contract/deploy/wasm.rs
fnando Jun 6, 2024
ac0ed75
Merge branch 'main' into alias
fnando Jun 6, 2024
8506896
Update cmd/soroban-cli/src/commands/contract/deploy/wasm.rs
fnando Jun 6, 2024
faac4af
Remove map_err in favor of macro implementation.
fnando Jun 6, 2024
0108530
Early return when no alias has been provided.
fnando Jun 6, 2024
80fa1f2
Make use of Option, instead of checking for the string's content.
fnando Jun 7, 2024
cda2713
Use other rust idioms.
fnando Jun 7, 2024
b1dc95e
Merge branch 'main' into alias
fnando Jun 7, 2024
e18e96e
Ensure network name is set.
fnando Jun 7, 2024
ea24a9a
Scope aliases by network passphrases.
fnando Jun 10, 2024
d28e46f
Merge branch 'main' into alias
fnando Jun 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions FULL_HELP_DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ Deploy a wasm contract

Possible values: `true`, `false`

* `--alias <ALIAS>` — The alias that will be used to save the contract's id



Expand Down
75 changes: 74 additions & 1 deletion cmd/soroban-cli/src/commands/contract/deploy/wasm.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use std::array::TryFromSliceError;
use std::fmt::Debug;
use std::fs::create_dir_all;
use std::io::Write;
use std::num::ParseIntError;
use std::path::PathBuf;
use std::{array::TryFromSliceError, fs::OpenOptions};

use clap::{arg, command, Parser};
use rand::Rng;
use regex::Regex;
use soroban_env_host::{
xdr::{
AccountId, ContractExecutable, ContractIdPreimage, ContractIdPreimageFromAddress,
Expand Down Expand Up @@ -54,6 +58,9 @@ pub struct Cmd {
#[arg(long, short = 'i', default_value = "false")]
/// Whether to ignore safety checks when deploying contracts
pub ignore_checks: bool,
/// The alias that will be used to save the contract's id.
#[arg(long)]
pub alias: Option<String>,
}

#[derive(thiserror::Error, Debug)]
Expand Down Expand Up @@ -100,19 +107,85 @@ pub enum Error {
Network(#[from] network::Error),
#[error(transparent)]
Wasm(#[from] wasm::Error),
#[error("cannot access config dir for alias file")]
CannotAccessConfigDir,
#[error("cannot create alias file")]
CannotCreateAliasFile,
#[error(
"alias must be 1-30 chars long, and have only letters, numbers, underscores and dashes"
)]
InvalidAliasFormat { alias: String },
}

impl Cmd {
pub async fn run(&self) -> Result<(), Error> {
self.validate_alias()?;

let res = self.run_against_rpc_server(None, None).await?.to_envelope();
match res {
TxnEnvelopeResult::TxnEnvelope(tx) => println!("{}", tx.to_xdr_base64(Limits::none())?),
TxnEnvelopeResult::Res(contract) => {
self.save_contract_id(&contract)?;
println!("{contract}");
}
}
Ok(())
}

fn validate_alias(&self) -> Result<(), Error> {
let alias = self.alias();

if alias.is_empty() {
return Ok(());
}

let regex = Regex::new(r"^[a-zA-Z0-9_-]{1,30}$").unwrap();

if regex.is_match(&alias) {
Ok(())
} else {
Err(Error::InvalidAliasFormat { alias })
}
}

fn alias(&self) -> String {
self.alias.as_ref().map(Clone::clone).unwrap_or_default()
}
fnando marked this conversation as resolved.
Show resolved Hide resolved

fn alias_path(&self) -> Result<PathBuf, Error> {
let config_dir = self.config.config_dir()?;
let network = self.config.network.network.clone().expect("must be set");

leighmcculloch marked this conversation as resolved.
Show resolved Hide resolved
Ok(self
.alias
.as_ref()
.map(|alias| config_dir.join("contract-ids").join(network).join(alias))
.expect("must be set"))
}

fn save_contract_id(&self, contract: &String) -> Result<(), Error> {
let file_path = self.alias_path()?;
fnando marked this conversation as resolved.
Show resolved Hide resolved

let Some(dir) = file_path.parent() else {
return Err(Error::CannotAccessConfigDir);
};

fnando marked this conversation as resolved.
Show resolved Hide resolved
match create_dir_all(dir) {
Ok(()) => {}
_ => return Err(Error::CannotAccessConfigDir),
};

fnando marked this conversation as resolved.
Show resolved Hide resolved
let mut to_file = OpenOptions::new()
.create(true)
.write(true)
fnando marked this conversation as resolved.
Show resolved Hide resolved
.open(file_path)
.expect("cannot open file");

match to_file.write_all(contract.as_bytes()) {
Ok(()) => Ok(()),
Err(_) => Err(Error::CannotCreateAliasFile),
}
}
}

#[async_trait::async_trait]
Expand Down
32 changes: 30 additions & 2 deletions cmd/soroban-cli/src/commands/contract/invoke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ pub enum Error {
Network(#[from] network::Error),
#[error(transparent)]
GetSpecError(#[from] get_spec::Error),
#[error("unable to read alias file")]
UnableToReadAliasFile,
#[error("alias file not found")]
NoAliasFileFound,
}

impl From<Infallible> for Error {
Expand Down Expand Up @@ -305,8 +309,32 @@ impl Cmd {

impl Cmd {
fn contract_id(&self) -> Result<[u8; 32], Error> {
soroban_spec_tools::utils::contract_id_from_str(&self.contract_id)
.map_err(|e| Error::CannotParseContractId(self.contract_id.clone(), e))
let contract_id = match self.load_contract_id() {
Ok(Some(id)) => id,
_ => self.contract_id.clone(),
};

soroban_spec_tools::utils::contract_id_from_str(&contract_id)
.map_err(|e| Error::CannotParseContractId(contract_id.clone(), e))
}

fn alias_path(&self) -> Result<PathBuf, Error> {
let config_dir = self.config.config_dir()?;
let network = self.config.network.network.clone().expect("must be set");

Ok(config_dir
.join("contract-ids")
.join(network)
.join(&self.contract_id))
}

fn load_contract_id(&self) -> Result<Option<String>, Error> {
let file_path = self.alias_path()?;

Ok(file_path
.exists()
.then(|| fs::read_to_string(file_path))
.transpose()?)
}
}

Expand Down
Loading