enclaves: light client check (#69)
Co-authored-by: dave <davidkajpust@informal.systems>
This commit is contained in:
parent
e1b13a0e06
commit
2a4e7f5ec5
9 changed files with 186 additions and 97 deletions
31
Cargo.lock
generated
31
Cargo.lock
generated
|
@ -864,6 +864,26 @@ dependencies = [
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cw-multi-test"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e0034bfb4c06dfc8b50f0b1a06c3fc0f2312a1bae568a97db65930de071288ba"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"bech32",
|
||||||
|
"cosmwasm-std",
|
||||||
|
"cw-storage-plus",
|
||||||
|
"cw-utils",
|
||||||
|
"derivative",
|
||||||
|
"itertools 0.13.0",
|
||||||
|
"prost",
|
||||||
|
"schemars",
|
||||||
|
"serde",
|
||||||
|
"sha2 0.10.8",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cw-proof"
|
name = "cw-proof"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -1839,6 +1859,15 @@ dependencies = [
|
||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.11"
|
version = "1.0.11"
|
||||||
|
@ -2563,6 +2592,8 @@ dependencies = [
|
||||||
"color-eyre",
|
"color-eyre",
|
||||||
"cosmrs",
|
"cosmrs",
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
|
"cw-multi-test",
|
||||||
|
"cw-proof",
|
||||||
"cw-tee-mtcs",
|
"cw-tee-mtcs",
|
||||||
"cycles-sync",
|
"cycles-sync",
|
||||||
"ecies",
|
"ecies",
|
||||||
|
|
|
@ -28,12 +28,17 @@ tendermint.workspace = true
|
||||||
tendermint-light-client.workspace = true
|
tendermint-light-client.workspace = true
|
||||||
|
|
||||||
# quartz
|
# quartz
|
||||||
|
cw-proof.workspace = true
|
||||||
cw-tee-mtcs.workspace = true
|
cw-tee-mtcs.workspace = true
|
||||||
cycles-sync.workspace = true
|
cycles-sync.workspace = true
|
||||||
mtcs.workspace = true
|
mtcs.workspace = true
|
||||||
quartz-cw.workspace = true
|
quartz-cw.workspace = true
|
||||||
quartz-proto.workspace = true
|
|
||||||
quartz-enclave.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]
|
[build-dependencies]
|
||||||
tonic-build.workspace = true
|
tonic-build.workspace = true
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
clippy::checked_conversions,
|
clippy::checked_conversions,
|
||||||
clippy::panic,
|
clippy::panic,
|
||||||
clippy::panic_in_result_fn,
|
clippy::panic_in_result_fn,
|
||||||
missing_docs,
|
|
||||||
trivial_casts,
|
trivial_casts,
|
||||||
trivial_numeric_casts,
|
trivial_numeric_casts,
|
||||||
rust_2018_idioms,
|
rust_2018_idioms,
|
||||||
|
@ -65,11 +64,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
|
||||||
Server::builder()
|
Server::builder()
|
||||||
.add_service(CoreServer::new(CoreService::new(
|
.add_service(CoreServer::new(CoreService::new(
|
||||||
config,
|
config.clone(),
|
||||||
sk.clone(),
|
sk.clone(),
|
||||||
attestor.clone(),
|
attestor.clone(),
|
||||||
)))
|
)))
|
||||||
.add_service(MtcsServer::new(MtcsService::new(sk, attestor)))
|
.add_service(MtcsServer::new(MtcsService::new(config, sk, attestor)))
|
||||||
.serve(args.rpc_addr)
|
.serve(args.rpc_addr)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,8 @@ use mtcs::{
|
||||||
algo::mcmf::primal_dual::PrimalDual, impls::complex_id::ComplexIdMtcs,
|
algo::mcmf::primal_dual::PrimalDual, impls::complex_id::ComplexIdMtcs,
|
||||||
obligation::SimpleObligation, prelude::DefaultMtcs, setoff::SimpleSetoff, Mtcs,
|
obligation::SimpleObligation, prelude::DefaultMtcs, setoff::SimpleSetoff, Mtcs,
|
||||||
};
|
};
|
||||||
use quartz_cw::msg::execute::attested::RawAttested;
|
use quartz_cw::{msg::execute::attested::RawAttested, state::Config};
|
||||||
use quartz_enclave::attestor::Attestor;
|
use quartz_enclave::{attestor::Attestor, server::ProofOfPublication};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tonic::{Request, Response, Result as TonicResult, Status};
|
use tonic::{Request, Response, Result as TonicResult, Status};
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ pub type RawCipherText = HexBinary;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct MtcsService<A> {
|
pub struct MtcsService<A> {
|
||||||
|
config: Config,
|
||||||
sk: Arc<Mutex<Option<SigningKey>>>,
|
sk: Arc<Mutex<Option<SigningKey>>>,
|
||||||
attestor: A,
|
attestor: A,
|
||||||
}
|
}
|
||||||
|
@ -42,8 +43,12 @@ impl<A> MtcsService<A>
|
||||||
where
|
where
|
||||||
A: Attestor,
|
A: Attestor,
|
||||||
{
|
{
|
||||||
pub fn new(sk: Arc<Mutex<Option<SigningKey>>>, attestor: A) -> Self {
|
pub fn new(config: Config, sk: Arc<Mutex<Option<SigningKey>>>, attestor: A) -> Self {
|
||||||
Self { sk, attestor }
|
Self {
|
||||||
|
config,
|
||||||
|
sk,
|
||||||
|
attestor,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,28 +61,21 @@ where
|
||||||
&self,
|
&self,
|
||||||
request: Request<RunClearingRequest>,
|
request: Request<RunClearingRequest>,
|
||||||
) -> TonicResult<Response<RunClearingResponse>> {
|
) -> TonicResult<Response<RunClearingResponse>> {
|
||||||
// Pass in JSON of Requests vector and the STATE
|
let message: ProofOfPublication<RunClearingMessage> = {
|
||||||
|
|
||||||
// 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 = request.into_inner().message;
|
let message = request.into_inner().message;
|
||||||
serde_json::from_str(&message).map_err(|e| Status::invalid_argument(e.to_string()))?
|
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 = message.intents;
|
||||||
let (digests, ciphertexts): (Vec<_>, Vec<_>) = digests_ciphertexts.into_iter().unzip();
|
let (digests, ciphertexts): (Vec<_>, Vec<_>) = digests_ciphertexts.into_iter().unzip();
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use anyhow;
|
|
||||||
use cosmwasm_std::{Addr, HexBinary, Uint128};
|
use cosmwasm_std::{Addr, HexBinary, Uint128};
|
||||||
use ecies::encrypt;
|
use ecies::encrypt;
|
||||||
use k256::ecdsa::VerifyingKey;
|
use k256::ecdsa::VerifyingKey;
|
||||||
|
@ -42,7 +41,7 @@ fn main() {
|
||||||
let msg = ClearTextTransferRequestMsg {
|
let msg = ClearTextTransferRequestMsg {
|
||||||
sender: Addr::unchecked("alice"),
|
sender: Addr::unchecked("alice"),
|
||||||
receiver: Addr::unchecked("bob"),
|
receiver: Addr::unchecked("bob"),
|
||||||
amount: Uint128::from(100 as u32),
|
amount: Uint128::from(100_u32),
|
||||||
};
|
};
|
||||||
|
|
||||||
let decoded: Vec<u8> =
|
let decoded: Vec<u8> =
|
||||||
|
|
|
@ -65,11 +65,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
|
||||||
Server::builder()
|
Server::builder()
|
||||||
.add_service(CoreServer::new(CoreService::new(
|
.add_service(CoreServer::new(CoreService::new(
|
||||||
config,
|
config.clone(),
|
||||||
sk.clone(),
|
sk.clone(),
|
||||||
attestor.clone(),
|
attestor.clone(),
|
||||||
)))
|
)))
|
||||||
.add_service(TransfersServer::new(TransfersService::new(sk, attestor)))
|
.add_service(TransfersServer::new(TransfersService::new(
|
||||||
|
config, sk, attestor,
|
||||||
|
)))
|
||||||
.serve(args.rpc_addr)
|
.serve(args.rpc_addr)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,9 @@ use ecies::{decrypt, encrypt};
|
||||||
use k256::ecdsa::{SigningKey, VerifyingKey};
|
use k256::ecdsa::{SigningKey, VerifyingKey};
|
||||||
use quartz_cw::{
|
use quartz_cw::{
|
||||||
msg::execute::attested::{HasUserData, RawAttested},
|
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 serde::{Deserialize, Serialize};
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
use tonic::{Request, Response, Result as TonicResult, Status};
|
use tonic::{Request, Response, Result as TonicResult, Status};
|
||||||
|
@ -27,6 +27,7 @@ pub type RawCipherText = HexBinary;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct TransfersService<A> {
|
pub struct TransfersService<A> {
|
||||||
|
config: Config,
|
||||||
sk: Arc<Mutex<Option<SigningKey>>>,
|
sk: Arc<Mutex<Option<SigningKey>>>,
|
||||||
attestor: A,
|
attestor: A,
|
||||||
}
|
}
|
||||||
|
@ -91,8 +92,12 @@ impl<A> TransfersService<A>
|
||||||
where
|
where
|
||||||
A: Attestor,
|
A: Attestor,
|
||||||
{
|
{
|
||||||
pub fn new(sk: Arc<Mutex<Option<SigningKey>>>, attestor: A) -> Self {
|
pub fn new(config: Config, sk: Arc<Mutex<Option<SigningKey>>>, attestor: A) -> Self {
|
||||||
Self { sk, attestor }
|
Self {
|
||||||
|
config,
|
||||||
|
sk,
|
||||||
|
attestor,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,14 +107,22 @@ where
|
||||||
A: Attestor + Send + Sync + 'static,
|
A: Attestor + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
async fn run(&self, request: Request<UpdateRequest>) -> TonicResult<Response<UpdateResponse>> {
|
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
|
// Serialize request into struct containing State and the Requests vec
|
||||||
let message: UpdateRequestMessage = {
|
let message: ProofOfPublication<UpdateRequestMessage> = {
|
||||||
let message = request.into_inner().message;
|
let message = request.into_inner().message;
|
||||||
serde_json::from_str(&message).map_err(|e| Status::invalid_argument(e.to_string()))?
|
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
|
// Decrypt and deserialize the state
|
||||||
let mut state = {
|
let mut state = {
|
||||||
if message.state.len() == 1 && message.state[0] == 0 {
|
if message.state.len() == 1 && message.state[0] == 0 {
|
||||||
|
|
|
@ -39,19 +39,57 @@ REPORT_SIG_FILE="/tmp/${USER}_datareportsig"
|
||||||
if echo "$CLEAN_MSG" | grep -q 'wasm-transfer'; then
|
if echo "$CLEAN_MSG" | grep -q 'wasm-transfer'; then
|
||||||
echo "---------------------------------------------------------"
|
echo "---------------------------------------------------------"
|
||||||
echo "... received wasm-transfer event!"
|
echo "... received wasm-transfer event!"
|
||||||
|
|
||||||
|
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"
|
echo "... fetching requests"
|
||||||
REQUESTS=$($CMD query wasm contract-state raw $CONTRACT $(printf '%s' "requests" | \
|
REQUESTS=$($CMD query wasm contract-state raw $CONTRACT $(printf '%s' "requests" | \
|
||||||
hexdump -ve '/1 "%02X"') -o json | jq -r .data | base64 -d)
|
hexdump -ve '/1 "%02X"') -o json | jq -r .data | base64 -d)
|
||||||
STATE=$($CMD query wasm contract-state raw $CONTRACT $(printf '%s' "state" | \
|
STATE=$($CMD query wasm contract-state raw $CONTRACT $(printf '%s' "state" | \
|
||||||
hexdump -ve '/1 "%02X"') -o json | jq -r .data | base64 -d)
|
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 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
|
cd $ROOT/cycles-quartz/apps/transfers/enclave
|
||||||
|
|
||||||
echo "... executing transfer"
|
echo "... executing transfer"
|
||||||
export ATTESTED_MSG=$(grpcurl -plaintext -import-path ./proto/ -proto transfers.proto \
|
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)
|
jq .message | jq -R 'fromjson | fromjson' | jq -c)
|
||||||
QUOTE=$(echo "$ATTESTED_MSG" | jq -c '.attestation')
|
QUOTE=$(echo "$ATTESTED_MSG" | jq -c '.attestation')
|
||||||
MSG=$(echo "$ATTESTED_MSG" | jq -c '.msg')
|
MSG=$(echo "$ATTESTED_MSG" | jq -c '.msg')
|
||||||
|
|
|
@ -3,12 +3,9 @@ use std::{
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
use cw_proof::{
|
use cw_proof::proof::{
|
||||||
error::ProofError,
|
cw::{CwProof, RawCwProof},
|
||||||
proof::{
|
Proof,
|
||||||
cw::{CwProof, RawCwProof},
|
|
||||||
Proof,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use k256::ecdsa::SigningKey;
|
use k256::ecdsa::SigningKey;
|
||||||
use quartz_cw::{
|
use quartz_cw::{
|
||||||
|
@ -16,7 +13,7 @@ use quartz_cw::{
|
||||||
execute::{session_create::SessionCreate, session_set_pub_key::SessionSetPubKey},
|
execute::{session_create::SessionCreate, session_set_pub_key::SessionSetPubKey},
|
||||||
instantiate::CoreInstantiate,
|
instantiate::CoreInstantiate,
|
||||||
},
|
},
|
||||||
state::{Config, Nonce, Session},
|
state::{Config, LightClientOpts, Nonce, Session},
|
||||||
};
|
};
|
||||||
use quartz_proto::quartz::{
|
use quartz_proto::quartz::{
|
||||||
core_server::Core, InstantiateRequest as RawInstantiateRequest,
|
core_server::Core, InstantiateRequest as RawInstantiateRequest,
|
||||||
|
@ -102,58 +99,15 @@ where
|
||||||
request: Request<RawSessionSetPubKeyRequest>,
|
request: Request<RawSessionSetPubKeyRequest>,
|
||||||
) -> TonicResult<Response<RawSessionSetPubKeyResponse>> {
|
) -> TonicResult<Response<RawSessionSetPubKeyResponse>> {
|
||||||
// FIXME(hu55a1n1) - disallow calling more than once
|
// FIXME(hu55a1n1) - disallow calling more than once
|
||||||
let proof: ProofOfPublication = serde_json::from_str(&request.into_inner().message)
|
let proof: ProofOfPublication<Option<()>> =
|
||||||
.map_err(|e| Status::invalid_argument(e.to_string()))?;
|
serde_json::from_str(&request.into_inner().message)
|
||||||
|
.map_err(|e| Status::invalid_argument(e.to_string()))?;
|
||||||
|
|
||||||
let config_trust_threshold = self.config.light_client_opts().trust_threshold();
|
let (value, _msg) = proof
|
||||||
let trust_threshold =
|
.verify(self.config.light_client_opts())
|
||||||
TrustThreshold::new(config_trust_threshold.0, config_trust_threshold.1).unwrap();
|
.map_err(Status::failed_precondition)?;
|
||||||
|
|
||||||
let config_trusting_period = self.config.light_client_opts().trusting_period();
|
let session: Session = serde_json::from_slice(&value).unwrap();
|
||||||
let trusting_period = Duration::from_secs(config_trusting_period);
|
|
||||||
|
|
||||||
let config_clock_drift = self.config.light_client_opts().max_clock_drift();
|
|
||||||
let clock_drift = Duration::from_secs(config_clock_drift);
|
|
||||||
let options = Options {
|
|
||||||
trust_threshold,
|
|
||||||
trusting_period,
|
|
||||||
clock_drift,
|
|
||||||
};
|
|
||||||
|
|
||||||
let target_height = proof.light_client_proof.last().unwrap().height();
|
|
||||||
|
|
||||||
let primary_block = make_provider(
|
|
||||||
self.config.light_client_opts().chain_id(),
|
|
||||||
self.config
|
|
||||||
.light_client_opts()
|
|
||||||
.trusted_height()
|
|
||||||
.try_into()
|
|
||||||
.unwrap(),
|
|
||||||
self.config
|
|
||||||
.light_client_opts()
|
|
||||||
.trusted_hash()
|
|
||||||
.to_vec()
|
|
||||||
.try_into()
|
|
||||||
.unwrap(),
|
|
||||||
proof.light_client_proof,
|
|
||||||
options,
|
|
||||||
)
|
|
||||||
.and_then(|mut primary| primary.verify_to_height(target_height))
|
|
||||||
.map_err(|e| Status::internal(e.to_string()))?;
|
|
||||||
|
|
||||||
let proof = CwProof::from(proof.merkle_proof);
|
|
||||||
proof
|
|
||||||
.verify(
|
|
||||||
primary_block
|
|
||||||
.signed_header
|
|
||||||
.header
|
|
||||||
.app_hash
|
|
||||||
.as_bytes()
|
|
||||||
.to_vec(),
|
|
||||||
)
|
|
||||||
.map_err(|e: ProofError| Status::internal(e.to_string()))?;
|
|
||||||
|
|
||||||
let session: Session = serde_json::from_slice(&proof.value).unwrap();
|
|
||||||
let nonce = self.nonce.lock().unwrap();
|
let nonce = self.nonce.lock().unwrap();
|
||||||
|
|
||||||
if session.nonce() != *nonce {
|
if session.nonce() != *nonce {
|
||||||
|
@ -177,7 +131,57 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct ProofOfPublication {
|
pub struct ProofOfPublication<M> {
|
||||||
light_client_proof: Vec<LightBlock>,
|
light_client_proof: Vec<LightBlock>,
|
||||||
merkle_proof: RawCwProof,
|
merkle_proof: RawCwProof,
|
||||||
|
msg: M,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M> ProofOfPublication<M> {
|
||||||
|
pub fn verify(self, light_client_opts: &LightClientOpts) -> Result<(Vec<u8>, M), String> {
|
||||||
|
let config_trust_threshold = light_client_opts.trust_threshold();
|
||||||
|
let trust_threshold =
|
||||||
|
TrustThreshold::new(config_trust_threshold.0, config_trust_threshold.1).unwrap();
|
||||||
|
|
||||||
|
let config_trusting_period = light_client_opts.trusting_period();
|
||||||
|
let trusting_period = Duration::from_secs(config_trusting_period);
|
||||||
|
|
||||||
|
let config_clock_drift = light_client_opts.max_clock_drift();
|
||||||
|
let clock_drift = Duration::from_secs(config_clock_drift);
|
||||||
|
let options = Options {
|
||||||
|
trust_threshold,
|
||||||
|
trusting_period,
|
||||||
|
clock_drift,
|
||||||
|
};
|
||||||
|
|
||||||
|
let target_height = self.light_client_proof.last().unwrap().height();
|
||||||
|
|
||||||
|
let primary_block = make_provider(
|
||||||
|
light_client_opts.chain_id(),
|
||||||
|
light_client_opts.trusted_height().try_into().unwrap(),
|
||||||
|
light_client_opts
|
||||||
|
.trusted_hash()
|
||||||
|
.to_vec()
|
||||||
|
.try_into()
|
||||||
|
.unwrap(),
|
||||||
|
self.light_client_proof,
|
||||||
|
options,
|
||||||
|
)
|
||||||
|
.and_then(|mut primary| primary.verify_to_height(target_height))
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
let proof = CwProof::from(self.merkle_proof);
|
||||||
|
proof
|
||||||
|
.verify(
|
||||||
|
primary_block
|
||||||
|
.signed_header
|
||||||
|
.header
|
||||||
|
.app_hash
|
||||||
|
.as_bytes()
|
||||||
|
.to_vec(),
|
||||||
|
)
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
Ok((proof.value, self.msg))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue