Skip to content

Commit c6fc281

Browse files
authored
Merge pull request #990 from LIT-Protocol/fix/artillery
fix(artillery): align init helpers, state cache, and docs
2 parents 2719265 + 1f9d2c7 commit c6fc281

File tree

16 files changed

+2376
-956
lines changed

16 files changed

+2376
-956
lines changed

README.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,68 @@ DIRECTORY_NAME=naga-local
9999
NETWORK=naga-local pnpm run test:e2e all
100100
```
101101

102+
# Artillery Load Testing
103+
104+
Use the standalone Artillery project under `packages/artillery`
105+
106+
## Preparation
107+
108+
```bash
109+
# from the repo root
110+
pnpm install
111+
112+
# pick your target network: naga-dev | naga-staging | naga-test | naga-local
113+
export NETWORK=naga-staging
114+
export LOG_LEVEL=info # optional: debug | debug2 | silent
115+
```
116+
117+
For live networks that read ABI data from the `networks` repo (for example `naga-staging`), run the sync script before firing Artillery so the contracts and addresses are up to date:
118+
119+
```bash
120+
pnpm run sync:contracts # requires GH_API_KEY in your environment
121+
```
122+
123+
Testing a custom local network? Point the runner at your generated `networkContext.json` and RPC URL. (/lit-assets/blockchain/contracts/networkContext.json)
124+
125+
```ts
126+
const networkModule = nagaLocal
127+
.withLocalContext({
128+
networkContextPath:
129+
'/Users/<username>/Projects/lit-assets/blockchain/contracts/networkContext.json',
130+
networkName: 'naga-local',
131+
})
132+
.withOverrides({ rpcUrl: process.env.LOCAL_RPC_URL });
133+
```
134+
135+
If you want Artillery Cloud reports, set `ARTILLERY_KEY=<your-key>` in `.env` before running a scenario.
136+
137+
## One-time initialisation
138+
139+
Master account, auth data and PKP info are written to this file:
140+
`packages/artillery/artillery-state.json`.
141+
142+
```bash
143+
pnpm nx run artillery:init
144+
```
145+
146+
(optional) Check master balances before blasting a load test:
147+
148+
```bash
149+
pnpm nx run artillery:balance-status
150+
```
151+
152+
## Run a workload
153+
154+
Each scenario is exposed as an Nx target. Use the `run:` prefixed name:
155+
156+
```bash
157+
pnpm nx run artillery:run:pkp-sign # PKP signing focus
158+
pnpm nx run artillery:run:encrypt-decrypt # Encryption/decryption focus
159+
pnpm nx run artillery:run:execute # Lit Action execution
160+
pnpm nx run artillery:run:mix # Mixed workload
161+
pnpm nx run artillery:run:sign-session-key # Session key signing
162+
```
163+
102164
# Manual Publishing
103165

104166
```bash

packages/artillery/README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ nx run artillery:sign-session-key
7373

7474
Generating a report required an API key, you can add that to the root `.env` file. You can find your key at [https://app.artillery.io/](https://app.artillery.io/oivpr8dw4i00f)
7575

76-
```jsx
77-
ARTILLERY_KEY = xxx;
76+
```bash
77+
ARTILLERY_KEY=xxx
7878
```
79+
80+
> ℹ️ The Nx run targets pass `ARTILLERY_KEY` to `artillery run` via `--key`, so no extra flags are needed when running the scripts.

packages/artillery/configs/execute.yml

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,46 @@ config:
1717
processor: '../src/processors/multi-endpoints.ts'
1818

1919
scenarios:
20-
- name: 'Execute JS Stress Test'
20+
- name: 'Execute JS Stress Test - Sign'
2121
weight: 100
22+
variables:
23+
# Access in the script via context.scenario.variables.variant
24+
variant: 'sign'
25+
flow:
26+
- function: 'runExecuteJSTest'
27+
- think: 0.1
28+
- name: 'Execute JS Stress Test - Broadcast and Collect'
29+
weight: 0
30+
variables:
31+
variant: 'broadcastAndCollect'
32+
flow:
33+
- function: 'runExecuteJSTest'
34+
- think: 0.1
35+
- name: 'Execute JS Stress Test - Check Conditions with Auth Sig'
36+
weight: 0
37+
variables:
38+
variant: 'checkConditionsWithoutAuthSig'
39+
flow:
40+
- function: 'runExecuteJSTest'
41+
- think: 0.1
42+
- name: 'Execute JS Stress Test - Sign Child Lit Action'
43+
weight: 0
44+
variables:
45+
variant: 'signChildLitAction'
46+
flow:
47+
- function: 'runExecuteJSTest'
48+
- think: 0.1
49+
- name: 'Execute JS Stress Test - Decrypt to Single Node without Auth Sig'
50+
weight: 0
51+
variables:
52+
variant: 'decryptToSingleNode'
53+
flow:
54+
- function: 'runExecuteJSTest'
55+
- think: 0.1
56+
- name: 'Execute JS Stress Test - Run Once'
57+
weight: 0
58+
variables:
59+
variant: 'runOnce'
2260
flow:
2361
- function: 'runExecuteJSTest'
2462
- think: 0.1

packages/artillery/configs/sign-session-key.yml

Lines changed: 3 additions & 5 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
7+
rampTo: 150
98
name: 'Ramp Up'
109
# Over 300s, create 50 vusers per second
1110
- duration: 300
12-
# arrivalRate: 50
13-
arrivalRate: 10
11+
arrivalRate: 150
1412
name: 'Sustained Sign Session Key'
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

packages/artillery/project.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,35 +22,35 @@
2222
"executor": "nx:run-commands",
2323
"options": {
2424
"cwd": "{projectRoot}",
25-
"command": "artillery run configs/pkp-sign.yml"
25+
"command": "artillery run configs/pkp-sign.yml $([ -n \"$ARTILLERY_KEY\" ] && echo \"--record --key $ARTILLERY_KEY\")"
2626
}
2727
},
2828
"run:encrypt-decrypt": {
2929
"executor": "nx:run-commands",
3030
"options": {
3131
"cwd": "{projectRoot}",
32-
"command": "artillery run configs/encrypt-decrypt.yml"
32+
"command": "artillery run configs/encrypt-decrypt.yml $([ -n \"$ARTILLERY_KEY\" ] && echo \"--record --key $ARTILLERY_KEY\")"
3333
}
3434
},
3535
"run:execute": {
3636
"executor": "nx:run-commands",
3737
"options": {
3838
"cwd": "{projectRoot}",
39-
"command": "artillery run configs/execute.yml"
39+
"command": "artillery run configs/execute.yml $([ -n \"$ARTILLERY_KEY\" ] && echo \"--record --key $ARTILLERY_KEY\")"
4040
}
4141
},
4242
"run:mix": {
4343
"executor": "nx:run-commands",
4444
"options": {
4545
"cwd": "{projectRoot}",
46-
"command": "artillery run configs/mix.yml"
46+
"command": "artillery run configs/mix.yml $([ -n \"$ARTILLERY_KEY\" ] && echo \"--record --key $ARTILLERY_KEY\")"
4747
}
4848
},
4949
"run:sign-session-key": {
5050
"executor": "nx:run-commands",
5151
"options": {
5252
"cwd": "{projectRoot}",
53-
"command": "artillery run configs/sign-session-key.yml"
53+
"command": "artillery run configs/sign-session-key.yml $([ -n \"$ARTILLERY_KEY\" ] && echo \"--record --key $ARTILLERY_KEY\")"
5454
}
5555
}
5656
},

packages/artillery/src/StateManager.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export const readFile = async (): Promise<State> => {
2424

2525
// If content is empty object, write base state
2626
if (Object.keys(content).length === 0) {
27-
await fs.writeFile(FILE_NAME, JSON.stringify(StateObject, null, 2));
27+
await fs.writeFile(FILE_NAME, stringify(StateObject));
2828
return StateObject;
2929
}
3030

@@ -42,7 +42,7 @@ export const readFile = async (): Promise<State> => {
4242

4343
// create the file if it doesn't exist
4444
export const createFile = async () => {
45-
await fs.writeFile(FILE_NAME, JSON.stringify(StateObject, null, 2));
45+
await fs.writeFile(FILE_NAME, stringify(StateObject));
4646
};
4747

4848
// Type-safe field paths - dynamically derived from State type
@@ -93,7 +93,7 @@ export const updateField = async <T extends StatePaths>(
9393
state[rootKey] !== null
9494
) {
9595
(state[rootKey] as any)[nestedKey] = value;
96-
await fs.writeFile(FILE_NAME, JSON.stringify(state, null, 2));
96+
await fs.writeFile(FILE_NAME, stringify(state));
9797
} else {
9898
throw new Error(`Invalid path: ${path}`);
9999
}
@@ -123,7 +123,7 @@ export const getOrUpdate = async <T extends StatePaths>(
123123

124124
// Otherwise, update with default value and return it
125125
(state as any)[path] = defaultValue;
126-
await fs.writeFile(FILE_NAME, JSON.stringify(state, null, 2));
126+
await fs.writeFile(FILE_NAME, stringify(state));
127127
return defaultValue;
128128
} else {
129129
// Nested property
@@ -144,10 +144,17 @@ export const getOrUpdate = async <T extends StatePaths>(
144144

145145
// Otherwise, update with default value and return it
146146
(state[rootKey] as any)[nestedKey] = defaultValue;
147-
await fs.writeFile(FILE_NAME, JSON.stringify(state, null, 2));
147+
await fs.writeFile(FILE_NAME, stringify(state));
148148
return defaultValue;
149149
} else {
150150
throw new Error(`Invalid path: ${path}`);
151151
}
152152
}
153153
};
154+
155+
const stringify = (value: unknown) =>
156+
JSON.stringify(
157+
value,
158+
(_, val) => (typeof val === 'bigint' ? val.toString() : val),
159+
2
160+
);

packages/artillery/src/init.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,18 @@ import {
66
} from '@lit-protocol/auth';
77
import * as StateManager from './StateManager';
88
import { createLitClient } from '@lit-protocol/lit-client';
9-
import { getOrCreatePkp } from '@lit-protocol/e2e/src/helper/pkp-utils';
10-
import * as NetworkManager from '@lit-protocol/e2e/src/helper/NetworkManager';
9+
import {
10+
getOrCreatePkp,
11+
getLitNetworkModule,
12+
getViemPublicClient,
13+
} from '@lit-protocol/e2e';
1114
import * as AccountManager from '../src/AccountManager';
1215

1316
const _network = process.env['NETWORK'];
1417

1518
// CONFIGURATIONS
1619
const REJECT_BALANCE_THRESHOLD = 0;
17-
const LEDGER_MINIMUM_BALANCE = 20000;
20+
const LEDGER_MINIMUM_BALANCE = 10000;
1821

1922
(async () => {
2023
// -- Start

0 commit comments

Comments
 (0)