Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enclaves: light client check #69

Merged
merged 29 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
1534dd5
Extract light client verification code
hu55a1n1 Jul 1, 2024
81a6df9
cargo fmt
hu55a1n1 Jul 1, 2024
0c6181d
Implement light client check for mtcs.run
hu55a1n1 Jul 1, 2024
fadf927
Remove #![warn(missing_docs)] from enclaves
hu55a1n1 Jul 2, 2024
92490bc
Rename value -> proof_value
hu55a1n1 Jul 2, 2024
754dcf1
Impl light client check for transfers enclave
hu55a1n1 Jul 2, 2024
f1c5495
Clippy fix
hu55a1n1 Jul 2, 2024
5ea2ff1
Update Cargo.lock
hu55a1n1 Jul 2, 2024
b2125ea
Fix workspace
hu55a1n1 Jul 2, 2024
b0125ea
Clippy fix
hu55a1n1 Jul 2, 2024
de58478
Pin rust to v1.78
hu55a1n1 Jul 2, 2024
4fa1bc9
Rename .cargo/config to config.toml
hu55a1n1 Jul 2, 2024
e75475c
Update CI to pick pinned toolchain
hu55a1n1 Jul 2, 2024
84df58c
Add rust-toolchain file
hu55a1n1 Jul 2, 2024
52392c8
Use old-style rust-toolchain
hu55a1n1 Jul 2, 2024
210d4f0
Fix Cargo.toml exclusion for transfers contract
hu55a1n1 Jul 2, 2024
499d49b
Merge branch 'main' into hu55a1n1/22-mtcs-enclave-light-client-check
hu55a1n1 Jul 8, 2024
ebd04bb
Merge remote-tracking branch 'origin/main' into hu55a1n1/22-mtcs-encl…
hu55a1n1 Jul 15, 2024
62dd959
Revert CI modifications
hu55a1n1 Jul 15, 2024
bfb139e
Update CosmWasm dev-deps
hu55a1n1 Jul 15, 2024
77323b8
Merge remote-tracking branch 'origin/main' into hu55a1n1/22-mtcs-encl…
hu55a1n1 Jul 23, 2024
f40d7ae
Update listen.sh to include query
hu55a1n1 Jul 23, 2024
2fb0197
Fix bug in request msg creation
hu55a1n1 Jul 23, 2024
5861640
Add delay to wait for block
hu55a1n1 Jul 23, 2024
b8fbb11
Undo remove newline from workflow .ymls
hu55a1n1 Jul 23, 2024
6c42c64
Replace sleep with `wasmd status` based delay
hu55a1n1 Jul 23, 2024
268f675
Fix listen.sh bug for wasmd commmand
Jul 24, 2024
b3df408
Remove redundant TODOs
hu55a1n1 Jul 24, 2024
5963400
Merge branch 'hu55a1n1/22-mtcs-enclave-light-client-check' of github.…
hu55a1n1 Jul 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion apps/mtcs/enclave/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,17 @@ tendermint.workspace = true
tendermint-light-client.workspace = true

# quartz
cw-proof.workspace = true
cw-tee-mtcs.workspace = true
cycles-sync.workspace = true
mtcs.workspace = true
quartz-cw.workspace = true
quartz-proto.workspace = true
quartz-enclave.workspace = true
quartz-proto.workspace = true

[dev-dependencies]
cw-multi-test = "2.0.0"
serde_json = "1.0.113"

[build-dependencies]
tonic-build.workspace = true
5 changes: 2 additions & 3 deletions apps/mtcs/enclave/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
clippy::checked_conversions,
clippy::panic,
clippy::panic_in_result_fn,
missing_docs,
trivial_casts,
trivial_numeric_casts,
rust_2018_idioms,
Expand Down Expand Up @@ -65,11 +64,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {

Server::builder()
.add_service(CoreServer::new(CoreService::new(
config,
config.clone(),
sk.clone(),
attestor.clone(),
)))
.add_service(MtcsServer::new(MtcsService::new(sk, attestor)))
.add_service(MtcsServer::new(MtcsService::new(config, sk, attestor)))
.serve(args.rpc_addr)
.await?;

Expand Down
42 changes: 20 additions & 22 deletions apps/mtcs/enclave/src/mtcs_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use mtcs::{
algo::mcmf::primal_dual::PrimalDual, impls::complex_id::ComplexIdMtcs,
obligation::SimpleObligation, prelude::DefaultMtcs, setoff::SimpleSetoff, Mtcs,
};
use quartz_cw::msg::execute::attested::RawAttested;
use quartz_enclave::attestor::Attestor;
use quartz_cw::{msg::execute::attested::RawAttested, state::Config};
use quartz_enclave::{attestor::Attestor, server::ProofOfPublication};
use serde::{Deserialize, Serialize};
use tonic::{Request, Response, Result as TonicResult, Status};

Expand All @@ -28,6 +28,7 @@ pub type RawCipherText = HexBinary;

#[derive(Clone, Debug)]
pub struct MtcsService<A> {
config: Config,
sk: Arc<Mutex<Option<SigningKey>>>,
attestor: A,
}
Expand All @@ -42,8 +43,12 @@ impl<A> MtcsService<A>
where
A: Attestor,
{
pub fn new(sk: Arc<Mutex<Option<SigningKey>>>, attestor: A) -> Self {
Self { sk, attestor }
pub fn new(config: Config, sk: Arc<Mutex<Option<SigningKey>>>, attestor: A) -> Self {
Self {
config,
sk,
attestor,
}
}
}

Expand All @@ -56,28 +61,21 @@ where
&self,
request: Request<RunClearingRequest>,
) -> TonicResult<Response<RunClearingResponse>> {
// Pass in JSON of Requests vector and the STATE

// Serialize into Requests enum
// Loop through, decrypt the ciphertexts

// Read the state blob from chain

// Decrypt and deserialize

// Loop through requests and apply onto state

// Encrypt state

// Create withdraw requests

// Send to chain

let message: RunClearingMessage = {
let message: ProofOfPublication<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_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 digests_ciphertexts = message.intents;
let (digests, ciphertexts): (Vec<_>, Vec<_>) = digests_ciphertexts.into_iter().unzip();

Expand Down
3 changes: 1 addition & 2 deletions apps/transfers/enclave/bin/encrypt.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::collections::BTreeMap;

use anyhow;
use cosmwasm_std::{Addr, HexBinary, Uint128};
use ecies::encrypt;
use k256::ecdsa::VerifyingKey;
Expand Down Expand Up @@ -42,7 +41,7 @@ fn main() {
let msg = ClearTextTransferRequestMsg {
sender: Addr::unchecked("alice"),
receiver: Addr::unchecked("bob"),
amount: Uint128::from(100 as u32),
amount: Uint128::from(100_u32),
};

let decoded: Vec<u8> =
Expand Down
6 changes: 4 additions & 2 deletions apps/transfers/enclave/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {

Server::builder()
.add_service(CoreServer::new(CoreService::new(
config,
config.clone(),
sk.clone(),
attestor.clone(),
)))
.add_service(TransfersServer::new(TransfersService::new(sk, attestor)))
.add_service(TransfersServer::new(TransfersService::new(
config, sk, attestor,
)))
.serve(args.rpc_addr)
.await?;

Expand Down
27 changes: 20 additions & 7 deletions apps/transfers/enclave/src/transfers_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use ecies::{decrypt, encrypt};
use k256::ecdsa::{SigningKey, VerifyingKey};
use quartz_cw::{
msg::execute::attested::{HasUserData, RawAttested},
state::UserData,
state::{Config, UserData},
};
use quartz_enclave::attestor::Attestor;
use quartz_enclave::{attestor::Attestor, server::ProofOfPublication};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use tonic::{Request, Response, Result as TonicResult, Status};
Expand All @@ -27,6 +27,7 @@ pub type RawCipherText = HexBinary;

#[derive(Clone, Debug)]
pub struct TransfersService<A> {
config: Config,
sk: Arc<Mutex<Option<SigningKey>>>,
attestor: A,
}
Expand Down Expand Up @@ -91,8 +92,12 @@ impl<A> TransfersService<A>
where
A: Attestor,
{
pub fn new(sk: Arc<Mutex<Option<SigningKey>>>, attestor: A) -> Self {
Self { sk, attestor }
pub fn new(config: Config, sk: Arc<Mutex<Option<SigningKey>>>, attestor: A) -> Self {
Self {
config,
sk,
attestor,
}
}
}

Expand All @@ -102,14 +107,22 @@ where
A: Attestor + Send + Sync + 'static,
{
async fn run(&self, request: Request<UpdateRequest>) -> TonicResult<Response<UpdateResponse>> {
// Request contains a serialized json string

// Serialize request into struct containing State and the Requests vec
let message: UpdateRequestMessage = {
let message: ProofOfPublication<UpdateRequestMessage> = {
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_matches_msg =
serde_json::to_string(&message.requests).is_ok_and(|s| s.as_bytes() == proof_value);
if !proof_value_matches_msg {
return Err(Status::failed_precondition("proof verification"));
}

// Decrypt and deserialize the state
let mut state = {
if message.state.len() == 1 && message.state[0] == 0 {
Expand Down
42 changes: 40 additions & 2 deletions apps/transfers/scripts/listen.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,57 @@ REPORT_SIG_FILE="/tmp/${USER}_datareportsig"
if echo "$CLEAN_MSG" | grep -q 'wasm-transfer'; then
echo "---------------------------------------------------------"
echo "... received wasm-transfer event!"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block seems important. Without it, it seems as though the latest request (i.e. the one that triggered this event) is not cleared/processed. I think this has to do with the way wasmd deals with events, i.e. events are sent out before the store is committed so at this point, the latest request is not written to the store and so the query below gives us old state.

I do remember this issue being discussed before but we probably lost it or did something to fix it.

Copy link
Member Author

@hu55a1n1 hu55a1n1 Jul 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related: /issues/65

current_height=$($CMD status | jq -r .SyncInfo.latest_block_height)
next_height=$((current_height + 1))

while [ "$($CMD status 2>&1 | jq -r .SyncInfo.latest_block_height)" -lt "$next_height" ]; do
echo "waiting for next block"
sleep 1
done

echo "... fetching requests"
REQUESTS=$($CMD query wasm contract-state raw $CONTRACT $(printf '%s' "requests" | \
hexdump -ve '/1 "%02X"') -o json | jq -r .data | base64 -d)
STATE=$($CMD query wasm contract-state raw $CONTRACT $(printf '%s' "state" | \
hexdump -ve '/1 "%02X"') -o json | jq -r .data | base64 -d)

cd "$ROOT/cycles-quartz/apps/transfers"
export TRUSTED_HASH=$(cat trusted.hash)
export TRUSTED_HEIGHT=$(cat trusted.height)

cd $ROOT/cycles-quartz/utils/tm-prover
export PROOF_FILE="light-client-proof.json"
if [ -f "$PROOF_FILE" ]; then
rm "$PROOF_FILE"
echo "removed old $PROOF_FILE"
fi

echo "trusted hash $TRUSTED_HASH"
echo "trusted hash $TRUSTED_HEIGHT"
echo "contract $CONTRACT"

# run prover to get light client proof
cargo run -- --chain-id testing \
--primary "http://$NODE_URL" \
--witnesses "http://$NODE_URL" \
--trusted-height $TRUSTED_HEIGHT \
--trusted-hash $TRUSTED_HASH \
--contract-address $CONTRACT \
--storage-key "requests" \
--trace-file $PROOF_FILE

export POP=$(cat $PROOF_FILE)

export ENCLAVE_REQUEST=$(jq -nc --argjson requests "$REQUESTS" --argjson state $STATE '$ARGS.named')
export REQUEST_MSG=$(jq -nc --arg message "$ENCLAVE_REQUEST" '$ARGS.named')
export REQUEST_MSG=$(jq --argjson msg "$ENCLAVE_REQUEST" '. + {msg: $msg}' <<< "$POP")
export PROTO_MSG=$(jq -nc --arg message "$REQUEST_MSG" '$ARGS.named')

cd $ROOT/cycles-quartz/apps/transfers/enclave

echo "... executing transfer"
export ATTESTED_MSG=$(grpcurl -plaintext -import-path ./proto/ -proto transfers.proto \
-d "$REQUEST_MSG" "127.0.0.1:$QUARTZ_PORT" transfers.Settlement/Run | \
-d "$PROTO_MSG" "127.0.0.1:$QUARTZ_PORT" transfers.Settlement/Run | \
jq .message | jq -R 'fromjson | fromjson' | jq -c)
QUOTE=$(echo "$ATTESTED_MSG" | jq -c '.attestation')
MSG=$(echo "$ATTESTED_MSG" | jq -c '.msg')
Expand Down
Loading
Loading