Skip to content

Commit

Permalink
Add RequestVcErrorDetail enum (#2836)
Browse files Browse the repository at this point in the history
  • Loading branch information
grumpygreenguy committed Jul 2, 2024
1 parent 03f7c4a commit 9b7946b
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 56 deletions.
31 changes: 28 additions & 3 deletions tee-worker/app-libs/stf/src/trusted_call_result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@
// passed back to the requester of trustedCall direct invocation (DI).
// They are mostly translated from the callback extrinsics in IMP.

use crate::{Box, String};
use codec::{Decode, Encode};
use itp_stf_interface::StfExecutionResult;
use itp_types::H256;
use litentry_primitives::AesOutput;
use litentry_primitives::{AesOutput, VCMPError};
use std::vec::Vec;

#[derive(Encode, Decode, Debug)]
Expand Down Expand Up @@ -102,10 +103,34 @@ pub struct RequestVCResult {
pub pre_id_graph_hash: H256,
}

#[derive(Debug, Encode, Decode, Clone)]
pub enum RequestVcErrorDetail {
UnexpectedCall(String),
DuplicateAssertionRequest,
ShieldingKeyRetrievalFailed(String), // Stringified itp_sgx_crypto::Error
RequestPayloadDecodingFailed,
SidechainDataRetrievalFailed(String), // Stringified itp_stf_state_handler::Error
IdentityAlreadyLinked,
NoEligibleIdentity,
InvalidSignerAccount,
UnauthorizedSigner,
AssertionBuildFailed(Box<VCMPError>),
MissingAesKey,
MrEnclaveRetrievalFailed,
EnclaveSignerRetrievalFailed,
SignatureVerificationFailed,
ConnectionHashNotFound(String),
MetadataRetrievalFailed(String), // Stringified itp_node_api_metadata_provider::Error
InvalidMetadata(String), // Stringified itp_node_api_metadata::Error
TrustedCallSendingFailed(String), // Stringified mpsc::SendError<(H256, TrustedCall)>
CallSendingFailed(String),
ExtrinsicConstructionFailed(String), // Stringified itp_extrinsics_factory::Error
ExtrinsicSendingFailed(String), // Stringified sgx_status_t
}

#[derive(Debug, Encode, Decode, Clone)]
pub struct RequestVcResultOrError {
pub payload: Vec<u8>,
pub is_error: bool,
pub result: Result<Vec<u8>, RequestVcErrorDetail>,
pub idx: u8,
pub len: u8,
}
23 changes: 13 additions & 10 deletions tee-worker/cli/src/trusted_base_cli/commands/litentry/request_vc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,16 +425,19 @@ impl RequestVcCommand {
match send_direct_vc_request(cli, trusted_cli, &top, key) {
Ok(result) =>
for res in result {
if res.is_error {
println!("received one error: {:?}", String::from_utf8(res.payload));
} else {
let mut vc =
RequestVCResult::decode(&mut res.payload.as_slice()).unwrap();
let decrypted = aes_decrypt(&key, &mut vc.vc_payload).unwrap();
let credential_str =
String::from_utf8(decrypted).expect("Found invalid UTF-8");
println!("----Generated VC-----");
println!("{}", credential_str);
match res.result {
Err(err) => {
println!("received one error: {:?}", err);
},
Ok(payload) => {
let mut vc =
RequestVCResult::decode(&mut payload.as_slice()).unwrap();
let decrypted = aes_decrypt(&key, &mut vc.vc_payload).unwrap();
let credential_str =
String::from_utf8(decrypted).expect("Found invalid UTF-8");
println!("----Generated VC-----");
println!("{}", credential_str);
},
}
},
Err(e) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,39 @@ export default {
pre_mutated_id_graph: "AesOutput",
pre_id_graph_hash: "H256",
},
VCMPError: {
_enum: {
RequestVCFailed: "(Assertion, ErrorDetail)",
UnclassifiedError: "(ErrorDetail)",
},
},
RequestVcErrorDetail: {
_enum: {
UnexpectedCall: "String",
DuplicateAssertionRequest: "Null",
ShieldingKeyRetrievalFailed: "String", // Stringified itp_sgx_crypto::Error
RequestPayloadDecodingFailed: "Null",
SidechainDataRetrievalFailed: "String", // Stringified itp_stf_state_handler::Error
IdentityAlreadyLinked: "Null",
NoEligibleIdentity: "Null",
InvalidSignerAccount: "Null",
UnauthorizedSigner: "Null",
AssertionBuildFailed: "VCMPError",
MissingAesKey: "Null",
MrEnclaveRetrievalFailed: "Null",
EnclaveSignerRetrievalFailed: "Null",
SignatureVerificationFailed: "Null",
ConnectionHashNotFound: "String",
MetadataRetrievalFailed: "String", // Stringified itp_node_api_metadata_provider::Error
InvalidMetadata: "String", // Stringified itp_node_api_metadata::Error
TrustedCallSendingFailed: "String", // Stringified mpsc::SendError<(H256, TrustedCall)>
CallSendingFailed: "String",
ExtrinsicConstructionFailed: "String", // Stringified itp_extrinsics_factory::Error
ExtrinsicSendingFailed: "String", // Stringified sgx_status_t
},
},
RequestVcResultOrError: {
payload: "Vec<u8>",
is_error: "bool",
result: "Result<Vec<u8>, RequestVcErrorDetail>",
idx: "u8",
len: "u8",
},
Expand Down
73 changes: 34 additions & 39 deletions tee-worker/litentry/core/vc-task/receiver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use ita_stf::helpers::ensure_alice;
use ita_stf::{
aes_encrypt_default,
helpers::ensure_self,
trusted_call_result::{RequestVCResult, RequestVcResultOrError},
trusted_call_result::{RequestVCResult, RequestVcErrorDetail, RequestVcResultOrError},
Getter, TrustedCall, TrustedCallSigned,
};
use itp_enclave_metrics::EnclaveMetric;
Expand Down Expand Up @@ -66,7 +66,7 @@ use std::{
boxed::Box,
collections::{HashMap, HashSet},
format,
string::{String, ToString},
string::ToString,
sync::{
mpsc::{channel, Sender},
Arc,
Expand Down Expand Up @@ -122,7 +122,7 @@ pub fn run_vc_handler_runner<ShieldingKeyRepository, A, S, H, O, N, AR>(
send_vc_response(
connection_hash,
context.clone(),
Err(format!("Failed to retrieve shielding key: {:?}", e)),
Err(RequestVcErrorDetail::ShieldingKeyRetrievalFailed(format!("{:?}", e))),
0u8,
0u8,
false,
Expand All @@ -143,7 +143,7 @@ pub fn run_vc_handler_runner<ShieldingKeyRepository, A, S, H, O, N, AR>(
send_vc_response(
connection_hash,
context.clone(),
Err("Failed to decode request payload".to_string()),
Err(RequestVcErrorDetail::RequestPayloadDecodingFailed),
0u8,
0u8,
false,
Expand All @@ -157,7 +157,7 @@ pub fn run_vc_handler_runner<ShieldingKeyRepository, A, S, H, O, N, AR>(
send_vc_response(
connection_hash,
context.clone(),
Err("Failed to get mrenclave".to_string()),
Err(RequestVcErrorDetail::MrEnclaveRetrievalFailed),
0u8,
0u8,
false,
Expand All @@ -169,7 +169,7 @@ pub fn run_vc_handler_runner<ShieldingKeyRepository, A, S, H, O, N, AR>(
send_vc_response(
connection_hash,
context.clone(),
Err("Failed to verify sig".to_string()),
Err(RequestVcErrorDetail::SignatureVerificationFailed),
0u8,
0u8,
false,
Expand Down Expand Up @@ -206,7 +206,7 @@ pub fn run_vc_handler_runner<ShieldingKeyRepository, A, S, H, O, N, AR>(
send_vc_response(
connection_hash,
context_pool,
Err(format!("1 couldn't find connection_hash: {:?}", e)),
Err(RequestVcErrorDetail::ConnectionHashNotFound(e.to_string())),
0u8,
1,
false,
Expand Down Expand Up @@ -278,7 +278,9 @@ pub fn run_vc_handler_runner<ShieldingKeyRepository, A, S, H, O, N, AR>(
send_vc_response(
connection_hash,
context_pool,
Err(format!("2 couldn't find connection_hash: {:?}", e)),
Err(RequestVcErrorDetail::ConnectionHashNotFound(
e.to_string(),
)),
idx as u8,
assertion_len,
false,
Expand All @@ -293,7 +295,7 @@ pub fn run_vc_handler_runner<ShieldingKeyRepository, A, S, H, O, N, AR>(
send_vc_response(
connection_hash,
context.clone(),
Err("Duplicate assertion request".to_string()),
Err(RequestVcErrorDetail::DuplicateAssertionRequest),
idx as u8,
assertion_len,
do_watch,
Expand All @@ -304,7 +306,7 @@ pub fn run_vc_handler_runner<ShieldingKeyRepository, A, S, H, O, N, AR>(
send_vc_response(
connection_hash,
context.clone(),
Err(format!("3 couldn't find connection_hash: {:?}", e)),
Err(RequestVcErrorDetail::ConnectionHashNotFound(e.to_string())),
idx as u8,
assertion_len,
false,
Expand All @@ -317,7 +319,7 @@ pub fn run_vc_handler_runner<ShieldingKeyRepository, A, S, H, O, N, AR>(
send_vc_response(
connection_hash,
context.clone(),
Err("Wrong trusted call. Expect request_batch_vc ".to_string()),
Err(RequestVcErrorDetail::UnexpectedCall("Expected request_batch_vc ".to_string())),
0u8,
0u8,
false,
Expand Down Expand Up @@ -372,7 +374,7 @@ impl RequestRegistry {
fn send_vc_response<ShieldingKeyRepository, A, S, H, O, AR>(
hash: H256,
context: Arc<StfTaskContext<ShieldingKeyRepository, A, S, H, O, AR>>,
response: Result<Vec<u8>, String>,
result: Result<Vec<u8>, RequestVcErrorDetail>,
idx: u8,
len: u8,
do_watch: bool,
Expand All @@ -387,15 +389,11 @@ fn send_vc_response<ShieldingKeyRepository, A, S, H, O, AR>(
O: EnclaveOnChainOCallApi + EnclaveMetricsOCallApi + EnclaveAttestationOCallApi + 'static,
AR: AssertionLogicRepository<Id = H160, Item = AssertionRepositoryItem>,
{
let vc_res: RequestVcResultOrError = match response.clone() {
Ok(payload) => RequestVcResultOrError { payload, is_error: false, idx, len },
Err(e) =>
RequestVcResultOrError { payload: e.as_bytes().to_vec(), is_error: true, idx, len },
};
let vc_res = RequestVcResultOrError { result: result.clone(), idx, len };

context.author_api.send_rpc_response(hash, vc_res.encode(), do_watch);

if response.is_err() {
if result.is_err() {
if let Err(e) = context.ocall_api.update_metric(EnclaveMetric::FailedVCIssuance) {
warn!("Failed to update metric for VC Issuance: {:?}", e);
}
Expand All @@ -410,7 +408,7 @@ fn process_single_request<ShieldingKeyRepository, A, S, H, O, N, AR>(
node_metadata_repo: Arc<N>,
tc_sender: Sender<(ShardIdentifier, TrustedCall)>,
call: TrustedCall,
) -> Result<Vec<u8>, String>
) -> Result<Vec<u8>, RequestVcErrorDetail>
where
ShieldingKeyRepository: AccessKey + core::marker::Send + core::marker::Sync,
<ShieldingKeyRepository as AccessKey>::KeyType:
Expand All @@ -428,9 +426,9 @@ where
let parachain_runtime_version = node_metadata_repo
.get_from_metadata(|m| {
m.system_version()
.map_err(|_| "Failed to get version from system pallet".to_string())
.map_err(|e| RequestVcErrorDetail::InvalidMetadata(format!("{:?}", e)))
})
.map_err(|_| "Failed to get metadata".to_string())??
.map_err(|e| RequestVcErrorDetail::MetadataRetrievalFailed(e.to_string()))??
.spec_version;
let sidechain_runtime_version = SIDECHAIN_VERSION.spec_version;

Expand Down Expand Up @@ -479,7 +477,7 @@ where
sidechain_block_number,
)
})
.map_err(|e| format!("Failed to fetch sidechain data due to: {:?}", e))?;
.map_err(|e| RequestVcErrorDetail::SidechainDataRetrievalFailed(e.to_string()))?;

let mut should_create_id_graph = false;
if id_graph.is_empty() {
Expand Down Expand Up @@ -507,7 +505,7 @@ where
// though it's lock guarded, because: a) it intereferes with the block import on another thread, which eventually
// cause state mismatch before/after applying the state diff b) it's not guaranteed to be broadcasted to other workers.
//
ensure!(!is_already_linked, "Identity already exists in other IDGraph".to_string());
ensure!(!is_already_linked, RequestVcErrorDetail::IdentityAlreadyLinked);
// we are safe to use `default_web3networks` and `Active` as IDGraph would be non-empty otherwise
id_graph.push((
who.clone(),
Expand All @@ -524,21 +522,20 @@ where
assertion_networks,
assertion.skip_identity_filtering(),
);
ensure!(!identities.is_empty(), "No eligible identity".to_string());
ensure!(!identities.is_empty(), RequestVcErrorDetail::NoEligibleIdentity);

let signer_account = signer
.to_account_id()
.ok_or_else(|| "Invalid signer account, failed to convert".to_string())?;
let signer_account =
signer.to_account_id().ok_or(RequestVcErrorDetail::InvalidSignerAccount)?;

match assertion {
// the signer will be checked inside A13, as we don't seem to have access to ocall_api here
Assertion::A13(_) => (),
_ => if_development_or!(
ensure!(
ensure_self(&signer, &who) || ensure_alice(&signer_account),
"Unauthorized signer",
RequestVcErrorDetail::UnauthorizedSigner,
),
ensure!(ensure_self(&signer, &who), "Unauthorized signer",)
ensure!(ensure_self(&signer, &who), RequestVcErrorDetail::UnauthorizedSigner)
),
}

Expand All @@ -559,14 +556,14 @@ where
};

let credential_str = create_credential_str(&req, &context)
.map_err(|e| format!("Failed to build assertion due to: {:?}", e))?;
.map_err(|e| RequestVcErrorDetail::AssertionBuildFailed(Box::new(e)))?;

let call_index = node_metadata_repo
.get_from_metadata(|m| m.vc_issued_call_indexes())
.map_err(|_| "Failed to get vc_issued_call_indexes".to_string())?
.map_err(|_| "Failed to get metadata".to_string())?;
.map_err(|e| RequestVcErrorDetail::MetadataRetrievalFailed(e.to_string()))?
.map_err(|e| RequestVcErrorDetail::InvalidMetadata(format!("{:?}", e)));

let key = maybe_key.ok_or_else(|| "Invalid aes key".to_string())?;
let key = maybe_key.ok_or(RequestVcErrorDetail::MissingAesKey)?;
let call = OpaqueCall::from_tuple(&(
call_index,
who.clone(),
Expand All @@ -587,16 +584,14 @@ where
let enclave_signer: AccountId = context
.enclave_signer
.get_enclave_account()
.map_err(|_| "Failed to get enclave signer".to_string())?;
.map_err(|_| RequestVcErrorDetail::EnclaveSignerRetrievalFailed)?;
let c = TrustedCall::maybe_create_id_graph(enclave_signer.into(), who);
tc_sender
.send((shard, c))
.map_err(|e| format!("Failed to send trusted call: {}", e))?;
.map_err(|e| RequestVcErrorDetail::TrustedCallSendingFailed(e.to_string()))?;

let extrinsic_sender = ParachainExtrinsicSender::new();
extrinsic_sender
.send(call)
.map_err(|e| format!("Failed to send call to the extrinsic sender: {}", e))?;
extrinsic_sender.send(call).map_err(RequestVcErrorDetail::CallSendingFailed)?;

if let Err(e) = context
.ocall_api
Expand All @@ -608,6 +603,6 @@ where
Ok(res.encode())
} else {
// Would never come here.
Err("Expect request_vc trusted call".to_string())
Err(RequestVcErrorDetail::UnexpectedCall("Expected request_vc".to_string()))
}
}
2 changes: 1 addition & 1 deletion tee-worker/ts-tests/integration-tests/dr_vc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ describe('Test Vc (direct request)', function () {
// if response is a A1 or A2, etc....
const vcresponse = context.api.createType('RequestVcResultOrError', res.value);
console.log(`vcresponse len: ${vcresponse.len}, idx: ${vcresponse.idx}`);
if (!vcresponse.is_error) await assertVc(context, aliceSubstrateIdentity, vcresponse.payload);
if (vcresponse.result.isOk) await assertVc(context, aliceSubstrateIdentity, vcresponse.result.asOk);
};

// the +res+ below is the last message with "do_watch: false" property and we may not need it at all
Expand Down
3 changes: 2 additions & 1 deletion tee-worker/ts-tests/integration-tests/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"ts-node": {
"esm": true,
"experimentalResolver": true,
"experimentalSpecifierResolution": "node"
"experimentalSpecifierResolution": "node",
"transpileOnly": true
}
}

0 comments on commit 9b7946b

Please sign in to comment.