feat: move proxy logic into enclave (#174)
This commit is contained in:
parent
628d7b4596
commit
69c1f63114
29 changed files with 1791 additions and 141 deletions
33
Cargo.lock
generated
33
Cargo.lock
generated
|
@ -144,6 +144,9 @@ name = "anyhow"
|
|||
version = "1.0.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e1496f8fb1fbf272686b8d37f523dab3e4a7443300055e74cdaa449f3114356"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anymap2"
|
||||
|
@ -462,7 +465,7 @@ dependencies = [
|
|||
"rustversion",
|
||||
"serde",
|
||||
"sync_wrapper 1.0.1",
|
||||
"tower",
|
||||
"tower 0.4.13",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
@ -2656,7 +2659,7 @@ dependencies = [
|
|||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tower",
|
||||
"tower 0.4.13",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
@ -3316,6 +3319,9 @@ dependencies = [
|
|||
name = "mtcs-enclave"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"base64 0.22.1",
|
||||
"clap",
|
||||
"color-eyre",
|
||||
"cosmrs",
|
||||
|
@ -3323,20 +3329,24 @@ dependencies = [
|
|||
"cw-multi-test",
|
||||
"cw-tee-mtcs",
|
||||
"ecies",
|
||||
"futures-util",
|
||||
"hex",
|
||||
"k256",
|
||||
"mtcs",
|
||||
"prost 0.13.2",
|
||||
"quartz-common",
|
||||
"reqwest 0.12.7",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tendermint 0.38.1",
|
||||
"tendermint-light-client",
|
||||
"tendermint-rpc",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tonic",
|
||||
"tonic-build",
|
||||
"uuid",
|
||||
"wasmd-client",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4087,7 +4097,6 @@ dependencies = [
|
|||
"hex",
|
||||
"k256",
|
||||
"miette",
|
||||
"mtcs-enclave",
|
||||
"once_cell",
|
||||
"prost 0.13.2",
|
||||
"quartz-common",
|
||||
|
@ -4147,12 +4156,15 @@ dependencies = [
|
|||
name = "quartz-enclave"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"clap",
|
||||
"color-eyre",
|
||||
"cosmrs",
|
||||
"cosmwasm-std",
|
||||
"cw-proof",
|
||||
"ecies",
|
||||
"futures-util",
|
||||
"hex",
|
||||
"k256",
|
||||
"mtcs",
|
||||
|
@ -4165,9 +4177,12 @@ dependencies = [
|
|||
"sha2 0.10.8",
|
||||
"tendermint 0.38.1",
|
||||
"tendermint-light-client",
|
||||
"tendermint-rpc",
|
||||
"thiserror",
|
||||
"tm-stateless-verifier",
|
||||
"tokio",
|
||||
"tonic",
|
||||
"tower 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -5750,7 +5765,7 @@ dependencies = [
|
|||
"socket2",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tower",
|
||||
"tower 0.4.13",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
|
@ -5789,6 +5804,16 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f"
|
||||
dependencies = [
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-layer"
|
||||
version = "0.3.3"
|
||||
|
|
|
@ -22,7 +22,7 @@ authors = ["Informal Systems <hello@informal.systems>"]
|
|||
|
||||
[workspace.dependencies]
|
||||
# external
|
||||
anyhow = { version = "1.0.86", default-features = false }
|
||||
anyhow = { version = "1.0.86", features = ["std", "backtrace"] }
|
||||
async-trait = { version = "0.1.79", default-features = false }
|
||||
bip32 = { version = "0.5.1", default-features = false, features = ["alloc", "secp256k1", "bip39"] }
|
||||
cargo-generate = "0.21.3"
|
||||
|
@ -32,6 +32,7 @@ der = { version = "0.7.9", default-features = false }
|
|||
displaydoc = { version = "0.2.4", default-features = false }
|
||||
ecies = { version = "0.2.3", default-features = false, features = ["pure"] }
|
||||
futures = { version = "0.3.27", default-features = false, features = ["alloc"] }
|
||||
futures-util = { version = "0.3.30" }
|
||||
hex = { version = "0.4.3", default-features = false }
|
||||
hex-literal = { version = "0.4.1", default-features = false }
|
||||
k256 = { version = "0.13.2", default-features = false, features = ["ecdsa", "alloc"] }
|
||||
|
@ -50,6 +51,7 @@ thiserror = { version = "1.0.49", default-features = false }
|
|||
tokio = { version = "=1.39.2", default-features = false, features = ["macros", "rt"] }
|
||||
tonic = { version = "=0.12.1", default-features = false, features = ["codegen", "prost", "transport"] }
|
||||
tonic-build = { version = "=0.12.1", default-features = false, features = ["prost", "transport"] }
|
||||
tower = { version = "0.5.0" }
|
||||
tracing = { version = "0.1.39", default-features = false }
|
||||
tracing-subscriber = { version = "0.3.17", default-features = false, features = ["fmt"] }
|
||||
uuid = { version = "1.4.1", default-features = false, features = ["serde"] }
|
||||
|
|
|
@ -20,6 +20,7 @@ mock-sgx = ["quartz-common/mock-sgx-cw", "quartz-common/mock-sgx-enclave"]
|
|||
|
||||
[dependencies]
|
||||
# external
|
||||
async-trait.workspace = true
|
||||
clap.workspace = true
|
||||
color-eyre.workspace = true
|
||||
ecies.workspace = true
|
||||
|
@ -32,12 +33,18 @@ thiserror.workspace = true
|
|||
tokio.workspace = true
|
||||
tonic.workspace = true
|
||||
uuid.workspace = true
|
||||
futures-util.workspace = true
|
||||
anyhow.workspace = true
|
||||
base64 = "0.22.1"
|
||||
reqwest.workspace = true
|
||||
|
||||
|
||||
# cosmos
|
||||
cosmrs.workspace = true
|
||||
cosmwasm-std.workspace = true
|
||||
tendermint.workspace = true
|
||||
tendermint-light-client.workspace = true
|
||||
tendermint-rpc.workspace = true
|
||||
|
||||
# quartz
|
||||
cw-tee-mtcs.workspace = true
|
||||
|
@ -45,6 +52,7 @@ mtcs.workspace = true
|
|||
|
||||
# quartz
|
||||
quartz-common = { workspace = true, features = ["full"]}
|
||||
wasmd-client = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
cw-multi-test = "2.1.0"
|
||||
|
|
|
@ -2,7 +2,8 @@ use std::net::SocketAddr;
|
|||
|
||||
use clap::Parser;
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use cosmrs::{tendermint::Hash, AccountId};
|
||||
use cosmrs::AccountId;
|
||||
use tendermint::Hash;
|
||||
use tendermint_light_client::types::{Height, TrustThreshold};
|
||||
|
||||
fn parse_trust_threshold(s: &str) -> Result<TrustThreshold> {
|
||||
|
@ -53,4 +54,10 @@ pub struct Cli {
|
|||
/// Maximum block lag, in seconds
|
||||
#[clap(long, default_value = "5")]
|
||||
pub max_block_lag: u64,
|
||||
|
||||
#[clap(long, default_value = "127.0.0.1:11090")]
|
||||
pub node_url: String,
|
||||
|
||||
#[clap(long, default_value = "admin")]
|
||||
pub tx_sender: String,
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![doc = include_str!("../README.md")]
|
||||
#![forbid(unsafe_code)]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![warn(
|
||||
clippy::checked_conversions,
|
||||
clippy::panic,
|
||||
|
@ -16,6 +16,7 @@ mod cli;
|
|||
mod mtcs_server;
|
||||
mod proto;
|
||||
mod types;
|
||||
mod wslistener;
|
||||
|
||||
use std::{
|
||||
sync::{Arc, Mutex},
|
||||
|
@ -25,23 +26,20 @@ use std::{
|
|||
use clap::Parser;
|
||||
use cli::Cli;
|
||||
use mtcs_server::MtcsService;
|
||||
use proto::clearing_server::ClearingServer as MtcsServer;
|
||||
use quartz_common::{
|
||||
contract::state::{Config, LightClientOpts},
|
||||
enclave::{
|
||||
attestor::{Attestor, DefaultAttestor},
|
||||
server::CoreService,
|
||||
server::{QuartzServer, WsListenerConfig},
|
||||
},
|
||||
proto::core_server::CoreServer,
|
||||
};
|
||||
use tonic::transport::Server;
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args = Cli::parse();
|
||||
|
||||
let light_client_opts = LightClientOpts::new(
|
||||
args.chain_id,
|
||||
args.chain_id.clone(),
|
||||
args.trusted_height.into(),
|
||||
Vec::from(args.trusted_hash)
|
||||
.try_into()
|
||||
|
@ -64,15 +62,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
args.tcbinfo_contract.map(|c| c.to_string()),
|
||||
);
|
||||
|
||||
let ws_config = WsListenerConfig {
|
||||
node_url: args.node_url,
|
||||
tx_sender: args.tx_sender,
|
||||
trusted_hash: args.trusted_hash,
|
||||
trusted_height: args.trusted_height,
|
||||
chain_id: args.chain_id,
|
||||
};
|
||||
|
||||
let sk = Arc::new(Mutex::new(None));
|
||||
|
||||
Server::builder()
|
||||
.add_service(CoreServer::new(CoreService::new(
|
||||
config.clone(),
|
||||
sk.clone(),
|
||||
attestor.clone(),
|
||||
)))
|
||||
.add_service(MtcsServer::new(MtcsService::new(config, sk, attestor)))
|
||||
QuartzServer::new(config.clone(), sk.clone(), attestor.clone(), ws_config)
|
||||
.add_service(MtcsService::new(config, sk, attestor))
|
||||
.serve(args.rpc_addr)
|
||||
.await?;
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ use std::{
|
|||
};
|
||||
|
||||
use cosmwasm_std::{Addr, HexBinary, Uint128};
|
||||
//TODO: get rid of this
|
||||
use cw_tee_mtcs::{
|
||||
msg::execute::SubmitSetoffsMsg,
|
||||
state::{LiquiditySource, LiquiditySourceType, RawHash, SettleOff, Transfer},
|
||||
|
@ -17,18 +16,29 @@ use mtcs::{
|
|||
};
|
||||
use quartz_common::{
|
||||
contract::{msg::execute::attested::RawAttested, state::Config},
|
||||
enclave::{attestor::Attestor, server::ProofOfPublication},
|
||||
enclave::{attestor::Attestor, server::IntoServer},
|
||||
};
|
||||
use tonic::{Request, Response, Result as TonicResult, Status};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
proto::{clearing_server::Clearing, RunClearingRequest, RunClearingResponse},
|
||||
proto::{
|
||||
clearing_server::{Clearing, ClearingServer},
|
||||
RunClearingRequest, RunClearingResponse,
|
||||
},
|
||||
types::{ContractObligation, RunClearingMessage},
|
||||
};
|
||||
|
||||
pub type RawCipherText = HexBinary;
|
||||
|
||||
impl<A: Attestor> IntoServer for MtcsService<A> {
|
||||
type Server = ClearingServer<MtcsService<A>>;
|
||||
|
||||
fn into_server(self) -> Self::Server {
|
||||
ClearingServer::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MtcsService<A> {
|
||||
config: Config, // TODO: this config is not used anywhere
|
||||
|
@ -59,20 +69,20 @@ where
|
|||
request: Request<RunClearingRequest>,
|
||||
) -> TonicResult<Response<RunClearingResponse>> {
|
||||
// Light client check
|
||||
let message: ProofOfPublication<RunClearingMessage> = {
|
||||
let message: RunClearingMessage = {
|
||||
let message = request.into_inner().message;
|
||||
serde_json::from_str(&message).map_err(|e| Status::invalid_argument(e.to_string()))?
|
||||
};
|
||||
|
||||
let (proof_value, message) = message
|
||||
.verify(self.config.light_client_opts())
|
||||
.map_err(Status::failed_precondition)?;
|
||||
// let (proof_value, message) = message
|
||||
// .verify(self.config.light_client_opts())
|
||||
// .map_err(Status::failed_precondition)?;
|
||||
|
||||
let proof_value_matches_msg =
|
||||
serde_json::to_string(&message.intents).is_ok_and(|s| s.as_bytes() == proof_value);
|
||||
if !proof_value_matches_msg {
|
||||
return Err(Status::failed_precondition("proof verification"));
|
||||
}
|
||||
// let proof_value_matches_msg =
|
||||
// serde_json::to_string(&message.intents).is_ok_and(|s| s.as_bytes() == proof_value);
|
||||
// if !proof_value_matches_msg {
|
||||
// return Err(Status::failed_precondition("proof verification"));
|
||||
// }
|
||||
// TODO: ensure no duplicates somewhere else!
|
||||
let liquidity_sources: Vec<LiquiditySource> =
|
||||
message.liquidity_sources.into_iter().collect();
|
||||
|
|
231
apps/mtcs/enclave/src/wslistener.rs
Normal file
231
apps/mtcs/enclave/src/wslistener.rs
Normal file
|
@ -0,0 +1,231 @@
|
|||
//TODO: get rid of this
|
||||
use std::{collections::BTreeMap, str::FromStr};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use base64::prelude::*;
|
||||
use cosmrs::{tendermint::chain::Id as ChainId, AccountId};
|
||||
use cosmwasm_std::{HexBinary, Uint64};
|
||||
use cw_tee_mtcs::msg::{
|
||||
execute::SubmitSetoffsMsg, AttestedMsg, ExecuteMsg, GetLiquiditySourcesResponse,
|
||||
QueryMsg::GetLiquiditySources,
|
||||
};
|
||||
use quartz_common::{
|
||||
contract::msg::execute::attested::{
|
||||
MockAttestation, RawAttested, RawAttestedMsgSansHandler, RawMockAttestation,
|
||||
},
|
||||
enclave::{
|
||||
attestor::Attestor,
|
||||
server::{WebSocketHandler, WsListenerConfig},
|
||||
},
|
||||
};
|
||||
use reqwest::Url;
|
||||
// use quartz_tee_ra::{intel_sgx::epid::types::ReportBody, IASReport};
|
||||
use serde_json::json;
|
||||
use tendermint_rpc::{event::Event, query::EventType};
|
||||
use tonic::Request;
|
||||
use wasmd_client::{CliWasmdClient, QueryResult, WasmdClient};
|
||||
|
||||
use crate::{
|
||||
mtcs_server::MtcsService,
|
||||
proto::{clearing_server::Clearing, RunClearingRequest},
|
||||
types::RunClearingMessage,
|
||||
};
|
||||
|
||||
// TODO: Need to prevent listener from taking actions until handshake is completed
|
||||
#[async_trait::async_trait]
|
||||
impl<A: Attestor> WebSocketHandler for MtcsService<A> {
|
||||
async fn handle(&self, event: Event, config: WsListenerConfig) -> Result<()> {
|
||||
// Validation
|
||||
if !is_init_clearing_event(&event) {
|
||||
return Ok(());
|
||||
} else {
|
||||
println!("Found clearing event");
|
||||
|
||||
let mut sender = None;
|
||||
let mut contract_address = None;
|
||||
|
||||
if let Some(events) = &event.events {
|
||||
for (key, values) in events {
|
||||
match key.as_str() {
|
||||
"message.sender" => {
|
||||
sender = values.first().cloned();
|
||||
}
|
||||
"wasm._contract_address" => {
|
||||
contract_address = values.first().cloned();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add some checks based on event messages
|
||||
|
||||
if sender.is_none() || contract_address.is_none() {
|
||||
return Ok(()); // TODO: change return type
|
||||
}
|
||||
|
||||
handler(
|
||||
self,
|
||||
&contract_address
|
||||
.expect("infallible")
|
||||
.parse::<AccountId>()
|
||||
.map_err(|e| anyhow!(e))?,
|
||||
sender.expect("infallible"),
|
||||
&config.node_url,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn is_init_clearing_event(event: &Event) -> bool {
|
||||
// Check if the event is a transaction type
|
||||
if let Some(EventType::Tx) = event.event_type() {
|
||||
// Check for the "wasm.action" key with the value "init_clearing"
|
||||
if let Some(events) = &event.events {
|
||||
return events.iter().any(|(key, values)| {
|
||||
key == "wasm.action" && values.contains(&"init_clearing".to_string())
|
||||
});
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
async fn handler<A: Attestor>(
|
||||
client: &MtcsService<A>,
|
||||
contract: &AccountId,
|
||||
sender: String,
|
||||
node_url: &str,
|
||||
) -> Result<()> {
|
||||
let chain_id = &ChainId::from_str("testing")?;
|
||||
let httpurl = Url::parse(&format!("http://{}", node_url))?;
|
||||
let wasmd_client = CliWasmdClient::new(httpurl);
|
||||
|
||||
// Query obligations and liquidity sources from chain
|
||||
let clearing_contents = query_chain(&wasmd_client, contract).await?;
|
||||
|
||||
// Send queried data to enclave over gRPC
|
||||
let request = Request::new(RunClearingRequest {
|
||||
message: json!(clearing_contents).to_string(),
|
||||
});
|
||||
|
||||
let clearing_response = client
|
||||
.run(request)
|
||||
.await
|
||||
.map_err(|e| anyhow!("Failed to communicate to relayer. {e}"))?
|
||||
.into_inner();
|
||||
// Extract json from the Protobuf message
|
||||
let attested: RawAttested<SubmitSetoffsMsg, Vec<u8>> =
|
||||
serde_json::from_str(&clearing_response.message)
|
||||
.map_err(|e| anyhow!("Error serializing SubmitSetoffs: {}", e))?;
|
||||
|
||||
// TODO add non-mock support, get IAS report and build attested message
|
||||
let msg = RawAttestedMsgSansHandler(attested.msg);
|
||||
|
||||
let setoffs_msg = ExecuteMsg::SubmitSetoffs::<RawMockAttestation>(AttestedMsg {
|
||||
msg,
|
||||
attestation: MockAttestation(attested.attestation.try_into().unwrap()).into(),
|
||||
});
|
||||
|
||||
// Send setoffs to mtcs contract on chain
|
||||
let output =
|
||||
wasmd_client.tx_execute(contract, chain_id, 2000000, &sender, json!(setoffs_msg))?;
|
||||
|
||||
println!("Setoffs TX: {}", output);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: replace raw queries with smart
|
||||
async fn query_chain(
|
||||
wasmd_client: &CliWasmdClient,
|
||||
contract: &AccountId,
|
||||
) -> Result<RunClearingMessage> {
|
||||
// Get epoch counter
|
||||
let resp: QueryResult<String> = wasmd_client
|
||||
.query_raw(contract, hex::encode("epoch_counter"))
|
||||
.map_err(|e| anyhow!("Problem querying epoch: {}", e))?;
|
||||
|
||||
let mut epoch_counter: usize = String::from_utf8(BASE64_STANDARD.decode(resp.data)?)?
|
||||
.trim_matches('"')
|
||||
.parse::<usize>()?;
|
||||
|
||||
if epoch_counter > 1 {
|
||||
epoch_counter -= 1;
|
||||
}
|
||||
|
||||
// TODO: replace with tracer log here
|
||||
// println!("epoch: {}", epoch_counter);
|
||||
|
||||
// Get obligations
|
||||
let resp: QueryResult<String> = wasmd_client
|
||||
.query_raw(
|
||||
contract,
|
||||
hex::encode(format!("{}/obligations", epoch_counter)),
|
||||
)
|
||||
.map_err(|e| anyhow!("Problem querying obligatons: {}", e))?;
|
||||
|
||||
let decoded_obligs = BASE64_STANDARD.decode(resp.data)?;
|
||||
let obligations_map: BTreeMap<HexBinary, HexBinary> =
|
||||
serde_json::from_slice(&decoded_obligs).unwrap_or_default();
|
||||
// println!("obligations \n {:?}", obligations_map);
|
||||
// TODO: replace with tracer log here
|
||||
|
||||
// Get liquidity sources
|
||||
let resp: QueryResult<GetLiquiditySourcesResponse> = wasmd_client
|
||||
.query_smart(
|
||||
contract,
|
||||
json!(GetLiquiditySources {
|
||||
epoch: Some(Uint64::new(epoch_counter as u64))
|
||||
}),
|
||||
)
|
||||
.map_err(|e| anyhow!("Problem querying liquidity sources: {}", e))?;
|
||||
|
||||
let liquidity_sources = resp.data.liquidity_sources;
|
||||
// TODO: replace with tracer log here
|
||||
// println!("liquidity_sources \n {:?}", liquidity_sources);
|
||||
|
||||
Ok(RunClearingMessage {
|
||||
intents: obligations_map,
|
||||
liquidity_sources: liquidity_sources.into_iter().collect(),
|
||||
})
|
||||
}
|
||||
|
||||
// Request the IAS report for EPID attestations
|
||||
// async fn gramine_ias_request(
|
||||
// attested_msg: Vec<u8>,
|
||||
// user: &str,
|
||||
// ) -> Result<EpidAttestation, anyhow::Error> {
|
||||
// let ias_api_key = String::from("669244b3e6364b5888289a11d2a1726d");
|
||||
// let ra_client_spid = String::from("51CAF5A48B450D624AEFE3286D314894");
|
||||
// let quote_file = format!("/tmp/{}_test.quote", user);
|
||||
// let report_file = format!("/tmp/{}_datareport", user);
|
||||
// let report_sig_file = format!("/tmp/{}_datareportsig", user);
|
||||
|
||||
// // Write the binary data to a file
|
||||
// let mut file = File::create("e_file).await?;
|
||||
// file.write_all(&attested_msg)
|
||||
// .await
|
||||
// .map_err(|e| anyhow!("Couldn't write to file. {e}"))?;
|
||||
|
||||
// let mut gramine = Command::new("gramine-sgx-ias-request");
|
||||
// let command = gramine
|
||||
// .arg("report")
|
||||
// .args(["-g", &ra_client_spid])
|
||||
// .args(["-k", &ias_api_key])
|
||||
// .args(["-q", "e_file])
|
||||
// .args(["-r", &report_file])
|
||||
// .args(["-s", &report_sig_file]);
|
||||
|
||||
// let output = command.output()?;
|
||||
// if !output.status.success() {
|
||||
// return Err(anyhow!("Couldn't run gramine. {:?}", output));
|
||||
// }
|
||||
|
||||
// let report: ReportBody = serde_json::from_str(&fs::read_to_string(report_file).await?)?;
|
||||
// let report_sig_str = fs::read_to_string(report_sig_file).await?.replace('\r', "");
|
||||
// let report_sig: Binary = Binary::from_base64(report_sig_str.trim())?;
|
||||
|
||||
// Ok(EpidAttestation::new(IASReport { report, report_sig }))
|
||||
// }
|
|
@ -44,6 +44,7 @@ cw20-base = { version = "2.0.0", default-features = false, features = ["library"
|
|||
cw-utils = { version = "2.0.0", default-features = false }
|
||||
|
||||
# quartz
|
||||
# quartz-common = { git = "ssh://git@github.com/informalsystems/cycles-quartz.git", features=["contract"]}
|
||||
quartz-common = { path = "../../../core/quartz-common", features=["contract"]}
|
||||
|
||||
# patch indirect deps
|
||||
|
|
|
@ -230,6 +230,8 @@ pub mod execute {
|
|||
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
|
||||
match msg {
|
||||
QueryMsg::GetBalance { address } => to_json_binary(&query::get_balance(deps, address)?),
|
||||
QueryMsg::GetRequests {} => to_json_binary(&query::get_requests(deps)?),
|
||||
QueryMsg::GetState {} => to_json_binary(&query::get_state(deps)?),
|
||||
}
|
||||
}
|
||||
mod query {
|
||||
|
@ -239,4 +241,12 @@ mod query {
|
|||
let balance = BALANCES.may_load(deps.storage, &address)?;
|
||||
Ok(balance.unwrap_or_default())
|
||||
}
|
||||
|
||||
pub fn get_requests(deps: Deps) -> StdResult<Vec<Request>> {
|
||||
Ok(REQUESTS.load(deps.storage)?)
|
||||
}
|
||||
|
||||
pub fn get_state(deps: Deps) -> StdResult<HexBinary> {
|
||||
Ok(STATE.load(deps.storage)?)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use quartz_common::contract::{
|
|||
prelude::*,
|
||||
};
|
||||
|
||||
type AttestedMsg<M, RA = RawDefaultAttestation> = RawAttested<RawAttestedMsgSansHandler<M>, RA>;
|
||||
pub type AttestedMsg<M, RA = RawDefaultAttestation> = RawAttested<RawAttestedMsgSansHandler<M>, RA>;
|
||||
|
||||
#[cw_serde]
|
||||
pub struct InstantiateMsg<RA = RawDefaultAttestation> {
|
||||
|
@ -15,6 +15,8 @@ pub struct InstantiateMsg<RA = RawDefaultAttestation> {
|
|||
#[cw_serde]
|
||||
pub enum QueryMsg {
|
||||
GetBalance { address: String },
|
||||
GetRequests {},
|
||||
GetState {},
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
|
|
631
apps/transfers/enclave/Cargo.lock
generated
631
apps/transfers/enclave/Cargo.lock
generated
|
@ -90,6 +90,9 @@ name = "anyhow"
|
|||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ark-bls12-381"
|
||||
|
@ -296,6 +299,23 @@ dependencies = [
|
|||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-tungstenite"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3609af4bbf701ddaf1f6bb4e6257dff4ff8932327d0e685d3f653724c258b1ac"
|
||||
dependencies = [
|
||||
"futures-io",
|
||||
"futures-util",
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"rustls-native-certs 0.7.3",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tokio-rustls 0.25.0",
|
||||
"tungstenite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.1.2"
|
||||
|
@ -330,7 +350,7 @@ dependencies = [
|
|||
"rustversion",
|
||||
"serde",
|
||||
"sync_wrapper 1.0.1",
|
||||
"tower",
|
||||
"tower 0.4.13",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
@ -1290,6 +1310,7 @@ version = "0.4.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c606d892c9de11507fa0dcffc116434f94e105d0bbdc4e405b61519464c49d7b"
|
||||
dependencies = [
|
||||
"eyre",
|
||||
"paste",
|
||||
]
|
||||
|
||||
|
@ -1299,6 +1320,21 @@ version = "1.0.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
dependencies = [
|
||||
"foreign-types-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
|
@ -1344,6 +1380,17 @@ version = "0.3.30"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.30"
|
||||
|
@ -1363,10 +1410,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1656,9 +1705,27 @@ dependencies = [
|
|||
"futures-util",
|
||||
"http 0.2.12",
|
||||
"hyper 0.14.30",
|
||||
"rustls",
|
||||
"rustls 0.21.12",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tokio-rustls 0.24.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-rustls"
|
||||
version = "0.27.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"hyper 1.4.1",
|
||||
"hyper-util",
|
||||
"rustls 0.23.12",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tokio-rustls 0.26.0",
|
||||
"tower-service",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1674,6 +1741,22 @@ dependencies = [
|
|||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-tls"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http-body-util",
|
||||
"hyper 1.4.1",
|
||||
"hyper-util",
|
||||
"native-tls",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.7"
|
||||
|
@ -1689,7 +1772,7 @@ dependencies = [
|
|||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tower",
|
||||
"tower 0.4.13",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
@ -1910,6 +1993,15 @@ version = "0.4.22"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
|
||||
dependencies = [
|
||||
"regex-automata 0.1.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matchit"
|
||||
version = "0.7.3"
|
||||
|
@ -2060,6 +2152,23 @@ version = "0.10.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"openssl",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
"security-framework-sys",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
|
@ -2179,12 +2288,50 @@ version = "0.3.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"openssl-macros",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "owo-colors"
|
||||
version = "3.5.0"
|
||||
|
@ -2336,6 +2483,12 @@ dependencies = [
|
|||
"spki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
||||
|
||||
[[package]]
|
||||
name = "polyval"
|
||||
version = "0.6.2"
|
||||
|
@ -2481,26 +2634,34 @@ name = "quartz-app-transfers-enclave"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"base64 0.22.1",
|
||||
"clap",
|
||||
"color-eyre",
|
||||
"cosmrs",
|
||||
"cosmwasm-std",
|
||||
"cw-multi-test",
|
||||
"ecies",
|
||||
"futures-util",
|
||||
"hex",
|
||||
"k256",
|
||||
"prost 0.13.1",
|
||||
"quartz-common",
|
||||
"reqwest 0.12.7",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.8",
|
||||
"tendermint 0.38.1",
|
||||
"tendermint-light-client",
|
||||
"tendermint-rpc",
|
||||
"thiserror",
|
||||
"tm-prover",
|
||||
"tokio",
|
||||
"tonic",
|
||||
"tonic-build",
|
||||
"tracing",
|
||||
"transfers-contract",
|
||||
"wasmd-client",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2534,12 +2695,15 @@ dependencies = [
|
|||
name = "quartz-enclave"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"clap",
|
||||
"color-eyre",
|
||||
"cosmrs",
|
||||
"cosmwasm-std",
|
||||
"cw-proof",
|
||||
"ecies",
|
||||
"futures-util",
|
||||
"hex",
|
||||
"k256",
|
||||
"mtcs",
|
||||
|
@ -2552,9 +2716,12 @@ dependencies = [
|
|||
"sha2 0.10.8",
|
||||
"tendermint 0.38.1",
|
||||
"tendermint-light-client",
|
||||
"tendermint-rpc",
|
||||
"thiserror",
|
||||
"tm-stateless-verifier",
|
||||
"tokio",
|
||||
"tonic",
|
||||
"tower 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2589,6 +2756,54 @@ dependencies = [
|
|||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn"
|
||||
version = "0.11.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"pin-project-lite",
|
||||
"quinn-proto",
|
||||
"quinn-udp",
|
||||
"rustc-hash",
|
||||
"rustls 0.23.12",
|
||||
"socket2",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn-proto"
|
||||
version = "0.11.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"rand",
|
||||
"ring",
|
||||
"rustc-hash",
|
||||
"rustls 0.23.12",
|
||||
"slab",
|
||||
"thiserror",
|
||||
"tinyvec",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn-udp"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fe68c2e9e1a1234e218683dbdf9f9dfcb094113c5ac2b938dfcb9bab4c4140b"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"once_cell",
|
||||
"socket2",
|
||||
"tracing",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.37"
|
||||
|
@ -2665,8 +2880,17 @@ checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
|
|||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
"regex-automata 0.4.7",
|
||||
"regex-syntax 0.8.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||
dependencies = [
|
||||
"regex-syntax 0.6.29",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2677,9 +2901,15 @@ checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
|
|||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
"regex-syntax 0.8.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.4"
|
||||
|
@ -2701,7 +2931,7 @@ dependencies = [
|
|||
"http 0.2.12",
|
||||
"http-body 0.4.6",
|
||||
"hyper 0.14.30",
|
||||
"hyper-rustls",
|
||||
"hyper-rustls 0.24.2",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"log",
|
||||
|
@ -2709,16 +2939,16 @@ dependencies = [
|
|||
"once_cell",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rustls",
|
||||
"rustls-native-certs",
|
||||
"rustls-pemfile",
|
||||
"rustls 0.21.12",
|
||||
"rustls-native-certs 0.6.3",
|
||||
"rustls-pemfile 1.0.4",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper 0.1.2",
|
||||
"system-configuration",
|
||||
"system-configuration 0.5.1",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tokio-rustls 0.24.1",
|
||||
"tower-service",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
|
@ -2727,6 +2957,54 @@ dependencies = [
|
|||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2 0.4.6",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.1",
|
||||
"http-body-util",
|
||||
"hyper 1.4.1",
|
||||
"hyper-rustls 0.27.3",
|
||||
"hyper-tls",
|
||||
"hyper-util",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"log",
|
||||
"mime",
|
||||
"native-tls",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"quinn",
|
||||
"rustls 0.23.12",
|
||||
"rustls-pemfile 2.1.3",
|
||||
"rustls-pki-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper 1.0.1",
|
||||
"system-configuration 0.6.1",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tokio-rustls 0.26.0",
|
||||
"tower-service",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"webpki-roots",
|
||||
"windows-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rfc6979"
|
||||
version = "0.4.0"
|
||||
|
@ -2767,6 +3045,12 @@ version = "0.1.24"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
|
@ -2806,10 +3090,38 @@ checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e"
|
|||
dependencies = [
|
||||
"log",
|
||||
"ring",
|
||||
"rustls-webpki",
|
||||
"rustls-webpki 0.101.7",
|
||||
"sct",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.22.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432"
|
||||
dependencies = [
|
||||
"log",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"rustls-webpki 0.102.7",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"rustls-webpki 0.102.7",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-native-certs"
|
||||
version = "0.6.3"
|
||||
|
@ -2817,7 +3129,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00"
|
||||
dependencies = [
|
||||
"openssl-probe",
|
||||
"rustls-pemfile",
|
||||
"rustls-pemfile 1.0.4",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-native-certs"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5"
|
||||
dependencies = [
|
||||
"openssl-probe",
|
||||
"rustls-pemfile 2.1.3",
|
||||
"rustls-pki-types",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
]
|
||||
|
@ -2831,6 +3156,22 @@ dependencies = [
|
|||
"base64 0.21.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0"
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.101.7"
|
||||
|
@ -2841,6 +3182,17 @@ dependencies = [
|
|||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.102.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84678086bd54edf2b415183ed7a94d0efb049f1b646a33e22a36f3794be6ae56"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.17"
|
||||
|
@ -3085,6 +3437,17 @@ dependencies = [
|
|||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest 0.10.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.9.9"
|
||||
|
@ -3119,6 +3482,15 @@ dependencies = [
|
|||
"keccak",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
|
@ -3242,6 +3614,9 @@ name = "sync_wrapper"
|
|||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
|
@ -3262,7 +3637,18 @@ checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
|
|||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"core-foundation",
|
||||
"system-configuration-sys",
|
||||
"system-configuration-sys 0.5.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"core-foundation",
|
||||
"system-configuration-sys 0.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3275,6 +3661,16 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration-sys"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tcbinfo"
|
||||
version = "0.1.0"
|
||||
|
@ -3284,6 +3680,7 @@ dependencies = [
|
|||
"cw-storage-plus",
|
||||
"cw2",
|
||||
"der",
|
||||
"getrandom",
|
||||
"hex",
|
||||
"mc-attestation-verifier",
|
||||
"p256",
|
||||
|
@ -3403,6 +3800,30 @@ dependencies = [
|
|||
"tendermint-light-client-verifier",
|
||||
"tendermint-rpc",
|
||||
"time",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tendermint-light-client-detector"
|
||||
version = "0.38.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb1ac1607eb7a3393313558b339c36eebeba15aa7f2d101d1d47299e65825152"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"derive_more 0.99.18",
|
||||
"flex-error",
|
||||
"futures",
|
||||
"serde",
|
||||
"serde_cbor",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"static_assertions",
|
||||
"tendermint 0.38.1",
|
||||
"tendermint-light-client",
|
||||
"tendermint-proto 0.38.1",
|
||||
"tendermint-rpc",
|
||||
"time",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
|
@ -3458,6 +3879,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "02f96a2b8a0d3d0b59e4024b1a6bdc1589efc6af4709d08a480a20cc4ba90f63"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"async-tungstenite",
|
||||
"bytes",
|
||||
"flex-error",
|
||||
"futures",
|
||||
|
@ -3465,7 +3887,7 @@ dependencies = [
|
|||
"peg",
|
||||
"pin-project",
|
||||
"rand",
|
||||
"reqwest",
|
||||
"reqwest 0.11.27",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
|
@ -3504,6 +3926,16 @@ dependencies = [
|
|||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.36"
|
||||
|
@ -3550,6 +3982,26 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tm-prover"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"color-eyre",
|
||||
"cosmrs",
|
||||
"cw-proof",
|
||||
"futures",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tendermint 0.38.1",
|
||||
"tendermint-light-client",
|
||||
"tendermint-light-client-detector",
|
||||
"tendermint-rpc",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tm-stateless-verifier"
|
||||
version = "0.1.0"
|
||||
|
@ -3586,13 +4038,45 @@ dependencies = [
|
|||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-native-tls"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
||||
dependencies = [
|
||||
"native-tls",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
|
||||
dependencies = [
|
||||
"rustls",
|
||||
"rustls 0.21.12",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f"
|
||||
dependencies = [
|
||||
"rustls 0.22.4",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
|
||||
dependencies = [
|
||||
"rustls 0.23.12",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
|
@ -3678,7 +4162,7 @@ dependencies = [
|
|||
"socket2",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tower",
|
||||
"tower 0.4.13",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
|
@ -3717,6 +4201,16 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f"
|
||||
dependencies = [
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-layer"
|
||||
version = "0.3.3"
|
||||
|
@ -3760,6 +4254,21 @@ dependencies = [
|
|||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
|
||||
dependencies = [
|
||||
"matchers",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"sharded-slab",
|
||||
"thread_local",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "transfers-contract"
|
||||
version = "0.1.0"
|
||||
|
@ -3784,6 +4293,27 @@ version = "0.2.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||
|
||||
[[package]]
|
||||
name = "tungstenite"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"data-encoding",
|
||||
"http 1.1.0",
|
||||
"httparse",
|
||||
"log",
|
||||
"rand",
|
||||
"rustls 0.22.4",
|
||||
"rustls-pki-types",
|
||||
"sha1",
|
||||
"thiserror",
|
||||
"url",
|
||||
"utf-8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
|
@ -3844,12 +4374,24 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf-8"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
|
@ -3948,6 +4490,18 @@ version = "0.2.93"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
|
||||
|
||||
[[package]]
|
||||
name = "wasmd-client"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cosmrs",
|
||||
"hex",
|
||||
"reqwest 0.12.7",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.70"
|
||||
|
@ -3958,6 +4512,15 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.26.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bd24728e5af82c6c4ec1b66ac4844bdf8156257fccda846ec58b42cd0cdbe6a"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.9"
|
||||
|
@ -3967,6 +4530,36 @@ dependencies = [
|
|||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-registry"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
|
||||
dependencies = [
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
|
||||
dependencies = [
|
||||
"windows-result",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
|
|
|
@ -15,7 +15,9 @@ default = []
|
|||
|
||||
[dependencies]
|
||||
# external
|
||||
anyhow = { version = "1.0.86", default-features = false }
|
||||
async-trait = "0.1.81"
|
||||
anyhow = { version = "1.0.86" }
|
||||
base64 = "0.22.1"
|
||||
clap = { version = "4.1.8", default-features = false, features = ["derive", "std"] }
|
||||
color-eyre = { version = "0.6.2", default-features = false }
|
||||
ecies = { version = "0.2.3", default-features = false, features = ["pure"] }
|
||||
|
@ -25,19 +27,26 @@ prost = { version = "=0.13.1", default-features = false }
|
|||
serde = { version = "1.0.203", default-features = false, features = ["derive"] }
|
||||
serde_json = { version = "1.0.94", default-features = false, features = ["alloc"] }
|
||||
sha2 = { version = "0.10.8", default-features = false }
|
||||
reqwest = "0.12.7"
|
||||
thiserror = { version = "1.0.49", default-features = false }
|
||||
tokio = { version = "=1.39.2", default-features = false, features = ["macros", "rt"] }
|
||||
tonic = { version = "=0.12.1", default-features = false, features = ["codegen", "prost", "transport"] }
|
||||
tracing = "0.1.39"
|
||||
futures-util = "0.3.30"
|
||||
|
||||
# cosmos
|
||||
cosmrs = { version = "=0.17.0", default-features = false }
|
||||
cosmwasm-std = { version = "2.1.1", default-features = false, features = ["std"] }
|
||||
tendermint = { version = "=0.38.1", default-features = false }
|
||||
tendermint-rpc = { version = "=0.38.1", default-features = false }
|
||||
tendermint-light-client = { version = "=0.38.1", default-features = false, features = ["rust-crypto"] }
|
||||
transfers-contract = { path = "../contracts", default-features = false }
|
||||
|
||||
# quartz
|
||||
# quartz-common = { git = "ssh://git@github.com/informalsystems/cycles-quartz.git", features=["full"]}
|
||||
quartz-common = { path = "../../../core/quartz-common", features=["full"]}
|
||||
wasmd-client = { path = "../../../cosmwasm/packages/wasmd-client"}
|
||||
tm-prover = { path = "../../../utils/tm-prover", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
cw-multi-test = "2.1.0"
|
||||
|
|
|
@ -2,7 +2,8 @@ use std::{env, net::SocketAddr};
|
|||
|
||||
use clap::Parser;
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use cosmrs::{tendermint::Hash, AccountId};
|
||||
use cosmrs::AccountId;
|
||||
use tendermint::Hash;
|
||||
use tendermint_light_client::types::{Height, TrustThreshold};
|
||||
|
||||
fn parse_trust_threshold(s: &str) -> Result<TrustThreshold> {
|
||||
|
@ -53,10 +54,16 @@ pub struct Cli {
|
|||
/// Maximum block lag, in seconds
|
||||
#[clap(long, default_value = "5")]
|
||||
pub max_block_lag: u64,
|
||||
|
||||
#[clap(long, default_value = "127.0.0.1:11090")]
|
||||
pub node_url: String,
|
||||
|
||||
#[clap(long, default_value = "admin")]
|
||||
pub tx_sender: String,
|
||||
}
|
||||
|
||||
fn default_rpc_addr() -> SocketAddr {
|
||||
let port = env::var("QUARTZ_PORT").unwrap_or_else(|_| "11090".to_string());
|
||||
let port = env::var("QUARTZ_ENCLAVE_RPC_PORT").unwrap_or_else(|_| "11090".to_string());
|
||||
format!("127.0.0.1:{}", port)
|
||||
.parse()
|
||||
.expect("Invalid socket address")
|
||||
|
|
|
@ -16,6 +16,7 @@ pub mod cli;
|
|||
pub mod proto;
|
||||
pub mod state;
|
||||
pub mod transfers_server;
|
||||
pub mod wslistener;
|
||||
|
||||
use std::{
|
||||
sync::{Arc, Mutex},
|
||||
|
@ -24,16 +25,13 @@ use std::{
|
|||
|
||||
use clap::Parser;
|
||||
use cli::Cli;
|
||||
use proto::settlement_server::SettlementServer as TransfersServer;
|
||||
use quartz_common::{
|
||||
contract::state::{Config, LightClientOpts},
|
||||
enclave::{
|
||||
attestor::{Attestor, DefaultAttestor},
|
||||
server::CoreService,
|
||||
server::{QuartzServer, WsListenerConfig},
|
||||
},
|
||||
proto::core_server::CoreServer,
|
||||
};
|
||||
use tonic::transport::Server;
|
||||
use transfers_server::TransfersService;
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
|
@ -41,7 +39,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
let args = Cli::parse();
|
||||
|
||||
let light_client_opts = LightClientOpts::new(
|
||||
args.chain_id,
|
||||
args.chain_id.clone(),
|
||||
args.trusted_height.into(),
|
||||
Vec::from(args.trusted_hash)
|
||||
.try_into()
|
||||
|
@ -64,17 +62,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
args.tcbinfo_contract.map(|c| c.to_string()),
|
||||
);
|
||||
|
||||
let ws_config = WsListenerConfig {
|
||||
node_url: args.node_url,
|
||||
tx_sender: args.tx_sender,
|
||||
trusted_hash: args.trusted_hash,
|
||||
trusted_height: args.trusted_height,
|
||||
chain_id: args.chain_id,
|
||||
};
|
||||
|
||||
let sk = Arc::new(Mutex::new(None));
|
||||
|
||||
Server::builder()
|
||||
.add_service(CoreServer::new(CoreService::new(
|
||||
config.clone(),
|
||||
sk.clone(),
|
||||
attestor.clone(),
|
||||
)))
|
||||
.add_service(TransfersServer::new(TransfersService::new(
|
||||
config, sk, attestor,
|
||||
)))
|
||||
QuartzServer::new(config.clone(), sk.clone(), attestor.clone(), ws_config)
|
||||
.add_service(TransfersService::new(config, sk, attestor))
|
||||
.serve(args.rpc_addr)
|
||||
.await?;
|
||||
|
||||
|
|
|
@ -23,6 +23,12 @@ pub struct QueryResponse {
|
|||
#[prost(string, tag = "1")]
|
||||
pub message: ::prost::alloc::string::String,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
|
||||
pub struct ListenRequest {}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
|
||||
pub struct ListenResponse {}
|
||||
/// Generated client implementations.
|
||||
pub mod settlement_client {
|
||||
#![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)]
|
||||
|
@ -151,6 +157,115 @@ pub mod settlement_client {
|
|||
}
|
||||
}
|
||||
}
|
||||
/// Generated client implementations.
|
||||
pub mod event_listener_client {
|
||||
#![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)]
|
||||
use tonic::codegen::*;
|
||||
use tonic::codegen::http::Uri;
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EventListenerClient<T> {
|
||||
inner: tonic::client::Grpc<T>,
|
||||
}
|
||||
impl EventListenerClient<tonic::transport::Channel> {
|
||||
/// Attempt to create a new client by connecting to a given endpoint.
|
||||
pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>
|
||||
where
|
||||
D: TryInto<tonic::transport::Endpoint>,
|
||||
D::Error: Into<StdError>,
|
||||
{
|
||||
let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;
|
||||
Ok(Self::new(conn))
|
||||
}
|
||||
}
|
||||
impl<T> EventListenerClient<T>
|
||||
where
|
||||
T: tonic::client::GrpcService<tonic::body::BoxBody>,
|
||||
T::Error: Into<StdError>,
|
||||
T::ResponseBody: Body<Data = Bytes> + Send + 'static,
|
||||
<T::ResponseBody as Body>::Error: Into<StdError> + Send,
|
||||
{
|
||||
pub fn new(inner: T) -> Self {
|
||||
let inner = tonic::client::Grpc::new(inner);
|
||||
Self { inner }
|
||||
}
|
||||
pub fn with_origin(inner: T, origin: Uri) -> Self {
|
||||
let inner = tonic::client::Grpc::with_origin(inner, origin);
|
||||
Self { inner }
|
||||
}
|
||||
pub fn with_interceptor<F>(
|
||||
inner: T,
|
||||
interceptor: F,
|
||||
) -> EventListenerClient<InterceptedService<T, F>>
|
||||
where
|
||||
F: tonic::service::Interceptor,
|
||||
T::ResponseBody: Default,
|
||||
T: tonic::codegen::Service<
|
||||
http::Request<tonic::body::BoxBody>,
|
||||
Response = http::Response<
|
||||
<T as tonic::client::GrpcService<tonic::body::BoxBody>>::ResponseBody,
|
||||
>,
|
||||
>,
|
||||
<T as tonic::codegen::Service<
|
||||
http::Request<tonic::body::BoxBody>,
|
||||
>>::Error: Into<StdError> + Send + Sync,
|
||||
{
|
||||
EventListenerClient::new(InterceptedService::new(inner, interceptor))
|
||||
}
|
||||
/// Compress requests with the given encoding.
|
||||
///
|
||||
/// This requires the server to support it otherwise it might respond with an
|
||||
/// error.
|
||||
#[must_use]
|
||||
pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
|
||||
self.inner = self.inner.send_compressed(encoding);
|
||||
self
|
||||
}
|
||||
/// Enable decompressing responses.
|
||||
#[must_use]
|
||||
pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
|
||||
self.inner = self.inner.accept_compressed(encoding);
|
||||
self
|
||||
}
|
||||
/// Limits the maximum size of a decoded message.
|
||||
///
|
||||
/// Default: `4MB`
|
||||
#[must_use]
|
||||
pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
|
||||
self.inner = self.inner.max_decoding_message_size(limit);
|
||||
self
|
||||
}
|
||||
/// Limits the maximum size of an encoded message.
|
||||
///
|
||||
/// Default: `usize::MAX`
|
||||
#[must_use]
|
||||
pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
|
||||
self.inner = self.inner.max_encoding_message_size(limit);
|
||||
self
|
||||
}
|
||||
pub async fn listen(
|
||||
&mut self,
|
||||
request: impl tonic::IntoRequest<super::ListenRequest>,
|
||||
) -> std::result::Result<tonic::Response<super::ListenResponse>, tonic::Status> {
|
||||
self.inner
|
||||
.ready()
|
||||
.await
|
||||
.map_err(|e| {
|
||||
tonic::Status::new(
|
||||
tonic::Code::Unknown,
|
||||
format!("Service was not ready: {}", e.into()),
|
||||
)
|
||||
})?;
|
||||
let codec = tonic::codec::ProstCodec::default();
|
||||
let path = http::uri::PathAndQuery::from_static(
|
||||
"/transfers.EventListener/Listen",
|
||||
);
|
||||
let mut req = request.into_request();
|
||||
req.extensions_mut()
|
||||
.insert(GrpcMethod::new("transfers.EventListener", "Listen"));
|
||||
self.inner.unary(req, path, codec).await
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Generated server implementations.
|
||||
pub mod settlement_server {
|
||||
#![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)]
|
||||
|
@ -363,3 +478,170 @@ pub mod settlement_server {
|
|||
const NAME: &'static str = "transfers.Settlement";
|
||||
}
|
||||
}
|
||||
/// Generated server implementations.
|
||||
pub mod event_listener_server {
|
||||
#![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)]
|
||||
use tonic::codegen::*;
|
||||
/// Generated trait containing gRPC methods that should be implemented for use with EventListenerServer.
|
||||
#[async_trait]
|
||||
pub trait EventListener: Send + Sync + 'static {
|
||||
async fn listen(
|
||||
&self,
|
||||
request: tonic::Request<super::ListenRequest>,
|
||||
) -> std::result::Result<tonic::Response<super::ListenResponse>, tonic::Status>;
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub struct EventListenerServer<T: EventListener> {
|
||||
inner: Arc<T>,
|
||||
accept_compression_encodings: EnabledCompressionEncodings,
|
||||
send_compression_encodings: EnabledCompressionEncodings,
|
||||
max_decoding_message_size: Option<usize>,
|
||||
max_encoding_message_size: Option<usize>,
|
||||
}
|
||||
impl<T: EventListener> EventListenerServer<T> {
|
||||
pub fn new(inner: T) -> Self {
|
||||
Self::from_arc(Arc::new(inner))
|
||||
}
|
||||
pub fn from_arc(inner: Arc<T>) -> Self {
|
||||
Self {
|
||||
inner,
|
||||
accept_compression_encodings: Default::default(),
|
||||
send_compression_encodings: Default::default(),
|
||||
max_decoding_message_size: None,
|
||||
max_encoding_message_size: None,
|
||||
}
|
||||
}
|
||||
pub fn with_interceptor<F>(
|
||||
inner: T,
|
||||
interceptor: F,
|
||||
) -> InterceptedService<Self, F>
|
||||
where
|
||||
F: tonic::service::Interceptor,
|
||||
{
|
||||
InterceptedService::new(Self::new(inner), interceptor)
|
||||
}
|
||||
/// Enable decompressing requests with the given encoding.
|
||||
#[must_use]
|
||||
pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
|
||||
self.accept_compression_encodings.enable(encoding);
|
||||
self
|
||||
}
|
||||
/// Compress responses with the given encoding, if the client supports it.
|
||||
#[must_use]
|
||||
pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
|
||||
self.send_compression_encodings.enable(encoding);
|
||||
self
|
||||
}
|
||||
/// Limits the maximum size of a decoded message.
|
||||
///
|
||||
/// Default: `4MB`
|
||||
#[must_use]
|
||||
pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
|
||||
self.max_decoding_message_size = Some(limit);
|
||||
self
|
||||
}
|
||||
/// Limits the maximum size of an encoded message.
|
||||
///
|
||||
/// Default: `usize::MAX`
|
||||
#[must_use]
|
||||
pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
|
||||
self.max_encoding_message_size = Some(limit);
|
||||
self
|
||||
}
|
||||
}
|
||||
impl<T, B> tonic::codegen::Service<http::Request<B>> for EventListenerServer<T>
|
||||
where
|
||||
T: EventListener,
|
||||
B: Body + Send + 'static,
|
||||
B::Error: Into<StdError> + Send + 'static,
|
||||
{
|
||||
type Response = http::Response<tonic::body::BoxBody>;
|
||||
type Error = std::convert::Infallible;
|
||||
type Future = BoxFuture<Self::Response, Self::Error>;
|
||||
fn poll_ready(
|
||||
&mut self,
|
||||
_cx: &mut Context<'_>,
|
||||
) -> Poll<std::result::Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
fn call(&mut self, req: http::Request<B>) -> Self::Future {
|
||||
match req.uri().path() {
|
||||
"/transfers.EventListener/Listen" => {
|
||||
#[allow(non_camel_case_types)]
|
||||
struct ListenSvc<T: EventListener>(pub Arc<T>);
|
||||
impl<
|
||||
T: EventListener,
|
||||
> tonic::server::UnaryService<super::ListenRequest>
|
||||
for ListenSvc<T> {
|
||||
type Response = super::ListenResponse;
|
||||
type Future = BoxFuture<
|
||||
tonic::Response<Self::Response>,
|
||||
tonic::Status,
|
||||
>;
|
||||
fn call(
|
||||
&mut self,
|
||||
request: tonic::Request<super::ListenRequest>,
|
||||
) -> Self::Future {
|
||||
let inner = Arc::clone(&self.0);
|
||||
let fut = async move {
|
||||
<T as EventListener>::listen(&inner, request).await
|
||||
};
|
||||
Box::pin(fut)
|
||||
}
|
||||
}
|
||||
let accept_compression_encodings = self.accept_compression_encodings;
|
||||
let send_compression_encodings = self.send_compression_encodings;
|
||||
let max_decoding_message_size = self.max_decoding_message_size;
|
||||
let max_encoding_message_size = self.max_encoding_message_size;
|
||||
let inner = self.inner.clone();
|
||||
let fut = async move {
|
||||
let method = ListenSvc(inner);
|
||||
let codec = tonic::codec::ProstCodec::default();
|
||||
let mut grpc = tonic::server::Grpc::new(codec)
|
||||
.apply_compression_config(
|
||||
accept_compression_encodings,
|
||||
send_compression_encodings,
|
||||
)
|
||||
.apply_max_message_size_config(
|
||||
max_decoding_message_size,
|
||||
max_encoding_message_size,
|
||||
);
|
||||
let res = grpc.unary(method, req).await;
|
||||
Ok(res)
|
||||
};
|
||||
Box::pin(fut)
|
||||
}
|
||||
_ => {
|
||||
Box::pin(async move {
|
||||
Ok(
|
||||
http::Response::builder()
|
||||
.status(200)
|
||||
.header("grpc-status", tonic::Code::Unimplemented as i32)
|
||||
.header(
|
||||
http::header::CONTENT_TYPE,
|
||||
tonic::metadata::GRPC_CONTENT_TYPE,
|
||||
)
|
||||
.body(empty_body())
|
||||
.unwrap(),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: EventListener> Clone for EventListenerServer<T> {
|
||||
fn clone(&self) -> Self {
|
||||
let inner = self.inner.clone();
|
||||
Self {
|
||||
inner,
|
||||
accept_compression_encodings: self.accept_compression_encodings,
|
||||
send_compression_encodings: self.send_compression_encodings,
|
||||
max_decoding_message_size: self.max_decoding_message_size,
|
||||
max_encoding_message_size: self.max_encoding_message_size,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: EventListener> tonic::server::NamedService for EventListenerServer<T> {
|
||||
const NAME: &'static str = "transfers.EventListener";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,10 @@ use quartz_common::{
|
|||
msg::execute::attested::{HasUserData, RawAttested},
|
||||
state::{Config, UserData},
|
||||
},
|
||||
enclave::{attestor::Attestor, server::ProofOfPublication},
|
||||
enclave::{
|
||||
attestor::Attestor,
|
||||
server::{IntoServer, ProofOfPublication},
|
||||
},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256};
|
||||
|
@ -20,11 +23,20 @@ use transfers_contract::msg::execute::{ClearTextTransferRequestMsg, Request as T
|
|||
|
||||
use crate::{
|
||||
proto::{
|
||||
settlement_server::Settlement, QueryRequest, QueryResponse, UpdateRequest, UpdateResponse,
|
||||
settlement_server::{Settlement, SettlementServer},
|
||||
QueryRequest, QueryResponse, UpdateRequest, UpdateResponse,
|
||||
},
|
||||
state::{RawBalance, RawState, State},
|
||||
};
|
||||
|
||||
impl<A: Attestor> IntoServer for TransfersService<A> {
|
||||
type Server = SettlementServer<TransfersService<A>>;
|
||||
|
||||
fn into_server(self) -> Self::Server {
|
||||
SettlementServer::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub type RawCipherText = HexBinary;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -34,17 +46,17 @@ pub struct TransfersService<A> {
|
|||
attestor: A,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
|
||||
pub struct UpdateRequestMessage {
|
||||
state: HexBinary,
|
||||
requests: Vec<TransfersRequest>,
|
||||
pub state: HexBinary,
|
||||
pub requests: Vec<TransfersRequest>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct QueryRequestMessage {
|
||||
state: HexBinary,
|
||||
address: Addr,
|
||||
ephemeral_pubkey: HexBinary,
|
||||
pub state: HexBinary,
|
||||
pub address: Addr,
|
||||
pub ephemeral_pubkey: HexBinary,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
|
|
321
apps/transfers/enclave/src/wslistener.rs
Normal file
321
apps/transfers/enclave/src/wslistener.rs
Normal file
|
@ -0,0 +1,321 @@
|
|||
//TODO: get rid of this
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use cosmrs::{tendermint::chain::Id as ChainId, AccountId};
|
||||
use cosmwasm_std::{Addr, HexBinary};
|
||||
use futures_util::StreamExt;
|
||||
use quartz_common::{
|
||||
contract::msg::execute::attested::{
|
||||
MockAttestation, RawAttested, RawAttestedMsgSansHandler, RawMockAttestation,
|
||||
},
|
||||
enclave::{
|
||||
attestor::Attestor,
|
||||
server::{WebSocketHandler, WsListenerConfig},
|
||||
},
|
||||
};
|
||||
use reqwest::Url;
|
||||
use serde_json::json;
|
||||
use tendermint_rpc::{event::Event, query::EventType, SubscriptionClient, WebSocketClient};
|
||||
use tm_prover::{config::Config as TmProverConfig, prover::prove};
|
||||
use tonic::Request;
|
||||
use tracing::info;
|
||||
use transfers_contract::msg::{
|
||||
execute::{QueryResponseMsg, Request as TransferRequest, UpdateMsg},
|
||||
AttestedMsg, ExecuteMsg,
|
||||
QueryMsg::{GetRequests, GetState},
|
||||
};
|
||||
use wasmd_client::{CliWasmdClient, QueryResult, WasmdClient};
|
||||
|
||||
use crate::{
|
||||
proto::{settlement_server::Settlement, QueryRequest, UpdateRequest},
|
||||
transfers_server::{QueryRequestMessage, TransfersService, UpdateRequestMessage},
|
||||
};
|
||||
|
||||
// TODO: Need to prevent listener from taking actions until handshake is completed
|
||||
#[async_trait::async_trait]
|
||||
impl<A: Attestor> WebSocketHandler for TransfersService<A> {
|
||||
async fn handle(&self, event: Event, config: WsListenerConfig) -> Result<()> {
|
||||
// Validation
|
||||
let is_transfer = is_transfer_event(&event);
|
||||
let is_query = is_query_event(&event);
|
||||
|
||||
if !is_transfer && !is_query {
|
||||
return Ok(());
|
||||
} else {
|
||||
let mut sender = None;
|
||||
let mut contract_address = None;
|
||||
let mut emphemeral_pubkey = None;
|
||||
|
||||
if let Some(events) = &event.events {
|
||||
for (key, values) in events {
|
||||
match key.as_str() {
|
||||
"message.sender" => {
|
||||
sender = values.first().cloned();
|
||||
}
|
||||
"execute._contract_address" => {
|
||||
contract_address = values.first().cloned();
|
||||
}
|
||||
"wasm-query_balance.emphemeral_pubkey" => {
|
||||
// TODO: fix typo
|
||||
emphemeral_pubkey = values.first().cloned();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if contract_address.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if is_transfer {
|
||||
println!("Processing transfer event");
|
||||
transfer_handler(
|
||||
self,
|
||||
&contract_address
|
||||
.expect("must be included in transfers event")
|
||||
.parse::<AccountId>()
|
||||
.map_err(|e| anyhow!(e))?,
|
||||
&config,
|
||||
)
|
||||
.await?;
|
||||
} else if is_query {
|
||||
println!("Processing query event");
|
||||
query_handler(
|
||||
self,
|
||||
&contract_address
|
||||
.expect("must be included in query event")
|
||||
.parse::<AccountId>()
|
||||
.map_err(|e| anyhow!(e))?,
|
||||
sender.expect("must be included in query event"),
|
||||
emphemeral_pubkey.expect("must be included in query event"),
|
||||
&config,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn is_transfer_event(event: &Event) -> bool {
|
||||
// Check if the event is a transaction type
|
||||
if let Some(EventType::Tx) = event.event_type() {
|
||||
// Check for the "wasm.action" key with the value "init_clearing"
|
||||
if let Some(events) = &event.events {
|
||||
return events.iter().any(|(key, _)| key == "wasm-transfer.action");
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn is_query_event(event: &Event) -> bool {
|
||||
// Check if the event is a transaction type
|
||||
if let Some(EventType::Tx) = event.event_type() {
|
||||
// Check for the "wasm.action" key with the value "init_clearing"
|
||||
if let Some(events) = &event.events {
|
||||
return events
|
||||
.iter()
|
||||
.any(|(key, _)| key.starts_with("wasm-query_balance"));
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
async fn transfer_handler<A: Attestor>(
|
||||
client: &TransfersService<A>,
|
||||
contract: &AccountId,
|
||||
ws_config: &WsListenerConfig,
|
||||
) -> Result<()> {
|
||||
let chain_id = &ChainId::from_str(&ws_config.chain_id)?;
|
||||
let httpurl = Url::parse(&format!("http://{}", ws_config.node_url))?;
|
||||
let wasmd_client = CliWasmdClient::new(httpurl.clone());
|
||||
|
||||
// Query chain
|
||||
// Get epoch, obligations, liquidity sources
|
||||
let resp: QueryResult<Vec<TransferRequest>> = wasmd_client
|
||||
.query_smart(contract, json!(GetRequests {}))
|
||||
.map_err(|e| anyhow!("Problem querying epoch: {}", e))?;
|
||||
let requests = resp.data;
|
||||
|
||||
let resp: QueryResult<HexBinary> = wasmd_client
|
||||
.query_smart(contract, json!(GetState {}))
|
||||
.map_err(|e| anyhow!("Problem querying epoch: {}", e))?;
|
||||
let state = resp.data;
|
||||
|
||||
// Request body contents
|
||||
let update_contents = UpdateRequestMessage { state, requests };
|
||||
|
||||
// Wait 2 blocks
|
||||
info!("Waiting 2 blocks for light client proof");
|
||||
let wsurl = format!("ws://{}/websocket", ws_config.node_url);
|
||||
two_block_waitoor(&wsurl).await?;
|
||||
|
||||
// Call tm prover with trusted hash and height
|
||||
let prover_config = TmProverConfig {
|
||||
primary: httpurl.as_str().parse()?,
|
||||
witnesses: httpurl.as_str().parse()?,
|
||||
trusted_height: ws_config.trusted_height,
|
||||
trusted_hash: ws_config.trusted_hash,
|
||||
verbose: "1".parse()?, // TODO: both tm-prover and cli define the same Verbosity struct. Need to define this once and import
|
||||
contract_address: contract.clone(),
|
||||
storage_key: "requests".to_string(),
|
||||
chain_id: ws_config.chain_id.to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let proof_output = tokio::task::spawn_blocking(move || {
|
||||
// Create a new runtime inside the blocking thread.
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
prove(prover_config)
|
||||
.await
|
||||
.map_err(|report| anyhow!("Tendermint prover failed. Report: {}", report))
|
||||
})
|
||||
})
|
||||
.await??; // Handle both JoinError and your custom error
|
||||
|
||||
// Merge the UpdateRequestMessage with the proof
|
||||
let mut proof_json = serde_json::to_value(proof_output)?;
|
||||
proof_json["msg"] = serde_json::to_value(&update_contents)?;
|
||||
|
||||
// Build final request object
|
||||
let request = Request::new(UpdateRequest {
|
||||
message: json!(proof_json).to_string(),
|
||||
});
|
||||
|
||||
// Send UpdateRequestMessage request to enclave over tonic gRPC client
|
||||
let update_response = client
|
||||
.run(request)
|
||||
.await
|
||||
.map_err(|e| anyhow!("Failed to communicate to relayer. {e}"))?
|
||||
.into_inner();
|
||||
|
||||
// Extract json from enclave response
|
||||
let attested: RawAttested<UpdateMsg, HexBinary> =
|
||||
serde_json::from_str(&update_response.message)
|
||||
.map_err(|e| anyhow!("Error deserializing UpdateMsg from enclave: {}", e))?;
|
||||
|
||||
// Build on-chain response
|
||||
// TODO add non-mock support
|
||||
let setoffs_msg = ExecuteMsg::Update::<RawMockAttestation>(AttestedMsg {
|
||||
msg: RawAttestedMsgSansHandler(attested.msg),
|
||||
attestation: MockAttestation(
|
||||
attested
|
||||
.attestation
|
||||
.as_slice()
|
||||
.try_into()
|
||||
.map_err(|_| anyhow!("slice with incorrect length"))?,
|
||||
)
|
||||
.into(),
|
||||
});
|
||||
|
||||
// Post response to chain
|
||||
let output = wasmd_client.tx_execute(
|
||||
contract,
|
||||
chain_id,
|
||||
2000000,
|
||||
&ws_config.tx_sender,
|
||||
json!(setoffs_msg),
|
||||
)?;
|
||||
|
||||
println!("Output TX: {}", output);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn query_handler<A: Attestor>(
|
||||
client: &TransfersService<A>,
|
||||
contract: &AccountId,
|
||||
msg_sender: String,
|
||||
pubkey: String,
|
||||
ws_config: &WsListenerConfig,
|
||||
) -> Result<()> {
|
||||
let chain_id = &ChainId::from_str(&ws_config.chain_id)?;
|
||||
let httpurl = Url::parse(&format!("http://{}", ws_config.node_url))?;
|
||||
let wasmd_client = CliWasmdClient::new(httpurl);
|
||||
|
||||
// Query Chain
|
||||
// Get state
|
||||
let resp: QueryResult<HexBinary> = wasmd_client
|
||||
.query_smart(contract, json!(GetState {}))
|
||||
.map_err(|e| anyhow!("Problem querying epoch: {}", e))?;
|
||||
let state = resp.data;
|
||||
|
||||
// Build request
|
||||
let update_contents = QueryRequestMessage {
|
||||
state,
|
||||
address: Addr::unchecked(&msg_sender), // sender comes from TX event, therefore is checked
|
||||
ephemeral_pubkey: HexBinary::from_hex(&pubkey)?,
|
||||
};
|
||||
|
||||
// Send QueryRequestMessage to enclave over tonic gRPC client
|
||||
let request = Request::new(QueryRequest {
|
||||
message: json!(update_contents).to_string(),
|
||||
});
|
||||
|
||||
let query_response = client
|
||||
.query(request)
|
||||
.await
|
||||
.map_err(|e| anyhow!("Failed to communicate to relayer. {e}"))?
|
||||
.into_inner();
|
||||
|
||||
// Extract json from the enclave response
|
||||
let attested: RawAttested<QueryResponseMsg, HexBinary> =
|
||||
serde_json::from_str(&query_response.message)
|
||||
.map_err(|e| anyhow!("Error deserializing QueryResponseMsg from enclave: {}", e))?;
|
||||
|
||||
// Build on-chain response
|
||||
// TODO add non-mock support
|
||||
let setoffs_msg = ExecuteMsg::QueryResponse::<RawMockAttestation>(AttestedMsg {
|
||||
msg: RawAttestedMsgSansHandler(attested.msg),
|
||||
attestation: MockAttestation(
|
||||
attested
|
||||
.attestation
|
||||
.as_slice()
|
||||
.try_into()
|
||||
.map_err(|_| anyhow!("slice with incorrect length"))?,
|
||||
)
|
||||
.into(),
|
||||
});
|
||||
|
||||
// Post response to chain
|
||||
let output = wasmd_client.tx_execute(
|
||||
contract,
|
||||
chain_id,
|
||||
2000000,
|
||||
&ws_config.tx_sender,
|
||||
json!(setoffs_msg),
|
||||
)?;
|
||||
|
||||
println!("Output TX: {}", output);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn two_block_waitoor(wsurl: &str) -> Result<(), anyhow::Error> {
|
||||
let (client, driver) = WebSocketClient::new(wsurl).await?;
|
||||
|
||||
let driver_handle = tokio::spawn(async move { driver.run().await });
|
||||
|
||||
// Subscription functionality
|
||||
let mut subs = client.subscribe(EventType::NewBlock.into()).await?;
|
||||
|
||||
// Wait 2 NewBlock events
|
||||
let mut ev_count = 2_i32;
|
||||
|
||||
while let Some(res) = subs.next().await {
|
||||
let _ev = res?;
|
||||
ev_count -= 1;
|
||||
if ev_count == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Signal to the driver to terminate.
|
||||
client.close()?;
|
||||
// Await the driver's termination to ensure proper connection closure.
|
||||
let _ = driver_handle.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -52,8 +52,7 @@ tendermint-light-client.workspace = true
|
|||
tendermint-rpc = { workspace = true, features=["websocket-client", "http-client"]}
|
||||
|
||||
tm-prover = { workspace = true}
|
||||
quartz-common = { workspace = true, features=["contract"]}
|
||||
quartz-common = { workspace = true, features=["contract", "proto"]}
|
||||
quartz-tee-ra = { workspace = true}
|
||||
mtcs-enclave = { workspace = true, optional = false}
|
||||
wasmd-client.workspace = true
|
||||
tempfile.workspace = true
|
||||
|
|
|
@ -38,6 +38,10 @@ impl Handler for EnclaveStartRequest {
|
|||
trusted_height.to_string(),
|
||||
"--trusted-hash".to_string(),
|
||||
trusted_hash.to_string(),
|
||||
"--node-url".to_string(),
|
||||
config.node_url,
|
||||
"--tx-sender".to_string(),
|
||||
config.tx_sender,
|
||||
];
|
||||
|
||||
// Run quartz enclave and block
|
||||
|
@ -98,7 +102,7 @@ async fn create_mock_enclave_child(
|
|||
|
||||
// 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"))
|
||||
.manifest_path(enclave_dir.join("Cargo.toml"))
|
||||
.exec()
|
||||
.map_err(|e| Error::GenericErr(e.to_string()))?
|
||||
.root_package()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::{fs, str::FromStr};
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use async_trait::async_trait;
|
||||
|
@ -57,7 +57,7 @@ async fn handshake(args: HandshakeRequest, config: Config) -> Result<String, any
|
|||
|
||||
info!("Running SessionCreate");
|
||||
|
||||
let res: serde_json::Value = RelayMessage::SessionCreate
|
||||
let res = RelayMessage::SessionCreate
|
||||
.run_relay(config.enclave_rpc(), config.mock_sgx)
|
||||
.await?;
|
||||
|
||||
|
@ -82,33 +82,26 @@ async fn handshake(args: HandshakeRequest, config: Config) -> Result<String, any
|
|||
info!("Waiting 2 blocks for light client proof");
|
||||
two_block_waitoor(&wsurl).await?;
|
||||
|
||||
let proof_path = config.cache_dir()?.join("light-client-proof.json");
|
||||
debug!("Proof path: {:?}", proof_path.to_str());
|
||||
|
||||
// Call tm prover with trusted hash and height
|
||||
let prover_config = TmProverConfig {
|
||||
primary: httpurl.as_str().parse()?,
|
||||
witnesses: httpurl.as_str().parse()?,
|
||||
trusted_height,
|
||||
trusted_hash,
|
||||
trace_file: Some(proof_path.clone()),
|
||||
verbose: "1".parse()?, // TODO: both tm-prover and cli define the same Verbosity struct. Need to define this once and import
|
||||
contract_address: args.contract.clone(),
|
||||
storage_key: "quartz_session".to_string(),
|
||||
chain_id: config.chain_id.to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
debug!("config: {:?}", prover_config);
|
||||
if let Err(report) = prove(prover_config).await {
|
||||
return Err(anyhow!("Tendermint prover failed. Report: {}", report));
|
||||
}
|
||||
|
||||
// Read proof file
|
||||
let proof = fs::read_to_string(proof_path.as_path())?;
|
||||
let proof_output = prove(prover_config)
|
||||
.await
|
||||
.map_err(|report| anyhow!("Tendermint prover failed. Report: {}", report))?;
|
||||
|
||||
// Execute SessionSetPubKey on enclave
|
||||
info!("Running SessionSetPubKey");
|
||||
let res: serde_json::Value = RelayMessage::SessionSetPubKey(proof.trim().to_string())
|
||||
let res = RelayMessage::SessionSetPubKey(serde_json::to_string(&proof_output)?)
|
||||
.run_relay(config.enclave_rpc(), config.mock_sgx)
|
||||
.await?;
|
||||
|
||||
|
|
|
@ -16,23 +16,29 @@ mock-sgx = ["quartz-cw/mock-sgx"]
|
|||
|
||||
[dependencies]
|
||||
# external
|
||||
anyhow.workspace = true
|
||||
async-trait.workspace = true
|
||||
sha2 = { workspace = true }
|
||||
clap.workspace = true
|
||||
color-eyre.workspace = true
|
||||
ecies.workspace = true
|
||||
futures-util.workspace = true
|
||||
hex.workspace = true
|
||||
k256.workspace = true
|
||||
rand.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
thiserror.workspace = true
|
||||
tonic.workspace = true
|
||||
tokio.workspace = true
|
||||
tower.workspace = true
|
||||
|
||||
# cosmos
|
||||
cosmrs.workspace = true
|
||||
cosmwasm-std.workspace = true
|
||||
tendermint.workspace = true
|
||||
tendermint-light-client.workspace = true
|
||||
tendermint-rpc = { workspace = true, features=["websocket-client", "http-client"] }
|
||||
|
||||
# quartz
|
||||
cw-proof.workspace = true
|
||||
|
|
|
@ -15,7 +15,7 @@ pub type DefaultAttestor = EpidAttestor;
|
|||
pub type DefaultAttestor = MockAttestor;
|
||||
|
||||
/// The trait defines the interface for generating attestations from within an enclave.
|
||||
pub trait Attestor {
|
||||
pub trait Attestor: Send + Sync + 'static {
|
||||
type Error: ToString;
|
||||
|
||||
fn quote(&self, user_data: impl HasUserData) -> Result<Vec<u8>, Self::Error>;
|
||||
|
|
15
core/quartz/src/error.rs
Normal file
15
core/quartz/src/error.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
use std::io;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum QuartzError {
|
||||
#[error("WebSocket error: {0}")]
|
||||
WebSocket(#[from] tendermint_rpc::Error),
|
||||
#[error("Tonic transport error: {0}")]
|
||||
TonicTransport(#[from] tonic::transport::Error),
|
||||
#[error("IO error: {0}")]
|
||||
Io(#[from] io::Error),
|
||||
#[error("Other error: {0}")]
|
||||
Other(String),
|
||||
}
|
|
@ -13,5 +13,6 @@
|
|||
)]
|
||||
|
||||
pub mod attestor;
|
||||
pub mod error;
|
||||
pub mod server;
|
||||
pub mod types;
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use std::{
|
||||
convert::Infallible,
|
||||
net::SocketAddr,
|
||||
sync::{Arc, Mutex},
|
||||
time::Duration,
|
||||
};
|
||||
|
@ -7,6 +9,7 @@ use cw_proof::proof::{
|
|||
cw::{CwProof, RawCwProof},
|
||||
Proof,
|
||||
};
|
||||
use futures_util::StreamExt;
|
||||
use k256::ecdsa::SigningKey;
|
||||
use quartz_cw::{
|
||||
msg::{
|
||||
|
@ -16,26 +19,156 @@ use quartz_cw::{
|
|||
state::{Config, LightClientOpts, Nonce, Session},
|
||||
};
|
||||
use quartz_proto::quartz::{
|
||||
core_server::Core, InstantiateRequest as RawInstantiateRequest,
|
||||
InstantiateResponse as RawInstantiateResponse, SessionCreateRequest as RawSessionCreateRequest,
|
||||
core_server::{Core, CoreServer},
|
||||
InstantiateRequest as RawInstantiateRequest, InstantiateResponse as RawInstantiateResponse,
|
||||
SessionCreateRequest as RawSessionCreateRequest,
|
||||
SessionCreateResponse as RawSessionCreateResponse,
|
||||
SessionSetPubKeyRequest as RawSessionSetPubKeyRequest,
|
||||
SessionSetPubKeyResponse as RawSessionSetPubKeyResponse,
|
||||
};
|
||||
use rand::Rng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tendermint::{block::Height, Hash};
|
||||
use tendermint_light_client::{
|
||||
light_client::Options,
|
||||
types::{LightBlock, TrustThreshold},
|
||||
};
|
||||
use tendermint_rpc::{
|
||||
event::Event,
|
||||
query::{EventType, Query},
|
||||
SubscriptionClient, WebSocketClient,
|
||||
};
|
||||
use tm_stateless_verifier::make_provider;
|
||||
use tonic::{Request, Response, Result as TonicResult, Status};
|
||||
use tonic::{
|
||||
body::BoxBody,
|
||||
codegen::http,
|
||||
server::NamedService,
|
||||
transport::{server::Router, Server},
|
||||
Request, Response, Result as TonicResult, Status,
|
||||
};
|
||||
use tower::Service;
|
||||
|
||||
use crate::{
|
||||
attestor::Attestor,
|
||||
attestor::{Attestor, DefaultAttestor},
|
||||
error::QuartzError,
|
||||
types::{InstantiateResponse, SessionCreateResponse, SessionSetPubKeyResponse},
|
||||
};
|
||||
|
||||
/// Trait for Quartz enclaves to process on-chain events.
|
||||
///
|
||||
/// Implementors of this trait should define how to process incoming WebSocket events,
|
||||
/// using the provided `event` and `ws_config` parameters.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `event` - The WebSocket event received from the Tendermint RPC server.
|
||||
/// * `ws_config` - Configuration values used for handling the WebSocket events,
|
||||
/// such as node URL, a signer for transactions, and trusted block information.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// An `anyhow::Result<()>` indicating success or failure in handling the event.
|
||||
#[tonic::async_trait]
|
||||
pub trait WebSocketHandler: Send + Sync + 'static {
|
||||
async fn handle(&self, event: Event, ws_config: WsListenerConfig) -> anyhow::Result<()>; // TODO: replace anyhow
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WsListenerConfig {
|
||||
pub node_url: String,
|
||||
pub chain_id: String,
|
||||
pub tx_sender: String,
|
||||
pub trusted_hash: Hash,
|
||||
pub trusted_height: Height,
|
||||
}
|
||||
|
||||
/// A trait for wrapping a tonic service with the gRPC server handler
|
||||
pub trait IntoServer {
|
||||
type Server;
|
||||
|
||||
fn into_server(self) -> Self::Server;
|
||||
}
|
||||
|
||||
pub struct QuartzServer {
|
||||
pub router: Router,
|
||||
ws_handlers: Vec<Box<dyn WebSocketHandler>>,
|
||||
pub ws_config: WsListenerConfig,
|
||||
}
|
||||
|
||||
impl QuartzServer {
|
||||
pub fn new(
|
||||
config: Config,
|
||||
sk: Arc<Mutex<Option<SigningKey>>>,
|
||||
attestor: DefaultAttestor,
|
||||
ws_config: WsListenerConfig,
|
||||
) -> Self {
|
||||
let core_service = CoreServer::new(CoreService::new(config, sk.clone(), attestor.clone()));
|
||||
|
||||
Self {
|
||||
router: Server::builder().add_service(core_service),
|
||||
ws_handlers: Vec::new(),
|
||||
ws_config,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_service<S>(mut self, service: S) -> Self
|
||||
where
|
||||
S: IntoServer + WebSocketHandler + Clone,
|
||||
S::Server: Service<
|
||||
http::request::Request<BoxBody>,
|
||||
Response = http::response::Response<BoxBody>,
|
||||
Error = Infallible,
|
||||
> + NamedService
|
||||
+ Clone
|
||||
+ Send
|
||||
+ 'static,
|
||||
<S::Server as Service<http::request::Request<BoxBody>>>::Future: Send + 'static,
|
||||
{
|
||||
self.ws_handlers.push(Box::new(service.clone()));
|
||||
|
||||
let tonic_server = service.into_server();
|
||||
self.router = self.router.add_service(tonic_server);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn serve(self, addr: SocketAddr) -> Result<(), QuartzError> {
|
||||
// Launch all WebSocket handlers as separate Tokio tasks
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = Self::websocket_events_listener(&self.ws_handlers, self.ws_config).await
|
||||
{
|
||||
eprintln!("Error in WebSocket event handler: {:?}", e);
|
||||
}
|
||||
});
|
||||
|
||||
Ok(self.router.serve(addr).await?)
|
||||
}
|
||||
|
||||
async fn websocket_events_listener(
|
||||
ws_handlers: &Vec<Box<dyn WebSocketHandler>>,
|
||||
ws_config: WsListenerConfig,
|
||||
) -> Result<(), QuartzError> {
|
||||
let wsurl = format!("ws://{}/websocket", ws_config.node_url);
|
||||
let (client, driver) = WebSocketClient::new(wsurl.as_str()).await.unwrap();
|
||||
let driver_handle = tokio::spawn(async move { driver.run().await });
|
||||
let mut subs = client.subscribe(Query::from(EventType::Tx)).await.unwrap();
|
||||
|
||||
while let Some(Ok(event)) = subs.next().await {
|
||||
for handler in ws_handlers {
|
||||
if let Err(e) = handler.handle(event.clone(), ws_config.clone()).await {
|
||||
eprintln!("Error in event handler: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close connection
|
||||
client.close()?;
|
||||
let _ = driver_handle.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CoreService<A> {
|
||||
config: Config,
|
||||
|
|
|
@ -12,9 +12,9 @@ authors.workspace = true
|
|||
path="src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
cosmrs.workspace = true
|
||||
hex.workspace = true
|
||||
reqwest.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
anyhow.workspace = true
|
|
@ -1,4 +1,4 @@
|
|||
use std::{num::ParseIntError, path::PathBuf, str::FromStr};
|
||||
use std::{num::ParseIntError, str::FromStr};
|
||||
|
||||
use clap::Parser;
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
|
@ -82,7 +82,6 @@ impl Default for Config {
|
|||
trusting_period: 1209600u64,
|
||||
max_clock_drift: 5u64,
|
||||
max_block_lag: 5u64,
|
||||
trace_file: None,
|
||||
verbose: Verbosity::default(),
|
||||
contract_address: "wasm14qdftsfk6fwn40l0xmruga08xlczl4g05npy70"
|
||||
.parse()
|
||||
|
@ -131,10 +130,6 @@ pub struct Config {
|
|||
#[clap(long, default_value = "5")]
|
||||
pub max_block_lag: u64,
|
||||
|
||||
/// Output file to store light client proof (AKA verification trace)
|
||||
#[clap(long)]
|
||||
pub trace_file: Option<PathBuf>,
|
||||
|
||||
/// Increase verbosity
|
||||
#[clap(flatten)]
|
||||
pub verbose: Verbosity,
|
||||
|
|
|
@ -19,5 +19,8 @@ async fn main() -> Result<()> {
|
|||
.finish()
|
||||
.init();
|
||||
|
||||
prove(args).await
|
||||
let proof = prove(args).await?;
|
||||
println!("{:?}", proof);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#![deny(
|
||||
warnings,
|
||||
// warnings,
|
||||
trivial_casts,
|
||||
trivial_numeric_casts,
|
||||
unused_import_braces,
|
||||
|
@ -7,12 +7,7 @@
|
|||
)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{BufWriter, Write},
|
||||
path::PathBuf,
|
||||
time::Duration,
|
||||
};
|
||||
use std::time::Duration;
|
||||
|
||||
use color_eyre::{
|
||||
eyre::{eyre, Result},
|
||||
|
@ -49,12 +44,11 @@ pub async fn prove(
|
|||
trusting_period,
|
||||
max_clock_drift,
|
||||
max_block_lag,
|
||||
trace_file,
|
||||
verbose: _,
|
||||
contract_address,
|
||||
storage_key,
|
||||
}: TmProverConfig,
|
||||
) -> Result<()> {
|
||||
) -> Result<ProofOutput> {
|
||||
let options = Options {
|
||||
trust_threshold,
|
||||
trusting_period: Duration::from_secs(trusting_period),
|
||||
|
@ -134,9 +128,8 @@ pub async fn prove(
|
|||
.verify(latest_app_hash.clone().into())
|
||||
.map_err(|e: ProofError| eyre!(e))?;
|
||||
|
||||
if let Some(trace_file) = trace_file {
|
||||
// replace the last block in the trace (i.e. the (latest - 1) block) with the latest block
|
||||
// we don't actually verify the latest block because it will be verified on the other side
|
||||
// Replace the last block in the trace (i.e., the (latest - 1) block) with the latest block
|
||||
// We don't actually verify the latest block because it will be verified on the other side
|
||||
let latest_block = provider.fetch_light_block(latest_height)?;
|
||||
let _ = primary_trace.pop();
|
||||
primary_trace.push(latest_block);
|
||||
|
@ -145,20 +138,8 @@ pub async fn prove(
|
|||
light_client_proof: primary_trace,
|
||||
merkle_proof: proof.into(),
|
||||
};
|
||||
write_proof_to_file(trace_file, output).await?;
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn write_proof_to_file(trace_file: PathBuf, output: ProofOutput) -> Result<()> {
|
||||
info!("Writing proof to output file ({})", trace_file.display());
|
||||
|
||||
let file = File::create(trace_file)?;
|
||||
let mut writer = BufWriter::new(file);
|
||||
serde_json::to_writer(&mut writer, &output)?;
|
||||
writer.flush()?;
|
||||
Ok(())
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
async fn run_detector(
|
||||
|
|
Loading…
Reference in a new issue