Skip to content

Commit 1e80233

Browse files
committed
Upgrade ping-pong example to new API
1 parent 93a982f commit 1e80233

File tree

11 files changed

+325
-541
lines changed

11 files changed

+325
-541
lines changed

examples/pingpong/contracts/Cargo.lock

+1-22
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/pingpong/enclave/Cargo.lock

+5-16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/pingpong/enclave/src/bin/send_message.rs

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use cosmrs::{tendermint::chain::Id as ChainId, AccountId};
44
use cosmwasm_std::HexBinary;
55
use cw_client::{CliClient, CwClient};
66
use ecies::encrypt;
7-
use hex;
87
use k256::ecdsa::VerifyingKey;
98
use ping_pong_contract::msg::{execute::Ping, ExecuteMsg};
109
use reqwest::Url;

examples/pingpong/enclave/src/cli.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use color_eyre::eyre::{eyre, Result};
55
use cosmrs::AccountId;
66
use quartz_common::enclave::types::Fmspc;
77
use reqwest::Url;
8-
use tendermint::Hash;
8+
use tendermint::{chain::Id, Hash};
99
use tendermint_light_client::types::{Height, TrustThreshold};
1010

1111
fn parse_trust_threshold(s: &str) -> Result<TrustThreshold> {
@@ -27,7 +27,7 @@ pub struct Cli {
2727

2828
/// Identifier of the chain
2929
#[clap(long)]
30-
pub chain_id: String,
30+
pub chain_id: Id,
3131

3232
/// FMSPC (Family-Model-Stepping-Platform-Custom SKU)
3333
#[clap(long)]
+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
use anyhow::{anyhow, Error as AnyhowError};
2+
use cosmrs::AccountId;
3+
use ping_pong_contract::{msg::execute::Ping, state::PINGS_KEY};
4+
use quartz_common::enclave::{
5+
chain_client::{default::Query, ChainClient},
6+
handler::Handler,
7+
};
8+
use serde_json::json;
9+
use tendermint_rpc::event::Event as TmEvent;
10+
use tracing::info;
11+
12+
use crate::{proto::PingRequest, request::EnclaveRequest};
13+
14+
#[derive(Clone, Debug)]
15+
pub enum EnclaveEvent {
16+
Ping(PingEvent),
17+
}
18+
19+
impl TryFrom<TmEvent> for EnclaveEvent {
20+
type Error = AnyhowError;
21+
22+
fn try_from(value: TmEvent) -> Result<Self, Self::Error> {
23+
if let Ok(event) = PingEvent::try_from(value.clone()) {
24+
Ok(Self::Ping(event))
25+
} else {
26+
Err(anyhow::anyhow!("unsupported event"))
27+
}
28+
}
29+
}
30+
31+
#[async_trait::async_trait]
32+
impl<C> Handler<C> for EnclaveEvent
33+
where
34+
C: ChainClient<Contract = AccountId, Query = Query>,
35+
{
36+
type Error = AnyhowError;
37+
type Response = EnclaveRequest;
38+
39+
async fn handle(self, ctx: &C) -> Result<Self::Response, Self::Error> {
40+
match self {
41+
EnclaveEvent::Ping(event) => event.handle(ctx).await.map(EnclaveRequest::Ping),
42+
}
43+
}
44+
}
45+
46+
#[derive(Clone, Debug)]
47+
pub struct PingEvent {
48+
pub contract: AccountId,
49+
pub ping: Ping,
50+
}
51+
52+
impl TryFrom<TmEvent> for PingEvent {
53+
type Error = AnyhowError;
54+
55+
fn try_from(event: TmEvent) -> Result<Self, Self::Error> {
56+
let Some(events) = &event.events else {
57+
return Err(anyhow!("no events in tx"));
58+
};
59+
60+
if !events.keys().any(|k| k.starts_with("wasm.action")) {
61+
return Err(anyhow!("irrelevant event"));
62+
};
63+
64+
let contract = events
65+
.get("execute._contract_address")
66+
.ok_or_else(|| anyhow!("missing execute._contract_address in events"))?
67+
.first()
68+
.ok_or_else(|| anyhow!("execute._contract_address is empty"))?
69+
.parse::<AccountId>()
70+
.map_err(|e| anyhow!("failed to parse contract address: {}", e))?;
71+
72+
let ping: Ping = {
73+
let ping_str = events
74+
.get("wasm.ping_data")
75+
.and_then(|v| v.first())
76+
.ok_or_else(|| anyhow!("Missing ping data in event"))?;
77+
serde_json::from_str(ping_str)?
78+
};
79+
80+
Ok(Self { contract, ping })
81+
}
82+
}
83+
84+
#[async_trait::async_trait]
85+
impl<C> Handler<C> for PingEvent
86+
where
87+
C: ChainClient<Contract = AccountId, Query = Query>,
88+
{
89+
type Error = AnyhowError;
90+
type Response = PingRequest;
91+
92+
async fn handle(self, ctx: &C) -> Result<Self::Response, Self::Error> {
93+
let contract = self.contract;
94+
95+
// Wait 2 blocks
96+
info!("Waiting 2 blocks for light client proof");
97+
ctx.wait_for_blocks(2)
98+
.await
99+
.map_err(|e| anyhow!("Problem waiting for proof: {}", e))?;
100+
101+
// Call tm prover with trusted hash and height
102+
let proof = ctx
103+
.existence_proof(&contract, PINGS_KEY)
104+
.await
105+
.map_err(|e| anyhow!("Problem getting existence proof: {}", e))?;
106+
107+
// Merge the UpdateRequestMessage with the proof
108+
let mut proof_json = serde_json::to_value(proof)?;
109+
proof_json["msg"] = serde_json::to_value(&self.ping)?;
110+
111+
// Build final request object
112+
let request = PingRequest {
113+
message: json!(proof_json).to_string(),
114+
};
115+
116+
Ok(request)
117+
}
118+
}

examples/pingpong/enclave/src/grpc.rs

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
use quartz_common::enclave::{handler::Handler, DefaultSharedEnclave};
2+
use tonic::{Request, Response, Status};
3+
4+
use crate::proto::{ping_pong_server::PingPong, PingRequest, PongResponse};
5+
6+
#[tonic::async_trait]
7+
impl PingPong for DefaultSharedEnclave<()> {
8+
async fn run(&self, request: Request<PingRequest>) -> Result<Response<PongResponse>, Status> {
9+
let response = request.handle(self).await?;
10+
Ok(response.map(|r| PongResponse {
11+
message: serde_json::to_string(&r).unwrap(),
12+
}))
13+
}
14+
}

0 commit comments

Comments
 (0)