Skip to content

Commit 0730bbe

Browse files
authored
Merge pull request #848 from LIT-Protocol/feature/jss-24-feature-update-datil-sdk-to-make-endpoint-health-checks-more
Feature/jss 24 feature update datil sdk to make endpoint health checks more
2 parents 6eef0b1 + f1f9373 commit 0730bbe

File tree

9 files changed

+1248
-8847
lines changed

9 files changed

+1248
-8847
lines changed

.env.sample

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,7 @@ TESTNET_MANAGER_URL=http://0.0.0.0:8000
1919
USE_LIT_BINARIES=true
2020
LIT_NODE_BINARY_PATH=/path/to/lit_node/binary
2121
LIT_ACTION_BINARY_PATH=/path/to/lit_action_binary
22+
23+
# ---------- For Health check ----------
24+
LIT_STATUS_BACKEND_URL=CHANGE_THIS
25+
LIT_STATUS_WRITE_KEY=CHANGE_THIS

local-tests/build.mjs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,28 @@ export const build = async () => {
3030
inject: [`./${TEST_DIR}/shim.mjs`],
3131
mainFields: ['module', 'main'],
3232
});
33+
34+
await esbuild.build({
35+
entryPoints: [`${TEST_DIR}/health/index.ts`],
36+
outfile: `./${TEST_DIR}/build/health/index.mjs`,
37+
bundle: true,
38+
plugins: [
39+
nodeExternalsPlugin({
40+
allowList: [
41+
'ethers',
42+
'@lit-protocol/accs-schemas',
43+
'@lit-protocol/contracts',
44+
'crypto',
45+
'secp256k1',
46+
],
47+
}),
48+
],
49+
platform: 'node',
50+
target: 'esnext',
51+
format: 'esm',
52+
inject: [`./${TEST_DIR}/shim.mjs`],
53+
mainFields: ['module', 'main'],
54+
});
3355
};
3456

3557
/**
@@ -56,10 +78,36 @@ try {
5678
}
5779
};
5880

81+
/**
82+
* Adds crypto polyfill to health check build
83+
*/
84+
export const postBuildHealthPolyfill = () => {
85+
try {
86+
const file = fs.readFileSync(
87+
`./${TEST_DIR}/build/health/index.mjs`,
88+
'utf8'
89+
);
90+
const content = `// Additional crypto polyfill check
91+
try {
92+
if (!globalThis.crypto && typeof webcrypto !== 'undefined') {
93+
globalThis.crypto = webcrypto;
94+
}
95+
} catch (error) {
96+
console.error('❌ Error in crypto polyfill', error);
97+
}
98+
`;
99+
const newFile = content + file;
100+
fs.writeFileSync(`./${TEST_DIR}/build/health/index.mjs`, newFile);
101+
} catch (e) {
102+
throw new Error(`Error in postBuildHealthPolyfill: ${e}`);
103+
}
104+
};
105+
59106
// Go!
60107
(async () => {
61108
const start = Date.now();
62109
await build();
63110
postBuildPolyfill();
111+
postBuildHealthPolyfill();
64112
console.log(`[build.mjs] 🚀 Build time: ${Date.now() - start}ms`);
65113
})();
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import { getEoaSessionSigs } from 'local-tests/setup/session-sigs/get-eoa-session-sigs';
2+
import { getPkpSessionSigs } from 'local-tests/setup/session-sigs/get-pkp-session-sigs';
3+
import { TinnyEnvironment } from 'local-tests/setup/tinny-environment';
4+
import { TinnyPerson } from 'local-tests/setup/tinny-person';
5+
import { LIT_ABILITY } from '@lit-protocol/constants';
6+
import { ILitNodeClient } from '@lit-protocol/types';
7+
import { AccessControlConditions } from 'local-tests/setup/accs/accs';
8+
import { LitAccessControlConditionResource } from '@lit-protocol/auth-helpers';
9+
import { encryptString, decryptToString } from '@lit-protocol/encryption';
10+
11+
export class DatilHealthManager {
12+
env: TinnyEnvironment;
13+
alice: TinnyPerson;
14+
eoaSessionSigs: any;
15+
16+
constructor() {
17+
this.env = new TinnyEnvironment();
18+
}
19+
20+
async init() {
21+
await this.env.init();
22+
}
23+
24+
// ========== Person Creation ==========
25+
// create a person
26+
// this action contains chain & rpc interactions
27+
// best to cache it, but for the time being, we will create a new person for each test, since we are only running this test
28+
// once in every 30 minutes.
29+
async initPerson() {
30+
this.alice = await this.env.createNewPerson('Alice');
31+
this.eoaSessionSigs = await getEoaSessionSigs(this.env, this.alice);
32+
}
33+
34+
validatePrerequisites() {
35+
if (!this.alice) {
36+
throw new Error('❌ Person not initialized');
37+
}
38+
if (!this.eoaSessionSigs) {
39+
throw new Error('❌ EOA Session Sigs not initialized');
40+
}
41+
}
42+
43+
// ========== Endpoint Tests ==========
44+
handshakeTest = async () => {
45+
try {
46+
await this.env.setupLitNodeClient();
47+
} catch (e) {
48+
console.error('❌ Failed to setup Lit Node Client');
49+
throw e;
50+
}
51+
};
52+
53+
pkpSignTest = async () => {
54+
this.validatePrerequisites();
55+
try {
56+
await this.env.litNodeClient.pkpSign({
57+
toSign: this.alice.loveLetter,
58+
pubKey: this.alice.pkp.publicKey,
59+
sessionSigs: this.eoaSessionSigs,
60+
});
61+
} catch (e) {
62+
console.error('❌ Failed to run pkpSign');
63+
throw e;
64+
}
65+
};
66+
67+
signSessionKeyTest = async () => {
68+
this.validatePrerequisites();
69+
try {
70+
await getPkpSessionSigs(this.env, this.alice);
71+
} catch (e) {
72+
console.error('❌ Failed to run signSessionKey');
73+
throw e;
74+
}
75+
};
76+
77+
executeJsTest = async () => {
78+
this.validatePrerequisites();
79+
try {
80+
await this.env.litNodeClient.executeJs({
81+
sessionSigs: this.eoaSessionSigs,
82+
code: `(async () => {
83+
const sigShare = await LitActions.signEcdsa({
84+
toSign: dataToSign,
85+
publicKey,
86+
sigName: "sig",
87+
});
88+
})();`,
89+
jsParams: {
90+
dataToSign: this.alice.loveLetter,
91+
publicKey: this.alice.pkp.publicKey,
92+
},
93+
});
94+
} catch (e) {
95+
console.error('❌ Failed to run executeJs');
96+
throw e;
97+
}
98+
};
99+
100+
decryptTest = async () => {
101+
this.validatePrerequisites();
102+
try {
103+
// Set access control conditions for encrypting and decrypting
104+
const accs = AccessControlConditions.getEmvBasicAccessControlConditions({
105+
userAddress: this.alice.wallet.address,
106+
});
107+
108+
// First encrypt some test data
109+
const encryptRes = await encryptString(
110+
{
111+
accessControlConditions: accs,
112+
dataToEncrypt: 'Hello world',
113+
},
114+
this.env.litNodeClient as unknown as ILitNodeClient
115+
);
116+
117+
if (!encryptRes.ciphertext) {
118+
throw new Error(`Expected "ciphertext" in encryptRes`);
119+
}
120+
121+
if (!encryptRes.dataToEncryptHash) {
122+
throw new Error(`Expected "dataToEncryptHash" in encryptRes`);
123+
}
124+
125+
// Generate resource string for the encrypted data
126+
const accsResourceString =
127+
await LitAccessControlConditionResource.generateResourceString(
128+
accs,
129+
encryptRes.dataToEncryptHash
130+
);
131+
132+
// Get session sigs with decryption capability
133+
const eoaSessionSigs = await getEoaSessionSigs(this.env, this.alice, [
134+
{
135+
resource: new LitAccessControlConditionResource(accsResourceString),
136+
ability: LIT_ABILITY.AccessControlConditionDecryption,
137+
},
138+
]);
139+
140+
// Decrypt the encrypted string
141+
const decryptRes = await decryptToString(
142+
{
143+
accessControlConditions: accs,
144+
ciphertext: encryptRes.ciphertext,
145+
dataToEncryptHash: encryptRes.dataToEncryptHash,
146+
sessionSigs: eoaSessionSigs,
147+
chain: 'ethereum',
148+
},
149+
this.env.litNodeClient as unknown as ILitNodeClient
150+
);
151+
152+
if (decryptRes !== 'Hello world') {
153+
throw new Error(
154+
`Expected decryptRes to be 'Hello world' but got ${decryptRes}`
155+
);
156+
}
157+
} catch (e) {
158+
console.error('❌ Failed to run decrypt');
159+
throw e;
160+
}
161+
};
162+
}

local-tests/health/index.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { createLitStatusClient } from '@lit-protocol/lit-status-sdk';
2+
import { DatilHealthManager } from './DatilHealthManager';
3+
4+
// Configuration
5+
const NETWORK = process.env.NETWORK!;
6+
const PRODUCT = 'js-sdk/datil';
7+
8+
async function runHealthCheck() {
9+
if (!NETWORK) {
10+
throw new Error('❌ NETWORK is not set');
11+
}
12+
13+
const statusClient = createLitStatusClient({
14+
url: process.env.LIT_STATUS_BACKEND_URL,
15+
apiKey: process.env.LIT_STATUS_WRITE_KEY,
16+
});
17+
18+
const txs = await statusClient.getOrRegisterFunctions({
19+
network: NETWORK,
20+
product: PRODUCT,
21+
functions: [
22+
'handshake',
23+
'pkpSign',
24+
'signSessionKey',
25+
'executeJs',
26+
'decrypt',
27+
] as const,
28+
});
29+
30+
const healthManager = new DatilHealthManager();
31+
await healthManager.init();
32+
33+
// (test) /web/handshake
34+
console.log('🔄 Running handshake test');
35+
await statusClient.executeAndLog(
36+
txs.handshake.id,
37+
healthManager.handshakeTest
38+
);
39+
40+
// after handshake, we can create a person to test
41+
await healthManager.initPerson();
42+
43+
// (test) /web/pkp/sign
44+
console.log('🔄 Running pkpSign test');
45+
await statusClient.executeAndLog(txs.pkpSign.id, healthManager.pkpSignTest);
46+
47+
// (test) /web/sign_session_key
48+
console.log('🔄 Running signSessionKey test');
49+
await statusClient.executeAndLog(
50+
txs.signSessionKey.id,
51+
healthManager.signSessionKeyTest
52+
);
53+
54+
// (test) /web/execute
55+
console.log('🔄 Running executeJs test');
56+
await statusClient.executeAndLog(
57+
txs.executeJs.id,
58+
healthManager.executeJsTest
59+
);
60+
61+
// (test) /web/encryption/sign
62+
console.log('🔄 Running decryptTest test');
63+
await statusClient.executeAndLog(txs.decrypt.id, healthManager.decryptTest);
64+
}
65+
66+
(async () => {
67+
try {
68+
await runHealthCheck();
69+
} catch (error) {
70+
console.error(error);
71+
} finally {
72+
process.exit();
73+
}
74+
})();

local-tests/setup/tinny-environment.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,10 @@ export class TinnyEnvironment {
402402
async setupBareEthAuthSig() {
403403
const privateKey = await this.getAvailablePrivateKey();
404404
try {
405-
const provider = new ethers.providers.JsonRpcBatchProvider(this.rpc);
405+
const provider = new ethers.providers.StaticJsonRpcProvider({
406+
url: this.rpc,
407+
skipFetchSetup: true,
408+
});
406409
const wallet = new ethers.Wallet(privateKey.privateKey, provider);
407410

408411
const toSign = await createSiweMessage({
@@ -450,7 +453,10 @@ export class TinnyEnvironment {
450453
const privateKey = await this.getAvailablePrivateKey();
451454

452455
try {
453-
const provider = new ethers.providers.JsonRpcBatchProvider(this.rpc);
456+
const provider = new ethers.providers.StaticJsonRpcProvider({
457+
url: this.rpc,
458+
skipFetchSetup: true,
459+
});
454460
const wallet = new ethers.Wallet(privateKey.privateKey, provider);
455461

456462
const tx = await wallet.sendTransaction({
@@ -473,7 +479,10 @@ export class TinnyEnvironment {
473479
*/
474480
setupSuperCapacityDelegationAuthSig = async () => {
475481
const privateKey = await this.getAvailablePrivateKey();
476-
const provider = new ethers.providers.JsonRpcBatchProvider(this.rpc);
482+
const provider = new ethers.providers.StaticJsonRpcProvider({
483+
url: this.rpc,
484+
skipFetchSetup: true,
485+
});
477486
const wallet = new ethers.Wallet(privateKey.privateKey, provider);
478487

479488
/**
@@ -498,6 +507,7 @@ export class TinnyEnvironment {
498507
this.contractsClient = new LitContracts({
499508
signer: wallet,
500509
debug: this.processEnvs.DEBUG,
510+
rpc: this.rpc,
501511
network: this.network,
502512
});
503513
}

local-tests/shim.mjs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
11
import { createRequire } from 'module';
2+
import { webcrypto } from 'node:crypto';
3+
24
const require = createRequire(import.meta.url);
35
global.require = require;
6+
7+
// Add crypto polyfill for Node.js
8+
if (!globalThis.crypto) {
9+
globalThis.crypto = webcrypto;
10+
}

package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"test:unit": "nx run-many --target=test",
2121
"test:unit:watch": "nx run-many --target=test --watch",
2222
"test:unit:bun": "bun ./tools/scripts/unit-test-with-bun.mjs",
23+
"test:health": "DEBUG=false node ./local-tests/build.mjs && dotenvx run --env-file=.env -- node ./local-tests/build/health/index.mjs",
2324
"publish:packages": "yarn node ./tools/scripts/pub.mjs --prod",
2425
"publish:beta": "yarn node ./tools/scripts/pub.mjs --tag beta",
2526
"publish:staging": "yarn node ./tools/scripts/pub.mjs --tag staging",
@@ -42,6 +43,7 @@
4243
"@dotenvx/dotenvx": "^1.6.4",
4344
"@lit-protocol/accs-schemas": "^0.0.31",
4445
"@lit-protocol/contracts": "^0.0.74",
46+
"@lit-protocol/lit-status-sdk": "^0.1.8",
4547
"@metamask/eth-sig-util": "5.0.2",
4648
"@mysten/sui.js": "^0.37.1",
4749
"@openagenda/verror": "^3.1.4",
@@ -97,9 +99,6 @@
9799
"babel-jest": "27.5.1",
98100
"buffer": "^6.0.3",
99101
"chalk": "^5.3.0",
100-
"cypress": "11.0.1",
101-
"cypress-metamask": "^1.0.5-development",
102-
"cypress-metamask-v2": "^1.7.2",
103102
"esbuild": "^0.17.3",
104103
"esbuild-node-builtins": "^0.1.0",
105104
"esbuild-node-externals": "^1.14.0",

0 commit comments

Comments
 (0)