refactor: replace ctrlc handler with tokio's built-in (#197)
This commit is contained in:
parent
43a1a49c3f
commit
628d7b4596
6 changed files with 29 additions and 111 deletions
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -1135,16 +1135,6 @@ dependencies = [
|
||||||
"cipher",
|
"cipher",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ctrlc"
|
|
||||||
version = "3.4.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3"
|
|
||||||
dependencies = [
|
|
||||||
"nix 0.29.0",
|
|
||||||
"windows-sys 0.59.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "curve25519-dalek"
|
name = "curve25519-dalek"
|
||||||
version = "4.1.3"
|
version = "4.1.3"
|
||||||
|
@ -4090,7 +4080,6 @@ dependencies = [
|
||||||
"color-eyre",
|
"color-eyre",
|
||||||
"cosmrs",
|
"cosmrs",
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
"ctrlc",
|
|
||||||
"dirs 5.0.1",
|
"dirs 5.0.1",
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"figment",
|
"figment",
|
||||||
|
|
|
@ -38,7 +38,6 @@ watchexec = "4.1.0"
|
||||||
watchexec-events = "3.0.0"
|
watchexec-events = "3.0.0"
|
||||||
watchexec-signals = "3.0.0"
|
watchexec-signals = "3.0.0"
|
||||||
miette = "7.2.0"
|
miette = "7.2.0"
|
||||||
ctrlc = { version = "3.4.5", features=["termination"]}
|
|
||||||
xxhash-rust = { version = "0.8.12", features=["xxh3"] }
|
xxhash-rust = { version = "0.8.12", features=["xxh3"] }
|
||||||
toml = "0.8.19"
|
toml = "0.8.19"
|
||||||
figment = { version = "0.10.19", features=["env", "toml"] }
|
figment = { version = "0.10.19", features=["env", "toml"] }
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
use std::{path::PathBuf, process::exit, time::Duration};
|
use std::{path::PathBuf, time::Duration};
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use color_eyre::owo_colors::OwoColorize;
|
use color_eyre::owo_colors::OwoColorize;
|
||||||
// todo get rid of this?
|
// todo get rid of this?
|
||||||
use miette::{IntoDiagnostic, Result};
|
use miette::{IntoDiagnostic, Result};
|
||||||
use quartz_common::proto::core_client::CoreClient;
|
use quartz_common::proto::core_client::CoreClient;
|
||||||
use tokio::{
|
use tokio::{sync::mpsc, time::sleep};
|
||||||
sync::{mpsc, watch},
|
|
||||||
time::sleep,
|
|
||||||
};
|
|
||||||
use tracing::{debug, info};
|
use tracing::{debug, info};
|
||||||
use watchexec::Watchexec;
|
use watchexec::Watchexec;
|
||||||
use watchexec_signals::Signal;
|
use watchexec_signals::Signal;
|
||||||
|
@ -63,21 +60,11 @@ async fn dev_driver(
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// State
|
// State
|
||||||
let mut shutdown_tx: Option<watch::Sender<()>> = None;
|
|
||||||
let mut first_enclave_message = true;
|
let mut first_enclave_message = true;
|
||||||
let mut first_contract_message = true;
|
let mut first_contract_message = true;
|
||||||
let mut contract = String::from("");
|
let mut contract = String::from("");
|
||||||
|
|
||||||
// Shutdown enclave upon interruption
|
// Shutdown enclave upon interruption
|
||||||
let shutdown_tx_cpy = shutdown_tx.clone();
|
|
||||||
ctrlc::set_handler(move || {
|
|
||||||
if let Some(tx) = &shutdown_tx_cpy {
|
|
||||||
let _res = tx.send(());
|
|
||||||
}
|
|
||||||
|
|
||||||
exit(130)
|
|
||||||
})
|
|
||||||
.expect("Error setting Ctrl-C handler");
|
|
||||||
|
|
||||||
// Drive
|
// Drive
|
||||||
while let Some(dev) = rx.recv().await {
|
while let Some(dev) = rx.recv().await {
|
||||||
|
@ -98,7 +85,7 @@ async fn dev_driver(
|
||||||
contract_build.handle(&config).await?;
|
contract_build.handle(&config).await?;
|
||||||
|
|
||||||
// Start enclave in background
|
// Start enclave in background
|
||||||
let new_shutdown_tx = spawn_enclave_start(args, &config).await?;
|
spawn_enclave_start(args, &config)?;
|
||||||
|
|
||||||
// Deploy new contract and perform handshake
|
// Deploy new contract and perform handshake
|
||||||
let res = deploy_and_handshake(None, args, &config).await;
|
let res = deploy_and_handshake(None, args, &config).await;
|
||||||
|
@ -108,17 +95,12 @@ async fn dev_driver(
|
||||||
Ok(res_contract) => {
|
Ok(res_contract) => {
|
||||||
// Set state
|
// Set state
|
||||||
contract = res_contract;
|
contract = res_contract;
|
||||||
shutdown_tx = Some(new_shutdown_tx);
|
|
||||||
|
|
||||||
info!("{}", "Enclave is listening for requests...".green().bold());
|
info!("{}", "Enclave is listening for requests...".green().bold());
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Error launching quartz app");
|
eprintln!("Error launching quartz app");
|
||||||
|
|
||||||
new_shutdown_tx
|
|
||||||
.send(())
|
|
||||||
.expect("Could not send signal on channel");
|
|
||||||
|
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,14 +115,11 @@ async fn dev_driver(
|
||||||
println!("{}", BANNER.yellow().bold());
|
println!("{}", BANNER.yellow().bold());
|
||||||
info!("{}", "Rebuilding Enclave...".green().bold());
|
info!("{}", "Rebuilding Enclave...".green().bold());
|
||||||
|
|
||||||
if let Some(shutdown_tx) = shutdown_tx.clone() {
|
|
||||||
let _res = shutdown_tx.send(());
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("Waiting 1 second for the enclave to shut down");
|
info!("Waiting 1 second for the enclave to shut down");
|
||||||
sleep(Duration::from_secs(1)).await;
|
sleep(Duration::from_secs(1)).await;
|
||||||
|
|
||||||
let new_shutdown_tx = spawn_enclave_start(args, &config).await?;
|
// Start enclave in background
|
||||||
|
spawn_enclave_start(args, &config)?;
|
||||||
|
|
||||||
// todo: should not unconditionally deploy here
|
// todo: should not unconditionally deploy here
|
||||||
let res = deploy_and_handshake(Some(&contract), args, &config).await;
|
let res = deploy_and_handshake(Some(&contract), args, &config).await;
|
||||||
|
@ -149,17 +128,12 @@ async fn dev_driver(
|
||||||
Ok(res_contract) => {
|
Ok(res_contract) => {
|
||||||
// Set state
|
// Set state
|
||||||
contract = res_contract;
|
contract = res_contract;
|
||||||
shutdown_tx = Some(new_shutdown_tx);
|
|
||||||
|
|
||||||
info!("{}", "Enclave is listening for requests...".green().bold());
|
info!("{}", "Enclave is listening for requests...".green().bold());
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Error restarting enclave and handshake");
|
eprintln!("Error restarting enclave and handshake");
|
||||||
|
|
||||||
new_shutdown_tx
|
|
||||||
.send(())
|
|
||||||
.expect("Could not send signal on channel");
|
|
||||||
|
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,7 +147,6 @@ async fn dev_driver(
|
||||||
println!("{}", BANNER.yellow().bold());
|
println!("{}", BANNER.yellow().bold());
|
||||||
info!("{}", "Rebuilding Contract...".green().bold());
|
info!("{}", "Rebuilding Contract...".green().bold());
|
||||||
|
|
||||||
if let Some(shutdown_tx) = shutdown_tx.clone() {
|
|
||||||
let res = deploy_and_handshake(None, args, &config).await;
|
let res = deploy_and_handshake(None, args, &config).await;
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
|
@ -181,18 +154,9 @@ async fn dev_driver(
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Error deploying contract and handshake:");
|
eprintln!("Error deploying contract and handshake:");
|
||||||
|
|
||||||
shutdown_tx
|
|
||||||
.send(())
|
|
||||||
.expect("Could not send signal on channel");
|
|
||||||
|
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return Err(Error::GenericErr(
|
|
||||||
"Attempting to redeploy contract, but enclave isn't running".to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("{}", "Enclave is listening for requests...".green().bold());
|
info!("{}", "Enclave is listening for requests...".green().bold());
|
||||||
}
|
}
|
||||||
|
@ -203,14 +167,9 @@ async fn dev_driver(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spawns enclve start in a separate task which runs in the background
|
// Spawns enclve start in a separate task which runs in the background
|
||||||
async fn spawn_enclave_start(
|
fn spawn_enclave_start(args: &DevRequest, config: &Config) -> Result<(), Error> {
|
||||||
args: &DevRequest,
|
|
||||||
config: &Config,
|
|
||||||
) -> Result<watch::Sender<()>, Error> {
|
|
||||||
// In separate process, launch the enclave
|
// In separate process, launch the enclave
|
||||||
let (shutdown_tx, shutdown_rx) = watch::channel(());
|
|
||||||
let enclave_start = EnclaveStartRequest {
|
let enclave_start = EnclaveStartRequest {
|
||||||
shutdown_rx: Some(shutdown_rx),
|
|
||||||
unsafe_trust_latest: args.unsafe_trust_latest,
|
unsafe_trust_latest: args.unsafe_trust_latest,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -222,7 +181,7 @@ async fn spawn_enclave_start(
|
||||||
Ok::<Response, Error>(res)
|
Ok::<Response, Error>(res)
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(shutdown_tx)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: do not shutdown if cli calls fail, just print
|
// TODO: do not shutdown if cli calls fail, just print
|
||||||
|
|
|
@ -3,10 +3,7 @@ use std::{fs, path::Path};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use cargo_metadata::MetadataCommand;
|
use cargo_metadata::MetadataCommand;
|
||||||
use color_eyre::owo_colors::OwoColorize;
|
use color_eyre::owo_colors::OwoColorize;
|
||||||
use tokio::{
|
use tokio::process::{Child, Command};
|
||||||
process::{Child, Command},
|
|
||||||
sync::watch,
|
|
||||||
};
|
|
||||||
use tracing::{debug, info};
|
use tracing::{debug, info};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -47,7 +44,7 @@ impl Handler for EnclaveStartRequest {
|
||||||
let enclave_child =
|
let enclave_child =
|
||||||
create_mock_enclave_child(config.app_dir.as_path(), config.release, enclave_args)
|
create_mock_enclave_child(config.app_dir.as_path(), config.release, enclave_args)
|
||||||
.await?;
|
.await?;
|
||||||
handle_process(self.shutdown_rx, enclave_child).await?;
|
handle_process(enclave_child).await?;
|
||||||
} else {
|
} else {
|
||||||
let enclave_dir = fs::canonicalize(config.app_dir.join("enclave"))?;
|
let enclave_dir = fs::canonicalize(config.app_dir.join("enclave"))?;
|
||||||
|
|
||||||
|
@ -69,40 +66,25 @@ impl Handler for EnclaveStartRequest {
|
||||||
|
|
||||||
// Run quartz enclave and block
|
// Run quartz enclave and block
|
||||||
let enclave_child = create_gramine_sgx_child(&enclave_dir).await?;
|
let enclave_child = create_gramine_sgx_child(&enclave_dir).await?;
|
||||||
handle_process(self.shutdown_rx, enclave_child).await?;
|
handle_process(enclave_child).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(EnclaveStartResponse.into())
|
Ok(EnclaveStartResponse.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_process(
|
async fn handle_process(mut child: Child) -> Result<(), Error> {
|
||||||
shutdown_rx: Option<watch::Receiver<()>>,
|
|
||||||
mut child: Child,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
info!("{}", "Running enclave ...".green().bold());
|
|
||||||
match shutdown_rx {
|
|
||||||
Some(mut rx) => {
|
|
||||||
tokio::select! {
|
|
||||||
status = child.wait() => {
|
|
||||||
handle_child_status(status.map_err(|e| Error::GenericErr(e.to_string()))?)?;
|
|
||||||
}
|
|
||||||
_ = rx.changed() => {
|
|
||||||
info!("Enclave shutdown signal received.");
|
|
||||||
let _ = child.kill().await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
// If no shutdown receiver is provided, just wait for the child process
|
|
||||||
let status = child
|
let status = child
|
||||||
.wait()
|
.wait()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
||||||
handle_child_status(status)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if !status.success() {
|
||||||
|
return Err(Error::GenericErr(format!(
|
||||||
|
"Couldn't build enclave. {:?}",
|
||||||
|
status
|
||||||
|
)));
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,22 +121,13 @@ async fn create_mock_enclave_child(
|
||||||
|
|
||||||
info!("{}", "🚧 Spawning enclave process ...".green().bold());
|
info!("{}", "🚧 Spawning enclave process ...".green().bold());
|
||||||
let child = command
|
let child = command
|
||||||
|
.kill_on_drop(true)
|
||||||
.spawn()
|
.spawn()
|
||||||
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
.map_err(|e| Error::GenericErr(e.to_string()))?;
|
||||||
|
|
||||||
Ok(child)
|
Ok(child)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_child_status(status: std::process::ExitStatus) -> Result<(), Error> {
|
|
||||||
if !status.success() {
|
|
||||||
return Err(Error::GenericErr(format!(
|
|
||||||
"Couldn't build enclave. {:?}",
|
|
||||||
status
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn gramine_sgx_gen_private_key(enclave_dir: &Path) -> Result<(), Error> {
|
async fn gramine_sgx_gen_private_key(enclave_dir: &Path) -> Result<(), Error> {
|
||||||
// Launch the gramine-sgx-gen-private-key command
|
// Launch the gramine-sgx-gen-private-key command
|
||||||
Command::new("gramine-sgx-gen-private-key")
|
Command::new("gramine-sgx-gen-private-key")
|
||||||
|
@ -244,6 +217,7 @@ async fn create_gramine_sgx_child(enclave_dir: &Path) -> Result<Child, Error> {
|
||||||
|
|
||||||
let child = Command::new("gramine-sgx")
|
let child = Command::new("gramine-sgx")
|
||||||
.arg("./quartz")
|
.arg("./quartz")
|
||||||
|
.kill_on_drop(true)
|
||||||
.current_dir(enclave_dir)
|
.current_dir(enclave_dir)
|
||||||
.spawn()?;
|
.spawn()?;
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,6 @@ impl TryFrom<EnclaveCommand> for Request {
|
||||||
match cmd {
|
match cmd {
|
||||||
EnclaveCommand::Build(_) => Ok(EnclaveBuildRequest {}.into()),
|
EnclaveCommand::Build(_) => Ok(EnclaveBuildRequest {}.into()),
|
||||||
EnclaveCommand::Start(args) => Ok(EnclaveStartRequest {
|
EnclaveCommand::Start(args) => Ok(EnclaveStartRequest {
|
||||||
shutdown_rx: None,
|
|
||||||
unsafe_trust_latest: args.unsafe_trust_latest,
|
unsafe_trust_latest: args.unsafe_trust_latest,
|
||||||
}
|
}
|
||||||
.into()),
|
.into()),
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use tendermint::{block::Height, Hash};
|
use tendermint::{block::Height, Hash};
|
||||||
use tokio::sync::watch;
|
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -9,7 +8,6 @@ use crate::{
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct EnclaveStartRequest {
|
pub struct EnclaveStartRequest {
|
||||||
pub shutdown_rx: Option<watch::Receiver<()>>,
|
|
||||||
pub unsafe_trust_latest: bool,
|
pub unsafe_trust_latest: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue