Try   HackMD

Implementing DID Indy

Discussion moved here:
Spec: Rendered/Github
Presentation and discussion in Indy Contributors Call

Approach

We started with implementing relevant changes to indy node. Although the NYM transaction is defined in Plenum we did not need to change Plenum yet, because the validation is not performed for some reason.

Clients (e.g. Indy SDK and Indy VDR) need (at least) to support the new buildNymRequest and buildGetNymRequest. This is an API change. In addtion a new DID focused API layer might be included or left to resolver library sitting on top of the client software.

In order to have a working PoC, we wrote a small server to resolve and update DIDs based on the current indy sdk and custom buildNymRequest and buildGetNymRequestfunctions.
The server can be used with an instance of von network running nodes with did:indy support.

Changes to Indy/Plenum Transactions

We added additional optional properties to NYM and GET_NYM transactions. Since these are optional and inside the operations object in a request, we might not need to change the protocol version or create new versions of transactions. But not sure about this.

NYM Transaction

Additional property in operation object: diddoc_content

NYM transactions are defined in Plenum. However, validation is currently not performed. Hence, we can add additional properties to the transaction without changes to Plenum. See this test. This needs further investigation. Validation should be performed.

GET_NYM Transaction

Additional properties in operation object:

  • timestamp [Int]
  • seqNo [Int]

See in Code

Changes to transaction handlers

NYM

DID Doc

If a transaction inlcudes diddoc_content there is additional static validation:

  • Must not have an id property
  • if @context is present, it must be a string or array and contain https://www.w3.org/ns/did/v1
  • No element in diddoc is allowed to have same id as verkey in base diddoc

Each check might throw an InvalidDIDDocException, but provides no reason currently.

Currently no exhaustive validation of the DID doc is performed. We might want to merge the diddoc_content with the base did doc (The base did doc is defined here but not used at the moment) and use pyDID to validate the complete DID document. Alternatively, we don't enforce this on server/node side and leave this to the client.

diddoc_content is directly added to the nym state and stored in the ledger. This might not be a good solution for large did docs as the content of an ATTRIB transaction is handled differently. See issue on Github.

Self-certifying identifier

If a new nym is written to the ledger a self-certification check is performed. This seems to break quite some tests in indy node, because there are many occassions where a trustee or steward creates a nym without a verkey. We've added an ENABLE_DID_INDY flag in the config to toggle the self-certification check. We need to check if and how we adapt/change the tests.

Code

GET NYM

We check for the additional properties seqNo and timestamp. If none of them are present, then we return the current state of the nym. Nothing has changed here except that the state might now contain a diddoc_content field.

Getting previous states by timestamp and seqNo

Because of the requirements for the revocation registry deltas, there's a mapping between time and state of the domain ledger. We can use this mapping to retrieve the state of a nym at a given timestamp. The relevant functionality is implemented in Plenum.

There seems to be no mapping between the sequence number and the state (Is this true?). Hence, we currently circumvent this by first retrieving the transaction by seqNo, parse the txnTime field and then use the timestamp to state mapping to get the state.

Code

Code without support of seqNo

Tests

Indy node uses indy sdk for tests. In order to perform tests for the new functionality, we added mock functions for buildNymRequest and buildGetNymRequest that are used in the relevant tests.

Relevant test files:

Proof of Concept

Network

VON Network with adapted Indy node image to build from feature/did-indy branch:
https://github.com/domwoe/von-network/tree/feature/did-indy

The Dockerfile for the indy node is here.

After changing code of indy node on the feature/did-indy branch you can create a new image with

python make_node_image.py --name indy-node did-indy  

in the von-image folder.

Starts also Indy DID Server described below.

Indy DID Server

The Indy DID Server is started with a trustee seed and provides two endpoints available at port 3000:

GET: /1.0/identifiers/:identifier

where identifier needs to be a fully qualified DID on the network, e.g. did:indy:sandbox:V4SGRU86Z58d6TV7PBUe6f.

Three different query parameters are supported, but only one can used at a time:

  • version_id: To get the DID Document at a specific version given by a sequence number.
  • version_time: To get the DID Document at a specific time given by a UNIX timestamp.
  • resource: If resource=true the raw nym data is returned

POST: /update

with payload:

{
    "diddoc": {...}
}

Only the update of the diddoc content of the trustee DID is supported (did:indy:sandbox:V4SGRU86Z58d6TV7PBUe6f).

The code is in Azure EoT Common.

How to start

git clone --single-branch --branch feature/did-indy https://github.com/domwoe/von-network
cd von-network
./manage build
./manage start

Indy DID server should be available at http://localhost:9001.

Development

I used the Devcontainer extension from VSCode to develop in a container with all the Indy dependencies.

The docker container is based on the image used by Github actions.

I needed to fix the installation of the Python VScode extension to an older version in order that discovering tests from vscode worked.

You can find my configuration here

I couldn't figure out how to debug properly and fell back to print statements
Print statements in tests can be captured using this method.