Adapt cw-tee-mtcs to use quartz (#12)
This commit is contained in:
parent
b4e5f01cd1
commit
57b2a050ff
16 changed files with 507 additions and 264 deletions
|
@ -54,5 +54,8 @@ schemars = "0.8.15"
|
|||
serde = { version = "1.0.189", default-features = false, features = ["derive"] }
|
||||
thiserror = { version = "1.0.49" }
|
||||
|
||||
quartz-cw = { path = "../../packages/quartz-cw" }
|
||||
|
||||
[dev-dependencies]
|
||||
cw-multi-test = "0.17.0"
|
||||
serde_json = "1.0.113"
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
use cosmwasm_std::{
|
||||
entry_point, to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult,
|
||||
};
|
||||
use cosmwasm_std::{entry_point, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult};
|
||||
use cw2::set_contract_version;
|
||||
use quartz_cw::handler::RawHandler;
|
||||
|
||||
use crate::error::ContractError;
|
||||
use crate::msg::execute::{BootstrapKeyManagerMsg, JoinComputeNodeMsg, RegisterEpochKeyMsg};
|
||||
use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
|
||||
use crate::state::{State, STATE};
|
||||
use crate::msg::execute::{SubmitObligationMsg, SubmitSetoffsMsg};
|
||||
use crate::msg::QueryMsg;
|
||||
use crate::msg::{ExecuteMsg, InstantiateMsg};
|
||||
use crate::state::{current_epoch_key, ObligationsItem, State, OBLIGATIONS_KEY, STATE};
|
||||
|
||||
// version info for migration info
|
||||
const CONTRACT_NAME: &str = "crates.io:cw-tee-mtcs";
|
||||
|
@ -14,17 +14,23 @@ const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
|
|||
|
||||
#[cfg_attr(not(feature = "library"), entry_point)]
|
||||
pub fn instantiate(
|
||||
deps: DepsMut,
|
||||
_env: Env,
|
||||
mut deps: DepsMut,
|
||||
env: Env,
|
||||
info: MessageInfo,
|
||||
_msg: InstantiateMsg,
|
||||
msg: InstantiateMsg,
|
||||
) -> Result<Response, ContractError> {
|
||||
// must be the handled first!
|
||||
msg.0.handle_raw(deps.branch(), &env, &info)?;
|
||||
|
||||
let state = State {
|
||||
owner: info.sender.to_string(),
|
||||
};
|
||||
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
|
||||
STATE.save(deps.storage, &state)?;
|
||||
|
||||
ObligationsItem::new(¤t_epoch_key(OBLIGATIONS_KEY, deps.storage)?)
|
||||
.save(deps.storage, &Default::default())?;
|
||||
|
||||
Ok(Response::new()
|
||||
.add_attribute("method", "instantiate")
|
||||
.add_attribute("owner", info.sender))
|
||||
|
@ -33,151 +39,70 @@ pub fn instantiate(
|
|||
#[cfg_attr(not(feature = "library"), entry_point)]
|
||||
pub fn execute(
|
||||
deps: DepsMut,
|
||||
_env: Env,
|
||||
_info: MessageInfo,
|
||||
env: Env,
|
||||
info: MessageInfo,
|
||||
msg: ExecuteMsg,
|
||||
) -> Result<Response, ContractError> {
|
||||
match msg {
|
||||
ExecuteMsg::BootstrapKeyManager(BootstrapKeyManagerMsg {
|
||||
compute_mrenclave,
|
||||
key_manager_mrenclave,
|
||||
tcb_info,
|
||||
}) => {
|
||||
execute::bootstrap_key_manger(deps, compute_mrenclave, key_manager_mrenclave, tcb_info)
|
||||
ExecuteMsg::Quartz(msg) => msg.handle_raw(deps, &env, &info).map_err(Into::into),
|
||||
ExecuteMsg::SubmitObligation(SubmitObligationMsg { ciphertext, digest }) => {
|
||||
execute::submit_obligation(deps, ciphertext, digest)
|
||||
}
|
||||
ExecuteMsg::RegisterEpochKey(RegisterEpochKeyMsg { epoch_key }) => {
|
||||
execute::register_epoch_key(deps, epoch_key)
|
||||
ExecuteMsg::SubmitSetoffs(SubmitSetoffsMsg { setoffs_enc }) => {
|
||||
execute::submit_setoffs(deps, setoffs_enc)
|
||||
}
|
||||
ExecuteMsg::JoinComputeNode(JoinComputeNodeMsg {
|
||||
io_exchange_key,
|
||||
address,
|
||||
nonce,
|
||||
}) => execute::enqueue_join_request(deps, io_exchange_key, address, nonce),
|
||||
}
|
||||
}
|
||||
|
||||
pub mod execute {
|
||||
use cosmwasm_std::{DepsMut, Response};
|
||||
use k256::ecdsa::VerifyingKey;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use cosmwasm_std::{DepsMut, HexBinary, Response};
|
||||
use quartz_cw::state::Hash;
|
||||
|
||||
use crate::state::{
|
||||
EpochState, Mrenclave, RawAddress, RawMrenclave, RawNonce, RawPublicKey, RawTcbInfo,
|
||||
SgxState, EPOCH_STATE, SGX_STATE,
|
||||
current_epoch_key, ObligationsItem, RawCipherText, RawHash, SetoffsItem, OBLIGATIONS_KEY,
|
||||
SETOFFS_KEY,
|
||||
};
|
||||
use crate::state::{Request, REQUESTS};
|
||||
use crate::ContractError;
|
||||
use crate::ContractError::BadLength;
|
||||
|
||||
pub fn bootstrap_key_manger(
|
||||
pub fn submit_obligation(
|
||||
deps: DepsMut,
|
||||
compute_mrenclave: RawMrenclave,
|
||||
key_manager_mrenclave: RawMrenclave,
|
||||
tcb_info: RawTcbInfo,
|
||||
ciphertext: HexBinary,
|
||||
digest: HexBinary,
|
||||
) -> Result<Response, ContractError> {
|
||||
let _: Mrenclave = hex::decode(&compute_mrenclave)?
|
||||
.try_into()
|
||||
.map_err(|_| BadLength)?;
|
||||
let _: Mrenclave = hex::decode(&key_manager_mrenclave)?
|
||||
.try_into()
|
||||
.map_err(|_| BadLength)?;
|
||||
// TODO(hu55a1n1): validate TcbInfo
|
||||
let _: Hash = digest.to_array()?;
|
||||
|
||||
let sgx_state = SgxState {
|
||||
compute_mrenclave: compute_mrenclave.clone(),
|
||||
key_manager_mrenclave: key_manager_mrenclave.clone(),
|
||||
tcb_info: tcb_info.clone(),
|
||||
};
|
||||
|
||||
if SGX_STATE.exists(deps.storage) {
|
||||
return Err(ContractError::Unauthorized);
|
||||
// store the `(digest, ciphertext)` tuple
|
||||
ObligationsItem::new(¤t_epoch_key(OBLIGATIONS_KEY, deps.storage)?).update(
|
||||
deps.storage,
|
||||
|mut obligations| {
|
||||
if let Some(_duplicate) = obligations.insert(digest.clone(), ciphertext.clone()) {
|
||||
return Err(ContractError::DuplicateEntry);
|
||||
}
|
||||
|
||||
SGX_STATE.save(deps.storage, &sgx_state)?;
|
||||
Ok(obligations)
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(Response::new()
|
||||
.add_attribute("action", "bootstrap_key_manger")
|
||||
.add_attribute("compute_mrenclave", compute_mrenclave)
|
||||
.add_attribute("key_manager_mrenclave", key_manager_mrenclave)
|
||||
.add_attribute("tcb_info", tcb_info))
|
||||
.add_attribute("action", "submit_obligation")
|
||||
.add_attribute("digest", digest.to_string())
|
||||
.add_attribute("ciphertext", ciphertext.to_string()))
|
||||
}
|
||||
|
||||
pub fn register_epoch_key(
|
||||
pub fn submit_setoffs(
|
||||
deps: DepsMut,
|
||||
epoch_key: RawPublicKey,
|
||||
setoffs_enc: BTreeMap<RawHash, RawCipherText>,
|
||||
) -> Result<Response, ContractError> {
|
||||
let _ = VerifyingKey::from_sec1_bytes(&hex::decode(&epoch_key)?)?;
|
||||
// store the `BTreeMap<RawHash, RawCipherText>`
|
||||
SetoffsItem::new(¤t_epoch_key(SETOFFS_KEY, deps.storage)?)
|
||||
.save(deps.storage, &setoffs_enc)?;
|
||||
|
||||
let epoch_state = EpochState {
|
||||
epoch_key: epoch_key.clone(),
|
||||
};
|
||||
EPOCH_STATE.save(deps.storage, &epoch_state)?;
|
||||
|
||||
Ok(Response::new()
|
||||
.add_attribute("action", "register_epoch_key")
|
||||
.add_attribute("epoch_key", epoch_key))
|
||||
}
|
||||
|
||||
pub fn enqueue_join_request(
|
||||
deps: DepsMut,
|
||||
io_exchange_key: RawPublicKey,
|
||||
address: RawAddress,
|
||||
nonce: RawNonce,
|
||||
) -> Result<Response, ContractError> {
|
||||
let _ = VerifyingKey::from_sec1_bytes(&hex::decode(&io_exchange_key)?)?;
|
||||
let _ = deps.api.addr_validate(&address)?;
|
||||
let _ = hex::decode(&nonce);
|
||||
|
||||
let mut requests = REQUESTS.may_load(deps.storage)?.unwrap_or_default();
|
||||
requests.push((
|
||||
nonce,
|
||||
Request::JoinComputeNode((io_exchange_key.clone(), address)),
|
||||
));
|
||||
REQUESTS.save(deps.storage, &requests)?;
|
||||
|
||||
Ok(Response::new()
|
||||
.add_attribute("action", "enqueue_request")
|
||||
.add_attribute("io_exchange_key", io_exchange_key))
|
||||
Ok(Response::new().add_attribute("action", "submit_setoffs"))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "library"), entry_point)]
|
||||
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
|
||||
match msg {
|
||||
QueryMsg::GetSgxState {} => to_json_binary(&query::get_sgx_state(deps)?),
|
||||
QueryMsg::GetEpochState {} => to_json_binary(&query::get_epoch_state(deps)?),
|
||||
QueryMsg::GetRequests {} => to_json_binary(&query::get_requests(deps)?),
|
||||
pub fn query(_deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
|
||||
match msg {}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod query {
|
||||
use cosmwasm_std::{Deps, StdResult};
|
||||
|
||||
use crate::msg::query::{GetEpochStateResponse, GetRequestsResponse, GetSgxStateResponse};
|
||||
use crate::state::{EpochState, SgxState, EPOCH_STATE, REQUESTS, SGX_STATE};
|
||||
|
||||
pub fn get_sgx_state(deps: Deps) -> StdResult<GetSgxStateResponse> {
|
||||
let SgxState {
|
||||
compute_mrenclave,
|
||||
key_manager_mrenclave,
|
||||
..
|
||||
} = SGX_STATE.load(deps.storage)?;
|
||||
Ok(GetSgxStateResponse {
|
||||
compute_mrenclave,
|
||||
key_manager_mrenclave,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_epoch_state(deps: Deps) -> StdResult<GetEpochStateResponse> {
|
||||
let EpochState { epoch_key } = EPOCH_STATE.load(deps.storage)?;
|
||||
Ok(GetEpochStateResponse { epoch_key })
|
||||
}
|
||||
|
||||
pub fn get_requests(deps: Deps) -> StdResult<GetRequestsResponse> {
|
||||
Ok(GetRequestsResponse {
|
||||
requests: REQUESTS.load(deps.storage)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use cosmwasm_std::StdError;
|
||||
use hex::FromHexError;
|
||||
use k256::ecdsa::Error as K256Error;
|
||||
use quartz_cw::error::Error as QuartzError;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
|
@ -8,14 +9,20 @@ pub enum ContractError {
|
|||
#[error("{0}")]
|
||||
Std(#[from] StdError),
|
||||
|
||||
#[error("{0}")]
|
||||
Quartz(#[from] QuartzError),
|
||||
|
||||
#[error("Unauthorized")]
|
||||
Unauthorized,
|
||||
|
||||
#[error("Duplicate entry found")]
|
||||
DuplicateEntry,
|
||||
|
||||
#[error("Not Secp256K1")]
|
||||
K256(K256Error),
|
||||
|
||||
#[error("Invalid hex")]
|
||||
Hex(FromHexError),
|
||||
Hex(#[from] FromHexError),
|
||||
|
||||
#[error("Invalid length")]
|
||||
BadLength,
|
||||
|
@ -23,12 +30,6 @@ pub enum ContractError {
|
|||
|
||||
impl From<K256Error> for ContractError {
|
||||
fn from(e: K256Error) -> Self {
|
||||
ContractError::K256(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FromHexError> for ContractError {
|
||||
fn from(e: FromHexError) -> Self {
|
||||
ContractError::Hex(e)
|
||||
Self::K256(e)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,67 +1,134 @@
|
|||
use std::collections::BTreeMap;
|
||||
|
||||
use cosmwasm_schema::{cw_serde, QueryResponses};
|
||||
use quartz_cw::prelude::*;
|
||||
|
||||
use crate::state::{RawCipherText, RawHash};
|
||||
|
||||
#[cw_serde]
|
||||
pub struct InstantiateMsg;
|
||||
#[serde(transparent)]
|
||||
pub struct InstantiateMsg(pub QuartzInstantiateMsg);
|
||||
|
||||
#[cw_serde]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum ExecuteMsg {
|
||||
BootstrapKeyManager(execute::BootstrapKeyManagerMsg),
|
||||
RegisterEpochKey(execute::RegisterEpochKeyMsg),
|
||||
JoinComputeNode(execute::JoinComputeNodeMsg),
|
||||
Quartz(QuartzExecuteMsg),
|
||||
SubmitObligation(execute::SubmitObligationMsg),
|
||||
SubmitSetoffs(execute::SubmitSetoffsMsg),
|
||||
}
|
||||
|
||||
pub mod execute {
|
||||
use cosmwasm_std::HexBinary;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[cw_serde]
|
||||
pub struct BootstrapKeyManagerMsg {
|
||||
pub compute_mrenclave: String,
|
||||
pub key_manager_mrenclave: String,
|
||||
pub tcb_info: String,
|
||||
pub struct SubmitObligationMsg {
|
||||
pub ciphertext: HexBinary,
|
||||
pub digest: HexBinary,
|
||||
// pub signatures: [HexBinary; 2],
|
||||
// pub proof: π
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct RegisterEpochKeyMsg {
|
||||
pub epoch_key: String,
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct JoinComputeNodeMsg {
|
||||
pub io_exchange_key: String,
|
||||
pub address: String,
|
||||
pub nonce: String,
|
||||
pub struct SubmitSetoffsMsg {
|
||||
pub setoffs_enc: BTreeMap<RawHash, RawCipherText>,
|
||||
// pub proof: π,
|
||||
}
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
#[derive(QueryResponses)]
|
||||
pub enum QueryMsg {
|
||||
#[returns(query::GetSgxStateResponse)]
|
||||
GetSgxState {},
|
||||
#[returns(query::GetEpochStateResponse)]
|
||||
GetEpochState {},
|
||||
#[returns(query::GetRequestsResponse)]
|
||||
GetRequests {},
|
||||
}
|
||||
pub enum QueryMsg {}
|
||||
|
||||
pub mod query {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use crate::state::{RawMrenclave, RawNonce, RawPublicKey, Request};
|
||||
|
||||
#[cw_serde]
|
||||
pub struct GetSgxStateResponse {
|
||||
pub compute_mrenclave: RawMrenclave,
|
||||
pub key_manager_mrenclave: RawMrenclave,
|
||||
#[test]
|
||||
fn test_serde_instantiate_msg() {
|
||||
let _: InstantiateMsg = serde_json::from_str(
|
||||
r#"{
|
||||
"msg": {
|
||||
"config": {
|
||||
"mr_enclave": "1bfb949d235f61e5dc40f874ba3e9c36adef1e7a521b4b5f70e10fb1dc803251",
|
||||
"epoch_duration": {
|
||||
"secs": 43200,
|
||||
"nanos": 0
|
||||
},
|
||||
"light_client_opts": {
|
||||
"chain_id": "testing",
|
||||
"trusted_height": 1,
|
||||
"trusted_hash": "a1d115ba3a5e9fcc12ed68a9d8669159e9085f6f96ec26619f5c7ceb4ee02869",
|
||||
"trust_threshold": [
|
||||
2,
|
||||
3
|
||||
],
|
||||
"trusting_period": 1209600,
|
||||
"max_clock_drift": 5,
|
||||
"max_block_lag": 5
|
||||
}
|
||||
}
|
||||
},
|
||||
"attestation": {
|
||||
"report": {
|
||||
"report": {
|
||||
"id": "5246688123689513540899231107533660789",
|
||||
"timestamp": "2024-02-07T17:06:23.913745",
|
||||
"version": 4,
|
||||
"epidPseudonym": "+CUyIi74LPqS6M0NF7YrSxLqPdX3MKs6D6LIPqRG/ZEB4WmxZVvxAJwdwg/0m9cYnUUQguLnJotthX645lAogfJgO8Xg5/91lSegwyUKvHmKgtjOHX/YTbVe/wmgWiBdaL+KmarY0Je459Px/FqGLWLsAF7egPAJRd1Xn88Znrs=",
|
||||
"advisoryURL": "https://security-center.intel.com",
|
||||
"advisoryIDs": [
|
||||
"INTEL-SA-00161",
|
||||
"INTEL-SA-00219",
|
||||
"INTEL-SA-00289",
|
||||
"INTEL-SA-00334",
|
||||
"INTEL-SA-00615"
|
||||
],
|
||||
"isvEnclaveQuoteStatus": "CONFIGURATION_AND_SW_HARDENING_NEEDED",
|
||||
"platformInfoBlob": "150200650000080000141402040180070000000000000000000D00000C000000020000000000000CB0F08115F3DE71AE97980FE5E10B042054930ACE356C79EC44603D3F890756EC6ED73927A7C58CDE9AF1E754AEC77E335E8D80294407936BEB6404F27669FF7BB1",
|
||||
"isvEnclaveQuoteBody": "AgABALAMAAAPAA8AAAAAAFHK9aSLRQ1iSu/jKG0xSJQAAAAAAAAAAAAAAAAAAAAAFBQCBwGAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAHAAAAAAAAAOPC8qW4QNieBprK/8rbZRDvhmpz06nuVxAO1fhkbuS7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc8uUpEUEPvz8ZkFapjVh5WlWaLoAJM/f80T0EhGInHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRE7C+d+1dDWhoDsdyBrjVh+1AZ5txMhzN1UBeTVSmggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
},
|
||||
"reportsig": "YcY4SPvkfR4P2E8A5huutCeS+vY/ir+xq6disalNfNtAcUyOIOqTPVXhAZgY1M5B47Hjj1oYWf2qC2w+dnj7VcZjzO9oR0pJYdA+A7jaVrNzH2eXA79yICkuU8WE/x58I0j5vjXLoHXahaKlpZkMeTphqBY8u+FTVSdP3cWPho4viPapTfQRuEWmYq4KIq2zSr6wLg3Pz+yQ+G3e9BASVkLYxdYGTDFH1pMmfas9SEI7V4I+j8DaXmL8bucSRakmcQdmDMPGiA7mvIhSAlprzCrdxM7CHeUC6MPLN1fmFFcc9kyO/ved69j/651MWC83GgxSJ15L80U+DQzmrSW8xg=="
|
||||
}
|
||||
}
|
||||
}"#,
|
||||
).expect("failed to deserialize hardcoded quartz instantiate msg");
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct GetEpochStateResponse {
|
||||
pub epoch_key: RawPublicKey,
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct GetRequestsResponse {
|
||||
pub requests: Vec<(RawNonce, Request)>,
|
||||
#[test]
|
||||
fn test_serde_execute_msg() {
|
||||
let _: ExecuteMsg = serde_json::from_str(
|
||||
r#"{
|
||||
"quartz": {
|
||||
"session_create": {
|
||||
"msg": {
|
||||
"nonce": "425d87f8620e1dedeee70590cc55b164b8f01480ee59e0b1da35436a2f7c2777"
|
||||
},
|
||||
"attestation": {
|
||||
"report": {
|
||||
"report": {
|
||||
"id": "5246688123689513540899231107533660789",
|
||||
"timestamp": "2024-02-07T17:06:23.913745",
|
||||
"version": 4,
|
||||
"epidPseudonym": "+CUyIi74LPqS6M0NF7YrSxLqPdX3MKs6D6LIPqRG/ZEB4WmxZVvxAJwdwg/0m9cYnUUQguLnJotthX645lAogfJgO8Xg5/91lSegwyUKvHmKgtjOHX/YTbVe/wmgWiBdaL+KmarY0Je459Px/FqGLWLsAF7egPAJRd1Xn88Znrs=",
|
||||
"advisoryURL": "https://security-center.intel.com",
|
||||
"advisoryIDs": [
|
||||
"INTEL-SA-00161",
|
||||
"INTEL-SA-00219",
|
||||
"INTEL-SA-00289",
|
||||
"INTEL-SA-00334",
|
||||
"INTEL-SA-00615"
|
||||
],
|
||||
"isvEnclaveQuoteStatus": "CONFIGURATION_AND_SW_HARDENING_NEEDED",
|
||||
"platformInfoBlob": "150200650000080000141402040180070000000000000000000D00000C000000020000000000000CB0F08115F3DE71AE97980FE5E10B042054930ACE356C79EC44603D3F890756EC6ED73927A7C58CDE9AF1E754AEC77E335E8D80294407936BEB6404F27669FF7BB1",
|
||||
"isvEnclaveQuoteBody": "AgABALAMAAAPAA8AAAAAAFHK9aSLRQ1iSu/jKG0xSJQAAAAAAAAAAAAAAAAAAAAAFBQCBwGAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAHAAAAAAAAAOPC8qW4QNieBprK/8rbZRDvhmpz06nuVxAO1fhkbuS7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc8uUpEUEPvz8ZkFapjVh5WlWaLoAJM/f80T0EhGInHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRE7C+d+1dDWhoDsdyBrjVh+1AZ5txMhzN1UBeTVSmggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
},
|
||||
"reportsig": "YcY4SPvkfR4P2E8A5huutCeS+vY/ir+xq6disalNfNtAcUyOIOqTPVXhAZgY1M5B47Hjj1oYWf2qC2w+dnj7VcZjzO9oR0pJYdA+A7jaVrNzH2eXA79yICkuU8WE/x58I0j5vjXLoHXahaKlpZkMeTphqBY8u+FTVSdP3cWPho4viPapTfQRuEWmYq4KIq2zSr6wLg3Pz+yQ+G3e9BASVkLYxdYGTDFH1pMmfas9SEI7V4I+j8DaXmL8bucSRakmcQdmDMPGiA7mvIhSAlprzCrdxM7CHeUC6MPLN1fmFFcc9kyO/ved69j/651MWC83GgxSJ15L80U+DQzmrSW8xg=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}"#,
|
||||
).expect("failed to deserialize hardcoded quartz msg");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,37 +1,25 @@
|
|||
use std::collections::BTreeMap;
|
||||
|
||||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::{HexBinary, StdError, Storage};
|
||||
use cw_storage_plus::Item;
|
||||
use quartz_cw::state::EPOCH_COUNTER;
|
||||
|
||||
pub type RawNonce = String;
|
||||
pub type RawPublicKey = String;
|
||||
pub type RawAddress = String;
|
||||
pub type RawMrenclave = String;
|
||||
pub type RawTcbInfo = String;
|
||||
pub type RawHash = HexBinary;
|
||||
pub type RawCipherText = HexBinary;
|
||||
|
||||
pub type Mrenclave = [u8; 32];
|
||||
pub type ObligationsItem<'a> = Item<'a, BTreeMap<RawHash, RawCipherText>>;
|
||||
pub type SetoffsItem<'a> = Item<'a, BTreeMap<RawHash, RawCipherText>>;
|
||||
|
||||
#[cw_serde]
|
||||
pub struct State {
|
||||
pub owner: String,
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub enum Request {
|
||||
JoinComputeNode((RawPublicKey, RawAddress)),
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct SgxState {
|
||||
pub compute_mrenclave: RawMrenclave,
|
||||
pub key_manager_mrenclave: RawMrenclave,
|
||||
pub tcb_info: RawTcbInfo,
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct EpochState {
|
||||
pub epoch_key: RawPublicKey,
|
||||
}
|
||||
|
||||
pub const STATE: Item<State> = Item::new("state");
|
||||
pub const REQUESTS: Item<Vec<(RawNonce, Request)>> = Item::new("requests");
|
||||
pub const SGX_STATE: Item<SgxState> = Item::new("sgx_state");
|
||||
pub const EPOCH_STATE: Item<EpochState> = Item::new("epoch_state");
|
||||
pub const OBLIGATIONS_KEY: &str = "obligations";
|
||||
pub const SETOFFS_KEY: &str = "setoffs";
|
||||
|
||||
pub fn current_epoch_key(key: &str, storage: &dyn Storage) -> Result<String, StdError> {
|
||||
Ok(format!("{}/{key}", EPOCH_COUNTER.load(storage)?))
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ cosmwasm-schema = "1.4.0"
|
|||
cosmwasm-std = "1.4.0"
|
||||
k256 = { version = "0.13.2", default-features = false, features = ["ecdsa", "alloc"] }
|
||||
serde = { version = "1.0.188", default-features = false, features = ["derive"] }
|
||||
serde_json = "1.0.94"
|
||||
sha2 = "0.10.8"
|
||||
thiserror = "1.0.57"
|
||||
|
||||
|
|
|
@ -6,9 +6,14 @@ use cosmwasm_std::{DepsMut, Env, MessageInfo, Response};
|
|||
|
||||
use crate::error::Error;
|
||||
use crate::handler::Handler;
|
||||
use crate::msg::execute::attested::Attestation;
|
||||
use crate::msg::execute::attested::HasUserData;
|
||||
use crate::msg::execute::Execute;
|
||||
|
||||
impl Handler for Execute {
|
||||
impl<A> Handler for Execute<A>
|
||||
where
|
||||
A: Handler + HasUserData + Attestation,
|
||||
{
|
||||
fn handle(self, deps: DepsMut<'_>, env: &Env, info: &MessageInfo) -> Result<Response, Error> {
|
||||
match self {
|
||||
Execute::SessionCreate(msg) => msg.handle(deps, env, info),
|
||||
|
|
|
@ -3,7 +3,9 @@ use quartz_tee_ra::{verify_epid_attestation, Error as RaVerificationError};
|
|||
|
||||
use crate::error::Error;
|
||||
use crate::handler::Handler;
|
||||
use crate::msg::execute::attested::{Attestation, Attested, EpidAttestation, HasUserData};
|
||||
use crate::msg::execute::attested::{
|
||||
Attestation, Attested, EpidAttestation, HasUserData, MockAttestation,
|
||||
};
|
||||
use crate::state::CONFIG;
|
||||
|
||||
impl Handler for EpidAttestation {
|
||||
|
@ -13,13 +15,28 @@ impl Handler for EpidAttestation {
|
|||
_env: &Env,
|
||||
_info: &MessageInfo,
|
||||
) -> Result<Response, Error> {
|
||||
let (report, mr_enclave, user_data) = self.into_tuple();
|
||||
verify_epid_attestation(report, mr_enclave, user_data)
|
||||
// attestation handler MUST verify that the user_data and mr_enclave match the config/msg
|
||||
verify_epid_attestation(
|
||||
self.clone().into_report(),
|
||||
self.mr_enclave(),
|
||||
self.user_data(),
|
||||
)
|
||||
.map(|_| Response::default())
|
||||
.map_err(Error::RaVerification)
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler for MockAttestation {
|
||||
fn handle(
|
||||
self,
|
||||
_deps: DepsMut<'_>,
|
||||
_env: &Env,
|
||||
_info: &MessageInfo,
|
||||
) -> Result<Response, Error> {
|
||||
Ok(Response::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, A> Handler for Attested<M, A>
|
||||
where
|
||||
M: Handler + HasUserData,
|
||||
|
@ -38,12 +55,17 @@ where
|
|||
|
||||
if let Some(config) = CONFIG.may_load(deps.storage)? {
|
||||
// if we weren't able to load then the context was from InstantiateMsg so we don't fail
|
||||
if *config.mr_enclave() != attestation.mr_enclave() {
|
||||
// in such cases, the InstantiateMsg handler will verify that the mr_enclave matches
|
||||
if config.mr_enclave() != attestation.mr_enclave() {
|
||||
return Err(RaVerificationError::MrEnclaveMismatch.into());
|
||||
}
|
||||
}
|
||||
|
||||
Handler::handle(attestation, deps.branch(), env, info)?;
|
||||
Handler::handle(msg, deps, env, info)
|
||||
// handle message first, this has 2 benefits -
|
||||
// 1. we avoid (the more expensive) attestation verification if the message handler fails
|
||||
// 2. we allow the message handler to make changes to the config so that the attestation
|
||||
// handler can use those changes, e.g. InstantiateMsg
|
||||
Handler::handle(msg, deps.branch(), env, info)?;
|
||||
Handler::handle(attestation, deps, env, info)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,25 +3,34 @@ use quartz_tee_ra::Error as RaVerificationError;
|
|||
|
||||
use crate::error::Error;
|
||||
use crate::handler::Handler;
|
||||
use crate::msg::execute::attested::{Attestation, EpidAttestation};
|
||||
use crate::msg::execute::attested::{Attestation, EpidAttestation, MockAttestation};
|
||||
use crate::msg::instantiate::{CoreInstantiate, Instantiate};
|
||||
use crate::state::Config;
|
||||
use crate::state::CONFIG;
|
||||
use crate::state::{RawConfig, EPOCH_COUNTER};
|
||||
|
||||
impl Handler for Instantiate<EpidAttestation> {
|
||||
fn handle(self, deps: DepsMut<'_>, env: &Env, info: &MessageInfo) -> Result<Response, Error> {
|
||||
if self.0.msg().mr_enclave() != self.0.attestation().mr_enclave() {
|
||||
if self.0.msg().config().mr_enclave() != self.0.attestation().mr_enclave() {
|
||||
return Err(RaVerificationError::MrEnclaveMismatch.into());
|
||||
}
|
||||
self.0.handle(deps, env, info)
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler for Instantiate<MockAttestation> {
|
||||
fn handle(self, deps: DepsMut<'_>, env: &Env, info: &MessageInfo) -> Result<Response, Error> {
|
||||
self.0.handle(deps, env, info)
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler for CoreInstantiate {
|
||||
fn handle(self, deps: DepsMut<'_>, _env: &Env, _info: &MessageInfo) -> Result<Response, Error> {
|
||||
CONFIG
|
||||
.save(deps.storage, &Config::new(self.mr_enclave()))
|
||||
.save(deps.storage, &RawConfig::from(self.config().clone()))
|
||||
.map_err(Error::Std)?;
|
||||
|
||||
EPOCH_COUNTER.save(deps.storage, &1).map_err(Error::Std)?;
|
||||
|
||||
Ok(Response::new().add_attribute("action", "instantiate"))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,9 +55,9 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<A> HasDomainType for RawExecute<A>
|
||||
impl<RA> HasDomainType for RawExecute<RA>
|
||||
where
|
||||
A: HasDomainType,
|
||||
RA: HasDomainType,
|
||||
{
|
||||
type DomainType = Execute<A::DomainType>;
|
||||
type DomainType = Execute<RA::DomainType>;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::{HexBinary, StdError};
|
||||
use cosmwasm_std::StdError;
|
||||
use quartz_tee_ra::IASReport;
|
||||
|
||||
use crate::msg::HasDomainType;
|
||||
|
@ -12,6 +12,10 @@ pub struct Attested<M, A> {
|
|||
}
|
||||
|
||||
impl<M, A> Attested<M, A> {
|
||||
pub fn new(msg: M, attestation: A) -> Self {
|
||||
Self { msg, attestation }
|
||||
}
|
||||
|
||||
pub fn into_tuple(self) -> (M, A) {
|
||||
let Attested { msg, attestation } = self;
|
||||
(msg, attestation)
|
||||
|
@ -75,42 +79,29 @@ pub trait HasUserData {
|
|||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct EpidAttestation {
|
||||
report: IASReport,
|
||||
mr_enclave: MrEnclave,
|
||||
user_data: UserData,
|
||||
}
|
||||
|
||||
impl EpidAttestation {
|
||||
pub fn into_tuple(self) -> (IASReport, MrEnclave, UserData) {
|
||||
let EpidAttestation {
|
||||
report,
|
||||
mr_enclave,
|
||||
user_data,
|
||||
} = self;
|
||||
(report, mr_enclave, user_data)
|
||||
pub fn new(report: IASReport) -> Self {
|
||||
Self { report }
|
||||
}
|
||||
|
||||
pub fn report(&self) -> &IASReport {
|
||||
&self.report
|
||||
pub fn into_report(self) -> IASReport {
|
||||
self.report
|
||||
}
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct RawEpidAttestation {
|
||||
report: IASReport,
|
||||
mr_enclave: HexBinary,
|
||||
user_data: HexBinary,
|
||||
}
|
||||
|
||||
impl TryFrom<RawEpidAttestation> for EpidAttestation {
|
||||
type Error = StdError;
|
||||
|
||||
fn try_from(value: RawEpidAttestation) -> Result<Self, Self::Error> {
|
||||
let mr_enclave = value.mr_enclave.to_array()?;
|
||||
let user_data = value.user_data.to_array()?;
|
||||
Ok(Self {
|
||||
report: value.report,
|
||||
mr_enclave,
|
||||
user_data,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -119,8 +110,6 @@ impl From<EpidAttestation> for RawEpidAttestation {
|
|||
fn from(value: EpidAttestation) -> Self {
|
||||
Self {
|
||||
report: value.report,
|
||||
mr_enclave: value.mr_enclave.into(),
|
||||
user_data: value.user_data.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +120,7 @@ impl HasDomainType for RawEpidAttestation {
|
|||
|
||||
impl HasUserData for EpidAttestation {
|
||||
fn user_data(&self) -> UserData {
|
||||
self.user_data
|
||||
self.report.report.isv_enclave_quote_body.user_data()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,6 +130,42 @@ pub trait Attestation {
|
|||
|
||||
impl Attestation for EpidAttestation {
|
||||
fn mr_enclave(&self) -> MrEnclave {
|
||||
self.report().report.isv_enclave_quote_body.mrenclave()
|
||||
self.report.report.isv_enclave_quote_body.mrenclave()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct MockAttestation;
|
||||
|
||||
#[cw_serde]
|
||||
pub struct RawMockAttestation;
|
||||
|
||||
impl TryFrom<RawMockAttestation> for MockAttestation {
|
||||
type Error = StdError;
|
||||
|
||||
fn try_from(_value: RawMockAttestation) -> Result<Self, Self::Error> {
|
||||
Ok(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MockAttestation> for RawMockAttestation {
|
||||
fn from(_value: MockAttestation) -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl HasDomainType for RawMockAttestation {
|
||||
type DomainType = MockAttestation;
|
||||
}
|
||||
|
||||
impl HasUserData for MockAttestation {
|
||||
fn user_data(&self) -> UserData {
|
||||
unimplemented!("MockAttestation handler is a noop")
|
||||
}
|
||||
}
|
||||
|
||||
impl Attestation for MockAttestation {
|
||||
fn mr_enclave(&self) -> MrEnclave {
|
||||
unimplemented!("MockAttestation handler is a noop")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,10 @@ pub struct SessionCreate {
|
|||
}
|
||||
|
||||
impl SessionCreate {
|
||||
pub fn new(nonce: Nonce) -> Self {
|
||||
Self { nonce }
|
||||
}
|
||||
|
||||
pub fn into_nonce(self) -> Nonce {
|
||||
self.nonce
|
||||
}
|
||||
|
|
|
@ -15,6 +15,10 @@ pub struct SessionSetPubKey {
|
|||
}
|
||||
|
||||
impl SessionSetPubKey {
|
||||
pub fn new(nonce: Nonce, pub_key: VerifyingKey) -> Self {
|
||||
Self { nonce, pub_key }
|
||||
}
|
||||
|
||||
pub fn into_tuple(self) -> (Nonce, VerifyingKey) {
|
||||
(self.nonce, self.pub_key)
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::{HexBinary, StdError};
|
||||
use cosmwasm_std::StdError;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
use crate::msg::execute::attested::{
|
||||
Attested, EpidAttestation, HasUserData, RawAttested, RawEpidAttestation,
|
||||
};
|
||||
use crate::msg::HasDomainType;
|
||||
use crate::state::{MrEnclave, UserData};
|
||||
use crate::state::{Config, RawConfig, UserData};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Instantiate<A = EpidAttestation>(pub(crate) Attested<CoreInstantiate, A>);
|
||||
pub struct Instantiate<A = EpidAttestation>(pub Attested<CoreInstantiate, A>);
|
||||
|
||||
#[cw_serde]
|
||||
pub struct RawInstantiate<RA = RawEpidAttestation>(RawAttested<RawCoreInstantiate, RA>);
|
||||
|
@ -34,40 +34,47 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl HasDomainType for RawInstantiate {
|
||||
type DomainType = Instantiate;
|
||||
impl<RA> HasDomainType for RawInstantiate<RA>
|
||||
where
|
||||
RA: HasDomainType,
|
||||
{
|
||||
type DomainType = Instantiate<RA::DomainType>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct CoreInstantiate {
|
||||
mr_enclave: MrEnclave,
|
||||
// TODO(hu55a1n1): config - e.g. Epoch duration, light client opts
|
||||
config: Config,
|
||||
}
|
||||
|
||||
impl CoreInstantiate {
|
||||
pub fn mr_enclave(&self) -> MrEnclave {
|
||||
self.mr_enclave
|
||||
pub fn new(config: Config) -> Self {
|
||||
Self { config }
|
||||
}
|
||||
|
||||
pub fn config(&self) -> &Config {
|
||||
&self.config
|
||||
}
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct RawCoreInstantiate {
|
||||
mr_enclave: HexBinary,
|
||||
config: RawConfig,
|
||||
}
|
||||
|
||||
impl TryFrom<RawCoreInstantiate> for CoreInstantiate {
|
||||
type Error = StdError;
|
||||
|
||||
fn try_from(value: RawCoreInstantiate) -> Result<Self, Self::Error> {
|
||||
let mr_enclave = value.mr_enclave.to_array()?;
|
||||
Ok(Self { mr_enclave })
|
||||
Ok(Self {
|
||||
config: value.config.try_into()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CoreInstantiate> for RawCoreInstantiate {
|
||||
fn from(value: CoreInstantiate) -> Self {
|
||||
Self {
|
||||
mr_enclave: value.mr_enclave.into(),
|
||||
config: value.config.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -79,7 +86,10 @@ impl HasDomainType for RawCoreInstantiate {
|
|||
impl HasUserData for CoreInstantiate {
|
||||
fn user_data(&self) -> UserData {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(self.mr_enclave);
|
||||
hasher.update(
|
||||
serde_json::to_string(&RawConfig::from(self.config.clone()))
|
||||
.expect("infallible serializer"),
|
||||
);
|
||||
let digest: [u8; 32] = hasher.finalize().into();
|
||||
|
||||
let mut user_data = [0u8; 64];
|
||||
|
|
|
@ -1,26 +1,199 @@
|
|||
use core::time::Duration;
|
||||
|
||||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::HexBinary;
|
||||
use cosmwasm_std::{HexBinary, StdError};
|
||||
use cw_storage_plus::Item;
|
||||
use k256::ecdsa::VerifyingKey;
|
||||
|
||||
pub type MrEnclave = [u8; 32];
|
||||
pub type Nonce = [u8; 32];
|
||||
pub type UserData = [u8; 64];
|
||||
pub type Hash = [u8; 32];
|
||||
pub type Height = u64;
|
||||
pub type TrustThreshold = (u64, u64);
|
||||
|
||||
#[cw_serde]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Config {
|
||||
mr_enclave: HexBinary,
|
||||
mr_enclave: MrEnclave,
|
||||
epoch_duration: Duration,
|
||||
light_client_opts: LightClientOpts,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new(mr_enclave: MrEnclave) -> Self {
|
||||
pub fn new(
|
||||
mr_enclave: MrEnclave,
|
||||
epoch_duration: Duration,
|
||||
light_client_opts: LightClientOpts,
|
||||
) -> Self {
|
||||
Self {
|
||||
mr_enclave: mr_enclave.into(),
|
||||
mr_enclave,
|
||||
epoch_duration,
|
||||
light_client_opts,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mr_enclave(&self) -> &HexBinary {
|
||||
&self.mr_enclave
|
||||
pub fn light_client_opts(&self) -> &LightClientOpts {
|
||||
&self.light_client_opts
|
||||
}
|
||||
|
||||
pub fn mr_enclave(&self) -> MrEnclave {
|
||||
self.mr_enclave
|
||||
}
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct RawConfig {
|
||||
mr_enclave: HexBinary,
|
||||
epoch_duration: Duration,
|
||||
light_client_opts: RawLightClientOpts,
|
||||
}
|
||||
|
||||
impl RawConfig {
|
||||
pub fn mr_enclave(&self) -> &[u8] {
|
||||
self.mr_enclave.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<RawConfig> for Config {
|
||||
type Error = StdError;
|
||||
|
||||
fn try_from(value: RawConfig) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
mr_enclave: value.mr_enclave.to_array()?,
|
||||
epoch_duration: value.epoch_duration,
|
||||
light_client_opts: value
|
||||
.light_client_opts
|
||||
.try_into()
|
||||
.map_err(|e| StdError::parse_err("light_client_opts", e))?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Config> for RawConfig {
|
||||
fn from(value: Config) -> Self {
|
||||
Self {
|
||||
mr_enclave: value.mr_enclave.into(),
|
||||
epoch_duration: value.epoch_duration,
|
||||
light_client_opts: value.light_client_opts.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct LightClientOpts {
|
||||
chain_id: String,
|
||||
trusted_height: Height,
|
||||
trusted_hash: Hash,
|
||||
trust_threshold: TrustThreshold,
|
||||
trusting_period: u64,
|
||||
max_clock_drift: u64,
|
||||
max_block_lag: u64,
|
||||
}
|
||||
|
||||
impl LightClientOpts {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
chain_id: String,
|
||||
trusted_height: Height,
|
||||
trusted_hash: Hash,
|
||||
trust_threshold: TrustThreshold,
|
||||
trusting_period: u64,
|
||||
max_clock_drift: u64,
|
||||
max_block_lag: u64,
|
||||
) -> Result<Self, StdError> {
|
||||
let (numerator, denominator) = (trust_threshold.0, trust_threshold.1);
|
||||
if numerator > denominator {
|
||||
return Err(StdError::generic_err("trust_threshold_too_large"));
|
||||
}
|
||||
if denominator == 0 {
|
||||
return Err(StdError::generic_err("undefined_trust_threshold"));
|
||||
}
|
||||
if 3 * numerator < denominator {
|
||||
return Err(StdError::generic_err("trust_threshold_too_small"));
|
||||
}
|
||||
|
||||
let _trusted_height: i64 = trusted_height
|
||||
.try_into()
|
||||
.map_err(|_| StdError::generic_err("trusted_height too large"))?;
|
||||
|
||||
Ok(Self {
|
||||
chain_id,
|
||||
trusted_height,
|
||||
trusted_hash,
|
||||
trust_threshold,
|
||||
trusting_period,
|
||||
max_clock_drift,
|
||||
max_block_lag,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn chain_id(&self) -> &String {
|
||||
&self.chain_id
|
||||
}
|
||||
|
||||
pub fn trusted_height(&self) -> Height {
|
||||
self.trusted_height
|
||||
}
|
||||
|
||||
pub fn trusted_hash(&self) -> &Hash {
|
||||
&self.trusted_hash
|
||||
}
|
||||
|
||||
pub fn trust_threshold(&self) -> &TrustThreshold {
|
||||
&self.trust_threshold
|
||||
}
|
||||
|
||||
pub fn trusting_period(&self) -> u64 {
|
||||
self.trusting_period
|
||||
}
|
||||
|
||||
pub fn max_clock_drift(&self) -> u64 {
|
||||
self.max_clock_drift
|
||||
}
|
||||
|
||||
pub fn max_block_lag(&self) -> u64 {
|
||||
self.max_block_lag
|
||||
}
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct RawLightClientOpts {
|
||||
chain_id: String,
|
||||
trusted_height: u64,
|
||||
trusted_hash: HexBinary,
|
||||
trust_threshold: (u64, u64),
|
||||
trusting_period: u64,
|
||||
max_clock_drift: u64,
|
||||
max_block_lag: u64,
|
||||
}
|
||||
|
||||
impl TryFrom<RawLightClientOpts> for LightClientOpts {
|
||||
type Error = StdError;
|
||||
|
||||
fn try_from(value: RawLightClientOpts) -> Result<Self, Self::Error> {
|
||||
Self::new(
|
||||
value.chain_id,
|
||||
value.trusted_height,
|
||||
value.trusted_hash.to_array()?,
|
||||
(value.trust_threshold.0, value.trust_threshold.1),
|
||||
value.trusting_period,
|
||||
value.max_clock_drift,
|
||||
value.max_block_lag,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LightClientOpts> for RawLightClientOpts {
|
||||
fn from(value: LightClientOpts) -> Self {
|
||||
Self {
|
||||
chain_id: value.chain_id,
|
||||
trusted_height: value.trusted_height,
|
||||
trusted_hash: Vec::<u8>::from(value.trusted_hash).into(),
|
||||
trust_threshold: (value.trust_threshold.0, value.trust_threshold.1),
|
||||
trusting_period: value.trusting_period,
|
||||
max_clock_drift: value.max_clock_drift,
|
||||
max_block_lag: value.max_block_lag,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,7 +219,12 @@ impl Session {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nonce(&self) -> Nonce {
|
||||
self.nonce.to_array().expect("correct by construction")
|
||||
}
|
||||
}
|
||||
|
||||
pub const CONFIG: Item<'_, Config> = Item::new("quartz_config");
|
||||
pub const CONFIG: Item<'_, RawConfig> = Item::new("quartz_config");
|
||||
pub const SESSION: Item<'_, Session> = Item::new("quartz_session");
|
||||
pub const EPOCH_COUNTER: Item<'_, usize> = Item::new("epoch_counter");
|
||||
|
|
|
@ -25,6 +25,7 @@ WASM_BIN="$1"
|
|||
CHAIN_ID=${CHAIN_ID:-testing}
|
||||
LABEL=${LABEL:-bisenzone-mvp}
|
||||
COUNT=${COUNT:-0}
|
||||
INSTANTIATE_MSG=${INSTANTIATE_MSG:-"{}"}
|
||||
|
||||
TXFLAG="--chain-id ${CHAIN_ID} --gas-prices 0.0025ucosm --gas auto --gas-adjustment 1.3"
|
||||
|
||||
|
@ -45,7 +46,7 @@ echo "--------------------------------------------------------"
|
|||
echo "Label: ${LABEL}"
|
||||
echo "--------------------------------------------------------"
|
||||
|
||||
wasmd tx wasm instantiate "$CODE_ID" "null" --from "$USER_ADDR" --label $LABEL $TXFLAG -y --no-admin 2>&1 > /dev/null
|
||||
wasmd tx wasm instantiate "$CODE_ID" "$INSTANTIATE_MSG" --from "$USER_ADDR" --label $LABEL $TXFLAG -y --no-admin 2>&1 > /dev/null
|
||||
|
||||
echo ""
|
||||
echo "🕐 Waiting for contract to be queryable..."
|
||||
|
|
Loading…
Reference in a new issue