@0xpolygonid/js-sdk 1.31.1 → 1.31.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/esm/index.js +773 -321
- package/dist/browser/esm/index.js.map +1 -1
- package/dist/browser/umd/index.js +773 -319
- package/dist/browser/umd/index.js.map +1 -1
- package/dist/node/cjs/credentials/status/on-chain-revocation.js +3 -10
- package/dist/node/cjs/identity/identity-wallet.js +17 -4
- package/dist/node/cjs/storage/blockchain/onchain-zkp-verifier.js +0 -1
- package/dist/node/cjs/storage/blockchain/state.js +120 -3
- package/dist/node/cjs/storage/memory/cache-lru.js +25 -0
- package/dist/node/cjs/storage/memory/index.js +1 -0
- package/dist/node/cjs/storage/shared/identity-storage.js +7 -0
- package/dist/node/cjs/verifiable/constants.js +6 -1
- package/dist/node/esm/credentials/status/on-chain-revocation.js +4 -11
- package/dist/node/esm/identity/identity-wallet.js +17 -4
- package/dist/node/esm/storage/blockchain/onchain-zkp-verifier.js +0 -1
- package/dist/node/esm/storage/blockchain/state.js +120 -3
- package/dist/node/esm/storage/memory/cache-lru.js +18 -0
- package/dist/node/esm/storage/memory/index.js +1 -0
- package/dist/node/esm/storage/shared/identity-storage.js +7 -0
- package/dist/node/esm/verifiable/constants.js +5 -0
- package/dist/types/credentials/status/on-chain-revocation.d.ts +6 -2
- package/dist/types/identity/identity-wallet.d.ts +18 -3
- package/dist/types/storage/blockchain/state.d.ts +65 -1
- package/dist/types/storage/entities/identity.d.ts +1 -0
- package/dist/types/storage/interfaces/identity.d.ts +8 -1
- package/dist/types/storage/memory/cache-lru.d.ts +10 -0
- package/dist/types/storage/memory/index.d.ts +1 -0
- package/dist/types/storage/shared/identity-storage.d.ts +5 -0
- package/dist/types/verifiable/constants.d.ts +5 -0
- package/package.json +3 -2
|
@@ -21,8 +21,9 @@ class OnChainResolver {
|
|
|
21
21
|
* @public
|
|
22
22
|
* @param {Array<EthConnectionConfig>} _configs - list of ethereum network connections
|
|
23
23
|
*/
|
|
24
|
-
constructor(_configs) {
|
|
24
|
+
constructor(_configs, _opts) {
|
|
25
25
|
this._configs = _configs;
|
|
26
|
+
this._stateStorage = new state_1.EthStateStorage(_configs, _opts?.stateStorageOptions);
|
|
26
27
|
}
|
|
27
28
|
/**
|
|
28
29
|
* resolve is a method to resolve a credential status from the blockchain.
|
|
@@ -53,8 +54,7 @@ class OnChainResolver {
|
|
|
53
54
|
const issuerId = js_iden3_core_1.DID.idFromDID(issuer);
|
|
54
55
|
let latestIssuerState;
|
|
55
56
|
try {
|
|
56
|
-
const
|
|
57
|
-
const latestStateInfo = await ethStorage.getLatestStateById(issuerId.bigInt());
|
|
57
|
+
const latestStateInfo = await this._stateStorage.getLatestStateById(issuerId.bigInt());
|
|
58
58
|
if (!latestStateInfo.state) {
|
|
59
59
|
throw new Error('state contract returned empty state');
|
|
60
60
|
}
|
|
@@ -120,13 +120,6 @@ class OnChainResolver {
|
|
|
120
120
|
}
|
|
121
121
|
return network;
|
|
122
122
|
}
|
|
123
|
-
// TODO: is dirty hack for mock in tests.
|
|
124
|
-
// need to pass to constructor list of state stores not list of network configs
|
|
125
|
-
_getStateStorageForIssuer(issuerId) {
|
|
126
|
-
const issuerChainId = (0, js_iden3_core_1.getChainId)(js_iden3_core_1.DID.blockchainFromId(issuerId), js_iden3_core_1.DID.networkIdFromId(issuerId));
|
|
127
|
-
const ethStorage = new state_1.EthStateStorage(this.networkByChainId(issuerChainId));
|
|
128
|
-
return ethStorage;
|
|
129
|
-
}
|
|
130
123
|
_getOnChainRevocationStorageForIssuer(chainId, contractAddress) {
|
|
131
124
|
const networkConfig = this.networkByChainId(chainId);
|
|
132
125
|
const onChainCaller = new onchain_revocation_1.OnChainRevocationStorage(networkConfig, contractAddress);
|
|
@@ -272,18 +272,23 @@ class IdentityWallet {
|
|
|
272
272
|
return { nonce: profile.nonce, genesisDID: js_iden3_core_1.DID.parse(profile.genesisIdentifier) };
|
|
273
273
|
}
|
|
274
274
|
/** {@inheritDoc IIdentityWallet.createProfile} */
|
|
275
|
-
async createProfile(did, nonce, verifier) {
|
|
275
|
+
async createProfile(did, nonce, verifier, tags) {
|
|
276
276
|
const profileDID = (0, common_1.generateProfileDID)(did, nonce);
|
|
277
277
|
const identityProfiles = await this._storage.identity.getProfilesByGenesisIdentifier(did.string());
|
|
278
|
-
const
|
|
279
|
-
if (
|
|
278
|
+
const profilesForTagAndVerifier = await this._storage.identity.getProfilesByVerifier(verifier, tags);
|
|
279
|
+
if (profilesForTagAndVerifier.length) {
|
|
280
|
+
throw new Error(verifiable_1.VerifiableConstants.ERRORS.ID_WALLET_PROFILE_ALREADY_EXISTS_VERIFIER_TAGS);
|
|
281
|
+
}
|
|
282
|
+
const existingProfileWithNonce = identityProfiles.find((p) => p.nonce == nonce);
|
|
283
|
+
if (existingProfileWithNonce) {
|
|
280
284
|
throw new Error(verifiable_1.VerifiableConstants.ERRORS.ID_WALLET_PROFILE_ALREADY_EXISTS);
|
|
281
285
|
}
|
|
282
286
|
await this._storage.identity.saveProfile({
|
|
283
287
|
id: profileDID.string(),
|
|
284
288
|
nonce,
|
|
285
289
|
genesisIdentifier: did.string(),
|
|
286
|
-
verifier
|
|
290
|
+
verifier,
|
|
291
|
+
tags
|
|
287
292
|
});
|
|
288
293
|
return profileDID;
|
|
289
294
|
}
|
|
@@ -302,9 +307,17 @@ class IdentityWallet {
|
|
|
302
307
|
const key = await this._kms.createKeyFromSeed(keyType, (0, js_crypto_1.getRandomBytes)(32));
|
|
303
308
|
return key;
|
|
304
309
|
}
|
|
310
|
+
/**
|
|
311
|
+
* @deprecated The method should not be used. It returns only one profile per verifier, which can potentially restrict business use cases
|
|
312
|
+
* {@inheritDoc IIdentityWallet.getProfileByVerifier}
|
|
313
|
+
*/
|
|
305
314
|
async getProfileByVerifier(verifier) {
|
|
306
315
|
return this._storage.identity.getProfileByVerifier(verifier);
|
|
307
316
|
}
|
|
317
|
+
/** {@inheritDoc IIdentityWallet.getProfilesByVerifier} */
|
|
318
|
+
async getProfilesByVerifier(verifier, tags) {
|
|
319
|
+
return this._storage.identity.getProfilesByVerifier(verifier, tags);
|
|
320
|
+
}
|
|
308
321
|
/** {@inheritDoc IIdentityWallet.getDIDTreeModel} */
|
|
309
322
|
async getDIDTreeModel(did) {
|
|
310
323
|
const didStr = did.string();
|
|
@@ -7,7 +7,6 @@ exports.packEthIdentityProof = exports.OnChainZKPVerifier = exports.toTxDataArgs
|
|
|
7
7
|
const ethers_1 = require("ethers");
|
|
8
8
|
const iden3comm_1 = require("../../iden3comm");
|
|
9
9
|
const ZkpVerifier_json_1 = __importDefault(require("./abi/ZkpVerifier.json"));
|
|
10
|
-
//import { UniversalVerifier } from '@iden3/universal-verifier-v2-abi';
|
|
11
10
|
const universal_verifier_v2_abi_1 = require("@iden3/universal-verifier-v2-abi");
|
|
12
11
|
const blockchain_1 = require("../../blockchain");
|
|
13
12
|
const js_iden3_core_1 = require("@iden3/js-iden3-core");
|
|
@@ -11,6 +11,9 @@ const State_json_1 = __importDefault(require("./abi/State.json"));
|
|
|
11
11
|
const js_iden3_core_1 = require("@iden3/js-iden3-core");
|
|
12
12
|
const blockchain_1 = require("../../blockchain");
|
|
13
13
|
const common_1 = require("./common");
|
|
14
|
+
const memory_1 = require("../memory");
|
|
15
|
+
const iden3comm_1 = require("../../iden3comm");
|
|
16
|
+
const verifiable_1 = require("../../verifiable");
|
|
14
17
|
exports.defaultEthConnectionConfig = {
|
|
15
18
|
url: 'http://localhost:8545',
|
|
16
19
|
defaultGasLimit: 600000,
|
|
@@ -36,15 +39,71 @@ class EthStateStorage {
|
|
|
36
39
|
* Creates an instance of EthStateStorage.
|
|
37
40
|
* @param {EthConnectionConfig} [ethConfig=defaultEthConnectionConfig]
|
|
38
41
|
*/
|
|
39
|
-
constructor(ethConfig) {
|
|
42
|
+
constructor(ethConfig, options) {
|
|
40
43
|
this.ethConfig = ethConfig;
|
|
44
|
+
this._disableCache = false;
|
|
41
45
|
const config = Array.isArray(ethConfig) ? ethConfig[0] : ethConfig;
|
|
42
46
|
this.provider = new ethers_1.JsonRpcProvider(config.url);
|
|
43
47
|
this.stateContract = new ethers_1.Contract(config.contractAddress, State_json_1.default, this.provider);
|
|
44
48
|
this._transactionService = new blockchain_1.TransactionService(this.getRpcProvider());
|
|
49
|
+
// Store cache options for later use
|
|
50
|
+
this._latestStateCacheOptions = {
|
|
51
|
+
ttl: options?.latestStateCacheOptions?.ttl ?? iden3comm_1.PROTOCOL_CONSTANTS.DEFAULT_PROOF_VERIFY_DELAY / 2,
|
|
52
|
+
maxSize: options?.latestStateCacheOptions?.maxSize ?? verifiable_1.DEFAULT_CACHE_MAX_SIZE
|
|
53
|
+
};
|
|
54
|
+
this._stateCacheOptions = {
|
|
55
|
+
notReplacedTtl: options?.stateCacheOptions?.notReplacedTtl ??
|
|
56
|
+
iden3comm_1.PROTOCOL_CONSTANTS.DEFAULT_PROOF_VERIFY_DELAY / 2,
|
|
57
|
+
replacedTtl: options?.stateCacheOptions?.replacedTtl ?? iden3comm_1.PROTOCOL_CONSTANTS.DEFAULT_PROOF_VERIFY_DELAY,
|
|
58
|
+
maxSize: options?.stateCacheOptions?.maxSize ?? verifiable_1.DEFAULT_CACHE_MAX_SIZE
|
|
59
|
+
};
|
|
60
|
+
this._rootCacheOptions = {
|
|
61
|
+
replacedTtl: options?.rootCacheOptions?.replacedTtl ?? iden3comm_1.PROTOCOL_CONSTANTS.DEFAULT_AUTH_VERIFY_DELAY,
|
|
62
|
+
notReplacedTtl: options?.rootCacheOptions?.notReplacedTtl ??
|
|
63
|
+
iden3comm_1.PROTOCOL_CONSTANTS.DEFAULT_AUTH_VERIFY_DELAY / 2,
|
|
64
|
+
maxSize: options?.rootCacheOptions?.maxSize ?? verifiable_1.DEFAULT_CACHE_MAX_SIZE
|
|
65
|
+
};
|
|
66
|
+
this._gistProofCacheOptions = {
|
|
67
|
+
ttl: iden3comm_1.PROTOCOL_CONSTANTS.DEFAULT_AUTH_VERIFY_DELAY / 2,
|
|
68
|
+
maxSize: options?.gistProofCacheOptions?.maxSize ?? verifiable_1.DEFAULT_CACHE_MAX_SIZE
|
|
69
|
+
};
|
|
70
|
+
// Initialize cache instances
|
|
71
|
+
this._latestStateResolveCache =
|
|
72
|
+
options?.latestStateCacheOptions?.cache ??
|
|
73
|
+
(0, memory_1.createInMemoryCache)({
|
|
74
|
+
maxSize: this._latestStateCacheOptions.maxSize,
|
|
75
|
+
ttl: this._latestStateCacheOptions.ttl
|
|
76
|
+
});
|
|
77
|
+
this._stateResolveCache =
|
|
78
|
+
options?.stateCacheOptions?.cache ??
|
|
79
|
+
(0, memory_1.createInMemoryCache)({
|
|
80
|
+
maxSize: this._stateCacheOptions.maxSize,
|
|
81
|
+
ttl: this._stateCacheOptions.replacedTtl
|
|
82
|
+
});
|
|
83
|
+
this._rootResolveCache =
|
|
84
|
+
options?.rootCacheOptions?.cache ??
|
|
85
|
+
(0, memory_1.createInMemoryCache)({
|
|
86
|
+
maxSize: this._rootCacheOptions.maxSize,
|
|
87
|
+
ttl: this._rootCacheOptions.replacedTtl
|
|
88
|
+
});
|
|
89
|
+
this._gistProofResolveCache =
|
|
90
|
+
options?.gistProofCacheOptions?.cache ??
|
|
91
|
+
(0, memory_1.createInMemoryCache)({
|
|
92
|
+
maxSize: this._gistProofCacheOptions.maxSize,
|
|
93
|
+
ttl: this._gistProofCacheOptions.ttl
|
|
94
|
+
});
|
|
95
|
+
this._disableCache = options?.disableCache ?? false;
|
|
45
96
|
}
|
|
46
97
|
/** {@inheritdoc IStateStorage.getLatestStateById} */
|
|
47
98
|
async getLatestStateById(id) {
|
|
99
|
+
const cacheKey = this.getLatestStateCacheKey(id);
|
|
100
|
+
if (!this._disableCache) {
|
|
101
|
+
// Check cache first
|
|
102
|
+
const cachedResult = await this._latestStateResolveCache?.get(cacheKey);
|
|
103
|
+
if (cachedResult) {
|
|
104
|
+
return cachedResult;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
48
107
|
const { stateContract } = this.getStateContractAndProviderForId(id);
|
|
49
108
|
const rawData = await stateContract.getStateInfoById(id);
|
|
50
109
|
const stateInfo = {
|
|
@@ -56,10 +115,20 @@ class EthStateStorage {
|
|
|
56
115
|
createdAtBlock: BigInt(rawData[5]),
|
|
57
116
|
replacedAtBlock: BigInt(rawData[6])
|
|
58
117
|
};
|
|
118
|
+
!this._disableCache &&
|
|
119
|
+
(await this._latestStateResolveCache?.set(cacheKey, stateInfo, this._latestStateCacheOptions.ttl));
|
|
59
120
|
return stateInfo;
|
|
60
121
|
}
|
|
61
122
|
/** {@inheritdoc IStateStorage.getStateInfoByIdAndState} */
|
|
62
123
|
async getStateInfoByIdAndState(id, state) {
|
|
124
|
+
const cacheKey = this.getStateCacheKey(id, state);
|
|
125
|
+
if (!this._disableCache) {
|
|
126
|
+
// Check cache first
|
|
127
|
+
const cachedResult = await this._stateResolveCache?.get(cacheKey);
|
|
128
|
+
if (cachedResult) {
|
|
129
|
+
return cachedResult;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
63
132
|
const { stateContract } = this.getStateContractAndProviderForId(id);
|
|
64
133
|
const rawData = await stateContract.getStateInfoByIdAndState(id, state);
|
|
65
134
|
const stateInfo = {
|
|
@@ -71,6 +140,10 @@ class EthStateStorage {
|
|
|
71
140
|
createdAtBlock: BigInt(rawData[5]),
|
|
72
141
|
replacedAtBlock: BigInt(rawData[6])
|
|
73
142
|
};
|
|
143
|
+
const ttl = stateInfo.replacedAtTimestamp === 0n
|
|
144
|
+
? this._stateCacheOptions.notReplacedTtl
|
|
145
|
+
: this._stateCacheOptions.replacedTtl;
|
|
146
|
+
!this._disableCache && (await this._stateResolveCache?.set(cacheKey, stateInfo, ttl));
|
|
74
147
|
return stateInfo;
|
|
75
148
|
}
|
|
76
149
|
/** {@inheritdoc IStateStorage.publishState} */
|
|
@@ -143,9 +216,17 @@ class EthStateStorage {
|
|
|
143
216
|
}
|
|
144
217
|
/** {@inheritdoc IStateStorage.getGISTProof} */
|
|
145
218
|
async getGISTProof(id) {
|
|
219
|
+
const cacheKey = this.getGistProofCacheKey(id);
|
|
220
|
+
if (!this._disableCache) {
|
|
221
|
+
// Check cache first
|
|
222
|
+
const cachedResult = await this._gistProofResolveCache?.get(cacheKey);
|
|
223
|
+
if (cachedResult) {
|
|
224
|
+
return cachedResult;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
146
227
|
const { stateContract } = this.getStateContractAndProviderForId(id);
|
|
147
228
|
const data = await stateContract.getGISTProof(id);
|
|
148
|
-
|
|
229
|
+
const stateProof = {
|
|
149
230
|
root: BigInt(data.root.toString()),
|
|
150
231
|
existence: data.existence,
|
|
151
232
|
siblings: data.siblings?.map((sibling) => BigInt(sibling.toString())),
|
|
@@ -155,12 +236,23 @@ class EthStateStorage {
|
|
|
155
236
|
auxIndex: BigInt(data.auxIndex.toString()),
|
|
156
237
|
auxValue: BigInt(data.auxValue.toString())
|
|
157
238
|
};
|
|
239
|
+
!this._disableCache &&
|
|
240
|
+
(await this._gistProofResolveCache?.set(cacheKey, stateProof, this._gistProofCacheOptions.ttl));
|
|
241
|
+
return stateProof;
|
|
158
242
|
}
|
|
159
243
|
/** {@inheritdoc IStateStorage.getGISTRootInfo} */
|
|
160
244
|
async getGISTRootInfo(root, id) {
|
|
245
|
+
const cacheKey = this.getRootCacheKey(root);
|
|
246
|
+
if (!this._disableCache) {
|
|
247
|
+
// Check cache first
|
|
248
|
+
const cachedResult = await this._rootResolveCache?.get(cacheKey);
|
|
249
|
+
if (cachedResult) {
|
|
250
|
+
return cachedResult;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
161
253
|
const { stateContract } = this.getStateContractAndProviderForId(id);
|
|
162
254
|
const data = await stateContract.getGISTRootInfo(root);
|
|
163
|
-
|
|
255
|
+
const rootInfo = {
|
|
164
256
|
root: BigInt(data.root.toString()),
|
|
165
257
|
replacedByRoot: BigInt(data.replacedByRoot.toString()),
|
|
166
258
|
createdAtTimestamp: BigInt(data.createdAtTimestamp.toString()),
|
|
@@ -168,11 +260,24 @@ class EthStateStorage {
|
|
|
168
260
|
createdAtBlock: BigInt(data.createdAtBlock.toString()),
|
|
169
261
|
replacedAtBlock: BigInt(data.replacedAtBlock.toString())
|
|
170
262
|
};
|
|
263
|
+
const ttl = rootInfo.replacedAtTimestamp == 0n
|
|
264
|
+
? this._rootCacheOptions.notReplacedTtl
|
|
265
|
+
: this._rootCacheOptions.replacedTtl;
|
|
266
|
+
!this._disableCache && (await this._rootResolveCache?.set(cacheKey, rootInfo, ttl));
|
|
267
|
+
return rootInfo;
|
|
171
268
|
}
|
|
172
269
|
/** {@inheritdoc IStateStorage.getRpcProvider} */
|
|
173
270
|
getRpcProvider() {
|
|
174
271
|
return this.provider;
|
|
175
272
|
}
|
|
273
|
+
/** enable caching */
|
|
274
|
+
enableCache() {
|
|
275
|
+
this._disableCache = false;
|
|
276
|
+
}
|
|
277
|
+
/** disable caching */
|
|
278
|
+
disableCache() {
|
|
279
|
+
this._disableCache = true;
|
|
280
|
+
}
|
|
176
281
|
getStateContractAndProviderForId(id) {
|
|
177
282
|
const idTyped = js_iden3_core_1.Id.fromBigInt(id);
|
|
178
283
|
const chainId = (0, js_iden3_core_1.getChainId)(js_iden3_core_1.DID.blockchainFromId(idTyped), js_iden3_core_1.DID.networkIdFromId(idTyped));
|
|
@@ -189,5 +294,17 @@ class EthStateStorage {
|
|
|
189
294
|
}
|
|
190
295
|
return network;
|
|
191
296
|
}
|
|
297
|
+
getGistProofCacheKey(id) {
|
|
298
|
+
return `gist-${id.toString()}`;
|
|
299
|
+
}
|
|
300
|
+
getLatestStateCacheKey(id) {
|
|
301
|
+
return `latest-${id.toString()}`;
|
|
302
|
+
}
|
|
303
|
+
getStateCacheKey(id, state) {
|
|
304
|
+
return `${id.toString()}-${state.toString()}`;
|
|
305
|
+
}
|
|
306
|
+
getRootCacheKey(root) {
|
|
307
|
+
return root.toString();
|
|
308
|
+
}
|
|
192
309
|
}
|
|
193
310
|
exports.EthStateStorage = EthStateStorage;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createInMemoryCache = void 0;
|
|
7
|
+
const quick_lru_1 = __importDefault(require("quick-lru"));
|
|
8
|
+
function createInMemoryCache(params) {
|
|
9
|
+
const cache = new quick_lru_1.default({ maxSize: params.maxSize, maxAge: params.ttl });
|
|
10
|
+
return {
|
|
11
|
+
get: async (key) => {
|
|
12
|
+
return cache.get(key);
|
|
13
|
+
},
|
|
14
|
+
set: async (key, value, ttl) => {
|
|
15
|
+
cache.set(key, value, { maxAge: ttl ?? params.ttl });
|
|
16
|
+
},
|
|
17
|
+
clear: async () => {
|
|
18
|
+
cache.clear();
|
|
19
|
+
},
|
|
20
|
+
delete: async (key) => {
|
|
21
|
+
cache.delete(key);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
exports.createInMemoryCache = createInMemoryCache;
|
|
@@ -16,3 +16,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./merkletree"), exports);
|
|
18
18
|
__exportStar(require("./data-source"), exports);
|
|
19
|
+
__exportStar(require("./cache-lru"), exports);
|
|
@@ -27,9 +27,16 @@ class IdentityStorage {
|
|
|
27
27
|
await this._profileDataSource.save(element.id, element);
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* @deprecated The method should not be used. It returns only one profile per verifier, which can potentially restrict business use cases
|
|
32
|
+
* Use getProfilesByVerifier instead.
|
|
33
|
+
*/
|
|
30
34
|
async getProfileByVerifier(verifier) {
|
|
31
35
|
return this._profileDataSource.get(verifier, 'verifier');
|
|
32
36
|
}
|
|
37
|
+
async getProfilesByVerifier(verifier, tags) {
|
|
38
|
+
return (await this._profileDataSource.load()).filter((p) => p.verifier === verifier && (!tags || tags.every((tag) => p.tags?.includes(tag))));
|
|
39
|
+
}
|
|
33
40
|
async getProfileById(profileId) {
|
|
34
41
|
return this._profileDataSource.get(profileId);
|
|
35
42
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DisplayMethodType = exports.PaymentFeatures = exports.SupportedCurrencies = exports.SupportedPaymentProofType = exports.PaymentType = exports.PaymentRequestDataType = exports.RefreshServiceType = exports.SubjectPosition = exports.MerklizedRootPosition = exports.ProofPurpose = exports.CredentialStatusType = exports.ProofType = exports.VerifiableConstants = void 0;
|
|
3
|
+
exports.DEFAULT_CACHE_MAX_SIZE = exports.DisplayMethodType = exports.PaymentFeatures = exports.SupportedCurrencies = exports.SupportedPaymentProofType = exports.PaymentType = exports.PaymentRequestDataType = exports.RefreshServiceType = exports.SubjectPosition = exports.MerklizedRootPosition = exports.ProofPurpose = exports.CredentialStatusType = exports.ProofType = exports.VerifiableConstants = void 0;
|
|
4
4
|
/** Verifiable constants */
|
|
5
5
|
exports.VerifiableConstants = Object.freeze({
|
|
6
6
|
ERRORS: {
|
|
@@ -19,6 +19,7 @@ exports.VerifiableConstants = Object.freeze({
|
|
|
19
19
|
ID_WALLET_CORE_CLAIM_IS_NOT_SET: 'core claim is not set in credential proofs',
|
|
20
20
|
ID_WALLET_PROFILE_OR_IDENTITY_NOT_FOUND: 'profile or identity not found',
|
|
21
21
|
ID_WALLET_PROFILE_ALREADY_EXISTS: 'profile with given nonce or verifier already exists',
|
|
22
|
+
ID_WALLET_PROFILE_ALREADY_EXISTS_VERIFIER_TAGS: 'profile with given verifier and tags already exists',
|
|
22
23
|
ID_WALLET_ISSUER_AUTH_BJJ_CRED_MUST_HAVE_ANY_PROOF: 'issuer auth credential must have proof',
|
|
23
24
|
ID_WALLET_ISSUER_AUTH_BJJ_CRED_MUST_HAVE_MTP_PROOF: 'mtp is required for auth bjj key to issue new credentials',
|
|
24
25
|
// proof service
|
|
@@ -200,3 +201,7 @@ var DisplayMethodType;
|
|
|
200
201
|
(function (DisplayMethodType) {
|
|
201
202
|
DisplayMethodType["Iden3BasicDisplayMethodV1"] = "Iden3BasicDisplayMethodV1";
|
|
202
203
|
})(DisplayMethodType = exports.DisplayMethodType || (exports.DisplayMethodType = {}));
|
|
204
|
+
/**
|
|
205
|
+
* Default cache max size for in-memory cache
|
|
206
|
+
*/
|
|
207
|
+
exports.DEFAULT_CACHE_MAX_SIZE = 10000;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { OnChainRevocationStorage } from '../../storage/blockchain/onchain-revocation';
|
|
2
|
-
import { DID
|
|
2
|
+
import { DID } from '@iden3/js-iden3-core';
|
|
3
3
|
import { VerifiableConstants } from '../../verifiable/constants';
|
|
4
4
|
import { isGenesisState } from '../../utils';
|
|
5
5
|
import { EthStateStorage } from '../../storage/blockchain/state';
|
|
@@ -18,8 +18,9 @@ export class OnChainResolver {
|
|
|
18
18
|
* @public
|
|
19
19
|
* @param {Array<EthConnectionConfig>} _configs - list of ethereum network connections
|
|
20
20
|
*/
|
|
21
|
-
constructor(_configs) {
|
|
21
|
+
constructor(_configs, _opts) {
|
|
22
22
|
this._configs = _configs;
|
|
23
|
+
this._stateStorage = new EthStateStorage(_configs, _opts?.stateStorageOptions);
|
|
23
24
|
}
|
|
24
25
|
/**
|
|
25
26
|
* resolve is a method to resolve a credential status from the blockchain.
|
|
@@ -50,8 +51,7 @@ export class OnChainResolver {
|
|
|
50
51
|
const issuerId = DID.idFromDID(issuer);
|
|
51
52
|
let latestIssuerState;
|
|
52
53
|
try {
|
|
53
|
-
const
|
|
54
|
-
const latestStateInfo = await ethStorage.getLatestStateById(issuerId.bigInt());
|
|
54
|
+
const latestStateInfo = await this._stateStorage.getLatestStateById(issuerId.bigInt());
|
|
55
55
|
if (!latestStateInfo.state) {
|
|
56
56
|
throw new Error('state contract returned empty state');
|
|
57
57
|
}
|
|
@@ -117,13 +117,6 @@ export class OnChainResolver {
|
|
|
117
117
|
}
|
|
118
118
|
return network;
|
|
119
119
|
}
|
|
120
|
-
// TODO: is dirty hack for mock in tests.
|
|
121
|
-
// need to pass to constructor list of state stores not list of network configs
|
|
122
|
-
_getStateStorageForIssuer(issuerId) {
|
|
123
|
-
const issuerChainId = getChainId(DID.blockchainFromId(issuerId), DID.networkIdFromId(issuerId));
|
|
124
|
-
const ethStorage = new EthStateStorage(this.networkByChainId(issuerChainId));
|
|
125
|
-
return ethStorage;
|
|
126
|
-
}
|
|
127
120
|
_getOnChainRevocationStorageForIssuer(chainId, contractAddress) {
|
|
128
121
|
const networkConfig = this.networkByChainId(chainId);
|
|
129
122
|
const onChainCaller = new OnChainRevocationStorage(networkConfig, contractAddress);
|
|
@@ -246,18 +246,23 @@ export class IdentityWallet {
|
|
|
246
246
|
return { nonce: profile.nonce, genesisDID: DID.parse(profile.genesisIdentifier) };
|
|
247
247
|
}
|
|
248
248
|
/** {@inheritDoc IIdentityWallet.createProfile} */
|
|
249
|
-
async createProfile(did, nonce, verifier) {
|
|
249
|
+
async createProfile(did, nonce, verifier, tags) {
|
|
250
250
|
const profileDID = generateProfileDID(did, nonce);
|
|
251
251
|
const identityProfiles = await this._storage.identity.getProfilesByGenesisIdentifier(did.string());
|
|
252
|
-
const
|
|
253
|
-
if (
|
|
252
|
+
const profilesForTagAndVerifier = await this._storage.identity.getProfilesByVerifier(verifier, tags);
|
|
253
|
+
if (profilesForTagAndVerifier.length) {
|
|
254
|
+
throw new Error(VerifiableConstants.ERRORS.ID_WALLET_PROFILE_ALREADY_EXISTS_VERIFIER_TAGS);
|
|
255
|
+
}
|
|
256
|
+
const existingProfileWithNonce = identityProfiles.find((p) => p.nonce == nonce);
|
|
257
|
+
if (existingProfileWithNonce) {
|
|
254
258
|
throw new Error(VerifiableConstants.ERRORS.ID_WALLET_PROFILE_ALREADY_EXISTS);
|
|
255
259
|
}
|
|
256
260
|
await this._storage.identity.saveProfile({
|
|
257
261
|
id: profileDID.string(),
|
|
258
262
|
nonce,
|
|
259
263
|
genesisIdentifier: did.string(),
|
|
260
|
-
verifier
|
|
264
|
+
verifier,
|
|
265
|
+
tags
|
|
261
266
|
});
|
|
262
267
|
return profileDID;
|
|
263
268
|
}
|
|
@@ -276,9 +281,17 @@ export class IdentityWallet {
|
|
|
276
281
|
const key = await this._kms.createKeyFromSeed(keyType, getRandomBytes(32));
|
|
277
282
|
return key;
|
|
278
283
|
}
|
|
284
|
+
/**
|
|
285
|
+
* @deprecated The method should not be used. It returns only one profile per verifier, which can potentially restrict business use cases
|
|
286
|
+
* {@inheritDoc IIdentityWallet.getProfileByVerifier}
|
|
287
|
+
*/
|
|
279
288
|
async getProfileByVerifier(verifier) {
|
|
280
289
|
return this._storage.identity.getProfileByVerifier(verifier);
|
|
281
290
|
}
|
|
291
|
+
/** {@inheritDoc IIdentityWallet.getProfilesByVerifier} */
|
|
292
|
+
async getProfilesByVerifier(verifier, tags) {
|
|
293
|
+
return this._storage.identity.getProfilesByVerifier(verifier, tags);
|
|
294
|
+
}
|
|
282
295
|
/** {@inheritDoc IIdentityWallet.getDIDTreeModel} */
|
|
283
296
|
async getDIDTreeModel(did) {
|
|
284
297
|
const didStr = did.string();
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { JsonRpcProvider, Contract, ethers } from 'ethers';
|
|
2
2
|
import { AuthMethod, processProofResponse } from '../../iden3comm';
|
|
3
3
|
import abi from './abi/ZkpVerifier.json';
|
|
4
|
-
//import { UniversalVerifier } from '@iden3/universal-verifier-v2-abi';
|
|
5
4
|
import { IVerifierABI } from '@iden3/universal-verifier-v2-abi';
|
|
6
5
|
import { TransactionService } from '../../blockchain';
|
|
7
6
|
import { BytesHelper, chainIDfromDID, DID, Id } from '@iden3/js-iden3-core';
|
|
@@ -5,6 +5,9 @@ import abi from './abi/State.json';
|
|
|
5
5
|
import { DID, getChainId, Id } from '@iden3/js-iden3-core';
|
|
6
6
|
import { TransactionService } from '../../blockchain';
|
|
7
7
|
import { prepareZkpProof } from './common';
|
|
8
|
+
import { createInMemoryCache } from '../memory';
|
|
9
|
+
import { PROTOCOL_CONSTANTS } from '../../iden3comm';
|
|
10
|
+
import { DEFAULT_CACHE_MAX_SIZE } from '../../verifiable';
|
|
8
11
|
export /** @type {EthConnectionConfig} - default configuration for EthConnectionConfig */ const defaultEthConnectionConfig = {
|
|
9
12
|
url: 'http://localhost:8545',
|
|
10
13
|
defaultGasLimit: 600000,
|
|
@@ -30,15 +33,71 @@ export class EthStateStorage {
|
|
|
30
33
|
* Creates an instance of EthStateStorage.
|
|
31
34
|
* @param {EthConnectionConfig} [ethConfig=defaultEthConnectionConfig]
|
|
32
35
|
*/
|
|
33
|
-
constructor(ethConfig) {
|
|
36
|
+
constructor(ethConfig, options) {
|
|
34
37
|
this.ethConfig = ethConfig;
|
|
38
|
+
this._disableCache = false;
|
|
35
39
|
const config = Array.isArray(ethConfig) ? ethConfig[0] : ethConfig;
|
|
36
40
|
this.provider = new JsonRpcProvider(config.url);
|
|
37
41
|
this.stateContract = new Contract(config.contractAddress, abi, this.provider);
|
|
38
42
|
this._transactionService = new TransactionService(this.getRpcProvider());
|
|
43
|
+
// Store cache options for later use
|
|
44
|
+
this._latestStateCacheOptions = {
|
|
45
|
+
ttl: options?.latestStateCacheOptions?.ttl ?? PROTOCOL_CONSTANTS.DEFAULT_PROOF_VERIFY_DELAY / 2,
|
|
46
|
+
maxSize: options?.latestStateCacheOptions?.maxSize ?? DEFAULT_CACHE_MAX_SIZE
|
|
47
|
+
};
|
|
48
|
+
this._stateCacheOptions = {
|
|
49
|
+
notReplacedTtl: options?.stateCacheOptions?.notReplacedTtl ??
|
|
50
|
+
PROTOCOL_CONSTANTS.DEFAULT_PROOF_VERIFY_DELAY / 2,
|
|
51
|
+
replacedTtl: options?.stateCacheOptions?.replacedTtl ?? PROTOCOL_CONSTANTS.DEFAULT_PROOF_VERIFY_DELAY,
|
|
52
|
+
maxSize: options?.stateCacheOptions?.maxSize ?? DEFAULT_CACHE_MAX_SIZE
|
|
53
|
+
};
|
|
54
|
+
this._rootCacheOptions = {
|
|
55
|
+
replacedTtl: options?.rootCacheOptions?.replacedTtl ?? PROTOCOL_CONSTANTS.DEFAULT_AUTH_VERIFY_DELAY,
|
|
56
|
+
notReplacedTtl: options?.rootCacheOptions?.notReplacedTtl ??
|
|
57
|
+
PROTOCOL_CONSTANTS.DEFAULT_AUTH_VERIFY_DELAY / 2,
|
|
58
|
+
maxSize: options?.rootCacheOptions?.maxSize ?? DEFAULT_CACHE_MAX_SIZE
|
|
59
|
+
};
|
|
60
|
+
this._gistProofCacheOptions = {
|
|
61
|
+
ttl: PROTOCOL_CONSTANTS.DEFAULT_AUTH_VERIFY_DELAY / 2,
|
|
62
|
+
maxSize: options?.gistProofCacheOptions?.maxSize ?? DEFAULT_CACHE_MAX_SIZE
|
|
63
|
+
};
|
|
64
|
+
// Initialize cache instances
|
|
65
|
+
this._latestStateResolveCache =
|
|
66
|
+
options?.latestStateCacheOptions?.cache ??
|
|
67
|
+
createInMemoryCache({
|
|
68
|
+
maxSize: this._latestStateCacheOptions.maxSize,
|
|
69
|
+
ttl: this._latestStateCacheOptions.ttl
|
|
70
|
+
});
|
|
71
|
+
this._stateResolveCache =
|
|
72
|
+
options?.stateCacheOptions?.cache ??
|
|
73
|
+
createInMemoryCache({
|
|
74
|
+
maxSize: this._stateCacheOptions.maxSize,
|
|
75
|
+
ttl: this._stateCacheOptions.replacedTtl
|
|
76
|
+
});
|
|
77
|
+
this._rootResolveCache =
|
|
78
|
+
options?.rootCacheOptions?.cache ??
|
|
79
|
+
createInMemoryCache({
|
|
80
|
+
maxSize: this._rootCacheOptions.maxSize,
|
|
81
|
+
ttl: this._rootCacheOptions.replacedTtl
|
|
82
|
+
});
|
|
83
|
+
this._gistProofResolveCache =
|
|
84
|
+
options?.gistProofCacheOptions?.cache ??
|
|
85
|
+
createInMemoryCache({
|
|
86
|
+
maxSize: this._gistProofCacheOptions.maxSize,
|
|
87
|
+
ttl: this._gistProofCacheOptions.ttl
|
|
88
|
+
});
|
|
89
|
+
this._disableCache = options?.disableCache ?? false;
|
|
39
90
|
}
|
|
40
91
|
/** {@inheritdoc IStateStorage.getLatestStateById} */
|
|
41
92
|
async getLatestStateById(id) {
|
|
93
|
+
const cacheKey = this.getLatestStateCacheKey(id);
|
|
94
|
+
if (!this._disableCache) {
|
|
95
|
+
// Check cache first
|
|
96
|
+
const cachedResult = await this._latestStateResolveCache?.get(cacheKey);
|
|
97
|
+
if (cachedResult) {
|
|
98
|
+
return cachedResult;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
42
101
|
const { stateContract } = this.getStateContractAndProviderForId(id);
|
|
43
102
|
const rawData = await stateContract.getStateInfoById(id);
|
|
44
103
|
const stateInfo = {
|
|
@@ -50,10 +109,20 @@ export class EthStateStorage {
|
|
|
50
109
|
createdAtBlock: BigInt(rawData[5]),
|
|
51
110
|
replacedAtBlock: BigInt(rawData[6])
|
|
52
111
|
};
|
|
112
|
+
!this._disableCache &&
|
|
113
|
+
(await this._latestStateResolveCache?.set(cacheKey, stateInfo, this._latestStateCacheOptions.ttl));
|
|
53
114
|
return stateInfo;
|
|
54
115
|
}
|
|
55
116
|
/** {@inheritdoc IStateStorage.getStateInfoByIdAndState} */
|
|
56
117
|
async getStateInfoByIdAndState(id, state) {
|
|
118
|
+
const cacheKey = this.getStateCacheKey(id, state);
|
|
119
|
+
if (!this._disableCache) {
|
|
120
|
+
// Check cache first
|
|
121
|
+
const cachedResult = await this._stateResolveCache?.get(cacheKey);
|
|
122
|
+
if (cachedResult) {
|
|
123
|
+
return cachedResult;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
57
126
|
const { stateContract } = this.getStateContractAndProviderForId(id);
|
|
58
127
|
const rawData = await stateContract.getStateInfoByIdAndState(id, state);
|
|
59
128
|
const stateInfo = {
|
|
@@ -65,6 +134,10 @@ export class EthStateStorage {
|
|
|
65
134
|
createdAtBlock: BigInt(rawData[5]),
|
|
66
135
|
replacedAtBlock: BigInt(rawData[6])
|
|
67
136
|
};
|
|
137
|
+
const ttl = stateInfo.replacedAtTimestamp === 0n
|
|
138
|
+
? this._stateCacheOptions.notReplacedTtl
|
|
139
|
+
: this._stateCacheOptions.replacedTtl;
|
|
140
|
+
!this._disableCache && (await this._stateResolveCache?.set(cacheKey, stateInfo, ttl));
|
|
68
141
|
return stateInfo;
|
|
69
142
|
}
|
|
70
143
|
/** {@inheritdoc IStateStorage.publishState} */
|
|
@@ -137,9 +210,17 @@ export class EthStateStorage {
|
|
|
137
210
|
}
|
|
138
211
|
/** {@inheritdoc IStateStorage.getGISTProof} */
|
|
139
212
|
async getGISTProof(id) {
|
|
213
|
+
const cacheKey = this.getGistProofCacheKey(id);
|
|
214
|
+
if (!this._disableCache) {
|
|
215
|
+
// Check cache first
|
|
216
|
+
const cachedResult = await this._gistProofResolveCache?.get(cacheKey);
|
|
217
|
+
if (cachedResult) {
|
|
218
|
+
return cachedResult;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
140
221
|
const { stateContract } = this.getStateContractAndProviderForId(id);
|
|
141
222
|
const data = await stateContract.getGISTProof(id);
|
|
142
|
-
|
|
223
|
+
const stateProof = {
|
|
143
224
|
root: BigInt(data.root.toString()),
|
|
144
225
|
existence: data.existence,
|
|
145
226
|
siblings: data.siblings?.map((sibling) => BigInt(sibling.toString())),
|
|
@@ -149,12 +230,23 @@ export class EthStateStorage {
|
|
|
149
230
|
auxIndex: BigInt(data.auxIndex.toString()),
|
|
150
231
|
auxValue: BigInt(data.auxValue.toString())
|
|
151
232
|
};
|
|
233
|
+
!this._disableCache &&
|
|
234
|
+
(await this._gistProofResolveCache?.set(cacheKey, stateProof, this._gistProofCacheOptions.ttl));
|
|
235
|
+
return stateProof;
|
|
152
236
|
}
|
|
153
237
|
/** {@inheritdoc IStateStorage.getGISTRootInfo} */
|
|
154
238
|
async getGISTRootInfo(root, id) {
|
|
239
|
+
const cacheKey = this.getRootCacheKey(root);
|
|
240
|
+
if (!this._disableCache) {
|
|
241
|
+
// Check cache first
|
|
242
|
+
const cachedResult = await this._rootResolveCache?.get(cacheKey);
|
|
243
|
+
if (cachedResult) {
|
|
244
|
+
return cachedResult;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
155
247
|
const { stateContract } = this.getStateContractAndProviderForId(id);
|
|
156
248
|
const data = await stateContract.getGISTRootInfo(root);
|
|
157
|
-
|
|
249
|
+
const rootInfo = {
|
|
158
250
|
root: BigInt(data.root.toString()),
|
|
159
251
|
replacedByRoot: BigInt(data.replacedByRoot.toString()),
|
|
160
252
|
createdAtTimestamp: BigInt(data.createdAtTimestamp.toString()),
|
|
@@ -162,11 +254,24 @@ export class EthStateStorage {
|
|
|
162
254
|
createdAtBlock: BigInt(data.createdAtBlock.toString()),
|
|
163
255
|
replacedAtBlock: BigInt(data.replacedAtBlock.toString())
|
|
164
256
|
};
|
|
257
|
+
const ttl = rootInfo.replacedAtTimestamp == 0n
|
|
258
|
+
? this._rootCacheOptions.notReplacedTtl
|
|
259
|
+
: this._rootCacheOptions.replacedTtl;
|
|
260
|
+
!this._disableCache && (await this._rootResolveCache?.set(cacheKey, rootInfo, ttl));
|
|
261
|
+
return rootInfo;
|
|
165
262
|
}
|
|
166
263
|
/** {@inheritdoc IStateStorage.getRpcProvider} */
|
|
167
264
|
getRpcProvider() {
|
|
168
265
|
return this.provider;
|
|
169
266
|
}
|
|
267
|
+
/** enable caching */
|
|
268
|
+
enableCache() {
|
|
269
|
+
this._disableCache = false;
|
|
270
|
+
}
|
|
271
|
+
/** disable caching */
|
|
272
|
+
disableCache() {
|
|
273
|
+
this._disableCache = true;
|
|
274
|
+
}
|
|
170
275
|
getStateContractAndProviderForId(id) {
|
|
171
276
|
const idTyped = Id.fromBigInt(id);
|
|
172
277
|
const chainId = getChainId(DID.blockchainFromId(idTyped), DID.networkIdFromId(idTyped));
|
|
@@ -183,4 +288,16 @@ export class EthStateStorage {
|
|
|
183
288
|
}
|
|
184
289
|
return network;
|
|
185
290
|
}
|
|
291
|
+
getGistProofCacheKey(id) {
|
|
292
|
+
return `gist-${id.toString()}`;
|
|
293
|
+
}
|
|
294
|
+
getLatestStateCacheKey(id) {
|
|
295
|
+
return `latest-${id.toString()}`;
|
|
296
|
+
}
|
|
297
|
+
getStateCacheKey(id, state) {
|
|
298
|
+
return `${id.toString()}-${state.toString()}`;
|
|
299
|
+
}
|
|
300
|
+
getRootCacheKey(root) {
|
|
301
|
+
return root.toString();
|
|
302
|
+
}
|
|
186
303
|
}
|