From 18a858398d907c28a7224702ffd87d77b57b8ecd Mon Sep 17 00:00:00 2001 From: Dave Longley Date: Sat, 17 Feb 2024 15:39:18 -0500 Subject: [PATCH] Store status lists metadata in each LMD item. --- lib/CredentialStatusWriter.js | 17 ++++++++--------- lib/IndexAllocationCache.js | 9 +++++---- lib/ListManager.js | 31 +++++++++++++++---------------- 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/lib/CredentialStatusWriter.js b/lib/CredentialStatusWriter.js index 6572b9bd..52b3f2a0 100644 --- a/lib/CredentialStatusWriter.js +++ b/lib/CredentialStatusWriter.js @@ -193,18 +193,17 @@ export class CredentialStatusWriter { this.listShard = shardQueue.shift(); } - // FIXME: multiple credential statuses may be added for this writer; - // iterate `item.` to add each one - const statusMeta = []; - - // FIXME: get N-many statuses to be written from `item` and upsert each one - - // 4. Use the SL ID and the IAD from the LS to add the SL ID and the next - // unassigned SL index to a VC's credential status section. + // 4. Use LS to get the status lists metadata and IAD. Use the SL metadata + // and the next unassigned SL index from the IAD add the appropriate + // information (based on list type) to a VC's credential status section. const { - item: {statusListCredential, listNumber: listNumber}, + item: {statusLists, listNumber: listNumber}, } = this.listShard; const statusListIndex = _getStatusListIndex({listShard: this.listShard}); + + // FIXME: get N-many statuses to be written from `item` and upsert each one + const statusMeta = []; + const statusListCredential = statusLists[0].id; const meta = this._upsertStatusEntry({ credential, listNumber, statusListCredential, statusListIndex, credentialStatus: existingCredentialStatus diff --git a/lib/IndexAllocationCache.js b/lib/IndexAllocationCache.js index 59e8b29b..fa2d6f45 100644 --- a/lib/IndexAllocationCache.js +++ b/lib/IndexAllocationCache.js @@ -47,11 +47,12 @@ this.selectShard(): Select an IAD to use for assigning indexes: */ export class IndexAllocationCache { - constructor({edvClient, statusListConfig} = {}) { + constructor({statusListConfig, edvClient} = {}) { + assert.object(statusListConfig, 'statusListConfig'); assert.object(edvClient, 'edvClient'); + this.statusListConfig = statusListConfig; this.edvClient = edvClient; this.records = []; - this.statusListConfig = statusListConfig; this.outOfSync = false; } @@ -78,7 +79,7 @@ export class IndexAllocationCache { // reset and store the block assignment doc associated with cache `record` async resetBlockAssignmentDoc({record} = {}) { - const {edvClient, statusListConfig} = this; + const {statusListConfig, edvClient} = this; const {content} = record.blockAssignmentDoc; await _initBlockAssignmentDoc({ content, slSequence: record.item.slSequence, statusListConfig @@ -209,7 +210,7 @@ export class IndexAllocationCache { // read BAD contents referenced from LM doc item into a cache record async _readBlockAssignmentDoc({item}) { - const {edvClient, statusListConfig} = this; + const {statusListConfig, edvClient} = this; // executes step 1.1 of `populate()` let blockAssignmentDoc; diff --git a/lib/ListManager.js b/lib/ListManager.js index 46a47cef..74ec4dd6 100644 --- a/lib/ListManager.js +++ b/lib/ListManager.js @@ -11,8 +11,6 @@ import {ListSource} from './ListSource.js'; status list (SL) indexes to VCs in a parallel fashion. This design enables multiple "workers" to assign SL indexes and issue VCs concurrently. -// FIXME: `BAD` description might need update if SL ID moves out of items - 1. A list management document (LMD) tracks index allocation state for one or more status lists and is identified by the `indexAllocator` value in a `statusListConfig`. Index allocation is tracked using blocks of indexes @@ -23,10 +21,9 @@ import {ListSource} from './ListSource.js'; to pool and reuse of documents in the backing database, and to enable certain non-atomic operations to be continuable, should they fail before completing. Each set item is a 3-tuple, a block assignment document (BAD) - ID, an SL ID that is exposed in VCs, and an SL sequence number that is kept - private and used to resolve conflicts. Each SL (including its ID and - sequence number) is only ever paired with a single BAD, and SL sequence - numbers monotonically increase. + ID, status list metadata that is exposed in VCs, and an SL sequence number + that is kept private and used to resolve conflicts. Each SL is only ever + paired with a single BAD, and SL sequence numbers monotonically increase. 2. An "active" BAD enables workers to find an index assignment document (IAD) to use to find unused SL indexes to assign to VCs. Once all of the indexes for the SLs associated with a BAD are assigned, its active set item is moved @@ -71,15 +68,19 @@ from corrupt state (misimplementation). main: The process for issuing a VC with an assigned an index. 0. The worker sets up an in-memory set of list shards (LS), where LS includes - an SL ID, SL sequence number, BAD, and IAD. + status list metadata, SL sequence number, BAD, and IAD. 1. Create a CredentialStatusWriter instance `writer`. 2. While a VC has not been successfully written to the database (EDV): 2.1. Call writer.write(VC). 2.2. Sign the VC. 2.3. Attempt to insert the VC in to the database (EDV). - 2.3.1. Note: The database must have a unique index on SL ID + SL index. + 2.3.1. Note: The database must have a unique index on credential status ID + (where the ID includes the list identifier and list index), even is that + credential status ID is not present in a VC, it needs to be present in + metadata about that VC (the latter is implemented here to enable VCs + to omit this ID). 2.4. If a duplicate error occurs, first make sure it is a duplicate error - due to SL ID + SL index, and if so, loop, otherwise throw. + due to credential status ID, and if so, loop, otherwise throw. 2. VC has been successfully issued, return it immediately, the receiver of the VC response does not need to wait for the following steps to finish. 3. Call writer.finish(). @@ -149,7 +150,7 @@ this._tryAddCapacity(cache, target): Try to add another active BAD if necessary 4.4. Otherwise, if no inactive BADs exist, create a new item with a new BAD ID, otherwise, remove the first inactive item for modification and mark `cache` as out-of-sync. - 4.5. Set the new active item's SL ID and SL sequence number and add it + 4.5. Set the new active item's status lists and SL sequence number and add it to the "active" set. 5. Initialize `added` to `false`. 6. Update LMD, setting `added` to `add` on success and marking @@ -264,7 +265,7 @@ export class ListManager { while(!this.activeCache) { // 1.1. Read all active BADs into an index allocation cache, `cache`. const {blockAssignment} = this.lmDoc.content; - const cache = new IndexAllocationCache({edvClient, statusListConfig}); + const cache = new IndexAllocationCache({statusListConfig, edvClient}); await cache.populate({items: blockAssignment.active}); // 1.2. If cache is out of sync, read the LMD and loop to 1. @@ -402,11 +403,9 @@ export class ListManager { cache.outOfSync = true; } - // 4.5. Set the new active item's SL ID and SL sequence number and add it - // to the "active" set. - // FIXME: determine how SLC IDs will be stored - // newActiveItem.statusLists = nextStatusLists; - newActiveItem.statusListCredential = nextStatusLists[0].id; + // 4.5. Set the new active item's status lists and SL sequence number and + // add it to the "active" set. + newActiveItem.statusLists = nextStatusLists; newActiveItem.slSequence = slSequence; blockAssignment.active.push(newActiveItem); }