Skip to content

Commit cbcaade

Browse files
authored
Merge pull request #1 from AmplicaLabs/feature/use-schema-names
Use schema names functionality from @dsnp/frequency-schemas.
2 parents 0069d3e + 9462525 commit cbcaade

File tree

7 files changed

+615
-810
lines changed

7 files changed

+615
-810
lines changed

.env.example

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# Environment variables for testnet
22
FREQUENCY_NODE="wss://rpc.rococo.frequency.xyz"
3-
FREQUENCY_NETWORK="testnet"
43

5-
# If running locally, use these instead
4+
# If running locally, use this instead
65
#FREQUENCY_NODE="ws://127.0.0.1:9944"
7-
#FREQUENCY_NETWORK="local"

README.md

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,34 +17,29 @@ import { FrequencyResolver } from "@dsnp/did-resolver-frequency";
1717
1818
const frequencyResolver = new FrequencyResolver({
1919
providerUri: "ws://127.0.0.1:9944",
20-
frequencyNetwork: "local",
2120
});
2221
```
2322

2423
If constructed this way, you must call `disconnect()` to explicitly release the connection; the process will not exit if this is not done.
2524

2625
or,
2726

28-
2. Construct with preconfigured `ApiPromise` object from `@polkadot/api`:
27+
2. Construct with preconfigured `Promise<ApiPromise>` object from `@polkadot/api`:
2928

3029
```
3130
import { FrequencyResolver } from "@dsnp/did-resolver-frequency";
3231
3332
const frequencyResolver = new FrequencyResolver({
3433
apiPromise: myApiPromise, // from ApiPromise.create(...)
35-
frequencyNetwork: "local",
3634
});
3735
```
3836

39-
The `frequencyNetwork` key is required in both cases (this is expected to be unnecessary with Frequency schema naming in the future).
40-
4137
Summary of options:
4238

4339
| Configuration option | Description |
4440
| --- | --- |
4541
| `providerUri` | Provider URI for Frequency RPC node (optional; alternative to `apiPromise` |
46-
| `apiPromise` | An `ApiPromise` object (optional; alternative to `providerUri` |
47-
| `frequencyNetwork` | One of `local`, `testnet`, `mainnet` |
42+
| `apiPromise` | A `Promise<ApiPromise>` (optional; alternative to `providerUri` |
4843

4944
See `.env.example` for example configuration.
5045

@@ -56,7 +51,6 @@ import dsnp from "@dsnp/did-resolver";
5651
5752
const frequencyResolver = new FrequencyResolver({
5853
providerUri: "wss://rpc.rococo.frequency.xyz",
59-
frequencyNetwork: "testnet"
6054
});
6155
6256
const resolver = new Resolver(dsnp.getResolver([frequencyResolver]));
@@ -111,8 +105,3 @@ Currently this resolver implements the minimal functionality required to support
111105
Public keys are encoded using the `Multikey` type.
112106
The `id` consists of the DSNP DID and a URL fragment that is the same as the `publicKeyMultibase` value, which is a multicodec value in `base58btc` encoding.
113107
The decoded value for `ed25519-pub` keys will be 34 bytes, including the two-byte multicodec identifier.
114-
115-
## Known issues
116-
117-
- The resolver currently responds with a DID document for any valid-looking DSNP DID.
118-
It should return a `notFound` error if there is no corresponding Frequency MSA.

index.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ describe("dsnp-did-resolver-frequency", () => {
77
it("can be constructed with providerUri", async () => {
88
const resolver = new FrequencyResolver({
99
providerUri: "ws://127.0.0.1:9944",
10-
frequencyNetwork: "local",
1110
});
1211

1312
await resolver.disconnect();
1413
});
1514

15+
/* TODO needs mocking
1616
it("can be constructed with apiPromise", async () => {
1717
const apiPromise = ApiPromise.create({
1818
provider: new WsProvider("ws://127.0.0.1:9944"),
@@ -22,13 +22,13 @@ describe("dsnp-did-resolver-frequency", () => {
2222
2323
const resolver = new FrequencyResolver({
2424
apiPromise,
25-
frequencyNetwork: "local",
2625
});
2726
2827
await resolver.disconnect();
2928
});
29+
*/
3030

31-
/* Need to mock for this...
31+
/* TODO needs mocking
3232
it("resolves did:dsnp:13972", async () => {
3333
const myDid = "did:dsnp:13972";
3434
const result = await resolver.resolve(myDid);

index.ts

Lines changed: 41 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,15 @@ import { DSNPResolver } from "@dsnp/did-resolver";
55
import avro from "avro-js";
66
import { options } from "@frequency-chain/api-augment";
77
import { WsProvider, ApiPromise } from "@polkadot/api";
8+
import { xxhashAsHex } from "@polkadot/util-crypto";
9+
import { bnToU8a, u8aToHex } from "@polkadot/util";
810

911
const publicKeyAvroSchema = avro.parse(dsnp.publicKey);
1012

13+
const keyCountStorageKeyHex =
14+
xxhashAsHex("Msa", 128) +
15+
xxhashAsHex("PublicKeyCountForMsaId", 128).substring(2);
16+
1117
function makeVerificationMethod(
1218
controller: string,
1319
publicKeyMultibase: string,
@@ -23,27 +29,22 @@ function makeVerificationMethod(
2329

2430
export class FrequencyResolver implements DSNPResolver {
2531
private providerUri: string | null = null;
26-
private frequencyNetwork: string;
2732
private _singletonApi: Promise<ApiPromise> | null = null;
28-
29-
constructor(options: { providerUri?: string; apiPromise?: Promise<ApiPromise>, frequencyNetwork: string }) {
33+
private keyAgreementSchemaId: number | null = null;
34+
private assertionMethodSchemaId: number | null = null;
35+
private initialized: boolean = false;
36+
37+
constructor(options: {
38+
providerUri?: string;
39+
apiPromise?: Promise<ApiPromise>;
40+
}) {
3041
if (options.providerUri) {
3142
this.providerUri = options.providerUri;
3243
} else if (options.apiPromise != null) {
3344
this._singletonApi = options.apiPromise;
3445
} else {
3546
throw new Error("providerUri or apiPromise is required");
3647
}
37-
38-
this.frequencyNetwork = options.frequencyNetwork;
39-
if (
40-
!this.frequencyNetwork ||
41-
!["local", "testnet", "mainnet"].includes(this.frequencyNetwork)
42-
) {
43-
throw new Error(
44-
'frequencyNetwork must be one of: "local", "testnet", "mainnet"',
45-
);
46-
}
4748
}
4849

4950
async getApi(): Promise<ApiPromise> {
@@ -54,7 +55,6 @@ export class FrequencyResolver implements DSNPResolver {
5455
...options,
5556
});
5657
}
57-
5858
return this._singletonApi;
5959
}
6060

@@ -83,26 +83,37 @@ export class FrequencyResolver implements DSNPResolver {
8383
}
8484

8585
async resolve(dsnpUserId: bigint): Promise<DIDDocument | null> {
86-
const controller = `did:dsnp:${dsnpUserId}`;
87-
88-
// Attempt to retrieve public key(s)
89-
let keyAgreementSchemaId: number;
90-
let assertionMethodSchemaId: number;
86+
if (!this.initialized) {
87+
const api: Promise<ApiPromise> = this.getApi();
88+
// Get the appropriate schemaIds for the chain we're connecting to
89+
this.keyAgreementSchemaId = await dsnp.getSchemaId(
90+
api,
91+
"public-key-key-agreement",
92+
);
93+
this.assertionMethodSchemaId = await dsnp.getSchemaId(
94+
api,
95+
"public-key-assertion-method",
96+
);
97+
this.initialized = true;
98+
}
9199

92-
switch (this.frequencyNetwork) {
93-
case "testnet":
94-
keyAgreementSchemaId = 18;
95-
assertionMethodSchemaId = 100;
96-
break;
97-
default:
98-
keyAgreementSchemaId = 7;
99-
assertionMethodSchemaId = 11;
100-
break;
100+
// Determine if MSA exists by checking public key count
101+
const msaUint8a = bnToU8a(dsnpUserId, { bitLength: 64 });
102+
const key =
103+
keyCountStorageKeyHex +
104+
xxhashAsHex(msaUint8a).substring(2) +
105+
u8aToHex(msaUint8a).substring(2);
106+
const result = await (await this.getApi()).rpc.state.getStorage(key);
107+
if (Number(result) == 0) {
108+
return null;
101109
}
102110

111+
const controller = `did:dsnp:${dsnpUserId}`;
112+
113+
// Retrieve public key(s)
103114
const assertionMethodKeys = await this.getPublicKeysForSchema(
104115
dsnpUserId,
105-
assertionMethodSchemaId,
116+
this.assertionMethodSchemaId!,
106117
);
107118
const assertionMethod = assertionMethodKeys.map(
108119
(publicKeyMultibase: string) => {
@@ -112,7 +123,7 @@ export class FrequencyResolver implements DSNPResolver {
112123

113124
const keyAgreementKeys = await this.getPublicKeysForSchema(
114125
dsnpUserId,
115-
keyAgreementSchemaId,
126+
this.keyAgreementSchemaId!,
116127
);
117128
const keyAgreement = keyAgreementKeys.map((publicKeyMultibase) => {
118129
return makeVerificationMethod(controller, publicKeyMultibase);

0 commit comments

Comments
 (0)