public async Task CreatePairedAgentsWithRouting() { var pair = await InProcAgent.CreatePairedWithRoutingAsync(); var connections1 = await pair.Agent1.Connections.ListAsync(pair.Agent1.Context); var invitation1 = connections1.FirstOrDefault(x => x.State == ConnectionState.Invited); var connection1 = connections1.FirstOrDefault(x => x.Id != invitation1.Id); var connection2 = (await pair.Agent2.Connections.ListAsync(pair.Agent2.Context)).FirstOrDefault(); var provisioning1 = await pair.Agent1.Host.Services.GetRequiredService <IProvisioningService>() .GetProvisioningAsync(pair.Agent1.Context.Wallet); var provisioning2 = await pair.Agent2.Host.Services.GetRequiredService <IProvisioningService>() .GetProvisioningAsync(pair.Agent2.Context.Wallet); // Connections exist Assert.NotNull(invitation1); Assert.NotNull(connection1); Assert.NotNull(connection2); // The two connections are connected in the correct state Assert.Equal(ConnectionState.Connected, connection1.State); Assert.Equal(ConnectionState.Connected, connection2.State); // Check mediator and edge provisioning record states Assert.Equal(provisioning1.GetTag(MediatorProvisioningService.EdgeInvitationTagName), invitation1.Id); Assert.Equal(provisioning2.GetTag(EdgeProvisioningService.MediatorConnectionIdTagName), connection2.Id); }
public async Task InitializeAsync() { // Agent1 - Mediator // Agent2 - Edge Pair = await InProcAgent.CreatePairedWithRoutingAsync(); // WalletService = Pair.Agent2.Host.Services.GetRequiredService<IWalletService>(); EdgeClient = Pair.Agent2.Host.Services.GetRequiredService <IEdgeClientService>(); WalletService = Pair.Agent2.Host.Services.GetRequiredService <IWalletService>(); AgentOptions = Pair.Agent2.Host.Services.GetRequiredService <IOptions <AgentOptions> >().Value; EdgeContext = Pair.Agent2.Context; MediatorContext = Pair.Agent1.Context; }
public async Task IssueCredentialOverConnectionlessTransport() { var agents = await InProcAgent.CreatePairedAsync(false); var issuerProvisioningService = agents.Agent1.Host.Services.GetService <IProvisioningService>(); var issuerSchemaService = agents.Agent1.Host.Services.GetService <ISchemaService>(); var issuerCredentialService = agents.Agent1.Host.Services.GetService <ICredentialService>(); var issuerProvisioning = await issuerProvisioningService.GetProvisioningAsync(agents.Agent1.Context.Wallet); await PromoteTrustAnchor(issuerProvisioning.IssuerDid, issuerProvisioning.IssuerVerkey); var schemaId = await issuerSchemaService.CreateSchemaAsync( context : agents.Agent1.Context, issuerDid : issuerProvisioning.IssuerDid, name : $"test-schema-{Guid.NewGuid()}", version : "1.0", attributeNames : new[] { "test-attr" }); var credentialDefinitionId = await issuerSchemaService.CreateCredentialDefinitionAsync( context : agents.Agent1.Context, schemaId : schemaId, issuerDid : issuerProvisioning.IssuerDid, tag : "default", supportsRevocation : false, maxCredentialCount : 0, tailsBaseUri : new Uri("https://test")); var(offerMessage, issuerRecord) = await issuerCredentialService.CreateOfferAsync(agents.Agent1.Context, new OfferConfiguration { CredentialDefinitionId = credentialDefinitionId, CredentialAttributeValues = new [] { new CredentialPreviewAttribute("test-attr", "test-value") } }); Assert.NotNull(offerMessage.FindDecorator <ServiceDecorator>(DecoratorNames.ServiceDecorator)); Assert.Equal(CredentialState.Offered, issuerRecord.State); Assert.Null(issuerRecord.ConnectionId); var holderCredentialService = agents.Agent2.Host.Services.GetService <ICredentialService>(); var holderRecord = await holderCredentialService.CreateCredentialAsync(agents.Agent2.Context, offerMessage); issuerRecord = await issuerCredentialService.GetAsync(agents.Agent1.Context, issuerRecord.Id); Assert.NotNull(holderRecord); Assert.Equal(expected: CredentialState.Issued, actual: holderRecord.State); Assert.Equal(expected: CredentialState.Issued, actual: issuerRecord.State); Assert.NotNull(holderRecord.CredentialAttributesValues); Assert.Null(holderRecord.ConnectionId); }
public async Task CreateInProcAgentsAndConnect() { var agents = await InProcAgent.CreatePairedAsync(true); Assert.NotNull(agents.Agent1); Assert.NotNull(agents.Agent2); Assert.Equal(ConnectionState.Connected, agents.Connection1.State); Assert.Equal(ConnectionState.Connected, agents.Connection2.State); await agents.Agent1.DisposeAsync(); await agents.Agent2.DisposeAsync(); }
public async Task CreatePairedAgentsWithRoutingAndMetadata() { Dictionary <string, string> metaData = new Dictionary <string, string>() { { "tag", "value" } }; var pair = await InProcAgent.CreatePairedWithRoutingAsync(metaData); var connections1 = await pair.Agent1.Connections.ListAsync(pair.Agent1.Context); var invitation1 = connections1.FirstOrDefault(x => x.State == ConnectionState.Invited); var connection1 = connections1.FirstOrDefault(x => x.Id != invitation1.Id); var connection2 = (await pair.Agent2.Connections.ListAsync(pair.Agent2.Context)).FirstOrDefault(); var provisioning1 = await pair.Agent1.Host.Services.GetRequiredService <IProvisioningService>() .GetProvisioningAsync(pair.Agent1.Context.Wallet); var provisioning2 = await pair.Agent2.Host.Services.GetRequiredService <IProvisioningService>() .GetProvisioningAsync(pair.Agent2.Context.Wallet); // Connections exist invitation1.Should().NotBeNull(); connection1.Should().NotBeNull(); connection2.Should().NotBeNull(); // The two connections are connected in the correct state ConnectionState.Connected.Should().Be(connection1.State); ConnectionState.Connected.Should().Be(connection2.State); // Check mediator and edge provisioning record states provisioning1.GetTag(MediatorProvisioningService.EdgeInvitationTagName).Should().Be(invitation1.Id); provisioning2.GetTag(EdgeProvisioningService.MediatorConnectionIdTagName).Should().Be(connection2.Id); string inboxId = connection1.GetTag("InboxId"); IWalletRecordService recordService = pair.Agent1.Host.Services.GetRequiredService <IWalletRecordService>(); InboxRecord inboxRecord = await recordService.GetAsync <InboxRecord>(pair.Agent1.Context.Wallet, inboxId); inboxRecord.GetTag("tag").Should().Be(metaData["tag"]); }
public async Task TestCredentialIssuanceV1() { var pair = await InProcAgent.CreatePairedAsync(true); var credentialService1 = pair.Agent1.Provider.GetService <ICredentialService>(); var credentialService2 = pair.Agent2.Provider.GetService <ICredentialService>(); var proofService1 = pair.Agent1.Provider.GetService <IProofService>(); var proofService2 = pair.Agent2.Provider.GetService <IProofService>(); var context1 = pair.Agent1.Context; var context2 = pair.Agent2.Context; var messageService2 = pair.Agent2.Provider.GetService <IMessageService>(); var messageService1 = pair.Agent1.Provider.GetRequiredService <IMessageService>(); // Configure agent1 as issuer var issuerConfiguration = await pair.Agent1.Provider.GetRequiredService <IProvisioningService>() .GetProvisioningAsync(context1.Wallet); await PromoteTrustAnchor(issuerConfiguration.IssuerDid, issuerConfiguration.IssuerVerkey); var schemaId = await pair.Agent1.Provider.GetRequiredService <ISchemaService>() .CreateSchemaAsync( context: context1, issuerDid: issuerConfiguration.IssuerDid, name: $"test-schema-{Guid.NewGuid()}", version: "1.0", attributeNames: new[] { "name", "age" }); var definitionWithRevocationId = await pair.Agent1.Provider.GetRequiredService <ISchemaService>() .CreateCredentialDefinitionAsync( context: context1, new CredentialDefinitionConfiguration { SchemaId = schemaId, EnableRevocation = true, RevocationRegistryBaseUri = "http://localhost", Tag = "revoc" }); var definitionId = await pair.Agent1.Provider.GetRequiredService <ISchemaService>() .CreateCredentialDefinitionAsync( context: context1, new CredentialDefinitionConfiguration { SchemaId = schemaId, EnableRevocation = false, RevocationRegistryBaseUri = "http://localhost", Tag = "norevoc" }); // Send offer for two credentials var(offer, record) = await credentialService1 .CreateOfferAsync(context1, new OfferConfiguration { CredentialDefinitionId = definitionWithRevocationId, IssuerDid = issuerConfiguration.IssuerDid, CredentialAttributeValues = new[] { new CredentialPreviewAttribute("name", "random"), new CredentialPreviewAttribute("age", "22") } }); await messageService1.SendAsync(context1, offer, pair.Connection1); var issuerCredentialWithRevocationId = record.Id; (offer, record) = await credentialService1 .CreateOfferAsync(context1, new OfferConfiguration { CredentialDefinitionId = definitionId, IssuerDid = issuerConfiguration.IssuerDid, CredentialAttributeValues = new[] { new CredentialPreviewAttribute("name", "random"), new CredentialPreviewAttribute("age", "22") } }); await messageService1 .SendAsync(context1, offer, pair.Connection1); // Find credential for Agent 2 and accept all offers var credentials = await credentialService2.ListAsync(context2); foreach (var credential in credentials.Where(x => x.State == CredentialState.Offered)) { var(request, _) = await credentialService2.CreateRequestAsync(context2, credential.Id); await messageService2.SendAsync(context2, request, pair.Connection2); } // Issue credential credentials = await credentialService1.ListRequestsAsync(context1); foreach (var credential in credentials) { var(issue, _) = await credentialService1.CreateCredentialAsync(context1, credential.Id); await messageService1.SendAsync(context1, issue, pair.Connection1); } // Assert foreach (var credential in await credentialService1.ListAsync(context1)) { Assert.Equal(CredentialState.Issued, credential.State); } foreach (var credential in await credentialService2.ListAsync(context2)) { Assert.Equal(CredentialState.Issued, credential.State); } // Verification - without revocation var(requestPresentationMessage, proofRecordIssuer) = await proofService1 .CreateRequestAsync(context1, new ProofRequest { Name = "Test Verification", Version = "1.0", Nonce = await AnonCreds.GenerateNonceAsync(), RequestedAttributes = new Dictionary <string, ProofAttributeInfo> { { "id-verification", new ProofAttributeInfo { Names = new [] { "name", "age" } } } } }); var proofRecordHolder = await proofService2.ProcessRequestAsync(context2, requestPresentationMessage, pair.Connection2); var availableCredentials = await proofService2.ListCredentialsForProofRequestAsync(context2, proofRecordHolder.RequestJson.ToObject <ProofRequest>(), "id-verification"); var(presentationMessage, _) = await proofService2.CreatePresentationAsync( context2, proofRecordHolder.Id, new RequestedCredentials { RequestedAttributes = new Dictionary <string, RequestedAttribute> { { "id-verification", new RequestedAttribute { CredentialId = availableCredentials.First().CredentialInfo.Referent, Revealed = true } } } }); proofRecordIssuer = await proofService1.ProcessPresentationAsync(context1, presentationMessage); var valid = await proofService1.VerifyProofAsync(context1, proofRecordIssuer.Id); Assert.True(valid); // Verification - with revocation var now = (uint)DateTimeOffset.Now.ToUnixTimeSeconds(); (requestPresentationMessage, proofRecordIssuer) = await proofService1 .CreateRequestAsync(context1, new ProofRequest { Name = "Test Verification", Version = "1.0", Nonce = await AnonCreds.GenerateNonceAsync(), RequestedAttributes = new Dictionary <string, ProofAttributeInfo> { { "id-verification", new ProofAttributeInfo { Names = new [] { "name", "age" } } } }, NonRevoked = new RevocationInterval { From = 0, To = now } }); proofRecordHolder = await proofService2 .ProcessRequestAsync(context2, requestPresentationMessage, pair.Connection2); availableCredentials = await proofService2 .ListCredentialsForProofRequestAsync(context2, proofRecordHolder.RequestJson.ToObject <ProofRequest>(), "id-verification"); (presentationMessage, _) = await proofService2 .CreatePresentationAsync(context2, proofRecordHolder.Id, new RequestedCredentials { RequestedAttributes = new Dictionary <string, RequestedAttribute> { { "id-verification", new RequestedAttribute { CredentialId = availableCredentials.First().CredentialInfo.Referent, Revealed = true } } } }); proofRecordIssuer = await proofService1 .ProcessPresentationAsync(context1, presentationMessage); valid = await proofService1 .VerifyProofAsync(context1, proofRecordIssuer.Id); Assert.True(valid); Assert.False(await proofService2.IsRevokedAsync(context2, availableCredentials.First().CredentialInfo.Referent)); // Revoke the credential await pair.Agent1.Provider.GetService <ICredentialService>() .RevokeCredentialAsync(context1, issuerCredentialWithRevocationId); await Task.Delay(TimeSpan.FromSeconds(5)); now = (uint)DateTimeOffset.Now.ToUnixTimeSeconds(); (requestPresentationMessage, proofRecordIssuer) = await proofService1 .CreateRequestAsync(context1, new ProofRequest { Name = "Test Verification", Version = "1.0", Nonce = await AnonCreds.GenerateNonceAsync(), RequestedAttributes = new Dictionary <string, ProofAttributeInfo> { { "id-verification", new ProofAttributeInfo { Names = new [] { "name", "age" } } } }, NonRevoked = new RevocationInterval { From = 0, To = now } }); proofRecordHolder = await proofService2 .ProcessRequestAsync(context2, requestPresentationMessage, pair.Connection2); availableCredentials = await proofService2 .ListCredentialsForProofRequestAsync(context2, proofRecordHolder.RequestJson.ToObject <ProofRequest>(), "id-verification"); (presentationMessage, _) = await proofService2 .CreatePresentationAsync(context2, proofRecordHolder.Id, new RequestedCredentials { RequestedAttributes = new Dictionary <string, RequestedAttribute> { { "id-verification", new RequestedAttribute { CredentialId = availableCredentials.First().CredentialInfo.Referent, Revealed = true } } } }); proofRecordIssuer = await proofService1 .ProcessPresentationAsync(context1, presentationMessage); valid = await proofService1 .VerifyProofAsync(context1, proofRecordIssuer.Id); Assert.False(valid); Assert.True(await proofService2.IsRevokedAsync(context2, availableCredentials.First().CredentialInfo.Referent)); // Issue new credential after revoking previous one { (offer, record) = await credentialService1 .CreateOfferAsync(context1, new OfferConfiguration { CredentialDefinitionId = definitionWithRevocationId, IssuerDid = issuerConfiguration.IssuerDid, CredentialAttributeValues = new[] { new CredentialPreviewAttribute("name", "random"), new CredentialPreviewAttribute("age", "22") } }); await messageService1.SendAsync(context1, offer, pair.Connection1); string holderCredentialId = null; credentials = await credentialService2.ListAsync(context2); foreach (var credential in credentials.Where(x => x.State == CredentialState.Offered)) { var(request, _) = await credentialService2.CreateRequestAsync(context2, credential.Id); holderCredentialId = credential.Id; await messageService2.SendAsync(context2, request, pair.Connection2); } // Issue credential credentials = await credentialService1.ListRequestsAsync(context1); foreach (var credential in credentials) { var(issue, _) = await credentialService1.CreateCredentialAsync(context1, credential.Id); await messageService1.SendAsync(context1, issue, pair.Connection1); } await Task.Delay(TimeSpan.FromSeconds(15)); // Verify latest issued credential with non-revocation proof now = (uint)DateTimeOffset.Now.ToUnixTimeSeconds(); (requestPresentationMessage, proofRecordIssuer) = await proofService1 .CreateRequestAsync(context1, new ProofRequest { Name = "Test Verification", Version = "1.0", Nonce = await AnonCreds.GenerateNonceAsync(), RequestedAttributes = new Dictionary <string, ProofAttributeInfo> { { "id-verification", new ProofAttributeInfo { Names = new [] { "name", "age" } } } }, NonRevoked = new RevocationInterval { From = 0, To = now } }); proofRecordHolder = await proofService2.ProcessRequestAsync(context2, requestPresentationMessage, pair.Connection2); (presentationMessage, _) = await proofService2.CreatePresentationAsync( context2, proofRecordHolder.Id, new RequestedCredentials { RequestedAttributes = new Dictionary <string, RequestedAttribute> { { "id-verification", new RequestedAttribute { CredentialId = holderCredentialId, Revealed = true } } } }); proofRecordIssuer = await proofService1.ProcessPresentationAsync(context1, presentationMessage); valid = await proofService1.VerifyProofAsync(context1, proofRecordIssuer.Id); Assert.True(valid); } }
public async Task TestCredentialIssuanceV1() { var pair = await InProcAgent.CreatePairedAsync(true); // Configure agent1 as issuer var issuerConfiguration = await pair.Agent1.Provider.GetRequiredService <IProvisioningService>() .GetProvisioningAsync(pair.Agent1.Context.Wallet); await PromoteTrustAnchor(issuerConfiguration.IssuerDid, issuerConfiguration.IssuerVerkey); var schemaId = await pair.Agent1.Provider.GetRequiredService <ISchemaService>() .CreateSchemaAsync( context: pair.Agent1.Context, issuerDid: issuerConfiguration.IssuerDid, name: $"test-schema-{Guid.NewGuid().ToString()}", version: "1.0", attributeNames: new[] { "name" }); var definitionId = await pair.Agent1.Provider.GetRequiredService <ISchemaService>() .CreateCredentialDefinitionAsync( context: pair.Agent1.Context, schemaId: schemaId, issuerDid: issuerConfiguration.IssuerDid, tag: "tag", supportsRevocation: false, maxCredentialCount: 0, tailsBaseUri: new Uri("http://localhost")); // Send offer var(offer, record) = await pair.Agent1.Provider.GetRequiredService <ICredentialService>() .CreateOfferV1Async(pair.Agent1.Context, new OfferConfiguration { CredentialDefinitionId = definitionId, IssuerDid = issuerConfiguration.IssuerDid, CredentialAttributeValues = new [] { new CredentialPreviewAttribute { Name = "name", Value = "random", MimeType = CredentialMimeTypes.TextMimeType } } }); await pair.Agent1.Provider.GetRequiredService <IMessageService>() .SendAsync(pair.Agent1.Context.Wallet, offer, pair.Connection1); // Find credential for Agent 2 var credentials = await pair.Agent2.Provider.GetService <ICredentialService>() .ListAsync(pair.Agent2.Context); var credential = credentials.First(); // Accept the offer and send request var(request, _) = await pair.Agent2.Provider.GetService <ICredentialService>() .CreateRequestAsync(pair.Agent2.Context, credential.Id); await pair.Agent2.Provider.GetService <IMessageService>() .SendAsync(pair.Agent2.Context.Wallet, request, pair.Connection2); // Issue credential var(issue, _) = await pair.Agent1.Provider.GetRequiredService <ICredentialService>() .CreateCredentialAsync(pair.Agent1.Context, record.Id); await pair.Agent1.Provider.GetService <IMessageService>() .SendAsync(pair.Agent1.Context.Wallet, issue, pair.Connection1); // Assert var credentialHolder = await pair.Agent2.Provider.GetService <ICredentialService>() .GetAsync(pair.Agent2.Context, credential.Id); var credentialIssuer = await pair.Agent1.Provider.GetService <ICredentialService>() .GetAsync(pair.Agent1.Context, record.Id); Assert.Equal(CredentialState.Issued, credentialHolder.State); Assert.Equal(CredentialState.Issued, credentialIssuer.State); }
public async Task SendPaymentRequest() { // Create two agent hosts and establish pairwise connection between them var agents = await InProcAgent.CreatePairedAsync(true); // Get each agent payment address records var paymentAddress1 = await agents.Agent1.Payments.GetDefaultPaymentAddressAsync(agents.Agent1.Context); var paymentAddress2 = await agents.Agent2.Payments.GetDefaultPaymentAddressAsync(agents.Agent2.Context); // Internal reference number for this payment const string paymentReference = "INVOICE# 0001"; // Setup a basic use case for payments by using basic messages // Any AgentMessage can be used to attach payment requests and receipts var basicMessage = new BasicMessage { Content = "This is payment request" }; // Attach the payment request to the agent message var paymentRecord1 = await agents.Agent1.Payments.AttachPaymentRequestAsync( context : agents.Agent1.Context, agentMessage : basicMessage, details : new PaymentDetails { Id = paymentReference, Items = new List <PaymentItem> { new PaymentItem { Label = "Item 1", Amount = 8 }, new PaymentItem { Label = "Tax", Amount = 2 } }, Total = new PaymentItem { Amount = new PaymentAmount { Currency = "sov", Value = 10 }, Label = "Total" } }, payeeAddress : paymentAddress1); // PaymentRecord expectations Assert.NotNull(paymentRecord1); Assert.Equal(10UL, paymentRecord1.Amount); Assert.Equal(paymentAddress1.Address, paymentRecord1.Address); Assert.Equal(PaymentState.Requested, paymentRecord1.State); // Ensure the payment request is attached to the message var decorator = basicMessage.FindDecorator <PaymentRequestDecorator>("payment_request"); Assert.NotNull(decorator); // Send the message to agent 2 await agents.Agent1.Messages.SendAsync(agents.Agent1.Context.Wallet, basicMessage, agents.Connection1); // Find the payment record in the context of agent 2 var search = await agents.Agent2.Records.SearchAsync <PaymentRecord>( wallet : agents.Agent2.Context.Wallet, query : SearchQuery.And( SearchQuery.Equal(nameof(PaymentRecord.ReferenceId), paymentReference), SearchQuery.Equal(nameof(PaymentRecord.ConnectionId), agents.Connection2.Id))); var paymentRecord2 = search.FirstOrDefault(); Assert.Single(search); Assert.NotNull(paymentRecord2); Assert.Equal(PaymentState.RequestReceived, paymentRecord2.State); // Fund payment address of agent 2 so we can make payment to agent 1 await FundAccountAsync(50UL, paymentAddress2.Address); // Refresh balance to ensure it is funded correctly await agents.Agent2.Payments.RefreshBalanceAsync(agents.Agent2.Context, paymentAddress2); Assert.Equal(50UL, paymentAddress2.Balance); // Make payment for received request await agents.Agent2.Payments.MakePaymentAsync(agents.Agent2.Context, paymentRecord2, paymentAddress2); Assert.Equal(PaymentState.Paid, paymentRecord2.State); Assert.Equal(40UL, paymentAddress2.Balance); Assert.NotNull(paymentRecord2.ReceiptId); // Send a basic message back to agent 1 and attach a payment receipt var message2 = new BasicMessage { Content = "Here's a receipt" }; // Attach a payment receipt to the basic message // Receipts can be attached to any agent message agents.Agent2.Payments.AttachPaymentReceipt(agents.Agent2.Context, message2, paymentRecord2); // Send the message to agent 1 await agents.Agent2.Messages.SendAsync(agents.Agent2.Context.Wallet, message2, agents.Connection2); // Fetch payment record 1 again, to refresh state paymentRecord1 = await agents.Agent1.Records.GetAsync <PaymentRecord>(agents.Agent1.Context.Wallet, paymentRecord1.Id); // Check payment record 1 for receipt Assert.Equal(PaymentState.ReceiptReceived, paymentRecord1.State); Assert.NotNull(paymentRecord1.ReceiptId); // Check agent 1 balance await agents.Agent1.Payments.RefreshBalanceAsync(agents.Agent1.Context, paymentAddress1); Assert.Equal(10UL, paymentAddress1.Balance); // Verify the payment receipt on the ledger var verified = await agents.Agent1.Payments.VerifyPaymentAsync(agents.Agent1.Context, paymentRecord1); Assert.True(verified); // Clean things up and shut down hosts gracefully await agents.Agent1.DisposeAsync(); await agents.Agent2.DisposeAsync(); }
public async Task CreateCredentialAndAutoScaleRevocationRegistry() { var agents = await InProcAgent.CreatePairedAsync(false); var issuerProvisioningService = agents.Agent1.Host.Services.GetService <IProvisioningService>(); var issuerSchemaService = agents.Agent1.Host.Services.GetService <ISchemaService>(); var issuerCredentialService = agents.Agent1.Host.Services.GetService <ICredentialService>(); var issuerProvisioning = await issuerProvisioningService.GetProvisioningAsync(agents.Agent1.Context.Wallet); await PromoteTrustAnchor(issuerProvisioning.IssuerDid, issuerProvisioning.IssuerVerkey); var schemaId = await issuerSchemaService.CreateSchemaAsync( context : agents.Agent1.Context, issuerDid : issuerProvisioning.IssuerDid, name : $"test-schema-{Guid.NewGuid()}", version : "1.0", attributeNames : new[] { "test-attr" }); string revocationRegistryId1 = null; string revocationRegistryId2 = null; string revocationRegistryId3 = null; var credentialDefinitionId = await issuerSchemaService.CreateCredentialDefinitionAsync( context : agents.Agent1.Context, new CredentialDefinitionConfiguration { SchemaId = schemaId, EnableRevocation = true, RevocationRegistrySize = 1, RevocationRegistryBaseUri = "https://test" }); // First credential - will max out the registry { var(offerMessage, issuerRecord) = await issuerCredentialService.CreateOfferAsync(agents.Agent1.Context, new OfferConfiguration { CredentialDefinitionId = credentialDefinitionId, CredentialAttributeValues = new[] { new CredentialPreviewAttribute("test-attr", "test-value") } }); Assert.NotNull(offerMessage.FindDecorator <ServiceDecorator>(DecoratorNames.ServiceDecorator)); Assert.Equal(CredentialState.Offered, issuerRecord.State); Assert.Null(issuerRecord.ConnectionId); var holderCredentialService = agents.Agent2.Host.Services.GetService <ICredentialService>(); var holderRecord = await holderCredentialService.CreateCredentialAsync(agents.Agent2.Context, offerMessage); issuerRecord = await issuerCredentialService.GetAsync(agents.Agent1.Context, issuerRecord.Id); var definitionRecord = await agents.Agent1.Host.Services.GetService <ISchemaService>().GetCredentialDefinitionAsync(agents.Agent1.Context.Wallet, credentialDefinitionId); Assert.NotNull(holderRecord); Assert.Equal(expected: CredentialState.Issued, actual: holderRecord.State); Assert.Equal(expected: CredentialState.Issued, actual: issuerRecord.State); Assert.NotNull(holderRecord.CredentialAttributesValues); Assert.Null(holderRecord.ConnectionId); Assert.Equal(definitionRecord.CurrentRevocationRegistryId, issuerRecord.RevocationRegistryId); Assert.Equal(definitionRecord.CurrentRevocationRegistryId, holderRecord.RevocationRegistryId); revocationRegistryId1 = definitionRecord.CurrentRevocationRegistryId; } // Second credential, will auto scale registry { var(offerMessage, issuerRecord) = await issuerCredentialService.CreateOfferAsync(agents.Agent1.Context, new OfferConfiguration { CredentialDefinitionId = credentialDefinitionId, CredentialAttributeValues = new[] { new CredentialPreviewAttribute("test-attr", "test-value") } }); Assert.NotNull(offerMessage.FindDecorator <ServiceDecorator>(DecoratorNames.ServiceDecorator)); Assert.Equal(CredentialState.Offered, issuerRecord.State); Assert.Null(issuerRecord.ConnectionId); var holderCredentialService = agents.Agent2.Host.Services.GetService <ICredentialService>(); var holderRecord = await holderCredentialService.CreateCredentialAsync(agents.Agent2.Context, offerMessage); issuerRecord = await issuerCredentialService.GetAsync(agents.Agent1.Context, issuerRecord.Id); var definitionRecord = await agents.Agent1.Host.Services.GetService <ISchemaService>().GetCredentialDefinitionAsync(agents.Agent1.Context.Wallet, credentialDefinitionId); Assert.NotNull(holderRecord); Assert.Equal(expected: CredentialState.Issued, actual: holderRecord.State); Assert.Equal(expected: CredentialState.Issued, actual: issuerRecord.State); Assert.NotNull(holderRecord.CredentialAttributesValues); Assert.Null(holderRecord.ConnectionId); Assert.Equal(definitionRecord.CurrentRevocationRegistryId, issuerRecord.RevocationRegistryId); Assert.Equal(definitionRecord.CurrentRevocationRegistryId, holderRecord.RevocationRegistryId); revocationRegistryId2 = definitionRecord.CurrentRevocationRegistryId; } // Third credential, will auto scale registry { var(offerMessage, issuerRecord) = await issuerCredentialService.CreateOfferAsync(agents.Agent1.Context, new OfferConfiguration { CredentialDefinitionId = credentialDefinitionId, CredentialAttributeValues = new[] { new CredentialPreviewAttribute("test-attr", "test-value") } }); Assert.NotNull(offerMessage.FindDecorator <ServiceDecorator>(DecoratorNames.ServiceDecorator)); Assert.Equal(CredentialState.Offered, issuerRecord.State); Assert.Null(issuerRecord.ConnectionId); var holderCredentialService = agents.Agent2.Host.Services.GetService <ICredentialService>(); var holderRecord = await holderCredentialService.CreateCredentialAsync(agents.Agent2.Context, offerMessage); issuerRecord = await issuerCredentialService.GetAsync(agents.Agent1.Context, issuerRecord.Id); var definitionRecord = await agents.Agent1.Host.Services.GetService <ISchemaService>().GetCredentialDefinitionAsync(agents.Agent1.Context.Wallet, credentialDefinitionId); Assert.NotNull(holderRecord); Assert.Equal(expected: CredentialState.Issued, actual: holderRecord.State); Assert.Equal(expected: CredentialState.Issued, actual: issuerRecord.State); Assert.NotNull(holderRecord.CredentialAttributesValues); Assert.Null(holderRecord.ConnectionId); Assert.Equal(definitionRecord.CurrentRevocationRegistryId, issuerRecord.RevocationRegistryId); Assert.Equal(definitionRecord.CurrentRevocationRegistryId, holderRecord.RevocationRegistryId); revocationRegistryId3 = definitionRecord.CurrentRevocationRegistryId; } Assert.NotEqual(revocationRegistryId1, revocationRegistryId2); Assert.NotEqual(revocationRegistryId2, revocationRegistryId3); Assert.NotEqual(revocationRegistryId1, revocationRegistryId3); }