prool 0.0.14 → 0.0.15

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.
@@ -0,0 +1,347 @@
1
+ import { platform } from 'node:os'
2
+
3
+ import { rmSync } from 'node:fs'
4
+ import { defineInstance } from '../instance.js'
5
+ import { execa } from '../processes/execa.js'
6
+ import { toArgs } from '../utils.js'
7
+
8
+ export type SiliusParameters = {
9
+ /**
10
+ * The bundler beneficiary address.
11
+ */
12
+ beneficiary?: string | undefined
13
+ /**
14
+ * The bundle interval in seconds.
15
+ * @default 10
16
+ */
17
+ bundleInterval?: number | undefined
18
+ bundler?:
19
+ | {
20
+ /**
21
+ * Bundler gRPC address to listen on.
22
+ * @default '127.0.0.1'
23
+ */
24
+ addr?: string | undefined
25
+ /**
26
+ * Bundler gRPC port to listen on.
27
+ * @default 3003
28
+ */
29
+ port?: number | undefined
30
+ }
31
+ | undefined
32
+ /**
33
+ * The chain id.
34
+ * @default 1
35
+ */
36
+ chain?: number | undefined
37
+ /**
38
+ * Path to the data directory.
39
+ */
40
+ dataDir?: string | undefined
41
+ discovery?:
42
+ | {
43
+ /**
44
+ * The udp4 port to broadcast to peers in order to reach back for discovery.
45
+ * @default 9000
46
+ */
47
+ port?: number | undefined
48
+ }
49
+ | undefined
50
+ /**
51
+ * Indicates whether the access list is enabled.
52
+ */
53
+ enableAccessList?: boolean | undefined
54
+ /**
55
+ * Indicates whether the P2P mode is enabled.
56
+ */
57
+ enableP2p?: boolean | undefined
58
+ /**
59
+ * Indicates whether the metrics are enabled.
60
+ */
61
+ enableMetrics?: boolean | undefined
62
+ /**
63
+ * The entry points for the bundler.
64
+ */
65
+ entryPoints?: string[] | undefined
66
+ /**
67
+ * RPC URL of the execution client.
68
+ */
69
+ ethClientAddress?: string | undefined
70
+ /**
71
+ * Ethereum execution client proxy HTTP RPC endpoint.
72
+ */
73
+ ethClientProxyAddress?: string | undefined
74
+ http?:
75
+ | {
76
+ /**
77
+ * HTTP address to listen on.
78
+ * @default '127.0.0.1'
79
+ */
80
+ addr?: string | undefined
81
+ /**
82
+ * Configures the HTTP RPC API modules
83
+ * @default 'eth'
84
+ */
85
+ api?: string[] | undefined
86
+ /**
87
+ * Configures the allowed CORS domains.
88
+ * @default '*'
89
+ */
90
+ corsdomain?: string[] | undefined
91
+ /**
92
+ * HTTP port to listen on.
93
+ * @default 3000
94
+ */
95
+ port?: number | undefined
96
+ }
97
+ | undefined
98
+ /**
99
+ * Maximum gas for verification.
100
+ * @default 5000000
101
+ */
102
+ maxVerificationGas?: bigint | undefined
103
+ metrics?:
104
+ | {
105
+ /**
106
+ * Metrics address to listen on.
107
+ * @default '127.0.0.1'
108
+ */
109
+ addr?: string | undefined
110
+ /**
111
+ * Metrics port to listen on.
112
+ * @default 3030
113
+ */
114
+ port?: number | undefined
115
+ }
116
+ | undefined
117
+ /**
118
+ * Minimum balance for the beneficiary account.
119
+ * @default 100000000000000000 wei
120
+ */
121
+ minBalance?: bigint | undefined
122
+ /**
123
+ * Minimum priority fee per gas.
124
+ * @default 0
125
+ */
126
+ minPriorityFeePerGas?: bigint | undefined
127
+ /**
128
+ * Minimum stake required for entities.
129
+ * @default 1
130
+ */
131
+ minStake?: number | undefined
132
+ /**
133
+ * Path to the mnemonic file.
134
+ */
135
+ mnemonicPath: string | undefined
136
+ /**
137
+ * The path to the file where the p2p private key is stored.
138
+ */
139
+ nodekey?: string | undefined
140
+ /**
141
+ * The path to the file where the p2p enr is stored.
142
+ */
143
+ nodeenr?: string | undefined
144
+ p2p?:
145
+ | {
146
+ /**
147
+ * Sets the p2p listen address
148
+ * @default '0.0.0.0'
149
+ */
150
+ addr?: string | undefined
151
+ /**
152
+ * The ipv4 address to broadcast to peers about which address we are listening on.
153
+ */
154
+ baddr?: string | undefined
155
+ /**
156
+ * The tcp4 port to boardcast to peers in order to reach back for discovery.
157
+ * @default 9000
158
+ */
159
+ bport?: number | undefined
160
+ }
161
+ | undefined
162
+ /**
163
+ * Poll interval event filters and pending transactions in milliseconds.
164
+ * @default 500
165
+ */
166
+ pollInterval?: number | undefined
167
+ /**
168
+ * Port to start the instance on.
169
+ */
170
+ port?: number | undefined
171
+ /**
172
+ * Sets the send bundle mode.
173
+ * @default "ethereum-client"
174
+ */
175
+ sendBundleMode?: string | undefined
176
+ uopool?:
177
+ | {
178
+ /**
179
+ * UoPool gRPC address to listen on.
180
+ * @default '127.0.0.1'
181
+ */
182
+ addr?: string | undefined
183
+ /**
184
+ * UoPool gRPC port to listen on.
185
+ * @default 3002
186
+ */
187
+ port?: number | undefined
188
+ }
189
+ | undefined
190
+ /**
191
+ * Sets the UoPool mode.
192
+ */
193
+ uopoolMode?: string | undefined
194
+ /**
195
+ * Sets the verbosity level.
196
+ * @default 2
197
+ */
198
+ verbosity?: number | undefined
199
+ /**
200
+ * Addresses of whitelisted entities.
201
+ */
202
+ whitelist?: string[] | undefined
203
+ ws?:
204
+ | {
205
+ /**
206
+ * WS address to listen on.
207
+ * @default '127.0.0.1'
208
+ */
209
+ addr?: string | undefined
210
+ /**
211
+ * Configures the HTTP RPC API modules
212
+ * @default 'eth'
213
+ */
214
+ api?: string[] | undefined
215
+ /**
216
+ * Configures the allowed WS origins.
217
+ * @default '*'
218
+ */
219
+ origins?: string[] | undefined
220
+ /**
221
+ * WS port to listen on.
222
+ * @default 3001
223
+ */
224
+ port?: number | undefined
225
+ }
226
+ | undefined
227
+ }
228
+
229
+ /**
230
+ * Defines an Anvil instance.
231
+ *
232
+ * @example
233
+ * ```ts
234
+ * const instance = silius({
235
+ * port: 4337,
236
+ * })
237
+ * await instance.start()
238
+ * // ...
239
+ * await instance.stop()
240
+ * ```
241
+ */
242
+ export const silius = defineInstance((parameters?: SiliusParameters) => {
243
+ const args = (parameters || {}) as SiliusParameters
244
+ const { dataDir = '.local', mnemonicPath, port: _, ...rest } = args
245
+
246
+ const host = 'localhost'
247
+ const name = 'silius'
248
+ const process = execa({ name })
249
+ let port = args.port ?? 4000
250
+
251
+ return {
252
+ _internal: {
253
+ args,
254
+ get process() {
255
+ return process._internal.process
256
+ },
257
+ },
258
+ host,
259
+ name,
260
+ port,
261
+ async start({ port: port_ = port }, options) {
262
+ port = port_
263
+
264
+ const args_ = [
265
+ ...(platform() === 'linux' ? ['--net', 'host'] : []),
266
+ '--add-host',
267
+ 'host.docker.internal:host-gateway',
268
+ '--add-host',
269
+ 'localhost:host-gateway',
270
+ '-p',
271
+ `${port}:${port}`,
272
+ '-v',
273
+ `${mnemonicPath}:/data/silius/mnemonic`,
274
+ '-v',
275
+ `./${dataDir}/${port_}/db:/data/silius/db`,
276
+ 'ghcr.io/silius-rs/silius:latest',
277
+ 'node',
278
+ '--datadir',
279
+ 'data/silius',
280
+ '--mnemonic-file',
281
+ 'data/silius/mnemonic',
282
+ '--http',
283
+ '--ws',
284
+ ...toArgs({
285
+ ...rest,
286
+ beneficiary:
287
+ rest.beneficiary ?? '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
288
+ bundler: {
289
+ ...rest.bundler,
290
+ addr: rest.bundler?.addr ?? '0.0.0.0',
291
+ },
292
+ entryPoints: rest.entryPoints ?? [
293
+ '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
294
+ ],
295
+ ethClientAddress: rest.ethClientAddress?.replaceAll(
296
+ /127\.0\.0\.1|0\.0\.0\.0/g,
297
+ 'host.docker.internal',
298
+ ),
299
+ ethClientProxyAddress: rest.ethClientProxyAddress?.replaceAll(
300
+ /127\.0\.0\.1|0\.0\.0\.0/g,
301
+ 'host.docker.internal',
302
+ ),
303
+ http: {
304
+ ...rest.http,
305
+ addr: rest.http?.addr ?? '0.0.0.0',
306
+ api: rest.http?.api ?? ['eth', 'debug', 'web3'],
307
+ port,
308
+ },
309
+ metrics: {
310
+ ...rest.metrics,
311
+ addr: rest.metrics?.addr ?? '0.0.0.0',
312
+ },
313
+ uopool: {
314
+ ...rest.uopool,
315
+ addr: rest.uopool?.addr ?? '0.0.0.0',
316
+ },
317
+ ws: {
318
+ ...rest.ws,
319
+ addr: rest.ws?.addr ?? '0.0.0.0',
320
+ api: rest.ws?.api ?? ['eth', 'debug', 'web3'],
321
+ port: rest.ws?.port ?? 4001,
322
+ },
323
+ } satisfies Partial<SiliusParameters>),
324
+ ]
325
+
326
+ return await process.start(($) => $`docker run ${args_}`, {
327
+ ...options,
328
+ resolver({ process, resolve, reject }) {
329
+ process.stdout.on('data', (data) => {
330
+ const message = data.toString()
331
+ if (message.includes('Started bundler JSON-RPC server')) resolve()
332
+ })
333
+ process.stderr.on('data', (data) => {
334
+ if (data.toString().includes('WARNING')) return
335
+ reject(data)
336
+ })
337
+ },
338
+ })
339
+ },
340
+ async stop() {
341
+ try {
342
+ rmSync(`${dataDir}/${port}`, { recursive: true, force: true })
343
+ } catch {}
344
+ await process.stop()
345
+ },
346
+ }
347
+ })
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "prool",
3
3
  "description": "HTTP testing instances for Ethereum",
4
- "version": "0.0.14",
4
+ "version": "0.0.15",
5
5
  "type": "module",
6
6
  "module": "_lib/exports/index.mjs",
7
7
  "types": "_lib/exports/index.d.ts",
package/pool.test.ts CHANGED
@@ -115,25 +115,29 @@ describe.each([
115
115
  expect(pool.size).toEqual(0)
116
116
  })
117
117
 
118
- test('restart', async () => {
119
- pool = definePool({
120
- instance,
121
- })
122
-
123
- const instance_1 = await pool.start(1)
124
- const instance_2 = await pool.start(2)
125
- const instance_3 = await pool.start(3)
126
-
127
- expect(instance_1.status).toBe('started')
128
- expect(instance_2.status).toBe('started')
129
- expect(instance_3.status).toBe('started')
130
- expect(pool.size).toEqual(3)
131
-
132
- const promise_1 = pool.restart(1)
133
- expect(instance_1.status).toBe('restarting')
134
- await promise_1
135
- expect(instance_1.status).toBe('started')
136
- })
118
+ test(
119
+ 'restart',
120
+ async () => {
121
+ pool = definePool({
122
+ instance,
123
+ })
124
+
125
+ const instance_1 = await pool.start(1)
126
+ const instance_2 = await pool.start(2)
127
+ const instance_3 = await pool.start(3)
128
+
129
+ expect(instance_1.status).toBe('started')
130
+ expect(instance_2.status).toBe('started')
131
+ expect(instance_3.status).toBe('started')
132
+ expect(pool.size).toEqual(3)
133
+
134
+ const promise_1 = pool.restart(1)
135
+ expect(instance_1.status).toBe('restarting')
136
+ await promise_1
137
+ expect(instance_1.status).toBe('started')
138
+ },
139
+ { timeout: 10_000 },
140
+ )
137
141
 
138
142
  test('start > stop > start', async () => {
139
143
  pool = definePool({
package/server.test.ts CHANGED
@@ -1,8 +1,13 @@
1
1
  import getPort from 'get-port'
2
2
  import { beforeAll, describe, expect, test } from 'vitest'
3
3
  import { type MessageEvent, WebSocket } from 'ws'
4
- import { altoOptions, rundlerOptions, stackupOptions } from '../test/utils.js'
5
- import { rundler } from './exports/instances.js'
4
+ import {
5
+ altoOptions,
6
+ rundlerOptions,
7
+ siliusOptions,
8
+ stackupOptions,
9
+ } from '../test/utils.js'
10
+ import { rundler, silius } from './exports/instances.js'
6
11
  import { alto } from './instances/alto.js'
7
12
  import { anvil } from './instances/anvil.js'
8
13
  import { stackup } from './instances/stackup.js'
@@ -470,6 +475,45 @@ describe("instance: 'rundler'", () => {
470
475
  })
471
476
  })
472
477
 
478
+ describe("instance: 'silius'", () => {
479
+ test(
480
+ 'request: /{id}',
481
+ async () => {
482
+ const server = createServer({
483
+ instance: silius(siliusOptions({ port })),
484
+ })
485
+
486
+ const stop = await server.start()
487
+ const { port: port_2 } = server.address()!
488
+ const response = await fetch(`http://localhost:${port_2}/1`, {
489
+ body: JSON.stringify({
490
+ method: 'eth_supportedEntryPoints',
491
+ params: [],
492
+ id: 0,
493
+ jsonrpc: '2.0',
494
+ }),
495
+ headers: {
496
+ 'Content-Type': 'application/json',
497
+ },
498
+ method: 'POST',
499
+ })
500
+ expect(response.status).toBe(200)
501
+ expect(await response.json()).toMatchInlineSnapshot(`
502
+ {
503
+ "id": 0,
504
+ "jsonrpc": "2.0",
505
+ "result": [
506
+ "0x0000000071727De22E5E9d8BAf0edAc6f37da032",
507
+ ],
508
+ }
509
+ `)
510
+
511
+ await stop()
512
+ },
513
+ { timeout: 10_000 },
514
+ )
515
+ })
516
+
473
517
  test('404', async () => {
474
518
  const server = createServer({
475
519
  instance: anvil(),