@aztec/foundation 0.66.0 → 0.67.1
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.
- package/dest/abi/abi.d.ts.map +1 -1
- package/dest/abi/abi.js +25 -10
- package/dest/abi/encoder.js +3 -3
- package/dest/abi/event_selector.js +2 -2
- package/dest/abi/function_selector.js +2 -2
- package/dest/collection/array.d.ts +2 -0
- package/dest/collection/array.d.ts.map +1 -1
- package/dest/collection/array.js +10 -1
- package/dest/collection/object.d.ts +6 -0
- package/dest/collection/object.d.ts.map +1 -1
- package/dest/collection/object.js +15 -1
- package/dest/config/env_var.d.ts +1 -1
- package/dest/config/env_var.d.ts.map +1 -1
- package/dest/crypto/random/randomness_singleton.js +3 -3
- package/dest/fields/fields.d.ts +20 -2
- package/dest/fields/fields.d.ts.map +1 -1
- package/dest/fields/fields.js +37 -3
- package/dest/fs/run_in_dir.js +2 -2
- package/dest/iterable/index.d.ts +1 -0
- package/dest/iterable/index.d.ts.map +1 -1
- package/dest/iterable/index.js +2 -1
- package/dest/iterable/toArray.d.ts +2 -0
- package/dest/iterable/toArray.d.ts.map +1 -0
- package/dest/iterable/toArray.js +8 -0
- package/dest/json-rpc/client/fetch.d.ts +2 -2
- package/dest/json-rpc/client/fetch.d.ts.map +1 -1
- package/dest/json-rpc/client/fetch.js +3 -3
- package/dest/json-rpc/client/safe_json_rpc_client.d.ts.map +1 -1
- package/dest/json-rpc/client/safe_json_rpc_client.js +7 -12
- package/dest/json-rpc/server/safe_json_rpc_server.d.ts +3 -2
- package/dest/json-rpc/server/safe_json_rpc_server.d.ts.map +1 -1
- package/dest/json-rpc/server/safe_json_rpc_server.js +5 -5
- package/dest/log/log-filters.d.ts.map +1 -1
- package/dest/log/log-filters.js +8 -2
- package/dest/log/log_fn.d.ts +1 -1
- package/dest/log/pino-logger.d.ts +18 -7
- package/dest/log/pino-logger.d.ts.map +1 -1
- package/dest/log/pino-logger.js +32 -18
- package/dest/queue/base_memory_queue.d.ts.map +1 -1
- package/dest/queue/base_memory_queue.js +3 -3
- package/dest/queue/bounded_serial_queue.d.ts.map +1 -1
- package/dest/queue/bounded_serial_queue.js +3 -3
- package/dest/queue/fifo_memory_queue.d.ts +2 -2
- package/dest/queue/fifo_memory_queue.d.ts.map +1 -1
- package/dest/queue/fifo_memory_queue.js +1 -1
- package/dest/retry/index.d.ts.map +1 -1
- package/dest/retry/index.js +3 -3
- package/dest/schemas/utils.d.ts +3 -1
- package/dest/schemas/utils.d.ts.map +1 -1
- package/dest/schemas/utils.js +8 -3
- package/dest/testing/test_data.d.ts +11 -0
- package/dest/testing/test_data.d.ts.map +1 -1
- package/dest/testing/test_data.js +24 -1
- package/dest/transport/dispatch/create_dispatch_fn.d.ts.map +1 -1
- package/dest/transport/dispatch/create_dispatch_fn.js +3 -3
- package/dest/transport/transport_client.js +3 -3
- package/dest/wasm/wasm_module.d.ts.map +1 -1
- package/dest/wasm/wasm_module.js +2 -2
- package/dest/worker/worker_pool.js +3 -3
- package/package.json +9 -3
- package/src/abi/abi.ts +30 -11
- package/src/abi/encoder.ts +2 -2
- package/src/abi/event_selector.ts +1 -1
- package/src/abi/function_selector.ts +1 -1
- package/src/collection/array.ts +10 -0
- package/src/collection/object.ts +22 -0
- package/src/config/env_var.ts +9 -2
- package/src/crypto/random/randomness_singleton.ts +2 -2
- package/src/fields/fields.ts +40 -2
- package/src/fs/run_in_dir.ts +1 -1
- package/src/iterable/index.ts +1 -0
- package/src/iterable/toArray.ts +7 -0
- package/src/jest/setup.mjs +9 -0
- package/src/json-rpc/client/fetch.ts +3 -3
- package/src/json-rpc/client/safe_json_rpc_client.ts +7 -15
- package/src/json-rpc/server/safe_json_rpc_server.ts +5 -5
- package/src/log/log-filters.ts +7 -1
- package/src/log/log_fn.ts +1 -1
- package/src/log/pino-logger.ts +48 -41
- package/src/queue/base_memory_queue.ts +2 -2
- package/src/queue/bounded_serial_queue.ts +2 -2
- package/src/queue/fifo_memory_queue.ts +2 -2
- package/src/retry/index.ts +2 -2
- package/src/schemas/utils.ts +10 -2
- package/src/testing/test_data.ts +25 -0
- package/src/transport/dispatch/create_dispatch_fn.ts +2 -2
- package/src/transport/transport_client.ts +2 -2
- package/src/wasm/wasm_module.ts +1 -1
- package/src/worker/worker_pool.ts +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/foundation",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.67.1",
|
|
4
4
|
"packageManager": "yarn@3.4.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dest/index.js",
|
|
@@ -96,10 +96,17 @@
|
|
|
96
96
|
"summaryThreshold": 9999
|
|
97
97
|
}
|
|
98
98
|
]
|
|
99
|
+
],
|
|
100
|
+
"testTimeout": 30000,
|
|
101
|
+
"setupFilesAfterEnv": [
|
|
102
|
+
"../../foundation/src/jest/setup.mjs"
|
|
103
|
+
],
|
|
104
|
+
"setupFiles": [
|
|
105
|
+
"../../foundation/src/jest/setup.mjs"
|
|
99
106
|
]
|
|
100
107
|
},
|
|
101
108
|
"dependencies": {
|
|
102
|
-
"@aztec/bb.js": "0.
|
|
109
|
+
"@aztec/bb.js": "0.67.1",
|
|
103
110
|
"@koa/cors": "^5.0.0",
|
|
104
111
|
"@noble/curves": "^1.2.0",
|
|
105
112
|
"bn.js": "^5.2.1",
|
|
@@ -133,7 +140,6 @@
|
|
|
133
140
|
"@types/koa": "^2.13.5",
|
|
134
141
|
"@types/koa-bodyparser": "^4.3.10",
|
|
135
142
|
"@types/koa-compress": "^4.0.3",
|
|
136
|
-
"@types/koa-cors": "^0.0.2",
|
|
137
143
|
"@types/koa-router": "^7.4.4",
|
|
138
144
|
"@types/koa__cors": "^4.0.0",
|
|
139
145
|
"@types/leveldown": "^4.0.3",
|
package/src/abi/abi.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { inflate } from 'pako';
|
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
|
|
5
5
|
import { type Fr } from '../fields/fields.js';
|
|
6
|
+
import { createLogger } from '../log/index.js';
|
|
6
7
|
import { schemas } from '../schemas/schemas.js';
|
|
7
8
|
import { type ZodFor } from '../schemas/types.js';
|
|
8
9
|
import { type FunctionSelector } from './function_selector.js';
|
|
@@ -15,6 +16,8 @@ export interface BasicValue<T extends string, V> {
|
|
|
15
16
|
value: V;
|
|
16
17
|
}
|
|
17
18
|
|
|
19
|
+
const logger = createLogger('aztec:foundation:abi');
|
|
20
|
+
|
|
18
21
|
/** An exported value. */
|
|
19
22
|
export type AbiValue =
|
|
20
23
|
| BasicValue<'boolean', boolean>
|
|
@@ -390,7 +393,9 @@ export function getFunctionArtifact(
|
|
|
390
393
|
if (!functionArtifact) {
|
|
391
394
|
throw new Error(`Unknown function ${functionNameOrSelector}`);
|
|
392
395
|
}
|
|
396
|
+
|
|
393
397
|
const debugMetadata = getFunctionDebugMetadata(artifact, functionArtifact);
|
|
398
|
+
|
|
394
399
|
return { ...functionArtifact, debug: debugMetadata };
|
|
395
400
|
}
|
|
396
401
|
|
|
@@ -404,18 +409,32 @@ export function getFunctionDebugMetadata(
|
|
|
404
409
|
contractArtifact: ContractArtifact,
|
|
405
410
|
functionArtifact: FunctionArtifact,
|
|
406
411
|
): FunctionDebugMetadata | undefined {
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
412
|
+
try {
|
|
413
|
+
if (functionArtifact.debugSymbols && contractArtifact.fileMap) {
|
|
414
|
+
// TODO(https://github.com/AztecProtocol/aztec-packages/issues/10546) investigate why debugMetadata is so big for some tests.
|
|
415
|
+
const programDebugSymbols = JSON.parse(
|
|
416
|
+
inflate(Buffer.from(functionArtifact.debugSymbols, 'base64'), { to: 'string', raw: true }),
|
|
417
|
+
);
|
|
418
|
+
// TODO(https://github.com/AztecProtocol/aztec-packages/issues/5813)
|
|
419
|
+
// We only support handling debug info for the contract function entry point.
|
|
420
|
+
// So for now we simply index into the first debug info.
|
|
421
|
+
return {
|
|
422
|
+
debugSymbols: programDebugSymbols.debug_infos[0],
|
|
423
|
+
files: contractArtifact.fileMap,
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
} catch (err: any) {
|
|
427
|
+
if (err instanceof RangeError && err.message.includes('Invalid string length')) {
|
|
428
|
+
logger.warn(
|
|
429
|
+
`Caught RangeError: Invalid string length. This suggests the debug_symbols field of the contract ${contractArtifact.name} and function ${functionArtifact.name} is huge; too big to parse. We'll skip returning this info until this issue is resolved. Here's the error:\n${err.message}`,
|
|
430
|
+
);
|
|
431
|
+
// We'll return undefined.
|
|
432
|
+
} else {
|
|
433
|
+
// Rethrow unexpected errors
|
|
434
|
+
throw err;
|
|
435
|
+
}
|
|
418
436
|
}
|
|
437
|
+
|
|
419
438
|
return undefined;
|
|
420
439
|
}
|
|
421
440
|
|
package/src/abi/encoder.ts
CHANGED
|
@@ -49,7 +49,7 @@ class ArgumentEncoder {
|
|
|
49
49
|
} else if (typeof arg === 'bigint') {
|
|
50
50
|
this.flattened.push(new Fr(arg));
|
|
51
51
|
} else if (typeof arg === 'string') {
|
|
52
|
-
this.flattened.push(Fr.
|
|
52
|
+
this.flattened.push(Fr.fromHexString(arg));
|
|
53
53
|
} else if (typeof arg === 'boolean') {
|
|
54
54
|
this.flattened.push(new Fr(arg ? 1n : 0n));
|
|
55
55
|
} else if (typeof arg === 'object') {
|
|
@@ -58,7 +58,7 @@ class ArgumentEncoder {
|
|
|
58
58
|
} else if (typeof arg.toField === 'function') {
|
|
59
59
|
this.flattened.push(arg.toField());
|
|
60
60
|
} else if (typeof arg.value === 'string') {
|
|
61
|
-
this.flattened.push(Fr.
|
|
61
|
+
this.flattened.push(Fr.fromHexString(arg.value));
|
|
62
62
|
} else {
|
|
63
63
|
throw new Error(`Argument for ${name} cannot be serialized to a field`);
|
|
64
64
|
}
|
|
@@ -62,7 +62,7 @@ export class EventSelector extends Selector {
|
|
|
62
62
|
static fromString(selector: string) {
|
|
63
63
|
const buf = fromHex(selector);
|
|
64
64
|
if (buf.length !== Selector.SIZE) {
|
|
65
|
-
throw new Error(`Invalid
|
|
65
|
+
throw new Error(`Invalid EventSelector length ${buf.length} (expected ${Selector.SIZE}).`);
|
|
66
66
|
}
|
|
67
67
|
return EventSelector.fromBuffer(buf);
|
|
68
68
|
}
|
|
@@ -91,7 +91,7 @@ export class FunctionSelector extends Selector {
|
|
|
91
91
|
static fromString(selector: string) {
|
|
92
92
|
const buf = fromHex(selector);
|
|
93
93
|
if (buf.length !== Selector.SIZE) {
|
|
94
|
-
throw new Error(`Invalid
|
|
94
|
+
throw new Error(`Invalid FunctionSelector length ${buf.length} (expected ${Selector.SIZE}).`);
|
|
95
95
|
}
|
|
96
96
|
return FunctionSelector.fromBuffer(buf);
|
|
97
97
|
}
|
package/src/collection/array.ts
CHANGED
|
@@ -145,3 +145,13 @@ export function areArraysEqual<T>(a: T[], b: T[], eq: (a: T, b: T) => boolean =
|
|
|
145
145
|
export function maxBy<T>(arr: T[], fn: (x: T) => number): T | undefined {
|
|
146
146
|
return arr.reduce((max, x) => (fn(x) > fn(max) ? x : max), arr[0]);
|
|
147
147
|
}
|
|
148
|
+
|
|
149
|
+
/** Computes the median of a numeric array. Returns undefined if array is empty. */
|
|
150
|
+
export function median(arr: number[]) {
|
|
151
|
+
if (arr.length === 0) {
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
const sorted = [...arr].sort((a, b) => a - b);
|
|
155
|
+
const mid = Math.floor(sorted.length / 2);
|
|
156
|
+
return sorted.length % 2 !== 0 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
|
|
157
|
+
}
|
package/src/collection/object.ts
CHANGED
|
@@ -28,3 +28,25 @@ export function compact<T extends object>(obj: T): { [P in keyof T]+?: Exclude<T
|
|
|
28
28
|
}
|
|
29
29
|
return result;
|
|
30
30
|
}
|
|
31
|
+
|
|
32
|
+
/** Returns a new object by picking the given keys. */
|
|
33
|
+
export function pick<T extends object, U extends keyof T>(object: T, ...props: U[]): Pick<T, U>;
|
|
34
|
+
export function pick<T extends object>(object: T, ...props: string[]): Partial<T>;
|
|
35
|
+
export function pick<T extends object>(object: T, ...props: string[]): Partial<T> {
|
|
36
|
+
const obj: any = {};
|
|
37
|
+
for (const prop of props) {
|
|
38
|
+
obj[prop] = (object as any)[prop];
|
|
39
|
+
}
|
|
40
|
+
return obj;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Returns a new object by omitting the given keys. */
|
|
44
|
+
export function omit<T extends object, K extends keyof T>(object: T, ...props: K[]): Omit<T, K>;
|
|
45
|
+
export function omit<T extends object>(object: T, ...props: string[]): Partial<T>;
|
|
46
|
+
export function omit<T extends object>(object: T, ...props: string[]): Partial<T> {
|
|
47
|
+
const obj: any = { ...object };
|
|
48
|
+
for (const prop of props) {
|
|
49
|
+
delete obj[prop];
|
|
50
|
+
}
|
|
51
|
+
return obj;
|
|
52
|
+
}
|
package/src/config/env_var.ts
CHANGED
|
@@ -56,10 +56,12 @@ export type EnvVar =
|
|
|
56
56
|
| 'L2_QUEUE_SIZE'
|
|
57
57
|
| 'LOG_ELAPSED_TIME'
|
|
58
58
|
| 'LOG_JSON'
|
|
59
|
+
| 'LOG_MULTILINE'
|
|
59
60
|
| 'LOG_LEVEL'
|
|
60
61
|
| 'MNEMONIC'
|
|
61
62
|
| 'NETWORK_NAME'
|
|
62
63
|
| 'NETWORK'
|
|
64
|
+
| 'NO_PXE'
|
|
63
65
|
| 'COIN_ISSUER_CONTRACT_ADDRESS'
|
|
64
66
|
| 'OTEL_EXPORTER_OTLP_METRICS_ENDPOINT'
|
|
65
67
|
| 'OTEL_EXPORTER_OTLP_TRACES_ENDPOINT'
|
|
@@ -124,7 +126,6 @@ export type EnvVar =
|
|
|
124
126
|
| 'PROVER_REQUIRED_CONFIRMATIONS'
|
|
125
127
|
| 'PROVER_TEST_DELAY_MS'
|
|
126
128
|
| 'PROVER_CACHE_DIR'
|
|
127
|
-
| 'PXE_BLOCK_POLLING_INTERVAL_MS'
|
|
128
129
|
| 'PXE_L2_STARTING_BLOCK'
|
|
129
130
|
| 'PXE_PROVER_ENABLED'
|
|
130
131
|
| 'QUOTE_PROVIDER_BASIS_POINT_FEE'
|
|
@@ -182,4 +183,10 @@ export type EnvVar =
|
|
|
182
183
|
| 'L1_TX_MONITOR_MAX_ATTEMPTS'
|
|
183
184
|
| 'L1_TX_MONITOR_CHECK_INTERVAL_MS'
|
|
184
185
|
| 'L1_TX_MONITOR_STALL_TIME_MS'
|
|
185
|
-
| 'L1_TX_MONITOR_TX_TIMEOUT_MS'
|
|
186
|
+
| 'L1_TX_MONITOR_TX_TIMEOUT_MS'
|
|
187
|
+
| 'FAUCET_MNEMONIC_ACCOUNT_INDEX'
|
|
188
|
+
| 'FAUCET_ETH_AMOUNT'
|
|
189
|
+
| 'FAUCET_INTERVAL_MS'
|
|
190
|
+
| 'FAUCET_L1_ASSETS'
|
|
191
|
+
| 'K8S_POD_NAME'
|
|
192
|
+
| 'K8S_POD_UID';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createLogger } from '../../log/pino-logger.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* A number generator which is used as a source of randomness in the system. If the SEED env variable is set, the
|
|
@@ -15,7 +15,7 @@ export class RandomnessSingleton {
|
|
|
15
15
|
|
|
16
16
|
private constructor(
|
|
17
17
|
private readonly seed?: number,
|
|
18
|
-
private readonly log =
|
|
18
|
+
private readonly log = createLogger('foundation:randomness_singleton'),
|
|
19
19
|
) {
|
|
20
20
|
if (seed !== undefined) {
|
|
21
21
|
this.log.debug(`Using pseudo-randomness with seed: ${seed}`);
|
package/src/fields/fields.ts
CHANGED
|
@@ -232,12 +232,31 @@ export class Fr extends BaseField {
|
|
|
232
232
|
return fromBufferReduce(buffer, Fr);
|
|
233
233
|
}
|
|
234
234
|
|
|
235
|
+
/**
|
|
236
|
+
* Creates a Fr instance from a string.
|
|
237
|
+
* @param buf - the string to create a Fr from.
|
|
238
|
+
* @returns the Fr instance
|
|
239
|
+
* @remarks if the string only consists of numbers, we assume we are parsing a bigint,
|
|
240
|
+
* otherwise we require the hex string to be prepended with "0x", to ensure there is no misunderstanding
|
|
241
|
+
* as to what is being parsed.
|
|
242
|
+
*/
|
|
243
|
+
static fromString(buf: string) {
|
|
244
|
+
if (buf.match(/^\d+$/) !== null) {
|
|
245
|
+
return new Fr(toBufferBE(BigInt(buf), 32));
|
|
246
|
+
}
|
|
247
|
+
if (buf.match(/^0x/i) !== null) {
|
|
248
|
+
return fromHexString(buf, Fr);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
throw new Error('Tried to create a Fr from an invalid string');
|
|
252
|
+
}
|
|
253
|
+
|
|
235
254
|
/**
|
|
236
255
|
* Creates a Fr instance from a hex string.
|
|
237
256
|
* @param buf - a hex encoded string.
|
|
238
257
|
* @returns the Fr instance
|
|
239
258
|
*/
|
|
240
|
-
static
|
|
259
|
+
static fromHexString(buf: string) {
|
|
241
260
|
return fromHexString(buf, Fr);
|
|
242
261
|
}
|
|
243
262
|
|
|
@@ -368,12 +387,31 @@ export class Fq extends BaseField {
|
|
|
368
387
|
return fromBufferReduce(buffer, Fq);
|
|
369
388
|
}
|
|
370
389
|
|
|
390
|
+
/**
|
|
391
|
+
* Creates a Fq instance from a string.
|
|
392
|
+
* @param buf - the string to create a Fq from.
|
|
393
|
+
* @returns the Fq instance
|
|
394
|
+
* @remarks if the string only consists of numbers, we assume we are parsing a bigint,
|
|
395
|
+
* otherwise we require the hex string to be prepended with "0x", to ensure there is no misunderstanding
|
|
396
|
+
* as to what is being parsed.
|
|
397
|
+
*/
|
|
398
|
+
static fromString(buf: string) {
|
|
399
|
+
if (buf.match(/^\d+$/) !== null) {
|
|
400
|
+
return new Fq(toBufferBE(BigInt(buf), 32));
|
|
401
|
+
}
|
|
402
|
+
if (buf.match(/^0x/i) !== null) {
|
|
403
|
+
return fromHexString(buf, Fq);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
throw new Error('Tried to create a Fq from an invalid string');
|
|
407
|
+
}
|
|
408
|
+
|
|
371
409
|
/**
|
|
372
410
|
* Creates a Fq instance from a hex string.
|
|
373
411
|
* @param buf - a hex encoded string.
|
|
374
412
|
* @returns the Fq instance
|
|
375
413
|
*/
|
|
376
|
-
static
|
|
414
|
+
static fromHexString(buf: string) {
|
|
377
415
|
return fromHexString(buf, Fq);
|
|
378
416
|
}
|
|
379
417
|
|
package/src/fs/run_in_dir.ts
CHANGED
package/src/iterable/index.ts
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { overwriteLoggingStream, pinoPrettyOpts } from '@aztec/foundation/log';
|
|
2
|
+
|
|
3
|
+
import pretty from 'pino-pretty';
|
|
4
|
+
|
|
5
|
+
// Overwrite logging stream with pino-pretty. We define this as a separate
|
|
6
|
+
// file so we don't mess up with dependencies in non-testing environments,
|
|
7
|
+
// since pino-pretty messes up with browser bundles.
|
|
8
|
+
// See also https://www.npmjs.com/package/pino-pretty?activeTab=readme#user-content-usage-with-jest
|
|
9
|
+
overwriteLoggingStream(pretty(pinoPrettyOpts));
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { format, inspect } from 'util';
|
|
2
2
|
|
|
3
|
-
import { type
|
|
3
|
+
import { type Logger, createLogger } from '../../log/index.js';
|
|
4
4
|
import { NoRetryError, makeBackoff, retry } from '../../retry/index.js';
|
|
5
5
|
import { jsonStringify } from '../convert.js';
|
|
6
6
|
|
|
7
|
-
const log =
|
|
7
|
+
const log = createLogger('json-rpc:json_rpc_client');
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* A normal fetch function that does not retry.
|
|
@@ -73,7 +73,7 @@ export async function defaultFetch(
|
|
|
73
73
|
* @param log - Optional logger for logging attempts.
|
|
74
74
|
* @returns A fetch function.
|
|
75
75
|
*/
|
|
76
|
-
export function makeFetch(retries: number[], defaultNoRetry: boolean, log?:
|
|
76
|
+
export function makeFetch(retries: number[], defaultNoRetry: boolean, log?: Logger) {
|
|
77
77
|
return async (host: string, rpcMethod: string, body: any, useApiEndpoints: boolean, noRetry?: boolean) => {
|
|
78
78
|
return await retry(
|
|
79
79
|
() => defaultFetch(host, rpcMethod, body, useApiEndpoints, noRetry ?? defaultNoRetry),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { format } from 'util';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { createLogger } from '../../log/pino-logger.js';
|
|
4
4
|
import { type ApiSchema, type ApiSchemaFor, schemaHasMethod } from '../../schemas/api.js';
|
|
5
5
|
import { defaultFetch } from './fetch.js';
|
|
6
6
|
|
|
@@ -19,7 +19,7 @@ export function createSafeJsonRpcClient<T extends object>(
|
|
|
19
19
|
useApiEndpoints: boolean = false,
|
|
20
20
|
namespaceMethods?: string | false,
|
|
21
21
|
fetch = defaultFetch,
|
|
22
|
-
log =
|
|
22
|
+
log = createLogger('json-rpc:client'),
|
|
23
23
|
): T {
|
|
24
24
|
let id = 0;
|
|
25
25
|
const request = async (methodName: string, params: any[]): Promise<any> => {
|
|
@@ -44,18 +44,10 @@ export function createSafeJsonRpcClient<T extends object>(
|
|
|
44
44
|
return (schema as ApiSchema)[methodName].returnType().parse(res.result);
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
get: (target, method: string) => {
|
|
52
|
-
if (['then', 'catch'].includes(method)) {
|
|
53
|
-
return Reflect.get(target, method);
|
|
54
|
-
}
|
|
55
|
-
return (...params: any[]) => request(method, params);
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
) as T;
|
|
47
|
+
const proxy: any = {};
|
|
48
|
+
for (const method of Object.keys(schema)) {
|
|
49
|
+
proxy[method] = (...params: any[]) => request(method, params);
|
|
50
|
+
}
|
|
59
51
|
|
|
60
|
-
return proxy;
|
|
52
|
+
return proxy as T;
|
|
61
53
|
}
|
|
@@ -8,7 +8,7 @@ import { type AddressInfo } from 'net';
|
|
|
8
8
|
import { format, inspect } from 'util';
|
|
9
9
|
import { ZodError } from 'zod';
|
|
10
10
|
|
|
11
|
-
import { type
|
|
11
|
+
import { type Logger, createLogger } from '../../log/index.js';
|
|
12
12
|
import { promiseWithResolvers } from '../../promise/utils.js';
|
|
13
13
|
import { type ApiSchema, type ApiSchemaFor, parseWithOptionals, schemaHasMethod } from '../../schemas/index.js';
|
|
14
14
|
import { jsonStringify } from '../convert.js';
|
|
@@ -27,7 +27,7 @@ export class SafeJsonRpcServer {
|
|
|
27
27
|
/** Health check function */
|
|
28
28
|
private readonly healthCheck: StatusCheckFn = () => true,
|
|
29
29
|
/** Logger */
|
|
30
|
-
private log =
|
|
30
|
+
private log = createLogger('json-rpc:server'),
|
|
31
31
|
) {}
|
|
32
32
|
|
|
33
33
|
public isHealthy(): boolean | Promise<boolean> {
|
|
@@ -170,7 +170,7 @@ interface Proxy {
|
|
|
170
170
|
* before forwarding calls, and then converts outputs into JSON using default conversions.
|
|
171
171
|
*/
|
|
172
172
|
export class SafeJsonProxy<T extends object = any> implements Proxy {
|
|
173
|
-
private log =
|
|
173
|
+
private log = createLogger('json-rpc:proxy');
|
|
174
174
|
private schema: ApiSchema;
|
|
175
175
|
|
|
176
176
|
constructor(private handler: T, schema: ApiSchemaFor<T>) {
|
|
@@ -233,7 +233,7 @@ export function makeHandler<T extends object>(handler: T, schema: ApiSchemaFor<T
|
|
|
233
233
|
return [handler, schema];
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
-
function makeAggregateHealthcheck(namedHandlers: NamespacedApiHandlers, log?:
|
|
236
|
+
function makeAggregateHealthcheck(namedHandlers: NamespacedApiHandlers, log?: Logger): StatusCheckFn {
|
|
237
237
|
return async () => {
|
|
238
238
|
try {
|
|
239
239
|
const results = await Promise.all(
|
|
@@ -259,7 +259,7 @@ function makeAggregateHealthcheck(namedHandlers: NamespacedApiHandlers, log?: De
|
|
|
259
259
|
*/
|
|
260
260
|
export function createNamespacedSafeJsonRpcServer(
|
|
261
261
|
handlers: NamespacedApiHandlers,
|
|
262
|
-
log =
|
|
262
|
+
log = createLogger('json-rpc:server'),
|
|
263
263
|
): SafeJsonRpcServer {
|
|
264
264
|
const proxy = new NamespacedSafeJsonProxy(handlers);
|
|
265
265
|
const healthCheck = makeAggregateHealthcheck(handlers, log);
|
package/src/log/log-filters.ts
CHANGED
|
@@ -42,7 +42,13 @@ export function parseFilters(definition: string | undefined): LogFilters {
|
|
|
42
42
|
const sanitizedLevel = level.trim().toLowerCase();
|
|
43
43
|
assertLogLevel(sanitizedLevel);
|
|
44
44
|
for (const module of modules.split(',')) {
|
|
45
|
-
filters.push([
|
|
45
|
+
filters.push([
|
|
46
|
+
module
|
|
47
|
+
.trim()
|
|
48
|
+
.toLowerCase()
|
|
49
|
+
.replace(/^aztec:/, ''),
|
|
50
|
+
sanitizedLevel as LogLevel | 'silent',
|
|
51
|
+
]);
|
|
46
52
|
}
|
|
47
53
|
}
|
|
48
54
|
return filters.reverse();
|
package/src/log/log_fn.ts
CHANGED
package/src/log/pino-logger.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { createColors } from 'colorette';
|
|
2
2
|
import isNode from 'detect-node';
|
|
3
3
|
import { pino, symbols } from 'pino';
|
|
4
|
-
import pretty from 'pino-pretty';
|
|
5
4
|
import { type Writable } from 'stream';
|
|
6
5
|
import { inspect } from 'util';
|
|
7
6
|
|
|
@@ -10,38 +9,37 @@ import { getLogLevelFromFilters, parseEnv } from './log-filters.js';
|
|
|
10
9
|
import { type LogLevel } from './log-levels.js';
|
|
11
10
|
import { type LogData, type LogFn } from './log_fn.js';
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const pinoLogger = logger.child(
|
|
17
|
-
{ module: module.replace(/^aztec:/, '') },
|
|
18
|
-
{ level: getLogLevelFromFilters(logFilters, module) },
|
|
19
|
-
);
|
|
12
|
+
export function createLogger(module: string): Logger {
|
|
13
|
+
module = module.replace(/^aztec:/, '');
|
|
14
|
+
const pinoLogger = logger.child({ module }, { level: getLogLevelFromFilters(logFilters, module) });
|
|
20
15
|
|
|
21
16
|
// We check manually for isLevelEnabled to avoid calling processLogData unnecessarily.
|
|
22
17
|
// Note that isLevelEnabled is missing from the browser version of pino.
|
|
23
|
-
const logFn = (level: LogLevel, msg: string, data?:
|
|
24
|
-
isLevelEnabled(pinoLogger, level) && pinoLogger[level](processLogData(data ?? {}), msg);
|
|
18
|
+
const logFn = (level: LogLevel, msg: string, data?: unknown) =>
|
|
19
|
+
isLevelEnabled(pinoLogger, level) && pinoLogger[level](processLogData((data as LogData) ?? {}), msg);
|
|
25
20
|
|
|
26
21
|
return {
|
|
27
22
|
silent: () => {},
|
|
28
23
|
// TODO(palla/log): Should we move err to data instead of the text message?
|
|
29
24
|
/** Log as fatal. Use when an error has brought down the system. */
|
|
30
|
-
fatal: (msg: string, err?: unknown, data?:
|
|
25
|
+
fatal: (msg: string, err?: unknown, data?: unknown) => logFn('fatal', formatErr(msg, err), data),
|
|
31
26
|
/** Log as error. Use for errors in general. */
|
|
32
|
-
error: (msg: string, err?: unknown, data?:
|
|
27
|
+
error: (msg: string, err?: unknown, data?: unknown) => logFn('error', formatErr(msg, err), data),
|
|
33
28
|
/** Log as warn. Use for when we stray from the happy path. */
|
|
34
|
-
warn: (msg: string, data?:
|
|
29
|
+
warn: (msg: string, data?: unknown) => logFn('warn', msg, data),
|
|
35
30
|
/** Log as info. Use for providing an operator with info on what the system is doing. */
|
|
36
|
-
info: (msg: string, data?:
|
|
31
|
+
info: (msg: string, data?: unknown) => logFn('info', msg, data),
|
|
37
32
|
/** Log as verbose. Use for when we need additional insight on what a subsystem is doing. */
|
|
38
|
-
verbose: (msg: string, data?:
|
|
33
|
+
verbose: (msg: string, data?: unknown) => logFn('verbose', msg, data),
|
|
39
34
|
/** Log as debug. Use for when we need debugging info to troubleshoot an issue on a specific component. */
|
|
40
|
-
debug: (msg: string, data?:
|
|
35
|
+
debug: (msg: string, data?: unknown) => logFn('debug', msg, data),
|
|
41
36
|
/** Log as trace. Use for when we want to denial-of-service any recipient of the logs. */
|
|
42
|
-
trace: (msg: string, data?:
|
|
37
|
+
trace: (msg: string, data?: unknown) => logFn('trace', msg, data),
|
|
43
38
|
level: pinoLogger.level as LogLevel,
|
|
39
|
+
/** Whether the given level is enabled for this logger. */
|
|
44
40
|
isLevelEnabled: (level: LogLevel) => isLevelEnabled(pinoLogger, level),
|
|
41
|
+
/** Module name for the logger. */
|
|
42
|
+
module,
|
|
45
43
|
};
|
|
46
44
|
}
|
|
47
45
|
|
|
@@ -69,10 +67,19 @@ function isLevelEnabled(logger: pino.Logger<'verbose', boolean>, level: LogLevel
|
|
|
69
67
|
const defaultLogLevel = process.env.NODE_ENV === 'test' ? 'silent' : 'info';
|
|
70
68
|
const [logLevel, logFilters] = parseEnv(process.env.LOG_LEVEL, defaultLogLevel);
|
|
71
69
|
|
|
70
|
+
// Define custom logging levels for pino.
|
|
71
|
+
const customLevels = { verbose: 25 };
|
|
72
|
+
const pinoOpts = { customLevels, useOnlyCustomLevels: false, level: logLevel };
|
|
73
|
+
|
|
74
|
+
export const levels = {
|
|
75
|
+
labels: { ...pino.levels.labels, ...Object.fromEntries(Object.entries(customLevels).map(e => e.reverse())) },
|
|
76
|
+
values: { ...pino.levels.values, ...customLevels },
|
|
77
|
+
};
|
|
78
|
+
|
|
72
79
|
// Transport options for pretty logging to stderr via pino-pretty.
|
|
73
80
|
const useColor = true;
|
|
74
81
|
const { bold, reset } = createColors({ useColor });
|
|
75
|
-
const pinoPrettyOpts = {
|
|
82
|
+
export const pinoPrettyOpts = {
|
|
76
83
|
destination: 2,
|
|
77
84
|
sync: true,
|
|
78
85
|
colorize: useColor,
|
|
@@ -81,25 +88,20 @@ const pinoPrettyOpts = {
|
|
|
81
88
|
customLevels: 'fatal:60,error:50,warn:40,info:30,verbose:25,debug:20,trace:10',
|
|
82
89
|
customColors: 'fatal:bgRed,error:red,warn:yellow,info:green,verbose:magenta,debug:blue,trace:gray',
|
|
83
90
|
minimumLevel: 'trace' as const,
|
|
91
|
+
singleLine: !['1', 'true'].includes(process.env.LOG_MULTILINE ?? ''),
|
|
84
92
|
};
|
|
85
|
-
|
|
93
|
+
|
|
94
|
+
const prettyTransport: pino.TransportTargetOptions = {
|
|
86
95
|
target: 'pino-pretty',
|
|
87
96
|
options: pinoPrettyOpts,
|
|
97
|
+
level: 'trace',
|
|
88
98
|
};
|
|
89
99
|
|
|
90
100
|
// Transport for vanilla stdio logging as JSON.
|
|
91
|
-
const stdioTransport: pino.
|
|
101
|
+
const stdioTransport: pino.TransportTargetOptions = {
|
|
92
102
|
target: 'pino/file',
|
|
93
103
|
options: { destination: 2 },
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
// Define custom logging levels for pino.
|
|
97
|
-
const customLevels = { verbose: 25 };
|
|
98
|
-
const pinoOpts = { customLevels, useOnlyCustomLevels: false, level: logLevel };
|
|
99
|
-
|
|
100
|
-
export const levels = {
|
|
101
|
-
labels: { ...pino.levels.labels, ...Object.fromEntries(Object.entries(customLevels).map(e => e.reverse())) },
|
|
102
|
-
values: { ...pino.levels.values, ...customLevels },
|
|
104
|
+
level: 'trace',
|
|
103
105
|
};
|
|
104
106
|
|
|
105
107
|
// Transport for OpenTelemetry logging. While defining this here is an abstraction leakage since this
|
|
@@ -110,18 +112,21 @@ export const levels = {
|
|
|
110
112
|
// since pino will load this transport separately on a worker thread, to minimize disruption to the main loop.
|
|
111
113
|
const otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT;
|
|
112
114
|
const otelOpts = { levels };
|
|
113
|
-
const otelTransport: pino.
|
|
115
|
+
const otelTransport: pino.TransportTargetOptions = {
|
|
114
116
|
target: '@aztec/telemetry-client/otel-pino-stream',
|
|
115
117
|
options: otelOpts,
|
|
118
|
+
level: 'trace',
|
|
116
119
|
};
|
|
117
120
|
|
|
118
121
|
function makeLogger() {
|
|
119
122
|
if (!isNode) {
|
|
120
|
-
// We are on the browser
|
|
123
|
+
// We are on the browser.
|
|
121
124
|
return pino({ ...pinoOpts, browser: { asObject: false } });
|
|
122
125
|
} else if (process.env.JEST_WORKER_ID) {
|
|
123
|
-
// We are on jest, so we need sync logging
|
|
124
|
-
|
|
126
|
+
// We are on jest, so we need sync logging and stream to stderr.
|
|
127
|
+
// We expect jest/setup.mjs to kick in later and replace set up a pretty logger,
|
|
128
|
+
// but if for some reason it doesn't, at least we're covered with a default logger.
|
|
129
|
+
return pino(pinoOpts, pino.destination(2));
|
|
125
130
|
} else {
|
|
126
131
|
// Regular nodejs with transports on worker thread, using pino-pretty for console logging if LOG_JSON
|
|
127
132
|
// is not set, and an optional OTLP transport if the OTLP endpoint is provided.
|
|
@@ -129,7 +134,7 @@ function makeLogger() {
|
|
|
129
134
|
['1', 'true', 'TRUE'].includes(process.env.LOG_JSON ?? '') ? stdioTransport : prettyTransport,
|
|
130
135
|
otlpEndpoint ? otelTransport : undefined,
|
|
131
136
|
]);
|
|
132
|
-
return pino(pinoOpts, pino.transport({ targets }));
|
|
137
|
+
return pino(pinoOpts, pino.transport({ targets, levels: levels.values }));
|
|
133
138
|
}
|
|
134
139
|
}
|
|
135
140
|
|
|
@@ -146,6 +151,14 @@ logger.verbose(
|
|
|
146
151
|
: `Browser console logger initialized with level ${logLevel}`,
|
|
147
152
|
);
|
|
148
153
|
|
|
154
|
+
/**
|
|
155
|
+
* Overwrites the logging stream with a different destination.
|
|
156
|
+
* Used by jest/setup.mjs to set up a pretty logger.
|
|
157
|
+
*/
|
|
158
|
+
export function overwriteLoggingStream(stream: Writable): void {
|
|
159
|
+
(logger as any)[symbols.streamSym] = stream;
|
|
160
|
+
}
|
|
161
|
+
|
|
149
162
|
/**
|
|
150
163
|
* Registers an additional destination to the pino logger.
|
|
151
164
|
* Use only when working with destinations, not worker transports.
|
|
@@ -176,15 +189,9 @@ type ErrorLogFn = (msg: string, err?: Error | unknown, data?: LogData) => void;
|
|
|
176
189
|
export type Logger = { [K in LogLevel]: LogFn } & { /** Error log function */ error: ErrorLogFn } & {
|
|
177
190
|
level: LogLevel;
|
|
178
191
|
isLevelEnabled: (level: LogLevel) => boolean;
|
|
192
|
+
module: string;
|
|
179
193
|
};
|
|
180
194
|
|
|
181
|
-
/**
|
|
182
|
-
* Logger that supports multiple severity levels and can be called directly to issue a debug statement.
|
|
183
|
-
* Intended as a drop-in replacement for the debug module.
|
|
184
|
-
* TODO(palla/log): Remove this alias
|
|
185
|
-
*/
|
|
186
|
-
export type DebugLogger = Logger;
|
|
187
|
-
|
|
188
195
|
/**
|
|
189
196
|
* Concatenates a log message and an exception.
|
|
190
197
|
* @param msg - Log message
|