Skip to content

Commit 19cd6c8

Browse files
authored
Merge pull request #858 from LIT-Protocol/hwrdtm/load-test-tweaks
Load Test Scripts
2 parents 61fe370 + df58fdf commit 19cd6c8

File tree

8 files changed

+249
-10
lines changed

8 files changed

+249
-10
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
config:
2+
target: "dummy"
3+
phases:
4+
# Over 60s, ramp up to creating 50 vusers per second
5+
- duration: 60
6+
arrivalRate: 5
7+
rampTo: 150
8+
name: "Ramp Up"
9+
# Over 300s, create 50 vusers per second
10+
- duration: 300
11+
arrivalRate: 150
12+
name: "Sustained Encrypt & Decrypt"
13+
# Over 60s, ramp down to creating 5 vusers per second
14+
- duration: 60
15+
arrivalRate: 20
16+
name: "Ramp Down"
17+
processor: "../src/processors/multi-endpoints.ts"
18+
19+
scenarios:
20+
- name: "Encrypt & Decrypt Stress Test"
21+
weight: 100
22+
flow:
23+
- function: "runEncryptDecryptTest"
24+
- think: 0.1

e2e/artillery/configs/execute.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
config:
2+
target: "dummy"
3+
phases:
4+
# Over 60s, ramp up to creating 50 vusers per second
5+
- duration: 60
6+
arrivalRate: 5
7+
rampTo: 100
8+
name: "Ramp Up"
9+
# Over 300s, create 50 vusers per second
10+
- duration: 300
11+
arrivalRate: 100
12+
name: "Sustained Encrypt & Decrypt"
13+
# Over 60s, ramp down to creating 5 vusers per second
14+
- duration: 60
15+
arrivalRate: 20
16+
name: "Ramp Down"
17+
processor: "../src/processors/multi-endpoints.ts"
18+
19+
scenarios:
20+
- name: "Execute JS Stress Test"
21+
weight: 100
22+
flow:
23+
- function: "runExecuteJSTest"
24+
- think: 0.1

e2e/artillery/configs/mix.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
config:
2+
target: "dummy"
3+
phases:
4+
# Over 60s, ramp up to creating 50 vusers per second
5+
- duration: 60
6+
arrivalRate: 5
7+
rampTo: 75
8+
name: "Ramp Up"
9+
# Over 300s, create 50 vusers per second
10+
- duration: 300
11+
arrivalRate: 75
12+
name: "Sustained Encrypt & Decrypt"
13+
# Over 60s, ramp down to creating 5 vusers per second
14+
- duration: 60
15+
arrivalRate: 20
16+
name: "Ramp Down"
17+
processor: "../src/processors/multi-endpoints.ts"
18+
19+
scenarios:
20+
- name: "PKP Sign Stress Test"
21+
weight: 50
22+
flow:
23+
- function: "runPkpSignTest"
24+
- think: 0.1
25+
- name: "Encrypt & Decrypt Stress Test"
26+
weight: 25
27+
flow:
28+
- function: "runEncryptDecryptTest"
29+
- think: 0.1
30+
- name: "Execute JS Stress Test"
31+
weight: 25
32+
flow:
33+
- function: "runExecuteJSTest"
34+
- think: 0.1

e2e/artillery/configs/pkp-sign.yml

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,15 @@ config:
44
# Over 60s, ramp up to creating 50 vusers per second
55
- duration: 60
66
arrivalRate: 5
7-
# rampTo: 50
8-
rampTo: 10
9-
name: 'Ramp Up'
7+
rampTo: 80
8+
name: "Ramp Up"
109
# Over 300s, create 50 vusers per second
1110
- duration: 300
12-
# arrivalRate: 50
13-
arrivalRate: 10
14-
name: 'Sustained PKP Signing'
11+
arrivalRate: 80
12+
name: "Sustained PKP Signing"
1513
# Over 60s, ramp down to creating 5 vusers per second
1614
- duration: 60
17-
arrivalRate: 5
15+
arrivalRate: 20
1816
name: 'Ramp Down'
1917
processor: '../src/processors/multi-endpoints.ts'
2018

e2e/artillery/src/init.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const _network = process.env['NETWORK'];
1414

1515
// CONFIGURATIONS
1616
const REJECT_BALANCE_THRESHOLD = 0;
17-
const LEDGER_MINIMUM_BALANCE = 10000;
17+
const LEDGER_MINIMUM_BALANCE = 20000;
1818

1919
(async () => {
2020
// -- Start

e2e/artillery/src/processors/multi-endpoints.ts

Lines changed: 156 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { z } from 'zod';
44
import * as StateManager from '../StateManager';
55
import * as NetworkManager from '../../../src/helper/NetworkManager';
66
import * as AccountManager from '../AccountManager';
7+
import { createAccBuilder } from '@lit-protocol/access-control-conditions';
78

89
// PKP Sign Result Schema
910
const PkpSignResultSchema = z.object({
@@ -17,6 +18,28 @@ const PkpSignResultSchema = z.object({
1718
sigType: z.string().min(1, 'Signature type cannot be empty'),
1819
});
1920

21+
// Execute JS Result Schema
22+
const ExecuteJsResultSchema = z.object({
23+
success: z.boolean(),
24+
signatures: z.record(
25+
z.string(),
26+
z.object({
27+
signature: z.string().regex(/^0x[a-fA-F0-9]+$/, 'Invalid hex signature'),
28+
verifyingKey: z
29+
.string()
30+
.regex(/^0x[a-fA-F0-9]+$/, 'Invalid hex verifying key'),
31+
signedData: z
32+
.string()
33+
.regex(/^0x[a-fA-F0-9]+$/, 'Invalid hex signed data'),
34+
recoveryId: z.number().int().min(0).max(3, 'Recovery ID must be 0-3'),
35+
publicKey: z.string().regex(/^0x[a-fA-F0-9]+$/, 'Invalid hex public key'),
36+
sigType: z.string().min(1, 'Signature type cannot be empty'),
37+
})
38+
),
39+
response: z.string(),
40+
logs: z.string(),
41+
});
42+
2043
// Global variables to cache expensive operations
2144
let litClient: LitClientType;
2245
let authManager: any = null;
@@ -147,6 +170,137 @@ export async function runPkpSignTest() {
147170
}
148171
}
149172

173+
// test '/web/encryption/sign/v2' endpoint
174+
export async function runEncryptDecryptTest() {
175+
const startTime = Date.now();
176+
177+
try {
178+
// 1. Initialise shared resources (only happens once)
179+
await initialiseSharedResources();
180+
181+
// 2. Read state
182+
const state = await StateManager.readFile();
183+
184+
// Create auth context
185+
const authContext = await createAuthContextFromState();
186+
187+
// Set up access control conditions requiring wallet ownership
188+
const addressToUse = authContext.account.address;
189+
const builder = createAccBuilder();
190+
const accs = builder
191+
.requireWalletOwnership(addressToUse)
192+
.on('ethereum')
193+
.build();
194+
195+
// Encrypt data with the access control conditions
196+
const dataToEncrypt = 'Hello from PKP encrypt-decrypt test!';
197+
const encryptedData = await litClient.encrypt({
198+
dataToEncrypt,
199+
unifiedAccessControlConditions: accs,
200+
chain: 'ethereum',
201+
});
202+
203+
// Decrypt the data using the appropriate auth context
204+
const decryptedData = await litClient.decrypt({
205+
data: encryptedData,
206+
unifiedAccessControlConditions: accs,
207+
chain: 'ethereum',
208+
authContext,
209+
});
210+
211+
// Assert that the decrypted data is the same as the original data
212+
if (decryptedData.convertedData !== dataToEncrypt) {
213+
throw new Error('❌ Decrypted data does not match the original data');
214+
}
215+
216+
const endTime = Date.now();
217+
const duration = endTime - startTime;
218+
219+
console.log(`✅ encrypt & decrypt successful in ${duration}ms`);
220+
221+
// For Artillery, just return - no need to call next()
222+
return;
223+
} catch (error) {
224+
const endTime = Date.now();
225+
const duration = endTime - startTime;
226+
227+
console.error(
228+
`❌ encrypt & decrypt failed in ${duration}ms:`,
229+
error instanceof Error ? error.message : String(error)
230+
);
231+
232+
// Throw the error to let Artillery handle it
233+
throw error;
234+
}
235+
}
236+
237+
// test '/web/execute/v2' endpoint
238+
export async function runExecuteJSTest() {
239+
const startTime = Date.now();
240+
241+
try {
242+
// 1. Initialise shared resources (only happens once)
243+
await initialiseSharedResources();
244+
245+
// 2. Read state
246+
const state = await StateManager.readFile();
247+
248+
// Create auth context
249+
const authContext = await createAuthContextFromState();
250+
251+
// Perform executeJs operation
252+
const litActionCode = `
253+
(async () => {
254+
const { sigName, toSign, publicKey } = jsParams;
255+
const { keccak256, arrayify } = ethers.utils;
256+
257+
const toSignBytes = new TextEncoder().encode(toSign);
258+
const toSignBytes32 = keccak256(toSignBytes);
259+
const toSignBytes32Array = arrayify(toSignBytes32);
260+
261+
const sigShare = await Lit.Actions.signEcdsa({
262+
toSign: toSignBytes32Array,
263+
publicKey,
264+
sigName,
265+
});
266+
})();`;
267+
268+
const result = await litClient.executeJs({
269+
code: litActionCode,
270+
authContext,
271+
jsParams: {
272+
message: 'Test message from e2e executeJs',
273+
sigName: 'e2e-test-sig',
274+
toSign: 'Test message from e2e executeJs',
275+
publicKey: state.masterAccount.pkp.publicKey,
276+
},
277+
});
278+
279+
// Validate the result using Zod schema
280+
const validatedResult = ExecuteJsResultSchema.parse(result);
281+
282+
const endTime = Date.now();
283+
const duration = endTime - startTime;
284+
285+
console.log(`✅ executeJs successful in ${duration}ms`);
286+
console.log('✅ executeJs result:', validatedResult);
287+
288+
// For Artillery, just return - no need to call next()
289+
return;
290+
} catch (error) {
291+
const endTime = Date.now();
292+
const duration = endTime - startTime;
293+
294+
console.error(
295+
`❌ executeJs failed in ${duration}ms:`,
296+
error instanceof Error ? error.message : String(error)
297+
);
298+
299+
// Throw the error to let Artillery handle it
300+
throw error;
301+
}
302+
}
303+
150304
// test '/web/sign_session_key' endpoint
151305
export async function runSignSessionKeyTest() {
152306
// ❗️ IT'S IMPORTANT TO SET THIS TO FALSE FOR TESTING
@@ -170,7 +324,8 @@ export async function runSignSessionKeyTest() {
170324
['lit-action-execution', '*'],
171325
['access-control-condition-decryption', '*'],
172326
],
173-
expiration: new Date(Date.now() + 1000 * 60 * 15).toISOString(),
327+
// 30m expiration
328+
expiration: new Date(Date.now() + 1000 * 60 * 30).toISOString(),
174329
},
175330
litClient: litClient,
176331
cache: {

e2e/src/init.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,8 @@ export const init = async (
224224
['lit-action-execution', '*'],
225225
['access-control-condition-decryption', '*'],
226226
],
227-
expiration: new Date(Date.now() + 1000 * 60 * 15).toISOString(),
227+
// 30m expiration
228+
expiration: new Date(Date.now() + 1000 * 60 * 30).toISOString(),
228229
},
229230
litClient: litClient,
230231
});

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
"artillery:init": "bun run ./e2e/artillery/src/init.ts",
2929
"artillery:balance-status": "LOG_LEVEL=silent bun run ./e2e/artillery/src/balance-status.ts",
3030
"artillery:pkp-sign": "DEBUG_HTTP=true LOG_LEVEL=silent dotenvx run --env-file=.env -- sh -c 'artillery run ./e2e/artillery/configs/pkp-sign.yml ${ARTILLERY_KEY:+--record --key $ARTILLERY_KEY}'",
31+
"artillery:encrypt-decrypt": "DEBUG_HTTP=true LOG_LEVEL=silent dotenvx run --env-file=.env -- sh -c 'artillery run ./e2e/artillery/configs/encrypt-decrypt.yml ${ARTILLERY_KEY:+--record --key $ARTILLERY_KEY}'",
32+
"artillery:execute-js": "DEBUG_HTTP=true LOG_LEVEL=silent dotenvx run --env-file=.env -- sh -c 'artillery run ./e2e/artillery/configs/execute.yml ${ARTILLERY_KEY:+--record --key $ARTILLERY_KEY}'",
33+
"artillery:mix": "DEBUG_HTTP=true LOG_LEVEL=silent dotenvx run --env-file=.env -- sh -c 'artillery run ./e2e/artillery/configs/mix.yml ${ARTILLERY_KEY:+--record --key $ARTILLERY_KEY}'",
3134
"artillery:sign-session-key": "DEBUG_HTTP=true LOG_LEVEL=silent dotenvx run --env-file=.env -- sh -c 'artillery run ./e2e/artillery/configs/sign-session-key.yml ${ARTILLERY_KEY:+--record --key $ARTILLERY_KEY}'"
3235
},
3336
"private": true,

0 commit comments

Comments
 (0)