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

(fix) Return IndyVdr based CredentialDefinition schemaId as full schemaId (not sequence number) #1313

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 16 additions & 2 deletions aries/aries_vcx/tests/test_primitives.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use std::error::Error;

use anoncreds_types::{
data_types::ledger::cred_def::CredentialDefinition, utils::validation::Validatable,
};
use aries_vcx::common::primitives::{
credential_definition::generate_cred_def, revocation_registry::generate_rev_reg,
};
Expand Down Expand Up @@ -46,13 +49,24 @@ async fn test_pool_create_cred_def_real() -> Result<(), Box<dyn Error>> {
.publish_cred_def(&setup.wallet, cred_def.try_clone()?, &setup.institution_did)
.await?;

std::thread::sleep(std::time::Duration::from_secs(2));
tokio::time::sleep(std::time::Duration::from_secs(2)).await;

let cred_def_json_ledger = ledger_read
.get_cred_def(&cred_def.id, Some(&setup.institution_did))
.await?;
cred_def_json_ledger.validate()?;

// same as the original generated cred def, but schema ID corrected to the qualified version
let cred_def_corrected_schema_id = CredentialDefinition {
schema_id: schema.schema_id,
..cred_def.try_clone().unwrap()
};

assert!(serde_json::to_string(&cred_def_json_ledger)?.contains(&cred_def.id.to_string()));
// check cred def matches originally, but with corected schema ID.
assert_eq!(
serde_json::to_value(cred_def_json_ledger)?,
serde_json::to_value(cred_def_corrected_schema_id)?
);
Ok(())
}

Expand Down
58 changes: 55 additions & 3 deletions aries/aries_vcx_ledger/src/ledger/indy_vdr_ledger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,17 @@ pub use indy_ledger_response_parser::GetTxnAuthorAgreementData;
use indy_ledger_response_parser::{
ResponseParser, RevocationRegistryDeltaInfo, RevocationRegistryInfo,
};
use indy_vdr as vdr;
use indy_vdr::{
self as vdr,
ledger::{
identifiers::SchemaId as IndyVdrSchemaId,
requests::cred_def::CredentialDefinition as IndyVdrCredentialDefinition,
},
utils::{did::DidValue, Validatable},
};
use log::{debug, trace};
use public_key::Key;
use serde_json::Value;
use serde_json::{json, Value};
use time::OffsetDateTime;
use vdr::{
config::PoolConfig,
Expand Down Expand Up @@ -162,6 +169,40 @@ where
trace!("submit_request << ledger response (is from cache: {is_from_cache}): {response}");
Ok(response)
}

async fn resolve_schema_id_from_seq_no(
&self,
seq_no: i32,
submitter_did: Option<&Did>,
) -> VcxLedgerResult<IndyVdrSchemaId> {
let response = self.get_ledger_txn(seq_no, submitter_did).await?;
let mut txn_response = self.response_parser.parse_get_txn_response(&response)?;
let txn = txn_response["txn"].take();

// mimic acapy & credo-ts behaviour - assumes node protocol >= 1.4

// check correct tx
if txn["type"] != json!("101") {
return Err(VcxLedgerError::InvalidLedgerResponse);
}

// pull schema identifier parts
let schema_did = &txn["metadata"]["from"];
let schema_name = &txn["data"]["data"]["name"];
let schema_version = &txn["data"]["data"]["version"];
let (Value::String(did), Value::String(name), Value::String(ver)) =
(schema_did, schema_name, schema_version)
else {
return Err(VcxLedgerError::InvalidLedgerResponse);
};

// construct indy schema ID from parts
let did = DidValue::new(did, None);
did.validate()?;
let schema_id = IndyVdrSchemaId::new(&did, name, ver);
schema_id.validate()?;
Ok(schema_id)
}
}

impl<T> IndyVdrLedgerWrite<T>
Expand Down Expand Up @@ -487,7 +528,18 @@ where
let cred_def = self
.response_parser
.parse_get_cred_def_response(&response, None)?;
Ok(cred_def.convert(())?)

// extract and map seqNo -> schemaId if required
let IndyVdrCredentialDefinition::CredentialDefinitionV1(mut cred_def) = cred_def;
if let Ok(seq_no) = cred_def.schema_id.0.parse::<i32>() {
cred_def.schema_id = self
.resolve_schema_id_from_seq_no(seq_no, submitter_did)
.await?;
}

let cred_def = IndyVdrCredentialDefinition::CredentialDefinitionV1(cred_def).convert(())?;

Ok(cred_def)
}

async fn get_rev_reg_def_json(
Expand Down
39 changes: 19 additions & 20 deletions aries/aries_vcx_ledger/src/ledger/type_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,26 +145,25 @@ impl Convert for IndyVdrCredentialDefinition {
fn convert(self, (): Self::Args) -> Result<Self::Target, Self::Error> {
match self {
IndyVdrCredentialDefinition::CredentialDefinitionV1(cred_def) => {
if let Some((_method, issuer_id, _sig_type, _schema_id, _tag)) = cred_def.id.parts()
{
Ok(OurCredentialDefinition {
id: OurCredentialDefinitionId::new(cred_def.id.to_string())?,
schema_id: OurSchemaId::new_unchecked(cred_def.schema_id.to_string()),
signature_type: OurSignatureType::CL,
tag: cred_def.tag,
value: OurCredentialDefinitionData {
primary: serde_json::from_value(cred_def.value.primary)?,
revocation: cred_def
.value
.revocation
.map(serde_json::from_value)
.transpose()?,
},
issuer_id: IssuerId::new(issuer_id.to_string())?,
})
} else {
todo!()
}
let id = &cred_def.id;
let Some((_method, issuer_id, _sig_type, _schema_id, _tag)) = id.parts() else {
return Err(format!("cred def ID is malformed. cannot convert. {}", id).into());
};
Ok(OurCredentialDefinition {
id: OurCredentialDefinitionId::new(id.to_string())?,
schema_id: OurSchemaId::new(cred_def.schema_id.to_string())?,
signature_type: OurSignatureType::CL,
tag: cred_def.tag,
value: OurCredentialDefinitionData {
primary: serde_json::from_value(cred_def.value.primary)?,
revocation: cred_def
.value
.revocation
.map(serde_json::from_value)
.transpose()?,
},
issuer_id: IssuerId::new(issuer_id.to_string())?,
})
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ pub const GET_REVOC_REG_DEF: &str = "115";
pub const GET_REVOC_REG: &str = "116";
pub const GET_REVOC_REG_DELTA: &str = "117";
pub const GET_TXN_AUTHR_AGRMT: &str = "6";
pub const GET_TXN: &str = "3";
1 change: 1 addition & 0 deletions aries/misc/indy_ledger_response_parser/src/domain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ pub mod response;
pub mod rev_reg;
pub mod rev_reg_def;
pub mod schema;
pub mod txn;
19 changes: 19 additions & 0 deletions aries/misc/indy_ledger_response_parser/src/domain/txn.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use serde_json::Value;

use super::{
constants::GET_TXN,
response::{GetReplyResultV0, GetReplyResultV1, ReplyType},
};

#[derive(Debug, Deserialize)]
#[serde(untagged)]
pub enum GetTxnReplyResult {
GetTxnReplyResultV0(GetReplyResultV0<Value>),
GetTxnReplyResultV1(GetReplyResultV1<Value>),
}

impl ReplyType for GetTxnReplyResult {
fn get_type<'a>() -> &'a str {
GET_TXN
}
}
18 changes: 17 additions & 1 deletion aries/misc/indy_ledger_response_parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub mod error;

use anoncreds_clsignatures::RevocationRegistryDelta as ClRevocationRegistryDelta;
pub use domain::author_agreement::GetTxnAuthorAgreementData;
use domain::author_agreement::GetTxnAuthorAgreementResult;
use domain::{author_agreement::GetTxnAuthorAgreementResult, txn::GetTxnReplyResult};
use error::LedgerResponseParserError;
use indy_vdr::{
ledger::{
Expand Down Expand Up @@ -236,6 +236,22 @@ impl ResponseParser {
})
}

// https://github.com/hyperledger/indy-node/blob/main/docs/source/requests.md#get_txn
pub fn parse_get_txn_response(
&self,
get_txn_response: &str,
) -> Result<serde_json::Value, LedgerResponseParserError> {
let reply: Reply<GetTxnReplyResult> = Self::parse_response(get_txn_response)?;

let data = match reply.result() {
GetTxnReplyResult::GetTxnReplyResultV0(res) => {
res.data.unwrap_or(serde_json::Value::Null)
}
GetTxnReplyResult::GetTxnReplyResultV1(res) => res.txn.data,
};
Ok(data)
}

pub fn parse_response<T>(response: &str) -> Result<Reply<T>, LedgerResponseParserError>
where
T: DeserializeOwned + ReplyType + ::std::fmt::Debug,
Expand Down
Loading