From 4fd86c089a77bd56626eb4393f3f9d3729b63293 Mon Sep 17 00:00:00 2001 From: Daniel Gushchyan <39884512+dangush@users.noreply.github.com> Date: Fri, 9 Aug 2024 16:24:57 -0700 Subject: [PATCH] feat: cli enclave start (#156) --- Cargo.lock | 50 ++++-- apps/mtcs/enclave/quartz.manifest.template | 58 +++++++ cli/Cargo.toml | 4 +- cli/src/cli.rs | 9 +- cli/src/handler.rs | 2 + cli/src/handler/enclave_start.rs | 187 +++++++++++++++++++++ cli/src/handler/handshake.rs | 18 +- cli/src/handler/utils/helpers.rs | 19 ++- cli/src/main.rs | 4 +- cli/src/request.rs | 24 ++- cli/src/request/enclave_start.rs | 15 ++ cli/src/response.rs | 5 +- cli/src/response/enclave_start.rs | 12 ++ 13 files changed, 364 insertions(+), 43 deletions(-) create mode 100644 apps/mtcs/enclave/quartz.manifest.template create mode 100644 cli/src/handler/enclave_start.rs create mode 100644 cli/src/request/enclave_start.rs create mode 100644 cli/src/response/enclave_start.rs diff --git a/Cargo.lock b/Cargo.lock index c85764d..68f67a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -751,9 +751,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.13" +version = "4.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc" +checksum = "c937d4061031a6d0c8da4b9a4f98a172fc2976dfb1c19213a9cf7d0d3c837e36" dependencies = [ "clap_builder", "clap_derive", @@ -761,9 +761,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.13" +version = "4.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99" +checksum = "85379ba512b21a328adf887e85f7742d12e96eb31f3ef077df4ffc26b506ffed" dependencies = [ "anstream", "anstyle", @@ -914,15 +914,15 @@ dependencies = [ [[package]] name = "cosmwasm-core" -version = "2.1.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "367fc87c43759098a476ef90f915aadc66c300480ad9c155b512081fbf327bc1" +checksum = "d905990ef3afb5753bb709dc7de88e9e370aa32bcc2f31731d4b533b63e82490" [[package]] name = "cosmwasm-crypto" -version = "2.1.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7c41f3e371ea457d3b98bb592c38858b46efcf614e0e988ec2ebbdb973954f" +checksum = "5b2a7bd9c1dd9a377a4dc0f4ad97d24b03c33798cd5a6d7ceb8869b41c5d2f2d" dependencies = [ "ark-bls12-381", "ark-ec", @@ -943,9 +943,9 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "2.1.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c10510e8eb66cf7e109741b1e2c76ad18f30b5a1daa064f5f7115c1f733aaea0" +checksum = "029910b409398fdf81955d7301b906caf81f2c42b013ea074fbd89720229c424" dependencies = [ "proc-macro2", "quote", @@ -954,9 +954,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema" -version = "2.1.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79879b6b7ef6a331b05030ce91ce46a7c4b0baf1ed6b382cce2e9a168109380" +checksum = "4bc0d4d85e83438ab9a0fea9348446f7268bc016aacfebce37e998559f151294" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -967,9 +967,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "2.1.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b53e33c0e97170c7ac9cb440f4bc599a07f9cbb9b7e87916cca37b1239d57b" +checksum = "edf5c8adac41bb7751c050d7c4c18675be19ee128714454454575e894424eeef" dependencies = [ "proc-macro2", "quote", @@ -978,9 +978,9 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "2.1.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92011c39570876f340d5f9defa68bf92797b1c44421f1b9ea9b04a31d6defd33" +checksum = "51dec99a2e478715c0a4277f0dbeadbb8466500eb7dec873d0924edd086e77f1" dependencies = [ "base64 0.22.1", "bech32", @@ -3627,6 +3627,7 @@ dependencies = [ "cosmrs", "cosmwasm-std", "cycles-sync", + "dirs", "displaydoc", "futures-util", "hex", @@ -3641,6 +3642,7 @@ dependencies = [ "serde", "serde_json", "subtle-encoding", + "target-lexicon", "tendermint 0.38.1", "tendermint-light-client", "tendermint-rpc", @@ -4597,6 +4599,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + [[package]] name = "signature" version = "2.2.0" @@ -4764,6 +4775,12 @@ dependencies = [ "libc", ] +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + [[package]] name = "tempfile" version = "3.10.1" @@ -5132,6 +5149,7 @@ dependencies = [ "libc", "mio", "pin-project-lite", + "signal-hook-registry", "socket2", "tokio-macros", "windows-sys 0.52.0", diff --git a/apps/mtcs/enclave/quartz.manifest.template b/apps/mtcs/enclave/quartz.manifest.template new file mode 100644 index 0000000..1b49538 --- /dev/null +++ b/apps/mtcs/enclave/quartz.manifest.template @@ -0,0 +1,58 @@ +# Quartz manifest file + +loader.entrypoint = "file:{{ gramine.libos }}" +libos.entrypoint = "{{ quartz_dir }}/target/release/enclave" + +loader.log_level = "{{ log_level }}" + +loader.env.LD_LIBRARY_PATH = "/lib:{{ arch_libdir }}:/usr/{{ arch_libdir }}" +loader.env.HOME = "{{ home }}" +loader.env.INSIDE_SGX = "1" +loader.env.TLS = { passthrough = true } +loader.env.RA_TYPE = { passthrough = true } +loader.env.RA_TLS_ALLOW_DEBUG_ENCLAVE_INSECURE = { passthrough = true } +loader.env.RA_TLS_ALLOW_OUTDATED_TCB_INSECURE = { passthrough = true } +loader.env.RA_TLS_MRENCLAVE = { passthrough = true } +loader.env.RA_TLS_MRSIGNER = { passthrough = true } +loader.env.RA_TLS_ISV_SVN = { passthrough = true } +loader.env.RA_TLS_ISV_PROD_ID = { passthrough = true } +loader.env.RA_TLS_EPID_API_KEY = { passthrough = true } +loader.env.MYAPP_DATA = { passthrough = true } +loader.env.QUARTZ_PORT = { passthrough = true } + +loader.argv = ["enclave", + "--chain-id", "testing", + "--trusted-height", "{{ trusted_height }}", + "--trusted-hash", "{{ trusted_hash }}"] + +fs.mounts = [ + { uri = "file:{{ gramine.runtimedir() }}", path = "/lib" }, + { uri = "file:{{ arch_libdir }}", path = "{{ arch_libdir }}" }, + { uri = "file:/usr/{{ arch_libdir }}", path = "/usr{{ arch_libdir }}" }, + { uri = "file:{{ quartz_dir }}", path = "{{ quartz_dir }}" }, +] + +# sgx.debug = true +sgx.enclave_size = "512M" +sgx.max_threads = 4 +sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} + +sgx.remote_attestation = "{{ ra_type }}" +sgx.ra_client_spid = "{{ ra_client_spid }}" +sgx.ra_client_linkable = {{ 'true' if ra_client_linkable == '1' else 'false' }} + +sgx.trusted_files = [ + "file:{{ gramine.libos }}", + "file:{{ quartz_dir }}/target/release/enclave", + "file:{{ gramine.runtimedir() }}/", + "file:{{ arch_libdir }}/", + "file:/usr/{{ arch_libdir }}/", +] + +sgx.allowed_files = [ + "file:{{ quartz_dir }}/exchange.sk", + "file:{{ quartz_dir }}/request.json", +] + +sys.insecure__allow_eventfd = true +sys.enable_sigterm_injection = true \ No newline at end of file diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 03ee6a3..5445ef5 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -15,6 +15,7 @@ cargo-generate.workspace = true clap = { workspace = true, features=["env"] } color-eyre.workspace = true displaydoc.workspace = true +dirs = "5.0.1" serde.workspace = true serde_json.workspace = true thiserror.workspace = true @@ -23,7 +24,7 @@ tracing-subscriber = { workspace = true, features = ["env-filter"] } hex.workspace = true k256.workspace = true prost.workspace = true -tokio.workspace = true +tokio = { workspace = true, features = ["process"] } tonic.workspace = true once_cell = "1.19.0" reqwest = { version = "0.12.2", default-features = false, features = ["json", "rustls-tls"] } @@ -31,6 +32,7 @@ anyhow = "1.0.86" base64 = "0.22.1" subtle-encoding = "0.5.1" futures-util = "0.3.30" +target-lexicon = "0.12.16" # cosmos cosmrs.workspace = true diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 5d70505..d5f893b 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -117,14 +117,19 @@ pub enum ContractCommand { 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 + /// 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)] - path: Option, + app_dir: Option, + /// The network chain ID + #[clap(long)] + chain_id: String, }, } diff --git a/cli/src/handler.rs b/cli/src/handler.rs index fc611b3..7dd693c 100644 --- a/cli/src/handler.rs +++ b/cli/src/handler.rs @@ -7,6 +7,7 @@ pub mod utils; pub mod contract_build; pub mod contract_deploy; pub mod enclave_build; +pub mod enclave_start; pub mod handshake; pub mod init; @@ -30,6 +31,7 @@ impl Handler for Request { Request::ContractBuild(request) => request.handle(config).await, Request::ContractDeploy(request) => request.handle(config).await, Request::EnclaveBuild(request) => request.handle(config).await, + Request::EnclaveStart(request) => request.handle(config).await, } .map(Into::into) } diff --git a/cli/src/handler/enclave_start.rs b/cli/src/handler/enclave_start.rs new file mode 100644 index 0000000..0caa797 --- /dev/null +++ b/cli/src/handler/enclave_start.rs @@ -0,0 +1,187 @@ +use std::env; + +use async_trait::async_trait; +use tokio::process::Command; +use tracing::{debug, info}; + +use super::utils::helpers::read_hash_height; +use crate::{ + error::Error, + handler::Handler, + request::enclave_start::EnclaveStartRequest, + response::{enclave_start::EnclaveStartResponse, Response}, + Config, +}; + +#[async_trait] +impl Handler for EnclaveStartRequest { + type Error = Error; + type Response = Response; + + async fn handle(self, config: Config) -> Result { + 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()))?; + + if config.mock_sgx { + let enclave_args: Vec = vec![ + "--chain-id".to_string(), + self.chain_id, + "--trusted-height".to_string(), + trusted_height.to_string(), + "--trusted-hash".to_string(), + trusted_hash.to_string(), + ]; + + // Run quartz enclave and block + let _res = run_enclave( + enclave_dir.join("Cargo.toml").display().to_string(), + config.mock_sgx, + enclave_args, + ) + .await?; + } else { + // set cwd to enclave app + env::set_current_dir(enclave_dir).map_err(|e| Error::GenericErr(e.to_string()))?; + // gramine private key + gramine_sgx_gen_private_key().await?; + // gramine manifest + gramine_manifest(&trusted_height.to_string(), &trusted_hash.to_string()).await?; + // gramine sign + gramine_sgx_sign().await?; + // Run quartz enclave and block + gramine_sgx().await?; + } + Ok(EnclaveStartResponse.into()) + } +} + +async fn run_enclave( + manifest_path: String, + mock_sgx: bool, + enclave_args: Vec, +) -> Result<(), Error> { + let mut cargo = Command::new("cargo"); + let command = cargo.args(["run", "--release", "--manifest-path", &manifest_path]); + + if mock_sgx { + debug!("Running with mock-sgx enabled"); + command.arg("--features=mock-sgx"); + } + + command.arg("--"); + command.args(enclave_args); + + println!("command: {:?}", command); + + info!("🚧 Running enclave ..."); + let status = command + .status() + .await + .map_err(|e| Error::GenericErr(e.to_string()))?; + + if !status.success() { + return Err(Error::GenericErr(format!( + "Couldn't build enclave. {:?}", + status + ))); + } + + Ok(()) +} + +async fn gramine_sgx_gen_private_key() -> Result<(), Error> { + // Launch the gramine-sgx-gen-private-key command + Command::new("gramine-sgx-gen-private-key") + .output() + .await + .map_err(|e| { + Error::GenericErr(format!( + "Failed to execute gramine-sgx-gen-private-key: {}", + e + )) + })?; + + // Continue regardless of error + // > /dev/null 2>&1 || : # may fail + Ok(()) +} + +async fn gramine_manifest(trusted_height: &str, trusted_hash: &str) -> Result<(), Error> { + let current_dir = env::current_dir().map_err(|e| Error::GenericErr(e.to_string()))?; + + let host = target_lexicon::HOST; + let arch_libdir = format!( + "/lib/{}-{}-{}", + host.architecture, host.operating_system, host.environment + ); + + let ra_client_spid = "51CAF5A48B450D624AEFE3286D314894"; + let home_dir = dirs::home_dir() + .ok_or(Error::GenericErr("home dir not set".to_string()))? + .display() + .to_string(); + + let status = Command::new("gramine-manifest") + .arg("-Dlog_level=error") + .arg(format!("-Dhome={}", home_dir)) + .arg(format!("-Darch_libdir={}", arch_libdir)) + .arg("-Dra_type=epid") + .arg(format!("-Dra_client_spid={}", ra_client_spid)) + .arg("-Dra_client_linkable=1") + .arg(format!("-Dquartz_dir={}", current_dir.display())) + .arg(format!("-Dtrusted_height={}", trusted_height)) + .arg(format!("-Dtrusted_hash={}", trusted_hash)) + .arg("quartz.manifest.template") + .arg("quartz.manifest") + .status() + .await + .map_err(|e| Error::GenericErr(e.to_string()))?; + + if !status.success() { + return Err(Error::GenericErr(format!( + "Couldn't run gramine manifest. {:?}", + status + ))); + } + + Ok(()) +} + +async fn gramine_sgx_sign() -> Result<(), Error> { + let status = Command::new("gramine-sgx-sign") + .arg("--manifest") + .arg("quartz.manifest") + .arg("--output") + .arg("quartz.manifest.sgx") + .status() + .await + .map_err(|e| Error::GenericErr(e.to_string()))?; + + if !status.success() { + return Err(Error::GenericErr(format!( + "gramine-sgx-sign command failed. {:?}", + status + ))); + } + + Ok(()) +} + +async fn gramine_sgx() -> Result<(), Error> { + let status = Command::new("gramine-sgx") + .arg("./quartz") + .status() + .await + .map_err(|e| Error::GenericErr(e.to_string()))?; + + if !status.success() { + return Err(Error::GenericErr(format!( + "gramine-sgx-sign command failed. {:?}", + status + ))); + } + + Ok(()) +} diff --git a/cli/src/handler/handshake.rs b/cli/src/handler/handshake.rs index a6d8b02..ed9d6d1 100644 --- a/cli/src/handler/handshake.rs +++ b/cli/src/handler/handshake.rs @@ -1,4 +1,4 @@ -use std::{env::current_dir, fs, path::Path, str::FromStr}; +use std::{env::current_dir, fs, str::FromStr}; use anyhow::anyhow; use async_trait::async_trait; @@ -8,7 +8,6 @@ use futures_util::stream::StreamExt; use reqwest::Url; use serde::Serialize; use serde_json::json; -use tendermint::{block::Height, Hash}; use tendermint_rpc::{query::EventType, HttpClient, SubscriptionClient, WebSocketClient}; use tm_prover::{config::Config as TmProverConfig, prover::prove}; use tracing::{debug, info, trace}; @@ -19,7 +18,10 @@ use super::utils::{ }; use crate::{ error::Error, - handler::{utils::types::RelayMessage, Handler}, + handler::{ + utils::{helpers::read_hash_height, types::RelayMessage}, + Handler, + }, request::handshake::HandshakeRequest, response::{handshake::HandshakeResponse, Response}, Config, @@ -185,13 +187,3 @@ async fn two_block_waitoor(wsurl: &str) -> Result<(), anyhow::Error> { Ok(()) } - -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())?.trim().parse()?; - - let hash_path = base_path.join("trusted.hash"); - let trusted_hash: Hash = fs::read_to_string(hash_path.as_path())?.trim().parse()?; - - Ok((trusted_height, trusted_hash)) -} diff --git a/cli/src/handler/utils/helpers.rs b/cli/src/handler/utils/helpers.rs index 91d176c..7a3c253 100644 --- a/cli/src/handler/utils/helpers.rs +++ b/cli/src/handler/utils/helpers.rs @@ -5,10 +5,11 @@ use cosmrs::{AccountId, ErrorReport}; use regex::Regex; use serde::de::DeserializeOwned; use subtle_encoding::bech32::decode as bech32_decode; -use tendermint::Hash; +use tendermint::{block::Height, Hash}; use tendermint_rpc::{ endpoint::tx::Response as TmTxResponse, error::ErrorDetail, Client, HttpClient, }; +use tokio::fs; use tracing::debug; use super::types::RelayMessage; @@ -85,3 +86,19 @@ pub async fn block_tx_commit(client: &HttpClient, tx: Hash) -> Result 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()?; + + 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)) +} diff --git a/cli/src/main.rs b/cli/src/main.rs index 265c502..c471f8e 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -26,11 +26,11 @@ use tracing_subscriber::{util::SubscriberInitExt, EnvFilter}; use crate::{cli::Cli, handler::Handler, request::Request}; const BANNER: &str = r" - ________ ___ ___ ________ ________ _________ ________ + ________ ___ ___ ________ ________ __________ ________ |\ __ \ |\ \|\ \ |\ __ \ |\ __ \ |\___ ___\ |\_____ \ \ \ \|\ \ \ \ \\\ \ \ \ \|\ \ \ \ \|\ \ \|___ \ \_| \|___/ /| \ \ \\\ \ \ \ \\\ \ \ \ __ \ \ \ _ _\ \ \ \ / / / - \ \ \\\ \ \ \ \\\ \ \ \ \ \ \ \ \ \\ \| \ \ \ / /_/__ + \ \ \\\ \ \ \ \\\ \ \ \ \ \ \ \ \ \\ \ \ \ \ / /_/__ \ \_____ \ \ \_______\ \ \__\ \__\ \ \__\\ _\ \ \__\ |\________\ \|___| \__\ \|_______| \|__|\|__| \|__|\|__| \|__| \|_______| \|__| diff --git a/cli/src/request.rs b/cli/src/request.rs index ab934e4..8a33389 100644 --- a/cli/src/request.rs +++ b/cli/src/request.rs @@ -5,13 +5,15 @@ use crate::{ error::Error, request::{ contract_build::ContractBuildRequest, contract_deploy::ContractDeployRequest, - enclave_build::EnclaveBuildRequest, handshake::HandshakeRequest, init::InitRequest, + enclave_build::EnclaveBuildRequest, enclave_start::EnclaveStartRequest, + handshake::HandshakeRequest, init::InitRequest, }, }; pub mod contract_build; pub mod contract_deploy; pub mod enclave_build; +pub mod enclave_start; pub mod handshake; pub mod init; @@ -22,6 +24,7 @@ pub enum Request { ContractBuild(ContractBuildRequest), ContractDeploy(ContractDeployRequest), EnclaveBuild(EnclaveBuildRequest), + EnclaveStart(EnclaveStartRequest), } impl TryFrom for Request { @@ -49,7 +52,7 @@ impl TryFrom for Request { } .into()), Command::Contract { contract_command } => contract_command.try_into(), - Command::Enclave { enclave_command } => Ok(enclave_command.into()), + Command::Enclave { enclave_command } => enclave_command.try_into(), } } } @@ -60,7 +63,6 @@ impl Request { 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()))?) @@ -107,11 +109,19 @@ impl TryFrom for Request { } } -impl From for Request { - fn from(cmd: EnclaveCommand) -> Request { +impl TryFrom for Request { + type Error = Error; + + fn try_from(cmd: EnclaveCommand) -> Result { match cmd { - EnclaveCommand::Build { manifest_path } => EnclaveBuildRequest { manifest_path }.into(), - EnclaveCommand::Start { path: _ } => todo!(), + EnclaveCommand::Build { manifest_path } => { + Ok(EnclaveBuildRequest { manifest_path }.into()) + } + EnclaveCommand::Start { app_dir, chain_id } => Ok(EnclaveStartRequest { + app_dir: Self::path_checked(app_dir)?, + chain_id, + } + .into()), } } } diff --git a/cli/src/request/enclave_start.rs b/cli/src/request/enclave_start.rs new file mode 100644 index 0000000..272c3dd --- /dev/null +++ b/cli/src/request/enclave_start.rs @@ -0,0 +1,15 @@ +use std::path::PathBuf; + +use crate::request::Request; + +#[derive(Clone, Debug)] +pub struct EnclaveStartRequest { + pub app_dir: PathBuf, + pub chain_id: String, +} + +impl From for Request { + fn from(request: EnclaveStartRequest) -> Self { + Self::EnclaveStart(request) + } +} diff --git a/cli/src/response.rs b/cli/src/response.rs index 74db3a8..aaa272d 100644 --- a/cli/src/response.rs +++ b/cli/src/response.rs @@ -2,12 +2,14 @@ use serde::Serialize; use crate::response::{ contract_build::ContractBuildResponse, contract_deploy::ContractDeployResponse, - enclave_build::EnclaveBuildResponse, handshake::HandshakeResponse, init::InitResponse, + enclave_build::EnclaveBuildResponse, enclave_start::EnclaveStartResponse, + handshake::HandshakeResponse, init::InitResponse, }; pub mod contract_build; pub mod contract_deploy; pub mod enclave_build; +pub mod enclave_start; pub mod handshake; pub mod init; @@ -18,4 +20,5 @@ pub enum Response { ContractBuild(ContractBuildResponse), ContractDeploy(ContractDeployResponse), EnclaveBuild(EnclaveBuildResponse), + EnclaveStart(EnclaveStartResponse), } diff --git a/cli/src/response/enclave_start.rs b/cli/src/response/enclave_start.rs new file mode 100644 index 0000000..22b802e --- /dev/null +++ b/cli/src/response/enclave_start.rs @@ -0,0 +1,12 @@ +use serde::Serialize; + +use crate::response::Response; + +#[derive(Clone, Debug, Serialize)] +pub struct EnclaveStartResponse; + +impl From for Response { + fn from(response: EnclaveStartResponse) -> Self { + Self::EnclaveStart(response) + } +}