Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions e2e/artillery/configs/encrypt-decrypt.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
config:
target: "dummy"
phases:
# Over 60s, ramp up to creating 50 vusers per second
- duration: 60
arrivalRate: 5
rampTo: 150
name: "Ramp Up"
# Over 300s, create 50 vusers per second
- duration: 300
arrivalRate: 150
name: "Sustained Encrypt & Decrypt"
# Over 60s, ramp down to creating 5 vusers per second
- duration: 60
arrivalRate: 20
name: "Ramp Down"
processor: "../src/processors/multi-endpoints.ts"

scenarios:
- name: "Encrypt & Decrypt Stress Test"
weight: 100
flow:
- function: "runEncryptDecryptTest"
- think: 0.1
24 changes: 24 additions & 0 deletions e2e/artillery/configs/execute.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
config:
target: "dummy"
phases:
# Over 60s, ramp up to creating 50 vusers per second
- duration: 60
arrivalRate: 5
rampTo: 100
name: "Ramp Up"
# Over 300s, create 50 vusers per second
- duration: 300
arrivalRate: 100
name: "Sustained Encrypt & Decrypt"
# Over 60s, ramp down to creating 5 vusers per second
- duration: 60
arrivalRate: 20
name: "Ramp Down"
processor: "../src/processors/multi-endpoints.ts"

scenarios:
- name: "Execute JS Stress Test"
weight: 100
flow:
- function: "runExecuteJSTest"
- think: 0.1
34 changes: 34 additions & 0 deletions e2e/artillery/configs/mix.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
config:
target: "dummy"
phases:
# Over 60s, ramp up to creating 50 vusers per second
- duration: 60
arrivalRate: 5
rampTo: 75
name: "Ramp Up"
# Over 300s, create 50 vusers per second
- duration: 300
arrivalRate: 75
name: "Sustained Encrypt & Decrypt"
# Over 60s, ramp down to creating 5 vusers per second
- duration: 60
arrivalRate: 20
name: "Ramp Down"
processor: "../src/processors/multi-endpoints.ts"

scenarios:
- name: "PKP Sign Stress Test"
weight: 50
flow:
- function: "runPkpSignTest"
- think: 0.1
- name: "Encrypt & Decrypt Stress Test"
weight: 25
flow:
- function: "runEncryptDecryptTest"
- think: 0.1
- name: "Execute JS Stress Test"
weight: 25
flow:
- function: "runExecuteJSTest"
- think: 0.1
12 changes: 5 additions & 7 deletions e2e/artillery/configs/pkp-sign.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,15 @@ config:
# Over 60s, ramp up to creating 50 vusers per second
- duration: 60
arrivalRate: 5
# rampTo: 50
rampTo: 10
name: 'Ramp Up'
rampTo: 80
name: "Ramp Up"
# Over 300s, create 50 vusers per second
- duration: 300
# arrivalRate: 50
arrivalRate: 10
name: 'Sustained PKP Signing'
arrivalRate: 80
name: "Sustained PKP Signing"
# Over 60s, ramp down to creating 5 vusers per second
- duration: 60
arrivalRate: 5
arrivalRate: 20
name: 'Ramp Down'
processor: '../src/processors/multi-endpoints.ts'

Expand Down
2 changes: 1 addition & 1 deletion e2e/artillery/src/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const _network = process.env['NETWORK'];

// CONFIGURATIONS
const REJECT_BALANCE_THRESHOLD = 0;
const LEDGER_MINIMUM_BALANCE = 10000;
const LEDGER_MINIMUM_BALANCE = 20000;

(async () => {
// -- Start
Expand Down
157 changes: 156 additions & 1 deletion e2e/artillery/src/processors/multi-endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { z } from 'zod';
import * as StateManager from '../StateManager';
import * as NetworkManager from '../../../src/helper/NetworkManager';
import * as AccountManager from '../AccountManager';
import { createAccBuilder } from '@lit-protocol/access-control-conditions';

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

// Execute JS Result Schema
const ExecuteJsResultSchema = z.object({
success: z.boolean(),
signatures: z.record(
z.string(),
z.object({
signature: z.string().regex(/^0x[a-fA-F0-9]+$/, 'Invalid hex signature'),
verifyingKey: z
.string()
.regex(/^0x[a-fA-F0-9]+$/, 'Invalid hex verifying key'),
signedData: z
.string()
.regex(/^0x[a-fA-F0-9]+$/, 'Invalid hex signed data'),
recoveryId: z.number().int().min(0).max(3, 'Recovery ID must be 0-3'),
publicKey: z.string().regex(/^0x[a-fA-F0-9]+$/, 'Invalid hex public key'),
sigType: z.string().min(1, 'Signature type cannot be empty'),
})
),
response: z.string(),
logs: z.string(),
});

// Global variables to cache expensive operations
let litClient: LitClientType;
let authManager: any = null;
Expand Down Expand Up @@ -147,6 +170,137 @@ export async function runPkpSignTest() {
}
}

// test '/web/encryption/sign/v2' endpoint
export async function runEncryptDecryptTest() {
const startTime = Date.now();

try {
// 1. Initialise shared resources (only happens once)
await initialiseSharedResources();

// 2. Read state
const state = await StateManager.readFile();

// Create auth context
const authContext = await createAuthContextFromState();

// Set up access control conditions requiring wallet ownership
const addressToUse = authContext.account.address;
const builder = createAccBuilder();
const accs = builder
.requireWalletOwnership(addressToUse)
.on('ethereum')
.build();

// Encrypt data with the access control conditions
const dataToEncrypt = 'Hello from PKP encrypt-decrypt test!';
const encryptedData = await litClient.encrypt({
dataToEncrypt,
unifiedAccessControlConditions: accs,
chain: 'ethereum',
});

// Decrypt the data using the appropriate auth context
const decryptedData = await litClient.decrypt({
data: encryptedData,
unifiedAccessControlConditions: accs,
chain: 'ethereum',
authContext,
});

// Assert that the decrypted data is the same as the original data
if (decryptedData.convertedData !== dataToEncrypt) {
throw new Error('❌ Decrypted data does not match the original data');
}

const endTime = Date.now();
const duration = endTime - startTime;

console.log(`✅ encrypt & decrypt successful in ${duration}ms`);

// For Artillery, just return - no need to call next()
return;
} catch (error) {
const endTime = Date.now();
const duration = endTime - startTime;

console.error(
`❌ encrypt & decrypt failed in ${duration}ms:`,
error instanceof Error ? error.message : String(error)
);

// Throw the error to let Artillery handle it
throw error;
}
}

// test '/web/execute/v2' endpoint
export async function runExecuteJSTest() {
const startTime = Date.now();

try {
// 1. Initialise shared resources (only happens once)
await initialiseSharedResources();

// 2. Read state
const state = await StateManager.readFile();

// Create auth context
const authContext = await createAuthContextFromState();

// Perform executeJs operation
const litActionCode = `
(async () => {
const { sigName, toSign, publicKey } = jsParams;
const { keccak256, arrayify } = ethers.utils;

const toSignBytes = new TextEncoder().encode(toSign);
const toSignBytes32 = keccak256(toSignBytes);
const toSignBytes32Array = arrayify(toSignBytes32);

const sigShare = await Lit.Actions.signEcdsa({
toSign: toSignBytes32Array,
publicKey,
sigName,
});
})();`;

const result = await litClient.executeJs({
code: litActionCode,
authContext,
jsParams: {
message: 'Test message from e2e executeJs',
sigName: 'e2e-test-sig',
toSign: 'Test message from e2e executeJs',
publicKey: state.masterAccount.pkp.publicKey,
},
});

// Validate the result using Zod schema
const validatedResult = ExecuteJsResultSchema.parse(result);

const endTime = Date.now();
const duration = endTime - startTime;

console.log(`✅ executeJs successful in ${duration}ms`);
console.log('✅ executeJs result:', validatedResult);

// For Artillery, just return - no need to call next()
return;
} catch (error) {
const endTime = Date.now();
const duration = endTime - startTime;

console.error(
`❌ executeJs failed in ${duration}ms:`,
error instanceof Error ? error.message : String(error)
);

// Throw the error to let Artillery handle it
throw error;
}
}

// test '/web/sign_session_key' endpoint
export async function runSignSessionKeyTest() {
// ❗️ IT'S IMPORTANT TO SET THIS TO FALSE FOR TESTING
Expand All @@ -170,7 +324,8 @@ export async function runSignSessionKeyTest() {
['lit-action-execution', '*'],
['access-control-condition-decryption', '*'],
],
expiration: new Date(Date.now() + 1000 * 60 * 15).toISOString(),
// 30m expiration
expiration: new Date(Date.now() + 1000 * 60 * 30).toISOString(),
},
litClient: litClient,
cache: {
Expand Down
3 changes: 2 additions & 1 deletion e2e/src/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,8 @@ export const init = async (
['lit-action-execution', '*'],
['access-control-condition-decryption', '*'],
],
expiration: new Date(Date.now() + 1000 * 60 * 15).toISOString(),
// 30m expiration
expiration: new Date(Date.now() + 1000 * 60 * 30).toISOString(),
},
litClient: litClient,
});
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
"artillery:init": "bun run ./e2e/artillery/src/init.ts",
"artillery:balance-status": "LOG_LEVEL=silent bun run ./e2e/artillery/src/balance-status.ts",
"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}'",
"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}'",
"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}'",
"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}'",
"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}'"
},
"private": true,
Expand Down
Loading