Skip to content

Commit

Permalink
Parametrize issuance with rev reg (#491)
Browse files Browse the repository at this point in the history
* Parametrize issuance with rev reg
* Update rustc version
* Expose get tails hash on rev reg
* Add vcx_revocation_registry_publish_revocations
* Remove callback argument to rev reg release

Signed-off-by: Miroslav Kovar <[email protected]>

Co-authored-by: Miroslav Kovar <[email protected]>
  • Loading branch information
mirgee and mirgee authored Jun 7, 2022
1 parent a4c434f commit c8c0a51
Show file tree
Hide file tree
Showing 28 changed files with 1,165 additions and 53 deletions.
1 change: 1 addition & 0 deletions agents/node/vcxagent-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"demo:faber:verify": "node demo/faber-verify-signature.js",
"test:integration": "npm run test:integration:update-state && npm run test:integration:signing && npm run test:integration:messaging && npm run test:integration:tails && npm run test:integration:trustping && npm run test:integration:feature-discovery && npm run test:integration:public-invite && npm run test:integration:out-of-band",
"test:integration:update-state": "jest --forceExit --env=node --runInBand test/update-state-v2.spec.js",
"test:integration:cred-def": "jest --forceExit --env=node --runInBand test/credential-def-v2.spec.js",
"test:integration:signing": "jest --forceExit --env=node --runInBand test/sign-verify.spec.js",
"test:integration:messaging": "jest --forceExit --env=node --runInBand test/sign-messaging.spec.js",
"test:integration:tails": "jest --forceExit --env=node --runInBand test/distribute-tails.spec.js",
Expand Down
9 changes: 9 additions & 0 deletions agents/node/vcxagent-core/src/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const { createServiceCredIssuer } = require('./services/service-cred-issuer')
const { createServiceConnections } = require('./services/service-connections')
const { createServicePublicAgents } = require('./services/service-public-agents')
const { createServiceOutOfBand } = require('./services/service-out-of-band')
const { createServiceLedgerRevocationRegistry } = require('./services/service-revocation-registry')
const { provisionAgentInAgency } = require('./utils/vcx-workflows')
const {
initThreadpool,
Expand Down Expand Up @@ -91,10 +92,17 @@ async function createVcxAgent ({ agentName, genesisPath, agencyUrl, seed, wallet
loadCredDef: storageService.loadCredentialDefinition,
listCredDefIds: storageService.listCredentialDefinitionKeys
})
const serviceLedgerRevReg = createServiceLedgerRevocationRegistry({
logger,
saveRevReg: storageService.saveRevocationRegistry,
loadRevReg: storageService.loadRevocationRegistry,
listCredDefIds: storageService.listCredentialDefinitionKeys
})
const serviceCredIssuer = createServiceCredIssuer({
logger,
loadConnection: storageService.loadConnection,
loadCredDef: storageService.loadCredentialDefinition,
loadRevReg: storageService.loadRevocationRegistry,
saveIssuerCredential: storageService.saveCredIssuer,
loadIssuerCredential: storageService.loadCredIssuer,
listIssuerCredentialIds: storageService.listCredIssuerKeys,
Expand Down Expand Up @@ -143,6 +151,7 @@ async function createVcxAgent ({ agentName, genesisPath, agencyUrl, seed, wallet
// ledger
serviceLedgerSchema,
serviceLedgerCredDef,
serviceLedgerRevReg,

// connections
serviceConnections,
Expand Down
25 changes: 24 additions & 1 deletion agents/node/vcxagent-core/src/services/service-cred-issuer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ const {
IssuerCredential
} = require('@hyperledger/node-vcx-wrapper')
const { pollFunction } = require('../common')
const assert = require('assert')

module.exports.createServiceCredIssuer = function createServiceCredIssuer ({ logger, loadConnection, loadCredDef, saveIssuerCredential, loadIssuerCredential, listIssuerCredentialIds, issuerDid }) {
module.exports.createServiceCredIssuer = function createServiceCredIssuer ({ logger, loadConnection, loadCredDef, loadRevReg, saveIssuerCredential, loadIssuerCredential, listIssuerCredentialIds, issuerDid }) {
async function buildOfferAndMarkAsSent (issuerCredId, credDefId, schemaAttrs) {
const credDef = await loadCredDef(credDefId)
logger.debug('Building issuer credential')
Expand Down Expand Up @@ -39,6 +40,27 @@ module.exports.createServiceCredIssuer = function createServiceCredIssuer ({ log
await saveIssuerCredential(issuerCredId, issuerCred)
}

async function sendOfferV2 (issuerCredId, revRegId, connectionId, credDefId, schemaAttrs) {
assert(revRegId)
const connection = await loadConnection(connectionId)
const credDef = await loadCredDef(credDefId)
const revReg = revRegId ? await loadRevReg(revRegId) : undefined
logger.debug('Building issuer credential')
const issuerCred = await IssuerCredential.create('alice_degree')
logger.info(`Per issuer credential ${issuerCredId}, sending cred offer to connection ${connectionId}`)
await issuerCred.buildCredentialOfferMsgV2({
credDef,
attr: schemaAttrs,
revReg
})
const state1 = await issuerCred.getState()
expect(state1).toBe(IssuerStateType.OfferSet)
await issuerCred.sendOfferV2(connection)
const state2 = await issuerCred.getState()
expect(state2).toBe(IssuerStateType.OfferSent)
await saveIssuerCredential(issuerCredId, issuerCred)
}

async function sendCredential (issuerCredId, connectionId) {
const connection = await loadConnection(connectionId)
const issuerCred = await loadIssuerCredential(issuerCredId)
Expand Down Expand Up @@ -139,6 +161,7 @@ module.exports.createServiceCredIssuer = function createServiceCredIssuer ({ log

return {
sendOffer,
sendOfferV2,
buildOfferAndMarkAsSent,
sendOfferAndWaitForCredRequest,
sendCredential,
Expand Down
25 changes: 24 additions & 1 deletion agents/node/vcxagent-core/src/services/service-ledger-creddef.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,21 @@ module.exports.createServiceLedgerCredDef = function createServiceLedgerCredDef
return credDef
}

async function createCredentialDefinitionV2 (schemaId, credDefId, supportRevocation, tag = 'tag1') {
const data = {
supportRevocation,
schemaId,
sourceId: credDefId,
tag
}
logger.info(`Creating a new credential definition on the ledger from input: ${JSON.stringify(data)}`)
const credDef = await CredentialDef.create(data)
await credDef.publish()
await saveCredDef(credDefId, credDef)
logger.info(`Created credentialDefinition ${credDefId}.`)
return credDef
}

async function listIds () {
return listCredDefIds()
}
Expand All @@ -40,11 +55,19 @@ module.exports.createServiceLedgerCredDef = function createServiceLedgerCredDef
return credDef.getTailsHash()
}

async function getCredDefId (credDefId) {
const credDef = await loadCredDef(credDefId)
logger.info(`Getting credDefId for credential definition ${credDefId}`)
return credDef.getCredDefId()
}

return {
createCredentialDefinition,
createCredentialDefinitionV2,
listIds,
printInfo,
getTailsFile,
getTailsHash
getTailsHash,
getCredDefId
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
const { RevocationRegistry } = require('@hyperledger/node-vcx-wrapper')

module.exports.createServiceLedgerRevocationRegistry = function createServiceLedgerRevocationRegistry ({ logger, saveRevReg, loadRevReg, listRevRegIds }) {
async function createRevocationRegistry (issuerDid, credDefId, tag, tailsDir, maxCreds, tailsUrl = 'dummy.org') {
const data = {
issuerDid,
credDefId,
tag,
tailsDir,
maxCreds
}
const revReg = await RevocationRegistry.create(data)
await revReg.publish(tailsUrl)
const revRegId = await revReg.getRevRegId()
await saveRevReg(revRegId, revReg)
return { revReg, revRegId }
}

async function rotateRevocationRegistry (revRegId, maxCreds, tailsUrl = 'dummy.org') {
logger.info(`Rotating revocation registry ${revRegId}, maxCreds ${maxCreds}`)
const revReg = await loadRevReg(revRegId)
let newRevReg
try {
newRevReg = await revReg.rotate(maxCreds)
await newRevReg.publish(tailsUrl)
} catch (err) {
throw Error(`Error rotating revocation registry ${revRegId}: ${err}`)
}
const newRevRegId = await newRevReg.getRevRegId()
await saveRevReg(newRevRegId, newRevReg)
logger.info(`Revocation registry ${revRegId} rotated, new rev reg id ${newRevRegId}`)
return { revReg: newRevReg, revRegId: newRevRegId }
}

return {
createRevocationRegistry,
rotateRevocationRegistry
}
}
24 changes: 24 additions & 0 deletions agents/node/vcxagent-core/src/storage/storage-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const {
Credential,
IssuerCredential,
CredentialDef,
RevocationRegistry,
Schema,
DisclosedProof,
Proof,
Expand All @@ -15,6 +16,7 @@ async function createStorageService (agentName) {
mkdirp.sync('storage-agentProvisions/')
mkdirp.sync('storage-connections/')
mkdirp.sync('storage-credentialDefinitions/')
mkdirp.sync('storage-revocationRegistries/')
mkdirp.sync('storage-schemas/')

const storageAgentProvisions = await createFileStorage(`storage-agentProvisions/${agentName}`)
Expand All @@ -24,6 +26,7 @@ async function createStorageService (agentName) {
const storageProof = await createFileStorage(`storage-proofs/${agentName}`)
const storageDisclosedProof = await createFileStorage(`storage-dislosedProofs/${agentName}`)
const storageCredentialDefinitons = await createFileStorage(`storage-credentialDefinitions/${agentName}`)
const storageRevocationRegistries = await createFileStorage(`storage-revocationRegistries/${agentName}`)
const storageSchemas = await createFileStorage(`storage-schemas/${agentName}`)
const storageAgents = await createFileStorage(`storage-agents/${agentName}`)

Expand Down Expand Up @@ -78,6 +81,19 @@ async function createStorageService (agentName) {
return CredentialDef.deserialize(serialized)
}

async function saveRevocationRegistry (name, revReg) {
const serialized = await revReg.serialize()
await storageRevocationRegistries.set(name, serialized)
}

async function loadRevocationRegistry (name) {
const serialized = await storageRevocationRegistries.get(name)
if (!serialized) {
throw Error(`RevocationRegistry ${name} was not found.`)
}
return RevocationRegistry.deserialize(serialized)
}

async function saveCredIssuer (name, credIssuer) {
const serialized = await credIssuer.serialize()
await storageCredIssuer.set(name, serialized)
Expand Down Expand Up @@ -155,6 +171,10 @@ async function createStorageService (agentName) {
return storageCredentialDefinitons.keys()
}

async function listRevocationRegistryKeys () {
return storageRevocationRegistries.keys()
}

async function listCredIssuerKeys () {
return storageCredIssuer.keys()
}
Expand Down Expand Up @@ -185,6 +205,9 @@ async function createStorageService (agentName) {
saveCredentialDefinition,
loadCredentialDefinition,

saveRevocationRegistry,
loadRevocationRegistry,

saveCredIssuer,
loadCredIssuer,

Expand All @@ -203,6 +226,7 @@ async function createStorageService (agentName) {
listConnectionKeys,
listSchemaKeys,
listCredentialDefinitionKeys,
listRevocationRegistryKeys,
listCredIssuerKeys,
listCredHolderKeys,
listDisclosedProofKeys,
Expand Down
42 changes: 42 additions & 0 deletions agents/node/vcxagent-core/test/credential-def-v2.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* eslint-env jest */
require('jest')
const { createPairedAliceAndFaber } = require('./utils/utils')
const { initRustapi } = require('../src/index')
const { IssuerStateType, HolderStateType, ProverStateType, VerifierStateType } = require('@hyperledger/node-vcx-wrapper')
const sleep = require('sleep-promise')

beforeAll(async () => {
jest.setTimeout(1000 * 60 * 4)
try {
await initRustapi(process.env.VCX_LOG_LEVEL || 'vcx=warn,aries_vcx=warn')
} catch (err) {
console.error(`ERROR: ${err}`)
}
})

describe('test send credential', () => {
it('Faber should send valid credential to Alice', async () => {
try {
const { alice, faber } = await createPairedAliceAndFaber()
const tailsDir = `${__dirname}/tmp/faber/tails`
await faber.buildLedgerPrimitivesV2({ tailsDir, maxCreds: 5 })
await faber.rotateRevReg(5)
await faber.sendCredentialOfferV2()
await alice.acceptCredentialOffer()

await faber.updateStateCredentialV2(IssuerStateType.RequestReceived)
await faber.sendCredential()
await alice.updateStateCredentialV2(HolderStateType.Finished)
await faber.receiveCredentialAck()

const request = await faber.requestProofFromAlice()
await alice.sendHolderProof(JSON.parse(request), revRegId => tailsDir)
await faber.updateStateVerifierProofV2(VerifierStateType.Finished)
await alice.updateStateHolderProofV2(ProverStateType.Finished)
} catch (err) {
console.error(`err = ${err.message} stack = ${err.stack}`)
await sleep(2000)
throw Error(err)
}
})
})
48 changes: 47 additions & 1 deletion agents/node/vcxagent-core/test/utils/faber.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module.exports.createFaber = async function createFaber () {
const connectionId = 'connection-faber-to-alice'
const issuerCredId = 'credential-for-alice'
const agentId = 'faber-public-agent'
let credDefId
let credDefId, revRegId
const proofId = 'proof-from-alice'
const logger = require('../../demo/logger')('Faber')

Expand Down Expand Up @@ -167,13 +167,56 @@ module.exports.createFaber = async function createFaber () {
await vcxAgent.agentShutdownVcx()
}

async function buildLedgerPrimitivesV2 (revocationDetails) {
await vcxAgent.agentInitVcx()

logger.info('Faber writing schema on ledger')
const schemaId = await vcxAgent.serviceLedgerSchema.createSchema(getSampleSchemaData())
await sleep(500)

logger.info('Faber writing credential definition on ledger')
const supportRevocation = !!revocationDetails
await vcxAgent.serviceLedgerCredDef.createCredentialDefinitionV2(
schemaId,
getFaberCredDefName(),
supportRevocation
)
credDefId = getFaberCredDefName()
const _credDefId = await vcxAgent.serviceLedgerCredDef.getCredDefId(credDefId)
if (supportRevocation) {
const { tailsDir, maxCreds } = revocationDetails
logger.info('Faber writing revocation registry');
({ revRegId } = await vcxAgent.serviceLedgerRevReg.createRevocationRegistry(institutionDid, _credDefId, 1, tailsDir, maxCreds))
}
await vcxAgent.agentShutdownVcx()
}

async function rotateRevReg (maxCreds) {
await vcxAgent.agentInitVcx()

logger.info('Faber rotating revocation registry');
({ revRegId } = await vcxAgent.serviceLedgerRevReg.rotateRevocationRegistry(revRegId, maxCreds))

await vcxAgent.agentShutdownVcx()
}

async function sendCredentialOffer () {
await vcxAgent.agentInitVcx()
const schemaAttrs = getAliceSchemaAttrs()
await vcxAgent.serviceCredIssuer.sendOffer(issuerCredId, connectionId, credDefId, schemaAttrs)
await vcxAgent.agentShutdownVcx()
}

async function sendCredentialOfferV2 () {
await vcxAgent.agentInitVcx()

logger.info('Issuer sending credential offer')
const schemaAttrs = getAliceSchemaAttrs()
await vcxAgent.serviceCredIssuer.sendOfferV2(issuerCredId, revRegId, connectionId, credDefId, schemaAttrs)
logger.debug('Credential offer sent')

await vcxAgent.agentShutdownVcx()
}
async function updateStateCredentialV2 (expectedState) {
await vcxAgent.agentInitVcx()

Expand Down Expand Up @@ -318,6 +361,8 @@ module.exports.createFaber = async function createFaber () {

return {
buildLedgerPrimitives,
buildLedgerPrimitivesV2,
rotateRevReg,
createCredDef,
downloadReceivedMessages,
downloadReceivedMessagesV2,
Expand All @@ -332,6 +377,7 @@ module.exports.createFaber = async function createFaber () {
updateConnection,
sendConnectionResponse,
sendCredentialOffer,
sendCredentialOfferV2,
createOobCredOffer,
updateStateCredentialV2,
sendCredential,
Expand Down
Loading

0 comments on commit c8c0a51

Please sign in to comment.