feat: move shared cli args to config file (#157)
This commit is contained in:
parent
f93da16c47
commit
72c7702719
23 changed files with 576 additions and 236 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -12,3 +12,4 @@ artifacts/
|
|||
.vscode/
|
||||
.DS_Store
|
||||
**/.env.local
|
||||
cli/quartz.toml
|
88
Cargo.lock
generated
88
Cargo.lock
generated
|
@ -382,6 +382,15 @@ dependencies = [
|
|||
"tungstenite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.1.2"
|
||||
|
@ -650,6 +659,12 @@ version = "3.16.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.16.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "102087e286b4677862ea56cf8fc58bb2cdfa8725c40ffb80fe3a008eb7f2fc83"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
|
@ -1690,6 +1705,20 @@ version = "0.2.9"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
|
||||
|
||||
[[package]]
|
||||
name = "figment"
|
||||
version = "0.10.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cb01cd46b0cf372153850f4c6c272d9cbea2da513e07538405148f95bd789f3"
|
||||
dependencies = [
|
||||
"atomic",
|
||||
"pear",
|
||||
"serde",
|
||||
"toml",
|
||||
"uncased",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixedbitset"
|
||||
version = "0.4.2"
|
||||
|
@ -2536,6 +2565,12 @@ dependencies = [
|
|||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inlinable_string"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb"
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.1.3"
|
||||
|
@ -3309,6 +3344,29 @@ dependencies = [
|
|||
"hmac",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pear"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdeeaa00ce488657faba8ebf44ab9361f9365a97bd39ffb8a60663f57ff4b467"
|
||||
dependencies = [
|
||||
"inlinable_string",
|
||||
"pear_codegen",
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pear_codegen"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bab5b985dc082b345f812b7df84e1bef27e7207b39e448439ba8bd69c93f147"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"proc-macro2-diagnostics",
|
||||
"quote",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peg"
|
||||
version = "0.8.4"
|
||||
|
@ -3525,6 +3583,19 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2-diagnostics"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.72",
|
||||
"version_check",
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prodash"
|
||||
version = "28.0.0"
|
||||
|
@ -3631,6 +3702,7 @@ dependencies = [
|
|||
"cycles-sync",
|
||||
"dirs",
|
||||
"displaydoc",
|
||||
"figment",
|
||||
"futures-util",
|
||||
"hex",
|
||||
"k256",
|
||||
|
@ -3651,6 +3723,7 @@ dependencies = [
|
|||
"thiserror",
|
||||
"tm-prover",
|
||||
"tokio",
|
||||
"toml",
|
||||
"tonic 0.12.1",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
|
@ -5498,6 +5571,15 @@ version = "0.1.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
|
||||
|
||||
[[package]]
|
||||
name = "uncased"
|
||||
version = "0.9.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.15"
|
||||
|
@ -5950,6 +6032,12 @@ dependencies = [
|
|||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[template]
|
||||
name = "quartz-app-template"
|
||||
description = "An functioning example of a quartz app"
|
||||
|
||||
ignore = [
|
||||
|
@ -9,5 +8,7 @@ ignore = [
|
|||
"enclave/target",
|
||||
"enclave/target/*",
|
||||
"frontend/package-lock.json",
|
||||
"frontend/public/images"
|
||||
"frontend/public/images",
|
||||
"trusted.hash",
|
||||
"trusted.height"
|
||||
]
|
8
apps/transfers/quartz.toml
Normal file
8
apps/transfers/quartz.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
mock_sgx = false
|
||||
tx_sender = "admin"
|
||||
chain_id = "testing"
|
||||
node_url = "http://127.0.0.1:26657"
|
||||
enclave_rpc_addr = "http://127.0.0.1"
|
||||
enclave_rpc_port = 11090
|
||||
trusted_hash = ""
|
||||
trusted_height = 0
|
|
@ -33,6 +33,8 @@ base64 = "0.22.1"
|
|||
subtle-encoding = "0.5.1"
|
||||
futures-util = "0.3.30"
|
||||
target-lexicon = "0.12.16"
|
||||
regex = "1.10.5"
|
||||
toml = "0.8.19"
|
||||
|
||||
# cosmos
|
||||
cosmrs.workspace = true
|
||||
|
@ -46,4 +48,4 @@ tm-prover = { workspace = true}
|
|||
quartz-common = { workspace = true, features=["contract"]}
|
||||
quartz-tee-ra = { workspace = true}
|
||||
mtcs-enclave = { workspace = true, optional = false}
|
||||
regex = "1.10.5"
|
||||
figment = { version = "0.10.19", features=["env", "toml"] }
|
||||
|
|
221
cli/src/cli.rs
221
cli/src/cli.rs
|
@ -1,12 +1,14 @@
|
|||
use std::{env, path::PathBuf};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use cosmrs::{tendermint::chain::Id as ChainId, AccountId};
|
||||
use figment::{providers::Serialized, Figment};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::metadata::LevelFilter;
|
||||
|
||||
use crate::handler::utils::helpers::wasmaddr_to_id;
|
||||
|
||||
#[derive(clap::Args, Debug, Clone)]
|
||||
#[derive(clap::Args, Debug, Clone, Serialize)]
|
||||
pub struct Verbosity {
|
||||
/// Increase verbosity, can be repeated up to 2 times
|
||||
#[arg(long, short, action = clap::ArgAction::Count)]
|
||||
|
@ -23,61 +25,45 @@ impl Verbosity {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[derive(Debug, Parser, Serialize)]
|
||||
#[command(version, long_about = None)]
|
||||
pub struct Cli {
|
||||
/// Increase log verbosity
|
||||
#[clap(flatten)]
|
||||
#[command(flatten)]
|
||||
pub verbose: Verbosity,
|
||||
|
||||
/// Enable mock SGX mode for testing purposes.
|
||||
/// This flag disables the use of an Intel SGX processor and allows the system to run without remote attestations.
|
||||
#[clap(long, env)]
|
||||
pub mock_sgx: bool,
|
||||
#[arg(long)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub mock_sgx: Option<bool>,
|
||||
|
||||
/// Path to Quartz app directory
|
||||
/// Defaults to current working dir
|
||||
/// For quartz init, root serves as the parent directory of the directory in which the quartz app is generated
|
||||
#[arg(long)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub app_dir: Option<PathBuf>,
|
||||
|
||||
/// Main command
|
||||
#[command(subcommand)]
|
||||
pub command: Command,
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
#[derive(Debug, Subcommand, Serialize, Clone)]
|
||||
pub enum Command {
|
||||
/// Create an empty Quartz app from a template
|
||||
Init {
|
||||
/// the name of your Quartz app directory, defaults to quartz_app
|
||||
#[clap(long, default_value = "quartz_app")]
|
||||
name: String,
|
||||
},
|
||||
Init(InitArgs),
|
||||
|
||||
/// Perform handshake
|
||||
Handshake {
|
||||
/// path to create & init a Quartz app, defaults to current path if unspecified
|
||||
#[arg(short, long, value_parser = wasmaddr_to_id)]
|
||||
contract: AccountId,
|
||||
/// Port enclave is listening on
|
||||
#[arg(short, long, default_value = "11090")]
|
||||
port: u16,
|
||||
/// Name or address of private key with which to sign
|
||||
#[arg(short, long, default_value = "admin")]
|
||||
sender: String,
|
||||
/// The network chain ID
|
||||
#[arg(long, default_value = "testing")]
|
||||
chain_id: ChainId,
|
||||
/// <host>:<port> to tendermint rpc interface for this chain
|
||||
#[clap(long, default_value_t = default_node_url())]
|
||||
node_url: String,
|
||||
/// RPC interface for the Quartz enclave
|
||||
#[clap(long, default_value_t = default_rpc_addr())]
|
||||
enclave_rpc_addr: String,
|
||||
/// Path to Quartz app directory
|
||||
/// Defaults to current working dir
|
||||
#[clap(long)]
|
||||
app_dir: Option<PathBuf>,
|
||||
},
|
||||
Handshake(HandshakeArgs),
|
||||
|
||||
/// Subcommands for handling the Quartz app contract
|
||||
Contract {
|
||||
#[command(subcommand)]
|
||||
contract_command: ContractCommand,
|
||||
},
|
||||
|
||||
/// Subcommands for handling the Quartz app enclave
|
||||
Enclave {
|
||||
#[command(subcommand)]
|
||||
|
@ -85,58 +71,131 @@ pub enum Command {
|
|||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Subcommand)]
|
||||
#[derive(Debug, Clone, Subcommand, Serialize)]
|
||||
pub enum ContractCommand {
|
||||
Build {
|
||||
#[clap(long)]
|
||||
manifest_path: PathBuf,
|
||||
},
|
||||
Deploy {
|
||||
/// Json-formatted cosmwasm contract initialization message
|
||||
#[clap(long, default_value = "{}")]
|
||||
init_msg: String,
|
||||
/// <host>:<port> to tendermint rpc interface for this chain
|
||||
#[clap(long, default_value_t = default_node_url())]
|
||||
node_url: String,
|
||||
/// Name or address of private key with which to sign
|
||||
#[arg(short, long, default_value = "admin")]
|
||||
sender: String,
|
||||
/// The network chain ID
|
||||
#[arg(long, default_value = "testing")]
|
||||
chain_id: ChainId,
|
||||
/// A human-readable name for this contract in lists
|
||||
#[arg(long, default_value = "Quartz App Contract")]
|
||||
label: String,
|
||||
/// Path to contract wasm binary for deployment
|
||||
#[clap(long)]
|
||||
wasm_bin_path: PathBuf,
|
||||
},
|
||||
Build(ContractBuildArgs),
|
||||
Deploy(ContractDeployArgs),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Subcommand)]
|
||||
#[derive(Debug, Clone, Subcommand, Serialize)]
|
||||
pub enum EnclaveCommand {
|
||||
/// Build the Quartz app's enclave
|
||||
Build {
|
||||
/// Path to Cargo.toml file of the Quartz app's enclave package, defaults to './enclave/Cargo.toml' if unspecified
|
||||
#[arg(long, default_value = "./enclave/Cargo.toml")]
|
||||
manifest_path: PathBuf,
|
||||
},
|
||||
// Run the Quartz app's enclave
|
||||
Start {
|
||||
/// Path to quartz app directory
|
||||
/// Defaults to current working dir
|
||||
#[clap(long)]
|
||||
app_dir: Option<PathBuf>,
|
||||
/// The network chain ID
|
||||
#[clap(long)]
|
||||
chain_id: String,
|
||||
},
|
||||
Build(EnclaveBuildArgs),
|
||||
/// Run the Quartz app's enclave
|
||||
Start(EnclaveStartArgs),
|
||||
}
|
||||
|
||||
fn default_rpc_addr() -> String {
|
||||
env::var("RPC_URL").unwrap_or_else(|_| "http://127.0.0.1".to_string())
|
||||
#[derive(Debug, Parser, Clone, Serialize, Deserialize)]
|
||||
pub struct InitArgs {
|
||||
/// The name of your Quartz app directory, defaults to quartz_app
|
||||
#[arg(default_value = "quartz_app")]
|
||||
pub name: PathBuf,
|
||||
}
|
||||
|
||||
fn default_node_url() -> String {
|
||||
env::var("NODE_URL").unwrap_or_else(|_| "http://127.0.0.1:26657".to_string())
|
||||
#[derive(Debug, Parser, Clone, Serialize, Deserialize)]
|
||||
pub struct HandshakeArgs {
|
||||
/// Path to create & init a Quartz app, defaults to current path if unspecified
|
||||
#[arg(short, long, value_parser = wasmaddr_to_id)]
|
||||
pub contract: AccountId,
|
||||
|
||||
/// Name or address of private key with which to sign
|
||||
#[arg(long)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tx_sender: Option<String>,
|
||||
|
||||
/// The network chain ID
|
||||
#[arg(long)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub chain_id: Option<ChainId>,
|
||||
|
||||
/// <host>:<port> to tendermint rpc interface for this chain
|
||||
#[arg(long)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub node_url: Option<String>,
|
||||
|
||||
/// RPC interface for the Quartz enclave
|
||||
#[arg(long)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub enclave_rpc_addr: Option<String>,
|
||||
|
||||
/// Port enclave is listening on
|
||||
#[arg(long)]
|
||||
#[serde(skip_serializing_if = "::std::option::Option::is_none")]
|
||||
pub enclave_rpc_port: Option<u16>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser, Clone, Serialize, Deserialize)]
|
||||
pub struct ContractBuildArgs {
|
||||
#[arg(long)]
|
||||
pub manifest_path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser, Clone, Serialize, Deserialize)]
|
||||
pub struct ContractDeployArgs {
|
||||
/// Json-formatted cosmwasm contract initialization message
|
||||
#[arg(long, default_value = "{}")]
|
||||
pub init_msg: String,
|
||||
|
||||
/// <host>:<port> to tendermint rpc interface for this chain
|
||||
#[arg(long)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub node_url: Option<String>,
|
||||
|
||||
/// Name or address of private key with which to sign
|
||||
#[arg(long)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tx_sender: Option<String>,
|
||||
|
||||
/// The network chain ID
|
||||
#[arg(long)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub chain_id: Option<ChainId>,
|
||||
|
||||
/// A human-readable name for this contract in lists
|
||||
#[arg(long, default_value = "Quartz App Contract")]
|
||||
pub label: String,
|
||||
|
||||
/// Path to contract wasm binary for deployment
|
||||
#[arg(long)]
|
||||
pub wasm_bin_path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser, Clone, Serialize, Deserialize)]
|
||||
pub struct EnclaveBuildArgs {
|
||||
/// Path to Cargo.toml file of the Quartz app's enclave package, defaults to './enclave/Cargo.toml' if unspecified
|
||||
#[arg(long, default_value = "./enclave/Cargo.toml")]
|
||||
pub manifest_path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser, Clone, Serialize, Deserialize)]
|
||||
pub struct EnclaveStartArgs {
|
||||
/// The network chain ID
|
||||
#[arg(long)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub chain_id: Option<ChainId>,
|
||||
|
||||
/// Fetch latest trusted hash and height from the chain instead of existing configuration
|
||||
#[arg(long)]
|
||||
pub use_latest_trusted: bool,
|
||||
}
|
||||
|
||||
pub trait ToFigment {
|
||||
fn to_figment(&self) -> Figment;
|
||||
}
|
||||
|
||||
impl ToFigment for Command {
|
||||
fn to_figment(&self) -> Figment {
|
||||
match self {
|
||||
Command::Init(args) => Figment::from(Serialized::defaults(args)),
|
||||
Command::Handshake(args) => Figment::from(Serialized::defaults(args)),
|
||||
Command::Contract { contract_command } => match contract_command {
|
||||
ContractCommand::Build(args) => Figment::from(Serialized::defaults(args)),
|
||||
ContractCommand::Deploy(args) => Figment::from(Serialized::defaults(args)),
|
||||
},
|
||||
Command::Enclave { enclave_command } => match enclave_command {
|
||||
EnclaveCommand::Build(args) => Figment::from(Serialized::defaults(args)),
|
||||
EnclaveCommand::Start(args) => Figment::from(Serialized::defaults(args)),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
85
cli/src/config.rs
Normal file
85
cli/src/config.rs
Normal file
|
@ -0,0 +1,85 @@
|
|||
use std::{env, path::PathBuf};
|
||||
|
||||
use cosmrs::tendermint::chain::Id as ChainId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct Config {
|
||||
/// Enable mock SGX mode for testing purposes.
|
||||
/// This flag disables the use of an Intel SGX processor and allows the system to run without remote attestations.
|
||||
#[serde(default)]
|
||||
pub mock_sgx: bool,
|
||||
|
||||
/// Name or address of private key with which to sign
|
||||
#[serde(default = "default_tx_sender")]
|
||||
pub tx_sender: String,
|
||||
|
||||
/// The network chain ID
|
||||
#[serde(default = "default_chain_id")]
|
||||
pub chain_id: ChainId,
|
||||
|
||||
/// <host>:<port> to tendermint rpc interface for this chain
|
||||
#[serde(default = "default_node_url")]
|
||||
pub node_url: String,
|
||||
|
||||
/// RPC interface for the Quartz enclave
|
||||
#[serde(default = "default_rpc_addr")]
|
||||
pub enclave_rpc_addr: String,
|
||||
|
||||
/// Port enclave is listening on
|
||||
#[serde(default = "default_port")]
|
||||
pub enclave_rpc_port: u16,
|
||||
|
||||
/// Path to Quartz app directory
|
||||
/// Defaults to current working dir
|
||||
#[serde(default = "default_app_dir")]
|
||||
pub app_dir: PathBuf,
|
||||
|
||||
/// Trusted height for light client proofs
|
||||
#[serde(default)]
|
||||
pub trusted_height: u64,
|
||||
|
||||
/// Trusted hash for block at trusted_height for light client proofs
|
||||
#[serde(default)]
|
||||
pub trusted_hash: String,
|
||||
}
|
||||
|
||||
fn default_rpc_addr() -> String {
|
||||
env::var("RPC_URL").unwrap_or_else(|_| "http://127.0.0.1".to_string())
|
||||
}
|
||||
|
||||
fn default_node_url() -> String {
|
||||
env::var("NODE_URL").unwrap_or_else(|_| "http://127.0.0.1:26657".to_string())
|
||||
}
|
||||
|
||||
fn default_tx_sender() -> String {
|
||||
String::from("admin")
|
||||
}
|
||||
|
||||
fn default_chain_id() -> ChainId {
|
||||
"testing".parse().expect("default chain_id failed")
|
||||
}
|
||||
|
||||
fn default_port() -> u16 {
|
||||
11090
|
||||
}
|
||||
|
||||
fn default_app_dir() -> PathBuf {
|
||||
".".parse().expect("default app_dir pathbuf failed")
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Config {
|
||||
mock_sgx: false,
|
||||
tx_sender: default_tx_sender(),
|
||||
chain_id: default_chain_id(),
|
||||
node_url: default_node_url(),
|
||||
enclave_rpc_addr: default_rpc_addr(),
|
||||
enclave_rpc_port: default_port(),
|
||||
app_dir: default_app_dir(),
|
||||
trusted_height: u64::default(),
|
||||
trusted_hash: String::default(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,4 +9,34 @@ pub enum Error {
|
|||
PathNotFile(String),
|
||||
/// unspecified error: {0}
|
||||
GenericErr(String),
|
||||
/// IoError: {0}
|
||||
IoError(String),
|
||||
/// TOML Error : {0}
|
||||
TomlError(String),
|
||||
/// Tendermint error: {0}
|
||||
TendermintError(String),
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for Error {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
Error::IoError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<toml::de::Error> for Error {
|
||||
fn from(err: toml::de::Error) -> Self {
|
||||
Error::TomlError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<toml::ser::Error> for Error {
|
||||
fn from(err: toml::ser::Error) -> Self {
|
||||
Error::TomlError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<tendermint::Error> for Error {
|
||||
fn from(err: tendermint::Error) -> Self {
|
||||
Error::TendermintError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use crate::{error::Error, request::Request, response::Response, Config};
|
||||
use crate::{config::Config, error::Error, request::Request, response::Response};
|
||||
|
||||
pub mod utils;
|
||||
// commands
|
||||
|
|
|
@ -4,11 +4,11 @@ use async_trait::async_trait;
|
|||
use tracing::{debug, trace};
|
||||
|
||||
use crate::{
|
||||
config::Config,
|
||||
error::Error,
|
||||
handler::Handler,
|
||||
request::contract_build::ContractBuildRequest,
|
||||
response::{contract_build::ContractBuildResponse, Response},
|
||||
Config,
|
||||
};
|
||||
|
||||
#[async_trait]
|
||||
|
|
|
@ -17,11 +17,11 @@ use super::utils::{
|
|||
types::{Log, WasmdTxResponse},
|
||||
};
|
||||
use crate::{
|
||||
config::Config,
|
||||
error::Error,
|
||||
handler::{utils::types::RelayMessage, Handler},
|
||||
request::contract_deploy::ContractDeployRequest,
|
||||
response::{contract_deploy::ContractDeployResponse, Response},
|
||||
Config,
|
||||
};
|
||||
|
||||
#[async_trait]
|
||||
|
@ -33,11 +33,11 @@ impl Handler for ContractDeployRequest {
|
|||
trace!("initializing directory structure...");
|
||||
|
||||
let (code_id, contract_addr) = if config.mock_sgx {
|
||||
deploy::<RawMockAttestation>(self, config.mock_sgx)
|
||||
deploy::<RawMockAttestation>(self, config)
|
||||
.await
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?
|
||||
} else {
|
||||
deploy::<RawEpidAttestation>(self, config.mock_sgx)
|
||||
deploy::<RawEpidAttestation>(self, config)
|
||||
.await
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?
|
||||
};
|
||||
|
@ -52,12 +52,12 @@ impl Handler for ContractDeployRequest {
|
|||
|
||||
async fn deploy<DA: Serialize + DeserializeOwned>(
|
||||
args: ContractDeployRequest,
|
||||
mock_sgx: bool,
|
||||
config: Config,
|
||||
) -> Result<(u64, String), anyhow::Error> {
|
||||
// TODO: Replace with call to Rust package
|
||||
let relay_path = current_dir()?.join("../");
|
||||
|
||||
let httpurl = Url::parse(&format!("http://{}", args.node_url))?;
|
||||
let httpurl = Url::parse(&format!("http://{}", config.node_url))?;
|
||||
let tmrpc_client = HttpClient::new(httpurl.as_str())?;
|
||||
let wasmd_client = CliWasmdClient::new(Url::parse(httpurl.as_str())?);
|
||||
|
||||
|
@ -67,8 +67,8 @@ async fn deploy<DA: Serialize + DeserializeOwned>(
|
|||
|
||||
// TODO: uncertain about the path -> string conversion
|
||||
let deploy_output: WasmdTxResponse = serde_json::from_str(&wasmd_client.deploy(
|
||||
&args.chain_id,
|
||||
&args.sender,
|
||||
&config.chain_id,
|
||||
&config.tx_sender,
|
||||
contract_path.display().to_string(),
|
||||
)?)?;
|
||||
let res = block_tx_commit(&tmrpc_client, deploy_output.txhash).await?;
|
||||
|
@ -79,17 +79,18 @@ async fn deploy<DA: Serialize + DeserializeOwned>(
|
|||
info!("\n🚀 Communicating with Relay to Instantiate...\n");
|
||||
let raw_init_msg = run_relay::<QuartzInstantiateMsg<DA>>(
|
||||
relay_path.as_path(),
|
||||
mock_sgx,
|
||||
config.mock_sgx,
|
||||
RelayMessage::Instantiate,
|
||||
)?;
|
||||
)
|
||||
.await?;
|
||||
|
||||
info!("\n🚀 Instantiating {} Contract\n", args.label);
|
||||
let mut init_msg = args.init_msg;
|
||||
init_msg["quartz"] = json!(raw_init_msg);
|
||||
|
||||
let init_output: WasmdTxResponse = serde_json::from_str(&wasmd_client.init(
|
||||
&args.chain_id,
|
||||
&args.sender,
|
||||
&config.chain_id,
|
||||
&config.tx_sender,
|
||||
code_id,
|
||||
json!(init_msg),
|
||||
&format!("{} Contract #{}", args.label, code_id),
|
||||
|
|
|
@ -4,11 +4,11 @@ use async_trait::async_trait;
|
|||
use tracing::{debug, info};
|
||||
|
||||
use crate::{
|
||||
config::Config,
|
||||
error::Error,
|
||||
handler::Handler,
|
||||
request::enclave_build::EnclaveBuildRequest,
|
||||
response::{enclave_build::EnclaveBuildResponse, Response},
|
||||
Config,
|
||||
};
|
||||
|
||||
#[async_trait]
|
||||
|
|
|
@ -4,13 +4,12 @@ use async_trait::async_trait;
|
|||
use tokio::process::Command;
|
||||
use tracing::{debug, info};
|
||||
|
||||
use super::utils::helpers::read_hash_height;
|
||||
use crate::{
|
||||
config::Config,
|
||||
error::Error,
|
||||
handler::Handler,
|
||||
handler::{utils::helpers::get_hash_height, Handler},
|
||||
request::enclave_start::EnclaveStartRequest,
|
||||
response::{enclave_start::EnclaveStartResponse, Response},
|
||||
Config,
|
||||
};
|
||||
|
||||
#[async_trait]
|
||||
|
@ -18,16 +17,16 @@ impl Handler for EnclaveStartRequest {
|
|||
type Error = Error;
|
||||
type Response = Response;
|
||||
|
||||
async fn handle(self, config: Config) -> Result<Self::Response, Self::Error> {
|
||||
let enclave_dir = self.app_dir.join("enclave");
|
||||
let (trusted_height, trusted_hash) = read_hash_height(self.app_dir.as_path())
|
||||
.await
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
||||
async fn handle(self, mut config: Config) -> Result<Self::Response, Self::Error> {
|
||||
// Get trusted height and hash
|
||||
let (trusted_height, trusted_hash) = get_hash_height(self.use_latest_trusted, &mut config)?;
|
||||
|
||||
let enclave_dir = config.app_dir.join("enclave");
|
||||
|
||||
if config.mock_sgx {
|
||||
let enclave_args: Vec<String> = vec![
|
||||
"--chain-id".to_string(),
|
||||
self.chain_id,
|
||||
config.chain_id.to_string(),
|
||||
"--trusted-height".to_string(),
|
||||
trusted_height.to_string(),
|
||||
"--trusted-hash".to_string(),
|
||||
|
|
|
@ -17,14 +17,14 @@ use super::utils::{
|
|||
types::WasmdTxResponse,
|
||||
};
|
||||
use crate::{
|
||||
config::Config,
|
||||
error::Error,
|
||||
handler::{
|
||||
utils::{helpers::read_hash_height, types::RelayMessage},
|
||||
utils::{helpers::get_hash_height, types::RelayMessage},
|
||||
Handler,
|
||||
},
|
||||
request::handshake::HandshakeRequest,
|
||||
response::{handshake::HandshakeResponse, Response},
|
||||
Config,
|
||||
};
|
||||
|
||||
#[async_trait]
|
||||
|
@ -36,7 +36,7 @@ impl Handler for HandshakeRequest {
|
|||
trace!("starting handshake...");
|
||||
|
||||
// TODO: may need to import verbosity here
|
||||
let pub_key = handshake(self, config.mock_sgx)
|
||||
let pub_key = handshake(self, config)
|
||||
.await
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
||||
|
||||
|
@ -49,30 +49,32 @@ struct Message<'a> {
|
|||
message: &'a str,
|
||||
}
|
||||
|
||||
async fn handshake(args: HandshakeRequest, mock_sgx: bool) -> Result<String, anyhow::Error> {
|
||||
let httpurl = Url::parse(&format!("http://{}", args.node_url))?;
|
||||
let wsurl = format!("ws://{}/websocket", args.node_url);
|
||||
async fn handshake(args: HandshakeRequest, mut config: Config) -> Result<String, anyhow::Error> {
|
||||
let httpurl = Url::parse(&format!("http://{}", config.node_url))?;
|
||||
let wsurl = format!("ws://{}/websocket", config.node_url);
|
||||
|
||||
let tmrpc_client = HttpClient::new(httpurl.as_str())?;
|
||||
let wasmd_client = CliWasmdClient::new(Url::parse(httpurl.as_str())?);
|
||||
|
||||
let (trusted_height, trusted_hash) = get_hash_height(false, &mut config)?;
|
||||
// TODO: dir logic issue #125
|
||||
// Read trusted hash and height from files
|
||||
let base_path = current_dir()?.join("../");
|
||||
let trusted_files_path = args.app_dir;
|
||||
let (trusted_height, trusted_hash) = read_hash_height(trusted_files_path.as_path()).await?;
|
||||
|
||||
info!("Running SessionCreate");
|
||||
let res: serde_json::Value =
|
||||
run_relay(base_path.as_path(), mock_sgx, RelayMessage::SessionCreate)?;
|
||||
let res: serde_json::Value = run_relay(
|
||||
base_path.as_path(),
|
||||
config.mock_sgx,
|
||||
RelayMessage::SessionCreate,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let output: WasmdTxResponse = serde_json::from_str(
|
||||
wasmd_client
|
||||
.tx_execute(
|
||||
&args.contract.clone(),
|
||||
&args.chain_id,
|
||||
&config.chain_id,
|
||||
2000000,
|
||||
&args.sender,
|
||||
&config.tx_sender,
|
||||
json!(res),
|
||||
)?
|
||||
.as_str(),
|
||||
|
@ -92,7 +94,7 @@ async fn handshake(args: HandshakeRequest, mock_sgx: bool) -> Result<String, any
|
|||
debug!("Proof path: {:?}", proof_path.to_str());
|
||||
|
||||
// Call tm prover with trusted hash and height
|
||||
let config = TmProverConfig {
|
||||
let prover_config = TmProverConfig {
|
||||
primary: httpurl.as_str().parse()?,
|
||||
witnesses: httpurl.as_str().parse()?,
|
||||
trusted_height,
|
||||
|
@ -101,11 +103,11 @@ async fn handshake(args: HandshakeRequest, mock_sgx: bool) -> Result<String, any
|
|||
verbose: "1".parse()?, // TODO: both tm-prover and cli define the same Verbosity struct. Need to define this once and import
|
||||
contract_address: args.contract.clone(),
|
||||
storage_key: "quartz_session".to_string(),
|
||||
chain_id: args.chain_id.to_string(),
|
||||
chain_id: config.chain_id.to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
debug!("config: {:?}", config);
|
||||
if let Err(report) = prove(config).await {
|
||||
debug!("config: {:?}", prover_config);
|
||||
if let Err(report) = prove(prover_config).await {
|
||||
return Err(anyhow!("Tendermint prover failed. Report: {}", report));
|
||||
}
|
||||
|
||||
|
@ -119,9 +121,10 @@ async fn handshake(args: HandshakeRequest, mock_sgx: bool) -> Result<String, any
|
|||
info!("Running SessionSetPubKey");
|
||||
let res: serde_json::Value = run_relay(
|
||||
base_path.as_path(),
|
||||
mock_sgx,
|
||||
config.mock_sgx,
|
||||
RelayMessage::SessionSetPubKey(proof_json),
|
||||
)?;
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Submit SessionSetPubKey to contract
|
||||
let output: WasmdTxResponse = serde_json::from_str(
|
||||
|
@ -130,7 +133,7 @@ async fn handshake(args: HandshakeRequest, mock_sgx: bool) -> Result<String, any
|
|||
&args.contract.clone(),
|
||||
&ChainId::from_str("testing")?,
|
||||
2000000,
|
||||
&args.sender,
|
||||
&config.tx_sender,
|
||||
json!(res),
|
||||
)?
|
||||
.as_str(),
|
||||
|
|
|
@ -2,14 +2,15 @@ use std::path::PathBuf;
|
|||
|
||||
use async_trait::async_trait;
|
||||
use cargo_generate::{generate, GenerateArgs, TemplatePath, Vcs};
|
||||
use tokio::fs;
|
||||
use tracing::trace;
|
||||
|
||||
use crate::{
|
||||
config::Config,
|
||||
error::Error,
|
||||
handler::Handler,
|
||||
request::init::InitRequest,
|
||||
response::{init::InitResponse, Response},
|
||||
Config,
|
||||
};
|
||||
|
||||
#[async_trait]
|
||||
|
@ -17,13 +18,30 @@ impl Handler for InitRequest {
|
|||
type Error = Error;
|
||||
type Response = Response;
|
||||
|
||||
async fn handle(self, _config: Config) -> Result<Self::Response, Self::Error> {
|
||||
async fn handle(self, config: Config) -> Result<Self::Response, Self::Error> {
|
||||
trace!("initializing directory structure...");
|
||||
|
||||
let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("..");
|
||||
|
||||
let parent = self
|
||||
.name
|
||||
.parent()
|
||||
.map(|p| p.to_path_buf())
|
||||
.expect("path already validated");
|
||||
fs::create_dir_all(&parent)
|
||||
.await
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
||||
|
||||
let file_name = self
|
||||
.name
|
||||
.file_name()
|
||||
.and_then(|f| f.to_str())
|
||||
.expect("path already validated");
|
||||
|
||||
let wasm_pack_args = GenerateArgs {
|
||||
name: Some(self.name),
|
||||
name: Some(file_name.to_string()),
|
||||
destination: Some(config.app_dir.join(parent)),
|
||||
overwrite: true,
|
||||
vcs: Some(Vcs::Git),
|
||||
template_path: TemplatePath {
|
||||
// git: Some("git@github.com:informalsystems/cycles-quartz.git".to_string()), // TODO: replace with public http address when open-sourced
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
use std::{path::Path, process::Command, time::Duration};
|
||||
use std::{path::Path, time::Duration};
|
||||
|
||||
use anyhow::anyhow;
|
||||
use cosmrs::{AccountId, ErrorReport};
|
||||
use cycles_sync::wasmd_client::{CliWasmdClient, WasmdClient};
|
||||
use regex::Regex;
|
||||
use reqwest::Url;
|
||||
use serde::de::DeserializeOwned;
|
||||
use subtle_encoding::bech32::decode as bech32_decode;
|
||||
use tendermint::{block::Height, Hash};
|
||||
use tendermint_rpc::{
|
||||
endpoint::tx::Response as TmTxResponse, error::ErrorDetail, Client, HttpClient,
|
||||
};
|
||||
use tokio::fs;
|
||||
use tokio::{fs, process::Command};
|
||||
use tracing::debug;
|
||||
|
||||
use super::types::RelayMessage;
|
||||
use crate::{config::Config, error};
|
||||
|
||||
pub fn wasmaddr_to_id(address_str: &str) -> Result<AccountId, anyhow::Error> {
|
||||
let (hr, _) = bech32_decode(address_str).map_err(|e| anyhow!(e))?;
|
||||
|
@ -24,7 +27,7 @@ pub fn wasmaddr_to_id(address_str: &str) -> Result<AccountId, anyhow::Error> {
|
|||
}
|
||||
|
||||
// TODO: move wrapping result with "quartz:" struct into here
|
||||
pub fn run_relay<R: DeserializeOwned>(
|
||||
pub async fn run_relay<R: DeserializeOwned>(
|
||||
base_path: &Path,
|
||||
mock_sgx: bool,
|
||||
msg: RelayMessage,
|
||||
|
@ -41,7 +44,7 @@ pub fn run_relay<R: DeserializeOwned>(
|
|||
command.arg(proof);
|
||||
}
|
||||
|
||||
let output = command.output()?;
|
||||
let output = command.output().await?;
|
||||
|
||||
if !output.status.success() {
|
||||
return Err(anyhow!("{:?}", output));
|
||||
|
@ -87,18 +90,55 @@ pub async fn block_tx_commit(client: &HttpClient, tx: Hash) -> Result<TmTxRespon
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn read_hash_height(base_path: &Path) -> Result<(Height, Hash), anyhow::Error> {
|
||||
let height_path = base_path.join("trusted.height");
|
||||
let trusted_height: Height = fs::read_to_string(height_path.as_path())
|
||||
.await?
|
||||
.trim()
|
||||
.parse()?;
|
||||
/// Returns the trusted hash and height
|
||||
pub fn get_hash_height(
|
||||
use_latest: bool,
|
||||
config: &mut Config,
|
||||
) -> Result<(Height, Hash), error::Error> {
|
||||
if use_latest || config.trusted_height == 0 || config.trusted_hash.is_empty() {
|
||||
let (trusted_height, trusted_hash) = latest_height_hash(&config.node_url)?;
|
||||
config.trusted_hash = trusted_hash.to_string();
|
||||
config.trusted_height = trusted_height.into();
|
||||
|
||||
let hash_path = base_path.join("trusted.hash");
|
||||
let trusted_hash: Hash = fs::read_to_string(hash_path.as_path())
|
||||
.await?
|
||||
.trim()
|
||||
.parse()?;
|
||||
|
||||
Ok((trusted_height, trusted_hash))
|
||||
Ok((trusted_height, trusted_hash))
|
||||
} else {
|
||||
Ok((
|
||||
config.trusted_height.try_into()?,
|
||||
config
|
||||
.trusted_hash
|
||||
.parse()
|
||||
.map_err(|_| error::Error::GenericErr("invalid hash".to_string()))?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
// Queries the chain for the latested height and hash
|
||||
pub fn latest_height_hash(node_url: &String) -> Result<(Height, Hash), error::Error> {
|
||||
let httpurl = Url::parse(&format!("http://{}", node_url))
|
||||
.map_err(|e| error::Error::GenericErr(e.to_string()))?;
|
||||
let wasmd_client = CliWasmdClient::new(httpurl);
|
||||
|
||||
let (trusted_height, trusted_hash) = wasmd_client
|
||||
.trusted_height_hash()
|
||||
.map_err(|e| error::Error::GenericErr(e.to_string()))?;
|
||||
|
||||
Ok((
|
||||
trusted_height.try_into()?,
|
||||
trusted_hash.parse().expect("invalid hash from wasmd"),
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn persist_config_hash_height(config: &Config) -> Result<(), error::Error> {
|
||||
let config_path = config.app_dir.join("quartz.toml");
|
||||
|
||||
let toml_content = fs::read_to_string(&config_path).await?;
|
||||
let mut written_config: Config = toml::from_str(&toml_content)?;
|
||||
|
||||
written_config.trusted_hash.clone_from(&config.trusted_hash);
|
||||
written_config.trusted_height = config.trusted_height;
|
||||
|
||||
let toml_string = toml::to_string(config)?;
|
||||
fs::write(&config_path, toml_string).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -14,13 +14,22 @@
|
|||
)]
|
||||
|
||||
pub mod cli;
|
||||
pub mod config;
|
||||
pub mod error;
|
||||
pub mod handler;
|
||||
pub mod request;
|
||||
pub mod response;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::Parser;
|
||||
use cli::ToFigment;
|
||||
use color_eyre::eyre::Result;
|
||||
use config::Config;
|
||||
use figment::{
|
||||
providers::{Env, Format, Serialized, Toml},
|
||||
Figment,
|
||||
};
|
||||
use tracing_subscriber::{util::SubscriberInitExt, EnvFilter};
|
||||
|
||||
use crate::{cli::Cli, handler::Handler, request::Request};
|
||||
|
@ -37,17 +46,26 @@ const BANNER: &str = r"
|
|||
|
||||
";
|
||||
|
||||
pub struct Config {
|
||||
pub mock_sgx: bool,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
|
||||
println!("{BANNER}");
|
||||
|
||||
let args = Cli::parse();
|
||||
let args: Cli = Cli::parse();
|
||||
check_path(&args.app_dir)?;
|
||||
|
||||
let config: Config = Figment::new()
|
||||
.merge(Toml::file(
|
||||
args.app_dir
|
||||
.as_ref()
|
||||
.unwrap_or(&PathBuf::from("."))
|
||||
.join("quartz.toml"),
|
||||
))
|
||||
.merge(Env::prefixed("QUARTZ_"))
|
||||
.merge(Serialized::defaults(&args))
|
||||
.merge(args.command.to_figment())
|
||||
.extract()?;
|
||||
|
||||
let env_filter = EnvFilter::builder()
|
||||
.with_default_directive(args.verbose.to_level_filter().into())
|
||||
|
@ -67,11 +85,7 @@ async fn main() -> Result<()> {
|
|||
|
||||
// Each `Request` defines an associated `Handler` (i.e. logic) and `Response`. All handlers are
|
||||
// free to log to the terminal and these logs are sent to `stderr`.
|
||||
let response = request
|
||||
.handle(Config {
|
||||
mock_sgx: args.mock_sgx,
|
||||
})
|
||||
.await?;
|
||||
let response = request.handle(config).await?;
|
||||
|
||||
// `Handlers` must use `Responses` to output to `stdout`.
|
||||
println!(
|
||||
|
@ -81,3 +95,13 @@ async fn main() -> Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_path(path: &Option<PathBuf>) -> Result<(), error::Error> {
|
||||
if let Some(path) = path {
|
||||
if !path.is_dir() {
|
||||
return Err(error::Error::PathNotDir(format!("{}", path.display())));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use std::{env::current_dir, path::PathBuf};
|
||||
|
||||
use crate::{
|
||||
cli::{Command, ContractCommand, EnclaveCommand},
|
||||
error::Error,
|
||||
|
@ -32,23 +30,9 @@ impl TryFrom<Command> for Request {
|
|||
|
||||
fn try_from(cmd: Command) -> Result<Self, Self::Error> {
|
||||
match cmd {
|
||||
Command::Init { name } => Ok(InitRequest { name }.try_into()?),
|
||||
Command::Handshake {
|
||||
contract,
|
||||
port,
|
||||
sender,
|
||||
chain_id,
|
||||
node_url,
|
||||
enclave_rpc_addr,
|
||||
app_dir,
|
||||
} => Ok(HandshakeRequest {
|
||||
contract,
|
||||
port,
|
||||
sender,
|
||||
chain_id,
|
||||
node_url,
|
||||
enclave_rpc_addr,
|
||||
app_dir: Self::path_checked(app_dir)?,
|
||||
Command::Init(args) => Ok(InitRequest { name: args.name }.try_into()?),
|
||||
Command::Handshake(args) => Ok(HandshakeRequest {
|
||||
contract: args.contract,
|
||||
}
|
||||
.into()),
|
||||
Command::Contract { contract_command } => contract_command.try_into(),
|
||||
|
@ -57,53 +41,33 @@ impl TryFrom<Command> for Request {
|
|||
}
|
||||
}
|
||||
|
||||
impl Request {
|
||||
fn path_checked(path: Option<PathBuf>) -> Result<PathBuf, Error> {
|
||||
if let Some(path) = path {
|
||||
if !path.is_dir() {
|
||||
return Err(Error::PathNotDir(format!("{}", path.display())));
|
||||
}
|
||||
Ok(path)
|
||||
} else {
|
||||
Ok(current_dir().map_err(|e| Error::GenericErr(e.to_string()))?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ContractCommand> for Request {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(cmd: ContractCommand) -> Result<Request, Error> {
|
||||
match cmd {
|
||||
ContractCommand::Deploy {
|
||||
init_msg,
|
||||
node_url,
|
||||
chain_id,
|
||||
sender,
|
||||
label,
|
||||
wasm_bin_path,
|
||||
} => {
|
||||
if !wasm_bin_path.exists() {
|
||||
return Err(Error::PathNotFile(wasm_bin_path.display().to_string()));
|
||||
ContractCommand::Deploy(args) => {
|
||||
if !args.wasm_bin_path.exists() {
|
||||
return Err(Error::PathNotFile(args.wasm_bin_path.display().to_string()));
|
||||
}
|
||||
|
||||
Ok(ContractDeployRequest {
|
||||
init_msg: serde_json::from_str(&init_msg)
|
||||
init_msg: serde_json::from_str(&args.init_msg)
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?,
|
||||
node_url,
|
||||
chain_id,
|
||||
sender,
|
||||
label,
|
||||
wasm_bin_path,
|
||||
label: args.label,
|
||||
wasm_bin_path: args.wasm_bin_path,
|
||||
}
|
||||
.into())
|
||||
}
|
||||
ContractCommand::Build { manifest_path } => {
|
||||
if !manifest_path.exists() {
|
||||
return Err(Error::PathNotFile(manifest_path.display().to_string()));
|
||||
ContractCommand::Build(args) => {
|
||||
if !args.manifest_path.exists() {
|
||||
return Err(Error::PathNotFile(args.manifest_path.display().to_string()));
|
||||
}
|
||||
|
||||
Ok(ContractBuildRequest { manifest_path }.into())
|
||||
Ok(ContractBuildRequest {
|
||||
manifest_path: args.manifest_path,
|
||||
}
|
||||
.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -114,12 +78,12 @@ impl TryFrom<EnclaveCommand> for Request {
|
|||
|
||||
fn try_from(cmd: EnclaveCommand) -> Result<Request, Error> {
|
||||
match cmd {
|
||||
EnclaveCommand::Build { manifest_path } => {
|
||||
Ok(EnclaveBuildRequest { manifest_path }.into())
|
||||
EnclaveCommand::Build(args) => Ok(EnclaveBuildRequest {
|
||||
manifest_path: args.manifest_path,
|
||||
}
|
||||
EnclaveCommand::Start { app_dir, chain_id } => Ok(EnclaveStartRequest {
|
||||
app_dir: Self::path_checked(app_dir)?,
|
||||
chain_id,
|
||||
.into()),
|
||||
EnclaveCommand::Start(args) => Ok(EnclaveStartRequest {
|
||||
use_latest_trusted: args.use_latest_trusted,
|
||||
}
|
||||
.into()),
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use cosmrs::tendermint::chain::Id as ChainId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{error::Error, request::Request};
|
||||
|
@ -8,9 +7,6 @@ use crate::{error::Error, request::Request};
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct ContractDeployRequest {
|
||||
pub init_msg: serde_json::Value,
|
||||
pub node_url: String,
|
||||
pub chain_id: ChainId,
|
||||
pub sender: String,
|
||||
pub label: String,
|
||||
pub wasm_bin_path: PathBuf,
|
||||
}
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use crate::request::Request;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EnclaveStartRequest {
|
||||
pub app_dir: PathBuf,
|
||||
pub chain_id: String,
|
||||
pub use_latest_trusted: bool,
|
||||
}
|
||||
|
||||
impl From<EnclaveStartRequest> for Request {
|
||||
|
|
|
@ -1,18 +1,10 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use cosmrs::{tendermint::chain::Id as ChainId, AccountId};
|
||||
use cosmrs::AccountId;
|
||||
|
||||
use crate::request::Request;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct HandshakeRequest {
|
||||
pub contract: AccountId,
|
||||
pub port: u16,
|
||||
pub sender: String,
|
||||
pub chain_id: ChainId,
|
||||
pub node_url: String,
|
||||
pub enclave_rpc_addr: String,
|
||||
pub app_dir: PathBuf,
|
||||
}
|
||||
|
||||
impl From<HandshakeRequest> for Request {
|
||||
|
|
|
@ -1,18 +1,23 @@
|
|||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::{error::Error, request::Request};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct InitRequest {
|
||||
pub name: String,
|
||||
pub name: PathBuf,
|
||||
}
|
||||
|
||||
impl TryFrom<InitRequest> for Request {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(request: InitRequest) -> Result<Request, Error> {
|
||||
if Path::new(&request.name).iter().count() != 1 {
|
||||
return Err(Error::GenericErr("App name contains path".to_string()));
|
||||
if request.name.extension().is_some() {
|
||||
return Err(Error::PathNotDir(format!("{}", request.name.display())));
|
||||
} else if request.name.exists() {
|
||||
return Err(Error::GenericErr(format!(
|
||||
"Directory already exists: {}",
|
||||
request.name.display()
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(Request::Init(request))
|
||||
|
|
|
@ -51,6 +51,8 @@ pub trait WasmdClient {
|
|||
init_msg: M,
|
||||
label: &str,
|
||||
) -> Result<String, Self::Error>;
|
||||
|
||||
fn trusted_height_hash(&self) -> Result<(u64, String), Self::Error>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
|
||||
|
@ -227,4 +229,29 @@ impl WasmdClient for CliWasmdClient {
|
|||
// TODO: find the rust type for the tx output and return that
|
||||
Ok((String::from_utf8(output.stdout)?).to_string())
|
||||
}
|
||||
|
||||
fn trusted_height_hash(&self) -> Result<(u64, String), Self::Error> {
|
||||
let mut wasmd = Command::new("wasmd");
|
||||
let command = wasmd.args(["--node", self.url.as_str()]).arg("status");
|
||||
|
||||
let output = command.output()?;
|
||||
|
||||
if !output.status.success() {
|
||||
return Err(anyhow!("{:?}", output));
|
||||
}
|
||||
|
||||
let query_result: serde_json::Value =
|
||||
serde_json::from_slice(&output.stdout).unwrap_or_default();
|
||||
|
||||
let trusted_height = query_result["SyncInfo"]["latest_block_height"]
|
||||
.as_u64()
|
||||
.ok_or(anyhow!("Could not query height"))?;
|
||||
|
||||
let trusted_hash = query_result["SyncInfo"]["latest_block_hash"]
|
||||
.as_str()
|
||||
.ok_or(anyhow!("Could not query height"))?
|
||||
.to_string();
|
||||
|
||||
Ok((trusted_height, trusted_hash))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue