feat: error reporting with eyre (#240)
Co-authored-by: hu55a1n1 <sufialhussaini@gmail.com>
This commit is contained in:
parent
634bc6a8f3
commit
df40e592c8
23 changed files with 322 additions and 383 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1285,6 +1285,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"color-eyre",
|
||||
"cosmos-sdk-proto",
|
||||
"cosmrs",
|
||||
"hex",
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
use color_eyre::{eyre::eyre, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::{
|
||||
fs::File,
|
||||
|
@ -8,7 +9,7 @@ use tokio::{
|
|||
use tracing::debug;
|
||||
use xxhash_rust::xxh3::Xxh3;
|
||||
|
||||
use crate::{config::Config, error::Error};
|
||||
use crate::config::Config;
|
||||
|
||||
const BUFFER_SIZE: usize = 16384; // 16 KB buffer
|
||||
type Hash = u64;
|
||||
|
@ -22,7 +23,7 @@ struct DeployedContract {
|
|||
// Porcelain
|
||||
|
||||
impl Config {
|
||||
pub async fn contract_has_changed(&self, file: &Path) -> Result<bool, Error> {
|
||||
pub async fn contract_has_changed(&self, file: &Path) -> Result<bool> {
|
||||
let cur_hash: Hash = Self::gen_hash(file).await?;
|
||||
debug!("current file hash: {}", cur_hash);
|
||||
|
||||
|
@ -39,20 +40,17 @@ impl Config {
|
|||
}
|
||||
|
||||
/// Return a hash of the given file's contents
|
||||
pub async fn gen_hash(file: &Path) -> Result<Hash, Error> {
|
||||
let file = File::open(file)
|
||||
.await
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
||||
pub async fn gen_hash(file: &Path) -> Result<Hash> {
|
||||
let file = File::open(file).await?;
|
||||
|
||||
let mut reader = BufReader::new(file);
|
||||
|
||||
let mut hasher = Xxh3::new();
|
||||
|
||||
let mut buffer = [0; BUFFER_SIZE];
|
||||
loop {
|
||||
let bytes_read = reader
|
||||
.read(&mut buffer)
|
||||
.await
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
||||
let bytes_read = reader.read(&mut buffer).await?;
|
||||
|
||||
if bytes_read == 0 {
|
||||
break;
|
||||
}
|
||||
|
@ -65,7 +63,7 @@ impl Config {
|
|||
Ok(hash)
|
||||
}
|
||||
|
||||
pub async fn save_codeid_to_cache(&self, file: &Path, code_id: u64) -> Result<(), Error> {
|
||||
pub async fn save_codeid_to_cache(&self, file: &Path, code_id: u64) -> Result<()> {
|
||||
let contract_hash = Self::gen_hash(file).await?;
|
||||
let dest = Self::to_cache_path(self, file)?;
|
||||
let deployed_contract = DeployedContract {
|
||||
|
@ -76,7 +74,7 @@ impl Config {
|
|||
Self::write_to_cache(dest.as_path(), &deployed_contract).await
|
||||
}
|
||||
|
||||
pub async fn get_cached_codeid(&self, file: &Path) -> Result<u64, Error> {
|
||||
pub async fn get_cached_codeid(&self, file: &Path) -> Result<u64> {
|
||||
let cache_path = Self::to_cache_path(self, file)?;
|
||||
let code_id = Self::read_from_cache(cache_path.as_path()).await?.code_id;
|
||||
|
||||
|
@ -85,12 +83,16 @@ impl Config {
|
|||
|
||||
// Plumbing
|
||||
|
||||
fn to_cache_path(&self, file: &Path) -> Result<PathBuf, Error> {
|
||||
fn to_cache_path(&self, file: &Path) -> Result<PathBuf> {
|
||||
// Get cache filepath (".quartz/cache/example.wasm.json") from "example.wasm" filepath
|
||||
let mut filename = file
|
||||
.file_name()
|
||||
.ok_or(Error::PathNotFile(file.display().to_string()))?
|
||||
.ok_or(eyre!(
|
||||
"file at cache filepath does not exist {}",
|
||||
file.display()
|
||||
))?
|
||||
.to_os_string();
|
||||
|
||||
filename.push(".json");
|
||||
|
||||
let cached_file_path = Self::cache_dir(self)?.join::<PathBuf>(filename.into());
|
||||
|
@ -99,42 +101,43 @@ impl Config {
|
|||
}
|
||||
|
||||
/// Retreive hash from cache file
|
||||
async fn read_from_cache(cache_file: &Path) -> Result<DeployedContract, Error> {
|
||||
let content = tokio::fs::read_to_string(cache_file)
|
||||
.await
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
||||
serde_json::from_str(&content).map_err(|e| Error::GenericErr(e.to_string()))
|
||||
async fn read_from_cache(cache_file: &Path) -> Result<DeployedContract> {
|
||||
let content = tokio::fs::read_to_string(cache_file).await?;
|
||||
|
||||
serde_json::from_str(&content).map_err(|e| eyre!(e))
|
||||
}
|
||||
|
||||
/// Write a given file's contents hash to a file in cache directory
|
||||
async fn write_to_cache(cache_file: &Path, data: &DeployedContract) -> Result<(), Error> {
|
||||
let content = serde_json::to_string(data).map_err(|e| Error::GenericErr(e.to_string()))?;
|
||||
async fn write_to_cache(cache_file: &Path, data: &DeployedContract) -> Result<()> {
|
||||
let content = serde_json::to_string(data)?;
|
||||
|
||||
tokio::fs::write(cache_file, content)
|
||||
.await
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))
|
||||
.map_err(|e| eyre!(e))
|
||||
}
|
||||
pub fn cache_dir(&self) -> Result<PathBuf> {
|
||||
let cache_dir = self.app_dir.join(".cache/");
|
||||
std::fs::create_dir_all(&cache_dir)?;
|
||||
Ok(cache_dir)
|
||||
}
|
||||
|
||||
pub fn cache_dir(&self) -> Result<PathBuf, Error> {
|
||||
Ok(self.app_dir.join(".cache/"))
|
||||
}
|
||||
|
||||
pub fn build_log_dir(&self) -> Result<PathBuf, Error> {
|
||||
Ok(self.app_dir.join(".cache/log/"))
|
||||
pub fn build_log_dir(&self) -> Result<PathBuf> {
|
||||
let build_log_dir = self.app_dir.join(".cache/log/");
|
||||
std::fs::create_dir_all(&build_log_dir)?;
|
||||
Ok(build_log_dir)
|
||||
}
|
||||
|
||||
/// Creates the build log if it isn't created already, returns relative path from app_dir to log directory
|
||||
pub async fn create_build_log(&self) -> Result<PathBuf, Error> {
|
||||
pub async fn create_build_log(&self) -> Result<PathBuf> {
|
||||
let log_dir = Self::build_log_dir(self)?;
|
||||
if !log_dir.exists() {
|
||||
tokio::fs::create_dir_all(&log_dir)
|
||||
.await
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
||||
tokio::fs::create_dir_all(&log_dir).await?;
|
||||
}
|
||||
|
||||
Ok(log_dir)
|
||||
}
|
||||
|
||||
pub async fn log_build(&self, is_enclave: bool) -> Result<(), Error> {
|
||||
pub async fn log_build(&self, is_enclave: bool) -> Result<()> {
|
||||
let log_dir = Self::create_build_log(self).await?;
|
||||
|
||||
let filename = match is_enclave {
|
||||
|
@ -142,9 +145,7 @@ impl Config {
|
|||
false => "contract",
|
||||
};
|
||||
|
||||
tokio::fs::write(log_dir.join(filename), "test")
|
||||
.await
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
||||
tokio::fs::write(log_dir.join(filename), "log").await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ fn default_ws_url() -> Url {
|
|||
}
|
||||
|
||||
fn default_grpc_url() -> Url {
|
||||
"http://127.0.0.1:9090,"
|
||||
"http://127.0.0.1:9090"
|
||||
.parse()
|
||||
.expect("valid hardcoded URL")
|
||||
}
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
use displaydoc::Display;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
pub enum Error {
|
||||
/// Specified path `{0}` is not a directory
|
||||
PathNotDir(String),
|
||||
/// Specified file `{0}` does not exist
|
||||
PathNotFile(String),
|
||||
/// unspecified error: {0}
|
||||
GenericErr(String),
|
||||
/// IoError: {0}
|
||||
IoError(String),
|
||||
/// TOML Error : {0}
|
||||
TomlError(String),
|
||||
/// Tendermint error: {0}
|
||||
TendermintError(String),
|
||||
/// Clearscreen error: {0}
|
||||
ClearscreenError(String),
|
||||
/// JSON Error: {0}
|
||||
JsonError(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())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<clearscreen::Error> for Error {
|
||||
fn from(err: clearscreen::Error) -> Self {
|
||||
Error::ClearscreenError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<serde_json::Error> for Error {
|
||||
fn from(err: serde_json::Error) -> Self {
|
||||
Error::JsonError(err.to_string())
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
use async_trait::async_trait;
|
||||
use color_eyre::{Report, Result};
|
||||
|
||||
use crate::{config::Config, error::Error, request::Request, response::Response};
|
||||
use crate::{config::Config, request::Request, response::Response};
|
||||
|
||||
pub mod utils;
|
||||
// commands
|
||||
|
@ -14,24 +15,16 @@ pub mod init;
|
|||
|
||||
#[async_trait]
|
||||
pub trait Handler {
|
||||
type Error;
|
||||
type Response;
|
||||
|
||||
async fn handle<C: AsRef<Config> + Send>(
|
||||
self,
|
||||
config: C,
|
||||
) -> Result<Self::Response, Self::Error>;
|
||||
async fn handle<C: AsRef<Config> + Send>(self, config: C) -> Result<Self::Response, Report>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Handler for Request {
|
||||
type Error = Error;
|
||||
type Response = Response;
|
||||
|
||||
async fn handle<C: AsRef<Config> + Send>(
|
||||
self,
|
||||
config: C,
|
||||
) -> Result<Self::Response, Self::Error> {
|
||||
async fn handle<C: AsRef<Config> + Send>(self, config: C) -> Result<Self::Response, Report> {
|
||||
match self {
|
||||
Request::Init(request) => request.handle(config).await,
|
||||
Request::Handshake(request) => request.handle(config).await,
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
use std::process::Command;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use color_eyre::owo_colors::OwoColorize;
|
||||
use color_eyre::{eyre::eyre, owo_colors::OwoColorize, Report, Result};
|
||||
use tracing::{debug, info};
|
||||
|
||||
use crate::{
|
||||
config::Config,
|
||||
error::Error,
|
||||
handler::Handler,
|
||||
request::contract_build::ContractBuildRequest,
|
||||
response::{contract_build::ContractBuildResponse, Response},
|
||||
|
@ -14,13 +13,9 @@ use crate::{
|
|||
|
||||
#[async_trait]
|
||||
impl Handler for ContractBuildRequest {
|
||||
type Error = Error;
|
||||
type Response = Response;
|
||||
|
||||
async fn handle<C: AsRef<Config> + Send>(
|
||||
self,
|
||||
config: C,
|
||||
) -> Result<Self::Response, Self::Error> {
|
||||
async fn handle<C: AsRef<Config> + Send>(self, config: C) -> Result<Self::Response, Report> {
|
||||
let config = config.as_ref();
|
||||
info!("{}", "\nPeforming Contract Build".blue().bold());
|
||||
|
||||
|
@ -46,15 +41,10 @@ impl Handler for ContractBuildRequest {
|
|||
}
|
||||
|
||||
info!("{}", "🚧 Building contract binary ...".green().bold());
|
||||
let status = command
|
||||
.status()
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
||||
let status = command.status()?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(Error::GenericErr(format!(
|
||||
"Couldn't build contract. \n{:?}",
|
||||
status
|
||||
)));
|
||||
return Err(eyre!("Couldn't build contract. \n{:?}", status));
|
||||
}
|
||||
|
||||
config.log_build(false).await?;
|
||||
|
|
|
@ -2,7 +2,11 @@ use std::path::Path;
|
|||
|
||||
use async_trait::async_trait;
|
||||
use cargo_metadata::MetadataCommand;
|
||||
use color_eyre::owo_colors::OwoColorize;
|
||||
use color_eyre::{
|
||||
eyre::{eyre, Context},
|
||||
owo_colors::OwoColorize,
|
||||
Report, Result,
|
||||
};
|
||||
use cw_client::{CliClient, CwClient};
|
||||
use serde_json::json;
|
||||
use tendermint_rpc::HttpClient;
|
||||
|
@ -11,7 +15,6 @@ use tracing::{debug, info};
|
|||
use super::utils::{helpers::block_tx_commit, types::WasmdTxResponse};
|
||||
use crate::{
|
||||
config::Config,
|
||||
error::Error,
|
||||
handler::{utils::relay::RelayMessage, Handler},
|
||||
request::contract_deploy::ContractDeployRequest,
|
||||
response::{contract_deploy::ContractDeployResponse, Response},
|
||||
|
@ -19,24 +22,18 @@ use crate::{
|
|||
|
||||
#[async_trait]
|
||||
impl Handler for ContractDeployRequest {
|
||||
type Error = Error;
|
||||
type Response = Response;
|
||||
|
||||
async fn handle<C: AsRef<Config> + Send>(
|
||||
self,
|
||||
config: C,
|
||||
) -> Result<Self::Response, Self::Error> {
|
||||
async fn handle<C: AsRef<Config> + Send>(self, config: C) -> Result<Self::Response, Report> {
|
||||
let config = config.as_ref();
|
||||
info!("{}", "\nPeforming Contract Deploy".blue().bold());
|
||||
|
||||
// Get contract package name in snake_case
|
||||
let package_name = MetadataCommand::new()
|
||||
.manifest_path(&self.contract_manifest)
|
||||
.exec()
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?
|
||||
.exec()?
|
||||
.root_package()
|
||||
.ok_or("No root package found in the metadata")
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?
|
||||
.ok_or(eyre!("No root package found in the metadata"))?
|
||||
.name
|
||||
.clone()
|
||||
.replace('-', "_");
|
||||
|
@ -47,9 +44,7 @@ impl Handler for ContractDeployRequest {
|
|||
.join(package_name)
|
||||
.with_extension("wasm");
|
||||
|
||||
let (code_id, contract_addr) = deploy(wasm_bin_path.as_path(), self, config)
|
||||
.await
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
||||
let (code_id, contract_addr) = deploy(wasm_bin_path.as_path(), self, config).await?;
|
||||
|
||||
Ok(ContractDeployResponse {
|
||||
code_id,
|
||||
|
@ -63,17 +58,23 @@ async fn deploy(
|
|||
wasm_bin_path: &Path,
|
||||
args: ContractDeployRequest,
|
||||
config: &Config,
|
||||
) -> Result<(u64, String), anyhow::Error> {
|
||||
) -> Result<(u64, String), Report> {
|
||||
let tmrpc_client = HttpClient::new(config.node_url.as_str())?;
|
||||
let cw_client = CliClient::neutrond(config.node_url.clone());
|
||||
|
||||
info!("🚀 Deploying {} Contract", args.label);
|
||||
let code_id = if config.contract_has_changed(wasm_bin_path).await? {
|
||||
let deploy_output: WasmdTxResponse = serde_json::from_str(&cw_client.deploy(
|
||||
&config.chain_id,
|
||||
&config.tx_sender,
|
||||
wasm_bin_path.display().to_string(),
|
||||
)?)?;
|
||||
let deploy_output: WasmdTxResponse = serde_json::from_str(
|
||||
&cw_client
|
||||
.deploy(
|
||||
&config.chain_id,
|
||||
&config.tx_sender,
|
||||
wasm_bin_path.display().to_string(),
|
||||
)
|
||||
.map_err(|err| eyre!(Box::new(err)))?,
|
||||
)
|
||||
.wrap_err("Error calling deploy on cw client")?;
|
||||
|
||||
let res = block_tx_commit(&tmrpc_client, deploy_output.txhash).await?;
|
||||
|
||||
// Find the 'code_id' attribute
|
||||
|
@ -89,15 +90,21 @@ async fn deploy(
|
|||
.find(|attr| attr.key_str().unwrap_or("") == "code_id")
|
||||
})
|
||||
.and_then(|attr| attr.value_str().ok().and_then(|v| v.parse().ok()))
|
||||
.ok_or_else(|| anyhow::anyhow!("Failed to find code_id in the transaction result"))?;
|
||||
.ok_or_else(|| eyre!("Failed to find code_id in the transaction result"))?;
|
||||
|
||||
info!("Code ID: {}", code_id);
|
||||
|
||||
config.save_codeid_to_cache(wasm_bin_path, code_id).await?;
|
||||
config
|
||||
.save_codeid_to_cache(wasm_bin_path, code_id)
|
||||
.await
|
||||
.wrap_err("Error saving contract code id to cache")?;
|
||||
|
||||
code_id
|
||||
} else {
|
||||
config.get_cached_codeid(wasm_bin_path).await?
|
||||
config
|
||||
.get_cached_codeid(wasm_bin_path)
|
||||
.await
|
||||
.wrap_err("Error getting contract code id from cache")?
|
||||
};
|
||||
|
||||
info!("🚀 Communicating with Relay to Instantiate...");
|
||||
|
@ -116,6 +123,7 @@ async fn deploy(
|
|||
json!(init_msg),
|
||||
&format!("{} Contract #{}", args.label, code_id),
|
||||
)?)?;
|
||||
|
||||
let res = block_tx_commit(&tmrpc_client, init_output.txhash).await?;
|
||||
|
||||
// Find the '_contract_address' attribute
|
||||
|
@ -131,9 +139,7 @@ async fn deploy(
|
|||
.find(|attr| attr.key_str().unwrap_or("") == "_contract_address")
|
||||
})
|
||||
.and_then(|attr| attr.value_str().ok().and_then(|v| v.parse().ok()))
|
||||
.ok_or_else(|| {
|
||||
anyhow::anyhow!("Failed to find contract_address in the transaction result")
|
||||
})?;
|
||||
.ok_or_else(|| eyre!("Failed to find contract_address in the transaction result"))?;
|
||||
|
||||
info!("🚀 Successfully deployed and instantiated contract!");
|
||||
info!("🆔 Code ID: {}", code_id);
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
use std::{path::PathBuf, time::Duration};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use color_eyre::owo_colors::OwoColorize;
|
||||
// todo get rid of this?
|
||||
use miette::{IntoDiagnostic, Result};
|
||||
use color_eyre::{
|
||||
eyre::{eyre, Context},
|
||||
owo_colors::OwoColorize,
|
||||
Report, Result,
|
||||
};
|
||||
use quartz_common::proto::core_client::CoreClient;
|
||||
use tokio::{sync::mpsc, time::sleep};
|
||||
use tracing::{debug, info};
|
||||
|
@ -11,7 +13,6 @@ use watchexec::Watchexec;
|
|||
use watchexec_signals::Signal;
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
handler::{utils::helpers::wasmaddr_to_id, Handler},
|
||||
request::{
|
||||
contract_build::ContractBuildRequest, contract_deploy::ContractDeployRequest,
|
||||
|
@ -24,13 +25,9 @@ use crate::{
|
|||
|
||||
#[async_trait]
|
||||
impl Handler for DevRequest {
|
||||
type Error = Error;
|
||||
type Response = Response;
|
||||
|
||||
async fn handle<C: AsRef<Config> + Send>(
|
||||
self,
|
||||
config: C,
|
||||
) -> Result<Self::Response, Self::Error> {
|
||||
async fn handle<C: AsRef<Config> + Send>(self, config: C) -> Result<Self::Response, Report> {
|
||||
let config = config.as_ref();
|
||||
info!("\nPeforming Dev");
|
||||
|
||||
|
@ -58,7 +55,7 @@ async fn dev_driver(
|
|||
mut rx: mpsc::Receiver<DevRebuild>,
|
||||
args: &DevRequest,
|
||||
config: Config,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), Report> {
|
||||
// State
|
||||
let mut first_enclave_message = true;
|
||||
let mut first_contract_message = true;
|
||||
|
@ -82,7 +79,10 @@ async fn dev_driver(
|
|||
let contract_build = ContractBuildRequest {
|
||||
contract_manifest: args.contract_manifest.clone(),
|
||||
};
|
||||
contract_build.handle(&config).await?;
|
||||
contract_build
|
||||
.handle(&config)
|
||||
.await
|
||||
.wrap_err("Could not run `contract build`")?;
|
||||
|
||||
// Start enclave in background
|
||||
spawn_enclave_start(args, &config)?;
|
||||
|
@ -99,9 +99,7 @@ async fn dev_driver(
|
|||
info!("{}", "Enclave is listening for requests...".green().bold());
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Error launching quartz app");
|
||||
|
||||
return Err(e);
|
||||
return Err(e).wrap_err("Error initializing `quartz dev`");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -132,9 +130,7 @@ async fn dev_driver(
|
|||
info!("{}", "Enclave is listening for requests...".green().bold());
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Error restarting enclave and handshake");
|
||||
|
||||
return Err(e);
|
||||
return Err(e).wrap_err("Error restarting enclave after rebuild");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -154,7 +150,7 @@ async fn dev_driver(
|
|||
Err(e) => {
|
||||
eprintln!("Error deploying contract and handshake:");
|
||||
|
||||
return Err(e);
|
||||
return Err(e).wrap_err("Error redeploying contract after rebuild");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,7 +163,7 @@ async fn dev_driver(
|
|||
}
|
||||
|
||||
// Spawns enclve start in a separate task which runs in the background
|
||||
fn spawn_enclave_start(args: &DevRequest, config: &Config) -> Result<(), Error> {
|
||||
fn spawn_enclave_start(args: &DevRequest, config: &Config) -> Result<()> {
|
||||
// In separate process, launch the enclave
|
||||
let enclave_start = EnclaveStartRequest {
|
||||
unsafe_trust_latest: args.unsafe_trust_latest,
|
||||
|
@ -180,10 +176,8 @@ fn spawn_enclave_start(args: &DevRequest, config: &Config) -> Result<(), Error>
|
|||
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = enclave_start.handle(config_cpy).await {
|
||||
eprintln!("Error running enclave start.\n {}", e);
|
||||
eprintln!("Error running enclave start.\n {:?}", e);
|
||||
}
|
||||
|
||||
Ok::<(), Error>(())
|
||||
});
|
||||
|
||||
Ok(())
|
||||
|
@ -194,7 +188,7 @@ async fn deploy_and_handshake(
|
|||
contract: Option<&str>,
|
||||
args: &DevRequest,
|
||||
config: &Config,
|
||||
) -> Result<String, Error> {
|
||||
) -> Result<String> {
|
||||
info!("Waiting for enclave start to deploy contract and handshake");
|
||||
|
||||
// Wait at most 60 seconds to connect to enclave
|
||||
|
@ -210,9 +204,7 @@ async fn deploy_and_handshake(
|
|||
i -= 1;
|
||||
|
||||
if i == 0 {
|
||||
return Err(Error::GenericErr(
|
||||
"Could not connect to enclave".to_string(),
|
||||
));
|
||||
return Err(eyre!("Could not connect to enclave"));
|
||||
}
|
||||
}
|
||||
// Calls which interact with enclave
|
||||
|
@ -231,34 +223,33 @@ async fn deploy_and_handshake(
|
|||
contract_manifest: args.contract_manifest.clone(),
|
||||
};
|
||||
// Call handler
|
||||
let cd_res = contract_deploy.handle(config).await;
|
||||
let cd_res = contract_deploy
|
||||
.handle(config)
|
||||
.await
|
||||
.wrap_err("Could not run `quartz contract deploy`")?;
|
||||
|
||||
// Return contract address or shutdown enclave & error
|
||||
match cd_res {
|
||||
Ok(Response::ContractDeploy(res)) => res.contract_addr,
|
||||
Err(e) => return Err(e),
|
||||
_ => unreachable!("Unexpected response variant"),
|
||||
if let Response::ContractDeploy(res) = cd_res {
|
||||
res.contract_addr
|
||||
} else {
|
||||
unreachable!("Unexpected response variant")
|
||||
}
|
||||
};
|
||||
|
||||
// Run handshake
|
||||
info!("Running handshake on contract `{}`", contract);
|
||||
let handshake = HandshakeRequest {
|
||||
contract: wasmaddr_to_id(&contract).map_err(|_| Error::GenericErr(String::default()))?,
|
||||
contract: wasmaddr_to_id(&contract)?,
|
||||
unsafe_trust_latest: args.unsafe_trust_latest,
|
||||
};
|
||||
|
||||
let h_res = handshake.handle(config).await;
|
||||
|
||||
match h_res {
|
||||
Ok(Response::Handshake(res)) => {
|
||||
info!("Handshake complete: {}", res.pub_key);
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
_ => unreachable!("Unexpected response variant"),
|
||||
};
|
||||
let h_res = handshake
|
||||
.handle(config)
|
||||
.await
|
||||
.wrap_err("Could not run `quartz handshake`")?;
|
||||
println!("got here");
|
||||
if let Response::Handshake(res) = h_res {
|
||||
info!("Handshake complete: {}", res.pub_key);
|
||||
}
|
||||
|
||||
Ok(contract)
|
||||
}
|
||||
|
@ -304,7 +295,7 @@ async fn watcher(tx: mpsc::Sender<DevRebuild>, log_dir: PathBuf) -> Result<()> {
|
|||
wx.config.pathset([log_dir]);
|
||||
|
||||
// Keep running until Watchexec quits
|
||||
let _ = main.await.into_diagnostic()?;
|
||||
let _ = main.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
use async_trait::async_trait;
|
||||
use color_eyre::owo_colors::OwoColorize;
|
||||
use color_eyre::{eyre::eyre, owo_colors::OwoColorize, Report, Result};
|
||||
use tokio::process::Command;
|
||||
use tracing::{debug, info};
|
||||
|
||||
use crate::{
|
||||
config::Config,
|
||||
error::Error,
|
||||
handler::Handler,
|
||||
request::enclave_build::EnclaveBuildRequest,
|
||||
response::{enclave_build::EnclaveBuildResponse, Response},
|
||||
|
@ -13,13 +12,9 @@ use crate::{
|
|||
|
||||
#[async_trait]
|
||||
impl Handler for EnclaveBuildRequest {
|
||||
type Error = Error;
|
||||
type Response = Response;
|
||||
|
||||
async fn handle<C: AsRef<Config> + Send>(
|
||||
self,
|
||||
config: C,
|
||||
) -> Result<Self::Response, Self::Error> {
|
||||
async fn handle<C: AsRef<Config> + Send>(self, config: C) -> Result<Self::Response, Report> {
|
||||
let config = config.as_ref();
|
||||
info!("{}", "\nPeforming Enclave Build".blue().bold());
|
||||
|
||||
|
@ -43,16 +38,10 @@ impl Handler for EnclaveBuildRequest {
|
|||
}
|
||||
|
||||
info!("{}", "🚧 Running build command ...".green().bold());
|
||||
let status = command
|
||||
.status()
|
||||
.await
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
||||
let status = command.status().await?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(Error::GenericErr(format!(
|
||||
"Couldn't build enclave. {:?}",
|
||||
status
|
||||
)));
|
||||
return Err(eyre!("Couldn't build enclave. {:?}", status));
|
||||
}
|
||||
|
||||
config.log_build(true).await?;
|
||||
|
|
|
@ -2,7 +2,11 @@ use std::{fs, path::Path};
|
|||
|
||||
use async_trait::async_trait;
|
||||
use cargo_metadata::MetadataCommand;
|
||||
use color_eyre::owo_colors::OwoColorize;
|
||||
use color_eyre::{
|
||||
eyre::{eyre, Context},
|
||||
owo_colors::OwoColorize,
|
||||
Report, Result,
|
||||
};
|
||||
use cosmrs::AccountId;
|
||||
use quartz_common::enclave::types::Fmspc;
|
||||
use reqwest::Url;
|
||||
|
@ -12,7 +16,6 @@ use tracing::{debug, info};
|
|||
|
||||
use crate::{
|
||||
config::Config,
|
||||
error::Error,
|
||||
handler::{utils::helpers::write_cache_hash_height, Handler},
|
||||
request::enclave_start::EnclaveStartRequest,
|
||||
response::{enclave_start::EnclaveStartResponse, Response},
|
||||
|
@ -20,18 +23,16 @@ use crate::{
|
|||
|
||||
#[async_trait]
|
||||
impl Handler for EnclaveStartRequest {
|
||||
type Error = Error;
|
||||
type Response = Response;
|
||||
|
||||
async fn handle<C: AsRef<Config> + Send>(
|
||||
self,
|
||||
config: C,
|
||||
) -> Result<Self::Response, Self::Error> {
|
||||
async fn handle<C: AsRef<Config> + Send>(self, config: C) -> Result<Self::Response, Report> {
|
||||
let config = config.as_ref().clone();
|
||||
info!("{}", "\nPeforming Enclave Start".blue().bold());
|
||||
|
||||
// Get trusted height and hash
|
||||
let (trusted_height, trusted_hash) = self.get_hash_height(&config)?;
|
||||
let (trusted_height, trusted_hash) = self
|
||||
.get_hash_height(&config)
|
||||
.wrap_err("Error getting trusted hash and height")?;
|
||||
write_cache_hash_height(trusted_height, trusted_hash, &config).await?;
|
||||
|
||||
if config.mock_sgx {
|
||||
|
@ -59,27 +60,21 @@ impl Handler for EnclaveStartRequest {
|
|||
handle_process(enclave_child).await?;
|
||||
} else {
|
||||
let Some(fmspc) = self.fmspc else {
|
||||
return Err(Error::GenericErr(
|
||||
"FMSPC is required if MOCK_SGX isn't set".to_string(),
|
||||
));
|
||||
return Err(eyre!("FMSPC is required if MOCK_SGX isn't set"));
|
||||
};
|
||||
|
||||
let Some(tcbinfo_contract) = self.tcbinfo_contract else {
|
||||
return Err(Error::GenericErr(
|
||||
"tcbinfo_contract is required if MOCK_SGX isn't set".to_string(),
|
||||
));
|
||||
return Err(eyre!("tcbinfo_contract is required if MOCK_SGX isn't set"));
|
||||
};
|
||||
|
||||
let Some(dcap_verifier_contract) = self.dcap_verifier_contract else {
|
||||
return Err(Error::GenericErr(
|
||||
"dcap_verifier_contract is required if MOCK_SGX isn't set".to_string(),
|
||||
return Err(eyre!(
|
||||
"dcap_verifier_contract is required if MOCK_SGX isn't set"
|
||||
));
|
||||
};
|
||||
|
||||
if let Err(_) = std::env::var("ADMIN_SK") {
|
||||
return Err(Error::GenericErr(
|
||||
"ADMIN_SK environment variable is not set".to_string(),
|
||||
));
|
||||
if std::env::var("ADMIN_SK").is_err() {
|
||||
return Err(eyre!("ADMIN_SK environment variable is not set"));
|
||||
};
|
||||
|
||||
let enclave_dir = fs::canonicalize(config.app_dir.join("enclave"))?;
|
||||
|
@ -119,17 +114,11 @@ impl Handler for EnclaveStartRequest {
|
|||
}
|
||||
}
|
||||
|
||||
async fn handle_process(mut child: Child) -> Result<(), Error> {
|
||||
let status = child
|
||||
.wait()
|
||||
.await
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
||||
async fn handle_process(mut child: Child) -> Result<()> {
|
||||
let status = child.wait().await?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(Error::GenericErr(format!(
|
||||
"Couldn't build enclave. {:?}",
|
||||
status
|
||||
)));
|
||||
return Err(eyre!("Couldn't build enclave. {:?}", status));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -138,18 +127,17 @@ async fn create_mock_enclave_child(
|
|||
app_dir: &Path,
|
||||
release: bool,
|
||||
enclave_args: Vec<String>,
|
||||
) -> Result<Child, Error> {
|
||||
) -> Result<Child> {
|
||||
let enclave_dir = app_dir.join("enclave");
|
||||
let target_dir = app_dir.join("target");
|
||||
|
||||
// Use the enclave package metadata to get the path to the program binary
|
||||
let package_name = MetadataCommand::new()
|
||||
.manifest_path(enclave_dir.join("Cargo.toml"))
|
||||
.exec()
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?
|
||||
.exec()?
|
||||
.root_package()
|
||||
.ok_or("No root package found in the metadata")
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?
|
||||
.map_err(|e| eyre!(e))?
|
||||
.name
|
||||
.clone();
|
||||
|
||||
|
@ -166,26 +154,18 @@ async fn create_mock_enclave_child(
|
|||
debug!("Enclave Start Command: {:?}", command);
|
||||
|
||||
info!("{}", "🚧 Spawning enclave process ...".green().bold());
|
||||
let child = command
|
||||
.kill_on_drop(true)
|
||||
.spawn()
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
||||
let child = command.kill_on_drop(true).spawn()?;
|
||||
|
||||
Ok(child)
|
||||
}
|
||||
|
||||
async fn gramine_sgx_gen_private_key(enclave_dir: &Path) -> Result<(), Error> {
|
||||
async fn gramine_sgx_gen_private_key(enclave_dir: &Path) -> Result<()> {
|
||||
// Launch the gramine-sgx-gen-private-key command
|
||||
Command::new("gramine-sgx-gen-private-key")
|
||||
.current_dir(enclave_dir)
|
||||
.output()
|
||||
.await
|
||||
.map_err(|e| {
|
||||
Error::GenericErr(format!(
|
||||
"Failed to execute gramine-sgx-gen-private-key: {}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
.map_err(|e| eyre!("Failed to execute gramine-sgx-gen-private-key: {}", e))?;
|
||||
|
||||
// Continue regardless of error
|
||||
// > /dev/null 2>&1 || : # may fail
|
||||
|
@ -205,7 +185,7 @@ async fn gramine_manifest(
|
|||
node_url: &Url,
|
||||
ws_url: &Url,
|
||||
grpc_url: &Url,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<()> {
|
||||
let host = target_lexicon::HOST;
|
||||
let arch_libdir = format!(
|
||||
"/lib/{}-{}-{}",
|
||||
|
@ -214,7 +194,7 @@ async fn gramine_manifest(
|
|||
|
||||
let ra_client_spid = "51CAF5A48B450D624AEFE3286D314894";
|
||||
let home_dir = dirs::home_dir()
|
||||
.ok_or(Error::GenericErr("home dir not set".to_string()))?
|
||||
.ok_or_else(|| eyre!("Home directory not set"))?
|
||||
.display()
|
||||
.to_string();
|
||||
|
||||
|
@ -243,19 +223,19 @@ async fn gramine_manifest(
|
|||
.current_dir(enclave_dir)
|
||||
.status()
|
||||
.await
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
||||
.map_err(|e| eyre!("Failed to execute gramine-manifest: {}", e))?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(Error::GenericErr(format!(
|
||||
"Couldn't run gramine manifest. {:?}",
|
||||
return Err(eyre!(
|
||||
"gramine-manifest command failed with status: {:?}",
|
||||
status
|
||||
)));
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn gramine_sgx_sign(enclave_dir: &Path) -> Result<(), Error> {
|
||||
async fn gramine_sgx_sign(enclave_dir: &Path) -> Result<()> {
|
||||
let status = Command::new("gramine-sgx-sign")
|
||||
.arg("--manifest")
|
||||
.arg("quartz.manifest")
|
||||
|
@ -264,26 +244,27 @@ async fn gramine_sgx_sign(enclave_dir: &Path) -> Result<(), Error> {
|
|||
.current_dir(enclave_dir)
|
||||
.status()
|
||||
.await
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
||||
.map_err(|e| eyre!("Failed to execute gramine-sgx-sign: {}", e))?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(Error::GenericErr(format!(
|
||||
"gramine-sgx-sign command failed. {:?}",
|
||||
return Err(eyre!(
|
||||
"gramine-sgx-sign command failed with status: {:?}",
|
||||
status
|
||||
)));
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn create_gramine_sgx_child(enclave_dir: &Path) -> Result<Child, Error> {
|
||||
async fn create_gramine_sgx_child(enclave_dir: &Path) -> Result<Child> {
|
||||
info!("🚧 Spawning enclave process ...");
|
||||
|
||||
let child = Command::new("gramine-sgx")
|
||||
.arg("./quartz")
|
||||
.kill_on_drop(true)
|
||||
.current_dir(enclave_dir)
|
||||
.spawn()?;
|
||||
.spawn()
|
||||
.map_err(|e| eyre!("Failed to spawn gramine-sgx child process: {}", e))?;
|
||||
|
||||
Ok(child)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use anyhow::anyhow;
|
||||
use async_trait::async_trait;
|
||||
use color_eyre::owo_colors::OwoColorize;
|
||||
use color_eyre::{eyre::eyre, owo_colors::OwoColorize, Report, Result};
|
||||
use cw_client::{CliClient, CwClient};
|
||||
use futures_util::stream::StreamExt;
|
||||
use quartz_tm_prover::{config::Config as TmProverConfig, prover::prove};
|
||||
|
@ -11,7 +10,6 @@ use tracing::{debug, info};
|
|||
use super::utils::{helpers::block_tx_commit, types::WasmdTxResponse};
|
||||
use crate::{
|
||||
config::Config,
|
||||
error::Error,
|
||||
handler::{
|
||||
utils::{helpers::read_cached_hash_height, relay::RelayMessage},
|
||||
Handler,
|
||||
|
@ -22,27 +20,21 @@ use crate::{
|
|||
|
||||
#[async_trait]
|
||||
impl Handler for HandshakeRequest {
|
||||
type Error = Error;
|
||||
type Response = Response;
|
||||
|
||||
async fn handle<C: AsRef<Config> + Send>(
|
||||
self,
|
||||
config: C,
|
||||
) -> Result<Self::Response, Self::Error> {
|
||||
async fn handle<C: AsRef<Config> + Send>(self, config: C) -> Result<Self::Response, Report> {
|
||||
let config = config.as_ref().clone();
|
||||
|
||||
info!("{}", "\nPeforming Handshake".blue().bold());
|
||||
|
||||
// TODO: may need to import verbosity here
|
||||
let pub_key = handshake(self, config)
|
||||
.await
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
||||
let pub_key = handshake(self, config).await?;
|
||||
|
||||
Ok(HandshakeResponse { pub_key }.into())
|
||||
}
|
||||
}
|
||||
|
||||
async fn handshake(args: HandshakeRequest, config: Config) -> Result<String, anyhow::Error> {
|
||||
async fn handshake(args: HandshakeRequest, config: Config) -> Result<String> {
|
||||
let tmrpc_client = HttpClient::new(config.node_url.as_str())?;
|
||||
let cw_client = CliClient::neutrond(config.node_url.clone());
|
||||
|
||||
|
@ -64,7 +56,8 @@ async fn handshake(args: HandshakeRequest, config: Config) -> Result<String, any
|
|||
json!(res),
|
||||
"11000untrn",
|
||||
)
|
||||
.await?
|
||||
.await
|
||||
.map_err(|err| eyre!(Box::new(err)))?// TODO: change
|
||||
.as_str(),
|
||||
)?;
|
||||
debug!("\n\n SessionCreate tx output: {:?}", output);
|
||||
|
@ -92,7 +85,7 @@ async fn handshake(args: HandshakeRequest, config: Config) -> Result<String, any
|
|||
|
||||
let proof_output = prove(prover_config)
|
||||
.await
|
||||
.map_err(|report| anyhow!("Tendermint prover failed. Report: {}", report))?;
|
||||
.map_err(|report| eyre!("Tendermint prover failed. Report: {}", report))?;
|
||||
|
||||
// Execute SessionSetPubKey on enclave
|
||||
info!("Running SessionSetPubKey");
|
||||
|
@ -113,7 +106,8 @@ async fn handshake(args: HandshakeRequest, config: Config) -> Result<String, any
|
|||
json!(res),
|
||||
"11000untrn",
|
||||
)
|
||||
.await?
|
||||
.await
|
||||
.map_err(|err| eyre!(Box::new(err)))? // todo change
|
||||
.as_str(),
|
||||
)?;
|
||||
|
||||
|
@ -121,7 +115,9 @@ async fn handshake(args: HandshakeRequest, config: Config) -> Result<String, any
|
|||
block_tx_commit(&tmrpc_client, output.txhash).await?;
|
||||
info!("SessionSetPubKey tx committed");
|
||||
|
||||
let output: WasmdTxResponse = cw_client.query_tx(&output.txhash.to_string())?;
|
||||
let output: WasmdTxResponse = cw_client
|
||||
.query_tx(&output.txhash.to_string())
|
||||
.map_err(|err| eyre!(Box::new(err)))?; // todo change
|
||||
|
||||
let wasm_event = output
|
||||
.events
|
||||
|
@ -136,11 +132,11 @@ async fn handshake(args: HandshakeRequest, config: Config) -> Result<String, any
|
|||
}) {
|
||||
Ok(pubkey.value_str()?.to_string())
|
||||
} else {
|
||||
Err(anyhow!("Failed to find pubkey from SetPubKey message"))
|
||||
Err(eyre!("Failed to find pubkey from SetPubKey message"))
|
||||
}
|
||||
}
|
||||
|
||||
async fn two_block_waitoor(wsurl: &str) -> Result<(), anyhow::Error> {
|
||||
async fn two_block_waitoor(wsurl: &str) -> Result<()> {
|
||||
let (client, driver) = WebSocketClient::new(wsurl).await?;
|
||||
|
||||
let driver_handle = tokio::spawn(async move { driver.run().await });
|
||||
|
|
|
@ -2,13 +2,12 @@ use std::path::PathBuf;
|
|||
|
||||
use async_trait::async_trait;
|
||||
use cargo_generate::{generate, GenerateArgs, TemplatePath, Vcs};
|
||||
use color_eyre::owo_colors::OwoColorize;
|
||||
use color_eyre::{eyre::Context, owo_colors::OwoColorize, Report, Result};
|
||||
use tokio::fs;
|
||||
use tracing::info;
|
||||
|
||||
use crate::{
|
||||
config::Config,
|
||||
error::Error,
|
||||
handler::Handler,
|
||||
request::init::InitRequest,
|
||||
response::{init::InitResponse, Response},
|
||||
|
@ -16,14 +15,10 @@ use crate::{
|
|||
|
||||
#[async_trait]
|
||||
impl Handler for InitRequest {
|
||||
type Error = Error;
|
||||
type Response = Response;
|
||||
|
||||
// TODO: Add non-template init method
|
||||
async fn handle<C: AsRef<Config> + Send>(
|
||||
self,
|
||||
config: C,
|
||||
) -> Result<Self::Response, Self::Error> {
|
||||
async fn handle<C: AsRef<Config> + Send>(self, config: C) -> Result<Self::Response, Report> {
|
||||
let config = config.as_ref();
|
||||
info!("{}", "\nPeforming Init".blue().bold());
|
||||
|
||||
|
@ -36,7 +31,7 @@ impl Handler for InitRequest {
|
|||
.expect("path already validated");
|
||||
fs::create_dir_all(&parent)
|
||||
.await
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
||||
.wrap_err("Error creating directories to target app folder")?;
|
||||
|
||||
let file_name = self
|
||||
.name
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use color_eyre::{
|
||||
eyre::{eyre, WrapErr},
|
||||
Result,
|
||||
};
|
||||
use cosmrs::{AccountId, ErrorReport};
|
||||
use cw_client::{CliClient, CwClient};
|
||||
use regex::Regex;
|
||||
|
@ -13,15 +16,15 @@ use tendermint_rpc::{
|
|||
use tokio::fs::{self};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::{config::Config, error::Error};
|
||||
use crate::config::Config;
|
||||
|
||||
pub fn wasmaddr_to_id(address_str: &str) -> Result<AccountId, anyhow::Error> {
|
||||
let _ = bech32_decode(address_str).map_err(|e| anyhow!(e))?;
|
||||
address_str.parse().map_err(|e: ErrorReport| anyhow!(e))
|
||||
pub fn wasmaddr_to_id(address_str: &str) -> Result<AccountId> {
|
||||
let _ = bech32_decode(address_str).map_err(|e| eyre!(e))?;
|
||||
address_str.parse().map_err(|e: ErrorReport| eyre!(e))
|
||||
}
|
||||
|
||||
// Note: time until tx commit is empiraclly 800ms on DO wasmd chain.
|
||||
pub async fn block_tx_commit(client: &HttpClient, tx: Hash) -> Result<TmTxResponse, anyhow::Error> {
|
||||
pub async fn block_tx_commit(client: &HttpClient, tx: Hash) -> Result<TmTxResponse> {
|
||||
let re = Regex::new(r"tx \([A-F0-9]{64}\) not found")?;
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(400)).await;
|
||||
|
@ -35,7 +38,7 @@ pub async fn block_tx_commit(client: &HttpClient, tx: Hash) -> Result<TmTxRespon
|
|||
match e.0 {
|
||||
ErrorDetail::Response(subdetail) => {
|
||||
if !re.is_match(subdetail.source.data().unwrap_or_default()) {
|
||||
return Err(anyhow!(
|
||||
return Err(eyre!(
|
||||
"Error querying for tx: {}",
|
||||
ErrorDetail::Response(subdetail)
|
||||
));
|
||||
|
@ -46,7 +49,7 @@ pub async fn block_tx_commit(client: &HttpClient, tx: Hash) -> Result<TmTxRespon
|
|||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(anyhow!("Error querying for tx: {}", e.0));
|
||||
return Err(eyre!("Error querying for tx: {}", e.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,12 +58,13 @@ pub async fn block_tx_commit(client: &HttpClient, tx: Hash) -> Result<TmTxRespon
|
|||
}
|
||||
|
||||
// Queries the chain for the latested height and hash
|
||||
pub fn query_latest_height_hash(node_url: Url) -> Result<(Height, Hash), Error> {
|
||||
pub fn query_latest_height_hash(node_url: Url) -> Result<(Height, Hash)> {
|
||||
let cw_client = CliClient::neutrond(node_url);
|
||||
|
||||
let (trusted_height, trusted_hash) = cw_client
|
||||
.trusted_height_hash()
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
||||
.map_err(|e| eyre!(e))
|
||||
.wrap_err("Could not query chain with cw client")?;
|
||||
|
||||
Ok((
|
||||
trusted_height.try_into()?,
|
||||
|
@ -72,7 +76,7 @@ pub async fn write_cache_hash_height(
|
|||
trusted_height: Height,
|
||||
trusted_hash: Hash,
|
||||
config: &Config,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<()> {
|
||||
let height_path = config.cache_dir()?.join("trusted.height");
|
||||
fs::write(height_path.as_path(), trusted_height.to_string()).await?;
|
||||
let hash_path = config.cache_dir()?.join("trusted.hash");
|
||||
|
@ -81,15 +85,21 @@ pub async fn write_cache_hash_height(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn read_cached_hash_height(config: &Config) -> Result<(Height, Hash), Error> {
|
||||
pub async fn read_cached_hash_height(config: &Config) -> Result<(Height, Hash)> {
|
||||
let height_path = config.cache_dir()?.join("trusted.height");
|
||||
let hash_path = config.cache_dir()?.join("trusted.hash");
|
||||
|
||||
if !height_path.exists() {
|
||||
return Err(Error::PathNotFile(height_path.display().to_string()));
|
||||
return Err(eyre!(
|
||||
"Could not read trusted height from cache: {}",
|
||||
height_path.display().to_string()
|
||||
));
|
||||
}
|
||||
if !hash_path.exists() {
|
||||
return Err(Error::PathNotFile(hash_path.display().to_string()));
|
||||
return Err(eyre!(
|
||||
"Could not read trusted hash from cache: {}",
|
||||
hash_path.display().to_string()
|
||||
));
|
||||
}
|
||||
|
||||
let trusted_height: Height = fs::read_to_string(height_path.as_path()).await?.parse()?;
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
use color_eyre::{eyre::eyre, Result};
|
||||
use quartz_common::proto::{
|
||||
core_client::CoreClient, InstantiateRequest, SessionCreateRequest, SessionSetPubKeyRequest,
|
||||
};
|
||||
use quartz_tm_prover::config::ProofOutput;
|
||||
use serde_json::{json, Value as JsonValue};
|
||||
|
||||
use crate::error::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RelayMessage {
|
||||
Instantiate { init_msg: JsonValue },
|
||||
|
@ -14,17 +13,25 @@ pub enum RelayMessage {
|
|||
}
|
||||
|
||||
impl RelayMessage {
|
||||
pub async fn run_relay(self, enclave_rpc: String) -> Result<JsonValue, Error> {
|
||||
pub async fn run_relay(self, enclave_rpc: String) -> Result<JsonValue> {
|
||||
// Query the gRPC quartz enclave service
|
||||
let mut qc_client = CoreClient::connect(enclave_rpc)
|
||||
.await
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
||||
let mut qc_client = CoreClient::connect(enclave_rpc).await.map_err(|e| {
|
||||
eyre!(
|
||||
"Failed to connect to the gRPC quartz enclave service: {}",
|
||||
e
|
||||
)
|
||||
})?;
|
||||
|
||||
let attested_msg = match self {
|
||||
RelayMessage::Instantiate { mut init_msg } => qc_client
|
||||
.instantiate(tonic::Request::new(InstantiateRequest {}))
|
||||
.await
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))
|
||||
.map_err(|e| {
|
||||
eyre!(
|
||||
"Failed to instantiate via gRPC quartz enclave service: {}",
|
||||
e
|
||||
)
|
||||
})
|
||||
.map(|res| serde_json::from_str::<JsonValue>(&res.into_inner().message))?
|
||||
.map(|msg| {
|
||||
init_msg["quartz"] = msg;
|
||||
|
@ -33,7 +40,12 @@ impl RelayMessage {
|
|||
RelayMessage::SessionCreate => qc_client
|
||||
.session_create(tonic::Request::new(SessionCreateRequest {}))
|
||||
.await
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))
|
||||
.map_err(|e| {
|
||||
eyre!(
|
||||
"Failed to create session via gRPC quartz enclave service: {}",
|
||||
e
|
||||
)
|
||||
})
|
||||
.map(|res| serde_json::from_str::<JsonValue>(&res.into_inner().message))?
|
||||
.map(|msg| json!({ "quartz": {"session_create": msg}}).to_string())?,
|
||||
RelayMessage::SessionSetPubKey { proof } => qc_client
|
||||
|
@ -41,7 +53,12 @@ impl RelayMessage {
|
|||
message: serde_json::to_string(&proof)?,
|
||||
})
|
||||
.await
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))
|
||||
.map_err(|e| {
|
||||
eyre!(
|
||||
"Failed to set public key via gRPC quartz enclave service: {}",
|
||||
e
|
||||
)
|
||||
})
|
||||
.map(|res| serde_json::from_str::<JsonValue>(&res.into_inner().message))?
|
||||
.map(|msg| json!({ "quartz": {"session_set_pub_key": msg}}).to_string())?,
|
||||
};
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
pub mod cache;
|
||||
pub mod cli;
|
||||
pub mod config;
|
||||
pub mod error;
|
||||
pub mod handler;
|
||||
pub mod request;
|
||||
pub mod response;
|
||||
|
@ -25,7 +24,10 @@ use std::path::PathBuf;
|
|||
|
||||
use clap::Parser;
|
||||
use cli::ToFigment;
|
||||
use color_eyre::{eyre::Result, owo_colors::OwoColorize};
|
||||
use color_eyre::{
|
||||
eyre::{eyre, Result},
|
||||
owo_colors::OwoColorize,
|
||||
};
|
||||
use config::Config;
|
||||
use figment::{
|
||||
providers::{Env, Format, Serialized, Toml},
|
||||
|
@ -97,10 +99,10 @@ async fn main() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn check_path(path: &Option<PathBuf>) -> Result<(), error::Error> {
|
||||
fn check_path(path: &Option<PathBuf>) -> Result<()> {
|
||||
if let Some(path) = path {
|
||||
if !path.is_dir() {
|
||||
return Err(error::Error::PathNotDir(format!("{}", path.display())));
|
||||
return Err(eyre!("Path is not a directory: {}", path.display()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use color_eyre::{eyre::eyre, Report, Result};
|
||||
|
||||
use crate::{
|
||||
cli::{Command, ContractCommand, EnclaveCommand},
|
||||
error::Error,
|
||||
request::{
|
||||
contract_build::ContractBuildRequest, contract_deploy::ContractDeployRequest,
|
||||
dev::DevRequest, enclave_build::EnclaveBuildRequest, enclave_start::EnclaveStartRequest,
|
||||
|
@ -28,7 +29,7 @@ pub enum Request {
|
|||
}
|
||||
|
||||
impl TryFrom<Command> for Request {
|
||||
type Error = Error;
|
||||
type Error = Report;
|
||||
|
||||
fn try_from(cmd: Command) -> Result<Self, Self::Error> {
|
||||
match cmd {
|
||||
|
@ -40,38 +41,46 @@ impl TryFrom<Command> for Request {
|
|||
.into()),
|
||||
Command::Contract { contract_command } => contract_command.try_into(),
|
||||
Command::Enclave { enclave_command } => enclave_command.try_into(),
|
||||
Command::Dev(args) => Ok(DevRequest {
|
||||
watch: args.watch,
|
||||
unsafe_trust_latest: args.unsafe_trust_latest,
|
||||
init_msg: serde_json::from_str(&args.contract_deploy.init_msg)
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?,
|
||||
label: args.contract_deploy.label,
|
||||
contract_manifest: args.contract_deploy.contract_manifest,
|
||||
release: args.enclave_build.release,
|
||||
fmspc: args.fmspc,
|
||||
tcbinfo_contract: args.tcbinfo_contract,
|
||||
dcap_verifier_contract: args.dcap_verifier_contract,
|
||||
Command::Dev(args) => {
|
||||
if !args.contract_deploy.contract_manifest.exists() {
|
||||
return Err(eyre!(
|
||||
"The contract manifest file does not exist: {}",
|
||||
args.contract_deploy.contract_manifest.display()
|
||||
));
|
||||
}
|
||||
|
||||
Ok(DevRequest {
|
||||
watch: args.watch,
|
||||
unsafe_trust_latest: args.unsafe_trust_latest,
|
||||
contract_manifest: args.contract_deploy.contract_manifest,
|
||||
init_msg: serde_json::from_str(&args.contract_deploy.init_msg)?,
|
||||
label: args.contract_deploy.label,
|
||||
release: args.enclave_build.release,
|
||||
fmspc: args.fmspc,
|
||||
tcbinfo_contract: args.tcbinfo_contract,
|
||||
dcap_verifier_contract: args.dcap_verifier_contract,
|
||||
}
|
||||
.into())
|
||||
}
|
||||
.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ContractCommand> for Request {
|
||||
type Error = Error;
|
||||
type Error = Report;
|
||||
|
||||
fn try_from(cmd: ContractCommand) -> Result<Request, Error> {
|
||||
fn try_from(cmd: ContractCommand) -> Result<Request> {
|
||||
match cmd {
|
||||
ContractCommand::Deploy(args) => {
|
||||
if !args.contract_manifest.exists() {
|
||||
return Err(Error::PathNotFile(
|
||||
args.contract_manifest.display().to_string(),
|
||||
return Err(eyre!(
|
||||
"The contract manifest file does not exist: {}",
|
||||
args.contract_manifest.display()
|
||||
));
|
||||
}
|
||||
|
||||
Ok(ContractDeployRequest {
|
||||
init_msg: serde_json::from_str(&args.init_msg)
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?,
|
||||
init_msg: serde_json::from_str(&args.init_msg)?,
|
||||
label: args.label,
|
||||
contract_manifest: args.contract_manifest,
|
||||
}
|
||||
|
@ -79,8 +88,9 @@ impl TryFrom<ContractCommand> for Request {
|
|||
}
|
||||
ContractCommand::Build(args) => {
|
||||
if !args.contract_manifest.exists() {
|
||||
return Err(Error::PathNotFile(
|
||||
args.contract_manifest.display().to_string(),
|
||||
return Err(eyre!(
|
||||
"The contract manifest file does not exist: {}",
|
||||
args.contract_manifest.display()
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -94,9 +104,9 @@ impl TryFrom<ContractCommand> for Request {
|
|||
}
|
||||
|
||||
impl TryFrom<EnclaveCommand> for Request {
|
||||
type Error = Error;
|
||||
type Error = Report;
|
||||
|
||||
fn try_from(cmd: EnclaveCommand) -> Result<Request, Error> {
|
||||
fn try_from(cmd: EnclaveCommand) -> Result<Request> {
|
||||
match cmd {
|
||||
EnclaveCommand::Build(_) => Ok(EnclaveBuildRequest {}.into()),
|
||||
EnclaveCommand::Start(args) => Ok(EnclaveStartRequest {
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use color_eyre::{eyre::Context, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{error::Error, request::Request};
|
||||
use crate::request::Request;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ContractDeployRequest {
|
||||
|
@ -18,10 +19,9 @@ impl From<ContractDeployRequest> for Request {
|
|||
}
|
||||
|
||||
impl ContractDeployRequest {
|
||||
pub fn checked_init(init_msg: String) -> Result<GenericQuartzInit, Error> {
|
||||
let parsed: GenericQuartzInit = serde_json::from_str(&init_msg).map_err(|_| {
|
||||
Error::GenericErr("Init message doesn't contain mandatory quartz field.".to_string())
|
||||
})?;
|
||||
pub fn checked_init(init_msg: String) -> Result<GenericQuartzInit> {
|
||||
let parsed: GenericQuartzInit = serde_json::from_str(&init_msg)
|
||||
.wrap_err("Init message doesn't contain mandatory quartz field")?;
|
||||
|
||||
Ok(parsed)
|
||||
}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
use color_eyre::Result;
|
||||
use cosmrs::AccountId;
|
||||
use quartz_common::enclave::types::Fmspc;
|
||||
use tendermint::{block::Height, Hash};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::{
|
||||
config::Config, error::Error, handler::utils::helpers::query_latest_height_hash,
|
||||
request::Request,
|
||||
};
|
||||
use crate::{config::Config, handler::utils::helpers::query_latest_height_hash, request::Request};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EnclaveStartRequest {
|
||||
|
@ -24,7 +22,7 @@ impl From<EnclaveStartRequest> for Request {
|
|||
|
||||
impl EnclaveStartRequest {
|
||||
/// Returns the trusted hash and height
|
||||
pub fn get_hash_height(&self, config: &Config) -> Result<(Height, Hash), Error> {
|
||||
pub fn get_hash_height(&self, config: &Config) -> Result<(Height, Hash)> {
|
||||
if self.unsafe_trust_latest || config.trusted_height == 0 || config.trusted_hash.is_empty()
|
||||
{
|
||||
debug!("querying latest trusted hash & height from node");
|
||||
|
@ -35,10 +33,7 @@ impl EnclaveStartRequest {
|
|||
debug!("reusing config trusted hash & height");
|
||||
Ok((
|
||||
config.trusted_height.try_into()?,
|
||||
config
|
||||
.trusted_hash
|
||||
.parse()
|
||||
.map_err(|_| Error::GenericErr("invalid hash".to_string()))?,
|
||||
config.trusted_hash.parse()?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use crate::{error::Error, request::Request};
|
||||
use color_eyre::{eyre::eyre, Report, Result};
|
||||
|
||||
use crate::request::Request;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct InitRequest {
|
||||
|
@ -8,16 +10,16 @@ pub struct InitRequest {
|
|||
}
|
||||
|
||||
impl TryFrom<InitRequest> for Request {
|
||||
type Error = Error;
|
||||
type Error = Report;
|
||||
|
||||
fn try_from(request: InitRequest) -> Result<Request, Error> {
|
||||
fn try_from(request: InitRequest) -> Result<Request> {
|
||||
if request.name.extension().is_some() {
|
||||
return Err(Error::PathNotDir(format!("{}", request.name.display())));
|
||||
return Err(eyre!("Path is not a directory: {}", request.name.display()));
|
||||
} else if request.name.exists() {
|
||||
return Err(Error::GenericErr(format!(
|
||||
return Err(eyre!(
|
||||
"Directory already exists: {}",
|
||||
request.name.display()
|
||||
)));
|
||||
));
|
||||
}
|
||||
|
||||
Ok(Request::Init(request))
|
||||
|
|
|
@ -12,12 +12,13 @@ authors.workspace = true
|
|||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
async-trait.workspace = true
|
||||
color-eyre.workspace = true
|
||||
hex.workspace = true
|
||||
reqwest.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
anyhow.workspace = true
|
||||
tonic.workspace = true
|
||||
|
||||
cosmrs = { workspace = true, default-features = false, features = ["cosmwasm"] }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::process::Command;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use color_eyre::{eyre::eyre, Help, Report, Result};
|
||||
use cosmrs::{tendermint::chain::Id, AccountId};
|
||||
use reqwest::Url;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
@ -55,8 +55,23 @@ impl CliClient {
|
|||
}
|
||||
}
|
||||
|
||||
fn new_command(&self) -> Command {
|
||||
Command::new(self.kind.bin())
|
||||
fn new_command(&self) -> Result<Command> {
|
||||
let bin = self.kind.bin();
|
||||
if !self.is_bin_available(&bin) {
|
||||
return Err(eyre!("Binary '{}' not found in PATH", bin)).suggestion(format!(
|
||||
"Have you installed {}? If so, check that it's in your PATH.",
|
||||
bin
|
||||
));
|
||||
}
|
||||
|
||||
Ok(Command::new(self.kind.bin()))
|
||||
}
|
||||
fn is_bin_available(&self, bin: &str) -> bool {
|
||||
Command::new("which")
|
||||
.arg(bin)
|
||||
.output()
|
||||
.map(|output| output.status.success())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,14 +81,14 @@ impl CwClient for CliClient {
|
|||
type Query = serde_json::Value;
|
||||
type RawQuery = String;
|
||||
type ChainId = Id;
|
||||
type Error = anyhow::Error;
|
||||
type Error = Report;
|
||||
|
||||
async fn query_smart<R: DeserializeOwned + Send>(
|
||||
&self,
|
||||
contract: &Self::Address,
|
||||
query: Self::Query,
|
||||
) -> Result<R, Self::Error> {
|
||||
let mut command = self.new_command();
|
||||
let mut command = self.new_command()?;
|
||||
let command = command
|
||||
.args(["--node", self.url.as_str()])
|
||||
.args(["query", "wasm"])
|
||||
|
@ -83,11 +98,11 @@ impl CwClient for CliClient {
|
|||
|
||||
let output = command.output()?;
|
||||
if !output.status.success() {
|
||||
return Err(anyhow!("{:?}", output));
|
||||
return Err(eyre!("{:?}", output));
|
||||
}
|
||||
|
||||
let query_result: R = serde_json::from_slice(&output.stdout)
|
||||
.map_err(|e| anyhow!("Error deserializing: {}", e))?;
|
||||
.map_err(|e| eyre!("Error deserializing: {}", e))?;
|
||||
Ok(query_result)
|
||||
}
|
||||
|
||||
|
@ -96,7 +111,7 @@ impl CwClient for CliClient {
|
|||
contract: &Self::Address,
|
||||
query: Self::RawQuery,
|
||||
) -> Result<R, Self::Error> {
|
||||
let mut command = self.new_command();
|
||||
let mut command = self.new_command()?;
|
||||
let command = command
|
||||
.args(["--node", self.url.as_str()])
|
||||
.args(["query", "wasm"])
|
||||
|
@ -106,7 +121,7 @@ impl CwClient for CliClient {
|
|||
|
||||
let output = command.output()?;
|
||||
if !output.status.success() {
|
||||
return Err(anyhow!("{:?}", output));
|
||||
return Err(eyre!("{:?}", output));
|
||||
}
|
||||
|
||||
let query_result: R = serde_json::from_slice(&output.stdout).unwrap_or_default();
|
||||
|
@ -114,7 +129,7 @@ impl CwClient for CliClient {
|
|||
}
|
||||
|
||||
fn query_tx<R: DeserializeOwned + Default>(&self, txhash: &str) -> Result<R, Self::Error> {
|
||||
let mut command = self.new_command();
|
||||
let mut command = self.new_command()?;
|
||||
let command = command
|
||||
.args(["--node", self.url.as_str()])
|
||||
.args(["query", "tx"])
|
||||
|
@ -123,7 +138,7 @@ impl CwClient for CliClient {
|
|||
|
||||
let output = command.output()?;
|
||||
if !output.status.success() {
|
||||
return Err(anyhow!("{:?}", output));
|
||||
return Err(eyre!("{:?}", output));
|
||||
}
|
||||
|
||||
let query_result: R = serde_json::from_slice(&output.stdout).unwrap_or_default();
|
||||
|
@ -139,7 +154,7 @@ impl CwClient for CliClient {
|
|||
msg: M,
|
||||
fees: &str,
|
||||
) -> Result<String, Self::Error> {
|
||||
let mut command = self.new_command();
|
||||
let mut command = self.new_command()?;
|
||||
let command = command
|
||||
.args(["--node", self.url.as_str()])
|
||||
.args(["--chain-id", chain_id.as_ref()])
|
||||
|
@ -154,7 +169,7 @@ impl CwClient for CliClient {
|
|||
let output = command.output()?;
|
||||
|
||||
if !output.status.success() {
|
||||
return Err(anyhow!("{:?}", output));
|
||||
return Err(eyre!("{:?}", output));
|
||||
}
|
||||
|
||||
// TODO: find the rust type for the tx output and return that
|
||||
|
@ -167,7 +182,7 @@ impl CwClient for CliClient {
|
|||
sender: &str,
|
||||
wasm_path: M,
|
||||
) -> Result<String, Self::Error> {
|
||||
let mut command = self.new_command();
|
||||
let mut command = self.new_command()?;
|
||||
let command = command
|
||||
.args(["--node", self.url.as_str()])
|
||||
.args(["tx", "wasm", "store", &wasm_path.to_string()])
|
||||
|
@ -182,7 +197,7 @@ impl CwClient for CliClient {
|
|||
let output = command.output()?;
|
||||
|
||||
if !output.status.success() {
|
||||
return Err(anyhow!("{:?}", output));
|
||||
return Err(eyre!("{:?}", output));
|
||||
}
|
||||
|
||||
// TODO: find the rust type for the tx output and return that
|
||||
|
@ -197,7 +212,7 @@ impl CwClient for CliClient {
|
|||
init_msg: M,
|
||||
label: &str,
|
||||
) -> Result<String, Self::Error> {
|
||||
let mut command = self.new_command();
|
||||
let mut command = self.new_command()?;
|
||||
let command = command
|
||||
.args(["--node", self.url.as_str()])
|
||||
.args(["tx", "wasm", "instantiate"])
|
||||
|
@ -215,7 +230,7 @@ impl CwClient for CliClient {
|
|||
let output = command.output()?;
|
||||
|
||||
if !output.status.success() {
|
||||
return Err(anyhow!("{:?}", output));
|
||||
return Err(eyre!("{:?}", output));
|
||||
}
|
||||
|
||||
// TODO: find the rust type for the tx output and return that
|
||||
|
@ -223,13 +238,13 @@ impl CwClient for CliClient {
|
|||
}
|
||||
|
||||
fn trusted_height_hash(&self) -> Result<(u64, String), Self::Error> {
|
||||
let mut command = self.new_command();
|
||||
let mut command = self.new_command()?;
|
||||
let command = command.args(["--node", self.url.as_str()]).arg("status");
|
||||
|
||||
let output = command.output()?;
|
||||
|
||||
if !output.status.success() {
|
||||
return Err(anyhow!("{:?}", output));
|
||||
return Err(eyre!("{:?}", output));
|
||||
}
|
||||
|
||||
let query_result: serde_json::Value =
|
||||
|
@ -241,13 +256,13 @@ impl CwClient for CliClient {
|
|||
};
|
||||
let trusted_height = query_result[sync_info]["latest_block_height"]
|
||||
.as_str()
|
||||
.ok_or(anyhow!("Could not query height"))?;
|
||||
.ok_or(eyre!("Could not query height"))?;
|
||||
|
||||
let trusted_height = trusted_height.parse::<u64>()?;
|
||||
|
||||
let trusted_hash = query_result[sync_info]["latest_block_hash"]
|
||||
.as_str()
|
||||
.ok_or(anyhow!("Could not query height"))?
|
||||
.ok_or(eyre!("Could not query height"))?
|
||||
.to_string();
|
||||
|
||||
Ok((trusted_height, trusted_hash))
|
||||
|
|
1
examples/transfers/enclave/Cargo.lock
generated
1
examples/transfers/enclave/Cargo.lock
generated
|
@ -950,6 +950,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"color-eyre",
|
||||
"cosmos-sdk-proto",
|
||||
"cosmrs",
|
||||
"hex",
|
||||
|
|
|
@ -41,7 +41,8 @@ use crate::wslistener::WsListener;
|
|||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args = Cli::parse();
|
||||
|
||||
let admin_sk = std::env::var("ADMIN_SK")?;
|
||||
let admin_sk = std::env::var("ADMIN_SK")
|
||||
.map_err(|_| anyhow::anyhow!("Admin secret key not found in env vars"))?;
|
||||
|
||||
let light_client_opts = LightClientOpts::new(
|
||||
args.chain_id.clone(),
|
||||
|
|
Loading…
Reference in a new issue