From 368a377a7a9af1f6b6a6fc822cc79ba1b6f29dbf Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab Date: Tue, 15 Nov 2022 00:43:43 +0100 Subject: [PATCH 1/6] add revocation examples --- .../wasm/examples/src/0_basic/7_revoke_vc.ts | 157 ++++++++++++++ bindings/wasm/examples/src/main.ts | 3 + examples/0_basic/7_revoke_vc.rs | 192 ++++++++++++++++++ examples/Cargo.toml | 4 + 4 files changed, 356 insertions(+) create mode 100644 bindings/wasm/examples/src/0_basic/7_revoke_vc.ts create mode 100644 examples/0_basic/7_revoke_vc.rs diff --git a/bindings/wasm/examples/src/0_basic/7_revoke_vc.ts b/bindings/wasm/examples/src/0_basic/7_revoke_vc.ts new file mode 100644 index 0000000000..afd368fe35 --- /dev/null +++ b/bindings/wasm/examples/src/0_basic/7_revoke_vc.ts @@ -0,0 +1,157 @@ +// Copyright 2020-2022 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { Bip39 } from "@iota/crypto.js"; +import { Client, MnemonicSecretManager } from "@iota/iota-client-wasm/node"; +import { IAliasOutput, IRent, TransactionHelper } from "@iota/iota.js"; +import { + Credential, + CredentialValidationOptions, + CredentialValidator, + FailFast, + IotaDocument, + IotaIdentityClient, + IotaService, + IotaVerificationMethod, + ProofOptions, + Resolver, + RevocationBitmap, +} from "../../../node"; +import { API_ENDPOINT, createDid } from "../util"; + +/** + * This example shows how to revoke a verifiable credential. + * It demonstrates two methods for revocation. The first uses a revocation bitmap of type `RevocationBitmap2022`, + * while the second method simply removes the verification method (public key) that signed the credential + * from the DID Document of the issuer. + * + * Note: make sure `API_ENDPOINT` and `FAUCET_ENDPOINT` are set to the correct network endpoints. + */ +export async function revokeVC() { + // =========================================================================== + // Create a Verifiable Credential. + // =========================================================================== + + const client = await Client.new({ + primaryNode: API_ENDPOINT, + localPow: true, + }); + const didClient = new IotaIdentityClient(client); + + // Generate a random mnemonic for our wallet. + const secretManager: MnemonicSecretManager = { + mnemonic: Bip39.randomMnemonic(), + }; + + // Create an identity for the issuer with one verification method `key-1`. + let { document: issuerDocument, keypair: keypairIssuer } = await createDid(client, secretManager); + + // Create an identity for the holder, in this case also the subject. + const { document: aliceDocument } = await createDid(client, secretManager); + + // Create a new empty revocation bitmap. No credential is revoked yet. + const revocationBitmap = new RevocationBitmap(); + + // Add the revocation bitmap to the DID Document of the issuer as a service. + const service: IotaService = new IotaService({ + id: issuerDocument.id().join("#my-revocation-service"), + type: RevocationBitmap.type(), + serviceEndpoint: revocationBitmap.toEndpoint(), + }); + issuerDocument.insertService(service); + + // Resolve the latest output and update it with the given document. + let aliasOutput: IAliasOutput = await didClient.updateDidOutput(issuerDocument); + + // Because the size of the DID document increased, we have to increase the allocated storage deposit. + // This increases the deposit amount to the new minimum. + let rentStructure: IRent = await didClient.getRentStructure(); + aliasOutput.amount = TransactionHelper.getStorageDeposit(aliasOutput, rentStructure).toString(); + + // Publish the document. + issuerDocument = await didClient.publishDidOutput(secretManager, aliasOutput); + + // Create a credential subject indicating the degree earned by Alice, linked to their DID. + const subject = { + id: aliceDocument.id(), + name: "Alice", + degreeName: "Bachelor of Science and Arts", + degreeType: "BachelorDegree", + GPA: "4.0", + }; + + // Create an unsigned `UniversityDegree` credential for Alice. + // The issuer also chooses a unique `RevocationBitmap` index to be able to revoke it later. + const CREDENTIAL_INDEX = 5; + const unsignedVc = new Credential({ + id: "https://example.edu/credentials/3732", + type: "UniversityDegreeCredential", + credentialStatus: { + id: issuerDocument.id() + "#my-revocation-service", + type: RevocationBitmap.type(), + revocationBitmapIndex: CREDENTIAL_INDEX, + }, + issuer: issuerDocument.id(), + credentialSubject: subject, + }); + + // Sign Credential. + let signedVc = issuerDocument.signCredential(unsignedVc, keypairIssuer.private(), "#key-1", ProofOptions.default()); + console.log(`Credential JSON > ${JSON.stringify(signedVc, null, 2)}`); + + // =========================================================================== + // Revocation of the Verifiable Credential. + // =========================================================================== + + // Update the RevocationBitmap service in the issuer's DID Document. + // This revokes the credential's unique index. + issuerDocument.revokeCredentials("my-revocation-service", CREDENTIAL_INDEX); + + // Publish the changes. + aliasOutput = await didClient.updateDidOutput(issuerDocument); + rentStructure = await didClient.getRentStructure(); + aliasOutput.amount = TransactionHelper.getStorageDeposit(aliasOutput, rentStructure).toString(); + const update2: IotaDocument = await didClient.publishDidOutput(secretManager, aliasOutput); + + // Credential verification now fails. + try { + CredentialValidator.validate(signedVc, update2, CredentialValidationOptions.default(), FailFast.FirstError); + console.log("Revocation Failed!"); + } catch (e) { + console.log(`Error during validation: ${e}`); + } + + // =========================================================================== + // Alternative revocation of the Verifiable Credential. + // =========================================================================== + + // By removing the verification method, that signed the credential, from the issuer's DID document, + // we effectively revoke the credential, as it will no longer be possible to validate the signature. + let originalMethod = issuerDocument.resolveMethod("#key-1") as IotaVerificationMethod; + await issuerDocument.removeMethod(originalMethod.id()); + + // Publish the changes. + aliasOutput = await didClient.updateDidOutput(issuerDocument); + rentStructure = await didClient.getRentStructure(); + aliasOutput.amount = TransactionHelper.getStorageDeposit(aliasOutput, rentStructure).toString(); + issuerDocument = await didClient.publishDidOutput(secretManager, aliasOutput); + + // We expect the verifiable credential to be revoked. + const resolver = new Resolver({ client: didClient }); + try { + // Resolve the issuer's updated DID Document to ensure the key was revoked successfully. + const resolvedIssuerDoc = await resolver.resolve(issuerDocument.id().toString()); + CredentialValidator.validate( + signedVc, + resolvedIssuerDoc, + CredentialValidationOptions.default(), + FailFast.FirstError, + ); + + // `CredentialValidator.validate` will throw an error, hence this will not be reached. + console.log("Revocation failed!"); + } catch (e) { + console.log(`Error during validation: ${e}`); + console.log(`Credential successfully revoked!`); + } +} diff --git a/bindings/wasm/examples/src/main.ts b/bindings/wasm/examples/src/main.ts index f55d824b35..164cbc3bd0 100644 --- a/bindings/wasm/examples/src/main.ts +++ b/bindings/wasm/examples/src/main.ts @@ -8,6 +8,7 @@ import { deactivateIdentity } from "./0_basic/3_deactivate_did"; import { deleteIdentity } from "./0_basic/4_delete_did"; import { createVC } from "./0_basic/5_create_vc"; import { createVP } from "./0_basic/6_create_vp"; +import { revokeVC } from "./0_basic/7_revoke_vc"; import { didControlsDid } from "./1_advanced/0_did_controls_did"; import { didIssuesNft } from "./1_advanced/1_did_issues_nft"; import { nftOwnsDid } from "./1_advanced/2_nft_owns_did"; @@ -37,6 +38,8 @@ async function main() { return await createVC(); case "6_create_vp": return await createVP(); + case "7_revoke_vc": + return await revokeVC(); case "0_did_controls_did": return await didControlsDid(); case "1_did_issues_nft": diff --git a/examples/0_basic/7_revoke_vc.rs b/examples/0_basic/7_revoke_vc.rs new file mode 100644 index 0000000000..7b34ce926d --- /dev/null +++ b/examples/0_basic/7_revoke_vc.rs @@ -0,0 +1,192 @@ +// Copyright 2020-2022 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +//! This example shows how to revoke a verifiable credential. +//! It demonstrates two methods for revocation. The first uses a revocation bitmap of type `RevocationBitmap2022`, +//! while the second method simply removes the verification method (public key) that signed the credential +//! from the DID Document of the issuer. +//! +//! Note: make sure `API_ENDPOINT` and `FAUCET_ENDPOINT` are set to the correct network endpoints. +//! +//! cargo run --example 7_revoke_vc + +use examples::create_did; +use examples::random_stronghold_path; +use examples::API_ENDPOINT; +use identity_iota::core::json; +use identity_iota::core::FromJson; +use identity_iota::core::Url; +use identity_iota::credential::AbstractThreadSafeValidatorDocument; +use identity_iota::credential::Credential; +use identity_iota::credential::CredentialBuilder; +use identity_iota::credential::CredentialValidationOptions; +use identity_iota::credential::CredentialValidator; +use identity_iota::credential::FailFast; +use identity_iota::credential::RevocationBitmapStatus; +use identity_iota::credential::Status; +use identity_iota::credential::Subject; +use identity_iota::credential::ValidationError; +use identity_iota::crypto::KeyPair; +use identity_iota::crypto::ProofOptions; +use identity_iota::did::DIDUrl; +use identity_iota::did::Document; +use identity_iota::did::RevocationBitmap; +use identity_iota::did::Service; +use identity_iota::did::DID; +use identity_iota::iota::IotaClientExt; +use identity_iota::iota::IotaDID; +use identity_iota::iota::IotaDocument; +use identity_iota::iota::IotaIdentityClientExt; +use identity_iota::iota::IotaService; +use identity_iota::resolver::Resolver; +use iota_client::block::address::Address; +use iota_client::block::output::AliasOutput; +use iota_client::block::output::AliasOutputBuilder; +use iota_client::block::output::RentStructure; +use iota_client::secret::stronghold::StrongholdSecretManager; +use iota_client::secret::SecretManager; +use iota_client::Client; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + // =========================================================================== + // Create a Verifiable Credential. + // =========================================================================== + + // Create a new client to interact with the IOTA ledger. + let client: Client = Client::builder().with_primary_node(API_ENDPOINT, None)?.finish()?; + + // Create an identity for the issuer with one verification method `key-1`. + let mut secret_manager_issuer: SecretManager = SecretManager::Stronghold( + StrongholdSecretManager::builder() + .password("secure_password_1") + .build(random_stronghold_path())?, + ); + let (_, mut issuer_document, key_pair): (Address, IotaDocument, KeyPair) = + create_did(&client, &mut secret_manager_issuer).await?; + + // Create an identity for the holder, in this case also the subject. + let mut secret_manager_alice: SecretManager = SecretManager::Stronghold( + StrongholdSecretManager::builder() + .password("secure_password_2") + .build(random_stronghold_path())?, + ); + let (_, alice_document, _): (Address, IotaDocument, KeyPair) = create_did(&client, &mut secret_manager_alice).await?; + + // Create a new empty revocation bitmap. No credential is revoked yet. + let revocation_bitmap: RevocationBitmap = RevocationBitmap::new(); + + // Add the revocation bitmap to the DID document of the issuer as a service. + let service: IotaService = Service::from_json_value(json!({ + "id": issuer_document.id().to_url().join("#my-revocation-service")?, + "type": RevocationBitmap::TYPE, + "serviceEndpoint": revocation_bitmap.to_endpoint()? + }))?; + issuer_document.insert_service(service); + + // Resolve the latest output and update it with the given document. + let alias_output: AliasOutput = client.update_did_output(issuer_document.clone()).await?; + + // Because the size of the DID document increased, we have to increase the allocated storage deposit. + // This increases the deposit amount to the new minimum. + let rent_structure: RentStructure = client.get_rent_structure()?; + let alias_output: AliasOutput = AliasOutputBuilder::from(&alias_output) + .with_minimum_storage_deposit(rent_structure) + .finish(client.get_token_supply()?)?; + + // Publish the updated Alias Output. + issuer_document = client.publish_did_output(&secret_manager_issuer, alias_output).await?; + + // Create a credential subject indicating the degree earned by Alice. + let subject: Subject = Subject::from_json_value(json!({ + "id": alice_document.id().as_str(), + "name": "Alice", + "degree": { + "type": "BachelorDegree", + "name": "Bachelor of Science and Arts", + }, + "GPA": "4.0", + }))?; + + // Create an unsigned `UniversityDegree` credential for Alice. + // The issuer also chooses a unique `RevocationBitmap` index to be able to revoke it later. + let service_url = issuer_document.id().to_url().join("#my-revocation-service")?; + let credential_index: u32 = 5; + let status: Status = RevocationBitmapStatus::new(service_url, credential_index).into(); + + // Build credential using subject above, status, and issuer. + let mut credential: Credential = CredentialBuilder::default() + .id(Url::parse("https://example.edu/credentials/3732")?) + .issuer(Url::parse(issuer_document.id().as_str())?) + .type_("UniversityDegreeCredential") + .status(status) + .subject(subject) + .build()?; + + // Sign the Credential with the issuer's verification method. + issuer_document.sign_data(&mut credential, key_pair.private(), "#key-1", ProofOptions::default())?; + println!("Credential JSON > {:#}", credential); + + // =========================================================================== + // Revocation of the Verifiable Credential. + // =========================================================================== + + // Update the RevocationBitmap service in the issuer's DID Document. + // This revokes the credential's unique index. + issuer_document.revoke_credentials("my-revocation-service", &[credential_index])?; + + // Publish the changes. + let alias_output: AliasOutput = client.update_did_output(issuer_document.clone()).await?; + let rent_structure: RentStructure = client.get_rent_structure()?; + let alias_output: AliasOutput = AliasOutputBuilder::from(&alias_output) + .with_minimum_storage_deposit(rent_structure) + .finish(client.get_token_supply()?)?; + issuer_document = client.publish_did_output(&secret_manager_issuer, alias_output).await?; + + let validation_result = CredentialValidator::validate( + &credential, + &issuer_document, + &CredentialValidationOptions::default(), + FailFast::FirstError, + ); + + // We expect validation to no longer succeed because the credential was revoked. + assert!(matches!( + validation_result.unwrap_err().validation_errors[0], + ValidationError::Revoked + )); + + // =========================================================================== + // Alternative revocation of the Verifiable Credential. + // =========================================================================== + + // By removing the verification method, that signed the credential, from the issuer's DID document, + // we effectively revoke the credential, as it will no longer be possible to validate the signature. + let original_method: DIDUrl = issuer_document.resolve_method("#key-1", None).unwrap().id().clone(); + issuer_document.remove_method(&original_method).unwrap(); + + // Publish the changes. + let alias_output: AliasOutput = client.update_did_output(issuer_document.clone()).await?; + let alias_output: AliasOutput = AliasOutputBuilder::from(&alias_output).finish(client.get_token_supply()?)?; + client.publish_did_output(&secret_manager_issuer, alias_output).await?; + + // We expect the verifiable credential to be revoked. + let mut resolver: Resolver = Resolver::new(); + resolver.attach_iota_handler(client); + let resolved_issuer_doc: AbstractThreadSafeValidatorDocument = + resolver.resolve_credential_issuer(&credential).await?; + + let validation_result = CredentialValidator::validate( + &credential, + &resolved_issuer_doc, + &CredentialValidationOptions::default(), + FailFast::FirstError, + ); + + println!("VC validation result: {:?}", validation_result); + assert!(validation_result.is_err()); + + println!("Credential successfully revoked!"); + + Ok(()) +} diff --git a/examples/Cargo.toml b/examples/Cargo.toml index e93c4a38b8..20204b7194 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -47,6 +47,10 @@ name = "5_create_vc" path = "0_basic/6_create_vp.rs" name = "6_create_vp" +[[example]] +path = "0_basic/7_revoke_vc.rs" +name = "7_revoke_vc" + [[example]] path = "1_advanced/0_did_controls_did.rs" name = "0_did_controls_did" From 6d801e8e2fe768719800881096c4b149aa0c9efb Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab Date: Tue, 15 Nov 2022 00:47:49 +0100 Subject: [PATCH 2/6] update readme --- bindings/wasm/examples/README.md | 3 ++- examples/README.md | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/bindings/wasm/examples/README.md b/bindings/wasm/examples/README.md index dbbd76f0f5..e1d6ccaf21 100644 --- a/bindings/wasm/examples/README.md +++ b/bindings/wasm/examples/README.md @@ -43,8 +43,9 @@ The following basic CRUD (Create, Read, Update, Delete) examples are available: | [2_resolve_did](src/0_basic/2_resolve_did.ts) | Demonstrates how to resolve an existing DID in an Alias Output. | | [3_deactivate_did](src/0_basic/3_deactivate_did.ts) | Demonstrates how to deactivate a DID in an Alias Output. | | [4_delete_did](src/0_basic/4_delete_did.ts) | Demonstrates how to delete a DID in an Alias Output, reclaiming the storage deposit. | -| [5_create_vc](src/0_basic/5_create_vc.ts) | Demonstrates how to create and verify verifiable credentials. | +| [5_create_vc](src/0_basic/5_create_vc.ts) | Demonstrates how to create and verify verifiable credentials. | | [6_create_vp](src/0_basic/6_create_vp.ts) | Demonstrates how to create and verify verifiable presentations. | +| [7_revoke_vc](src/0_basic/7_revoke_vc.ts) | Demonstrates how to revoke a verifiable credential. | ## Advanced Examples diff --git a/examples/README.md b/examples/README.md index 99479db44d..96f3642852 100644 --- a/examples/README.md +++ b/examples/README.md @@ -28,7 +28,8 @@ The following basic CRUD (Create, Read, Update, Delete) examples are available: | [3_deactivate_did](./0_basic/3_deactivate_did.rs) | Demonstrates how to deactivate a DID in an Alias Output. | | [4_delete_did](./0_basic/4_delete_did.rs) | Demonstrates how to delete a DID in an Alias Output, reclaiming the storage deposit. | | [5_create_vc](./0_basic/5_create_vc.rs) | Demonstrates how to create and verify verifiable credentials. | -| [4_create_vp](./0_basic/4_create_vp.rs) | Demonstrates how to create and verify verifiable presentations. | +| [6_create_vp](./0_basic/6_create_vp.rs) | Demonstrates how to create and verify verifiable presentations. | +| [7_revoke_vc](./0_basic/7_revoke_vc.rs) | Demonstrates how to revoke a verifiable credential. | ## Advanced Examples From 51fa84e24b2c0530dc1f94c828ec63991087ea63 Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab Date: Tue, 15 Nov 2022 13:06:04 +0100 Subject: [PATCH 3/6] add `revokeVC` to tests --- bindings/wasm/examples/src/tests/7_revoke_vc.ts | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 bindings/wasm/examples/src/tests/7_revoke_vc.ts diff --git a/bindings/wasm/examples/src/tests/7_revoke_vc.ts b/bindings/wasm/examples/src/tests/7_revoke_vc.ts new file mode 100644 index 0000000000..35debf79e6 --- /dev/null +++ b/bindings/wasm/examples/src/tests/7_revoke_vc.ts @@ -0,0 +1,8 @@ +import { revokeVC } from "../0_basic/7_revoke_vc"; + +// Only verifies that no uncaught exceptions are thrown, including syntax errors etc. +describe("Test node examples", function() { + it("Revoke VC", async () => { + await revokeVC(); + }); +}); From 62b793926b7c52a63cab3075908865125939695e Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab Date: Tue, 15 Nov 2022 17:13:20 +0100 Subject: [PATCH 4/6] verify credential before revoking it --- bindings/wasm/examples/src/0_basic/7_revoke_vc.ts | 5 ++++- examples/0_basic/7_revoke_vc.rs | 15 +++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/bindings/wasm/examples/src/0_basic/7_revoke_vc.ts b/bindings/wasm/examples/src/0_basic/7_revoke_vc.ts index afd368fe35..2dd6f578ca 100644 --- a/bindings/wasm/examples/src/0_basic/7_revoke_vc.ts +++ b/bindings/wasm/examples/src/0_basic/7_revoke_vc.ts @@ -89,7 +89,7 @@ export async function revokeVC() { credentialStatus: { id: issuerDocument.id() + "#my-revocation-service", type: RevocationBitmap.type(), - revocationBitmapIndex: CREDENTIAL_INDEX, + revocationBitmapIndex: CREDENTIAL_INDEX.toString(), }, issuer: issuerDocument.id(), credentialSubject: subject, @@ -99,6 +99,9 @@ export async function revokeVC() { let signedVc = issuerDocument.signCredential(unsignedVc, keypairIssuer.private(), "#key-1", ProofOptions.default()); console.log(`Credential JSON > ${JSON.stringify(signedVc, null, 2)}`); + // Validate the credential's signature using the issuer's DID Document. + CredentialValidator.validate(signedVc, issuerDocument, CredentialValidationOptions.default(), FailFast.AllErrors); + // =========================================================================== // Revocation of the Verifiable Credential. // =========================================================================== diff --git a/examples/0_basic/7_revoke_vc.rs b/examples/0_basic/7_revoke_vc.rs index 7b34ce926d..d48f20e62e 100644 --- a/examples/0_basic/7_revoke_vc.rs +++ b/examples/0_basic/7_revoke_vc.rs @@ -16,7 +16,6 @@ use examples::API_ENDPOINT; use identity_iota::core::json; use identity_iota::core::FromJson; use identity_iota::core::Url; -use identity_iota::credential::AbstractThreadSafeValidatorDocument; use identity_iota::credential::Credential; use identity_iota::credential::CredentialBuilder; use identity_iota::credential::CredentialValidationOptions; @@ -127,6 +126,15 @@ async fn main() -> anyhow::Result<()> { issuer_document.sign_data(&mut credential, key_pair.private(), "#key-1", ProofOptions::default())?; println!("Credential JSON > {:#}", credential); + // Validate the credential's signature using the issuer's DID Document. + CredentialValidator::validate( + &credential, + &issuer_document, + &CredentialValidationOptions::default(), + FailFast::FirstError, + ) + .unwrap(); + // =========================================================================== // Revocation of the Verifiable Credential. // =========================================================================== @@ -171,10 +179,9 @@ async fn main() -> anyhow::Result<()> { client.publish_did_output(&secret_manager_issuer, alias_output).await?; // We expect the verifiable credential to be revoked. - let mut resolver: Resolver = Resolver::new(); + let mut resolver: Resolver = Resolver::new(); resolver.attach_iota_handler(client); - let resolved_issuer_doc: AbstractThreadSafeValidatorDocument = - resolver.resolve_credential_issuer(&credential).await?; + let resolved_issuer_doc: IotaDocument = resolver.resolve_credential_issuer(&credential).await?; let validation_result = CredentialValidator::validate( &credential, From d6528f90a628a8aa4ba02bba66f3898a195a6df1 Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab Date: Tue, 15 Nov 2022 17:38:39 +0100 Subject: [PATCH 5/6] use return value --- examples/0_basic/7_revoke_vc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/0_basic/7_revoke_vc.rs b/examples/0_basic/7_revoke_vc.rs index d48f20e62e..e86b0c955b 100644 --- a/examples/0_basic/7_revoke_vc.rs +++ b/examples/0_basic/7_revoke_vc.rs @@ -81,7 +81,7 @@ async fn main() -> anyhow::Result<()> { "type": RevocationBitmap::TYPE, "serviceEndpoint": revocation_bitmap.to_endpoint()? }))?; - issuer_document.insert_service(service); + assert!(issuer_document.insert_service(service)); // Resolve the latest output and update it with the given document. let alias_output: AliasOutput = client.update_did_output(issuer_document.clone()).await?; From 98f150d630444032ff74de6feb45f0d11982d55c Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab Date: Tue, 15 Nov 2022 18:06:17 +0100 Subject: [PATCH 6/6] fix clippy --- examples/0_basic/7_revoke_vc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/0_basic/7_revoke_vc.rs b/examples/0_basic/7_revoke_vc.rs index e86b0c955b..874af3b0c0 100644 --- a/examples/0_basic/7_revoke_vc.rs +++ b/examples/0_basic/7_revoke_vc.rs @@ -81,7 +81,7 @@ async fn main() -> anyhow::Result<()> { "type": RevocationBitmap::TYPE, "serviceEndpoint": revocation_bitmap.to_endpoint()? }))?; - assert!(issuer_document.insert_service(service)); + assert!(issuer_document.insert_service(service).is_ok()); // Resolve the latest output and update it with the given document. let alias_output: AliasOutput = client.update_did_output(issuer_document.clone()).await?;