@aztec/aztec-node 5.0.0-nightly.20260429 → 5.0.0-nightly.20260430
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/aztec-node/block_response_helpers.d.ts +21 -0
- package/dest/aztec-node/block_response_helpers.d.ts.map +1 -0
- package/dest/aztec-node/block_response_helpers.js +88 -0
- package/dest/aztec-node/server.d.ts +18 -51
- package/dest/aztec-node/server.d.ts.map +1 -1
- package/dest/aztec-node/server.js +292 -109
- package/dest/sentinel/factory.d.ts +3 -2
- package/dest/sentinel/factory.d.ts.map +1 -1
- package/dest/sentinel/sentinel.d.ts +6 -3
- package/dest/sentinel/sentinel.d.ts.map +1 -1
- package/dest/sentinel/sentinel.js +7 -1
- package/package.json +26 -26
- package/src/aztec-node/block_response_helpers.ts +131 -0
- package/src/aztec-node/server.ts +319 -140
- package/src/sentinel/factory.ts +2 -1
- package/src/sentinel/sentinel.ts +17 -5
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
|
+
import {
|
|
3
|
+
type BlockData,
|
|
4
|
+
type BlockDataWithCheckpointContext,
|
|
5
|
+
type CheckpointedL2Block,
|
|
6
|
+
type CommitteeAttestation,
|
|
7
|
+
L2Block,
|
|
8
|
+
} from '@aztec/stdlib/block';
|
|
9
|
+
import type { CheckpointData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
10
|
+
import {
|
|
11
|
+
type BlockIncludeOptions,
|
|
12
|
+
type BlockResponse,
|
|
13
|
+
type CheckpointIncludeOptions,
|
|
14
|
+
type CheckpointResponse,
|
|
15
|
+
l1PublishInfoFromL1PublishedData,
|
|
16
|
+
} from '@aztec/stdlib/interfaces/client';
|
|
17
|
+
|
|
18
|
+
/** Projects a full {@link L2Block} into a {@link BlockResponse}, attaching L1 / attestation context when provided. */
|
|
19
|
+
export async function blockResponseFromL2Block(
|
|
20
|
+
block: L2Block,
|
|
21
|
+
options: BlockIncludeOptions,
|
|
22
|
+
context?: { l1?: BlockDataWithCheckpointContext['l1']; attestations?: CommitteeAttestation[] },
|
|
23
|
+
): Promise<BlockResponse> {
|
|
24
|
+
const response: BlockResponse = {
|
|
25
|
+
header: block.header,
|
|
26
|
+
archive: block.archive,
|
|
27
|
+
hash: await block.hash(),
|
|
28
|
+
checkpointNumber: block.checkpointNumber,
|
|
29
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
30
|
+
number: block.number,
|
|
31
|
+
};
|
|
32
|
+
if (options.includeTransactions) {
|
|
33
|
+
(response as BlockResponse).body = block.body;
|
|
34
|
+
}
|
|
35
|
+
if (options.includeL1PublishInfo) {
|
|
36
|
+
(response as BlockResponse).l1 = l1PublishInfoFromL1PublishedData(context?.l1);
|
|
37
|
+
}
|
|
38
|
+
if (options.includeAttestations) {
|
|
39
|
+
(response as BlockResponse).attestations = context?.attestations ?? [];
|
|
40
|
+
}
|
|
41
|
+
return response;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Projects metadata-only {@link BlockData} into a {@link BlockResponse}. */
|
|
45
|
+
export function blockResponseFromBlockData(
|
|
46
|
+
data: BlockData,
|
|
47
|
+
blockNumber: BlockNumber,
|
|
48
|
+
options: BlockIncludeOptions,
|
|
49
|
+
context?: { l1?: BlockDataWithCheckpointContext['l1']; attestations?: CommitteeAttestation[] },
|
|
50
|
+
): BlockResponse {
|
|
51
|
+
const response: BlockResponse = {
|
|
52
|
+
header: data.header,
|
|
53
|
+
archive: data.archive,
|
|
54
|
+
hash: data.blockHash,
|
|
55
|
+
checkpointNumber: data.checkpointNumber,
|
|
56
|
+
indexWithinCheckpoint: data.indexWithinCheckpoint,
|
|
57
|
+
number: blockNumber,
|
|
58
|
+
};
|
|
59
|
+
if (options.includeL1PublishInfo) {
|
|
60
|
+
(response as BlockResponse).l1 = l1PublishInfoFromL1PublishedData(context?.l1);
|
|
61
|
+
}
|
|
62
|
+
if (options.includeAttestations) {
|
|
63
|
+
(response as BlockResponse).attestations = context?.attestations ?? [];
|
|
64
|
+
}
|
|
65
|
+
return response;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Projects a {@link CheckpointedL2Block} into a {@link BlockResponse}. */
|
|
69
|
+
export function blockResponseFromCheckpointedL2Block(
|
|
70
|
+
cp: CheckpointedL2Block,
|
|
71
|
+
options: BlockIncludeOptions,
|
|
72
|
+
): Promise<BlockResponse> {
|
|
73
|
+
return blockResponseFromL2Block(cp.block, options, { l1: cp.l1, attestations: cp.attestations });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Projects a {@link PublishedCheckpoint} into a {@link CheckpointResponse}. */
|
|
77
|
+
export async function checkpointResponseFromPublishedCheckpoint(
|
|
78
|
+
pc: PublishedCheckpoint,
|
|
79
|
+
options: CheckpointIncludeOptions,
|
|
80
|
+
): Promise<CheckpointResponse> {
|
|
81
|
+
const response: CheckpointResponse = {
|
|
82
|
+
number: pc.checkpoint.number,
|
|
83
|
+
header: pc.checkpoint.header,
|
|
84
|
+
archive: pc.checkpoint.archive,
|
|
85
|
+
checkpointOutHash: pc.checkpoint.getCheckpointOutHash(),
|
|
86
|
+
startBlock: pc.checkpoint.blocks[0]?.number ?? BlockNumber.ZERO,
|
|
87
|
+
blockCount: pc.checkpoint.blocks.length,
|
|
88
|
+
feeAssetPriceModifier: pc.checkpoint.feeAssetPriceModifier,
|
|
89
|
+
};
|
|
90
|
+
if (options.includeBlocks) {
|
|
91
|
+
(response as CheckpointResponse).blocks = await Promise.all(
|
|
92
|
+
pc.checkpoint.blocks.map(block =>
|
|
93
|
+
blockResponseFromL2Block(block, {
|
|
94
|
+
includeTransactions: options.includeTransactions,
|
|
95
|
+
includeL1PublishInfo: false,
|
|
96
|
+
includeAttestations: false,
|
|
97
|
+
}),
|
|
98
|
+
),
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
if (options.includeL1PublishInfo) {
|
|
102
|
+
(response as CheckpointResponse).l1 = l1PublishInfoFromL1PublishedData(pc.l1);
|
|
103
|
+
}
|
|
104
|
+
if (options.includeAttestations) {
|
|
105
|
+
(response as CheckpointResponse).attestations = pc.attestations;
|
|
106
|
+
}
|
|
107
|
+
return response;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Projects metadata-only {@link CheckpointData} into a {@link CheckpointResponse}. `includeBlocks` is ignored (no blocks loaded). */
|
|
111
|
+
export function checkpointResponseFromCheckpointData(
|
|
112
|
+
cd: CheckpointData,
|
|
113
|
+
options: CheckpointIncludeOptions,
|
|
114
|
+
): CheckpointResponse {
|
|
115
|
+
const response: CheckpointResponse = {
|
|
116
|
+
number: cd.checkpointNumber,
|
|
117
|
+
header: cd.header,
|
|
118
|
+
archive: cd.archive,
|
|
119
|
+
checkpointOutHash: cd.checkpointOutHash,
|
|
120
|
+
startBlock: cd.startBlock,
|
|
121
|
+
blockCount: cd.blockCount,
|
|
122
|
+
feeAssetPriceModifier: cd.feeAssetPriceModifier,
|
|
123
|
+
};
|
|
124
|
+
if (options.includeL1PublishInfo) {
|
|
125
|
+
(response as CheckpointResponse).l1 = l1PublishInfoFromL1PublishedData(cd.l1);
|
|
126
|
+
}
|
|
127
|
+
if (options.includeAttestations) {
|
|
128
|
+
(response as CheckpointResponse).attestations = cd.attestations;
|
|
129
|
+
}
|
|
130
|
+
return response;
|
|
131
|
+
}
|
package/src/aztec-node/server.ts
CHANGED
|
@@ -50,14 +50,13 @@ import {
|
|
|
50
50
|
import { CollectionLimitsConfig, PublicSimulatorConfig } from '@aztec/stdlib/avm';
|
|
51
51
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
52
52
|
import {
|
|
53
|
-
type BlockData,
|
|
54
53
|
BlockHash,
|
|
55
54
|
type BlockParameter,
|
|
56
55
|
type DataInBlock,
|
|
57
56
|
L2Block,
|
|
58
57
|
type L2BlockSource,
|
|
58
|
+
inspectBlockParameter,
|
|
59
59
|
} from '@aztec/stdlib/block';
|
|
60
|
-
import type { PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
61
60
|
import type {
|
|
62
61
|
ContractClassPublic,
|
|
63
62
|
ContractDataSource,
|
|
@@ -67,15 +66,22 @@ import type {
|
|
|
67
66
|
} from '@aztec/stdlib/contract';
|
|
68
67
|
import { GasFees, type ManaUsageEstimate } from '@aztec/stdlib/gas';
|
|
69
68
|
import { computePublicDataTreeLeafSlot } from '@aztec/stdlib/hash';
|
|
70
|
-
import {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
69
|
+
import type {
|
|
70
|
+
AztecNode,
|
|
71
|
+
AztecNodeAdmin,
|
|
72
|
+
AztecNodeAdminConfig,
|
|
73
|
+
AztecNodeDebug,
|
|
74
|
+
BlockIncludeOptions,
|
|
75
|
+
BlockResponse,
|
|
76
|
+
ChainTip,
|
|
77
|
+
ChainTips,
|
|
78
|
+
CheckpointIncludeOptions,
|
|
79
|
+
CheckpointParameter,
|
|
80
|
+
CheckpointResponse,
|
|
81
|
+
GetContractClassLogsResponse,
|
|
82
|
+
GetPublicLogsResponse,
|
|
78
83
|
} from '@aztec/stdlib/interfaces/client';
|
|
84
|
+
import { AztecNodeAdminConfigSchema } from '@aztec/stdlib/interfaces/client';
|
|
79
85
|
import {
|
|
80
86
|
type AllowedElement,
|
|
81
87
|
type ClientProtocolCircuitVerifier,
|
|
@@ -129,6 +135,12 @@ import { createPublicClient } from 'viem';
|
|
|
129
135
|
|
|
130
136
|
import { createSentinel } from '../sentinel/factory.js';
|
|
131
137
|
import { Sentinel } from '../sentinel/sentinel.js';
|
|
138
|
+
import {
|
|
139
|
+
blockResponseFromBlockData,
|
|
140
|
+
blockResponseFromL2Block,
|
|
141
|
+
checkpointResponseFromCheckpointData,
|
|
142
|
+
checkpointResponseFromPublishedCheckpoint,
|
|
143
|
+
} from './block_response_helpers.js';
|
|
132
144
|
import { type AztecNodeConfig, createKeyStoreForValidator } from './config.js';
|
|
133
145
|
import { NodeMetrics } from './node_metrics.js';
|
|
134
146
|
|
|
@@ -197,10 +209,281 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
197
209
|
return status.syncSummary;
|
|
198
210
|
}
|
|
199
211
|
|
|
212
|
+
public async getChainTips(): Promise<ChainTips> {
|
|
213
|
+
const { proposed, checkpointed, proven, finalized } = await this.blockSource.getL2Tips();
|
|
214
|
+
return { proposed, checkpointed, proven, finalized };
|
|
215
|
+
}
|
|
216
|
+
|
|
200
217
|
public getL2Tips() {
|
|
201
218
|
return this.blockSource.getL2Tips();
|
|
202
219
|
}
|
|
203
220
|
|
|
221
|
+
public async getBlockHeader(number: BlockNumber | 'latest'): Promise<BlockHeader | undefined> {
|
|
222
|
+
const resolvedNumber = number === 'latest' ? await this.blockSource.getBlockNumber() : number;
|
|
223
|
+
if (resolvedNumber === BlockNumber.ZERO) {
|
|
224
|
+
return this.worldStateSynchronizer.getCommitted().getInitialHeader();
|
|
225
|
+
}
|
|
226
|
+
return this.blockSource.getBlockHeader(resolvedNumber);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
public async getCheckpointedBlocks(from: BlockNumber, limit: number) {
|
|
230
|
+
return (await this.blockSource.getCheckpointedBlocks(from, limit)) ?? [];
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
public getCheckpointsDataForEpoch(epoch: EpochNumber) {
|
|
234
|
+
return this.blockSource.getCheckpointsDataForEpoch(epoch);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
public getBlockNumber(tip?: ChainTip): Promise<BlockNumber> {
|
|
238
|
+
switch (tip) {
|
|
239
|
+
case undefined:
|
|
240
|
+
case 'proposed':
|
|
241
|
+
return this.blockSource.getBlockNumber();
|
|
242
|
+
case 'checkpointed':
|
|
243
|
+
return this.blockSource.getCheckpointedL2BlockNumber();
|
|
244
|
+
case 'proven':
|
|
245
|
+
return this.blockSource.getProvenBlockNumber();
|
|
246
|
+
case 'finalized':
|
|
247
|
+
return this.blockSource.getFinalizedL2BlockNumber();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
public async getCheckpointNumber(tip?: ChainTip): Promise<CheckpointNumber> {
|
|
252
|
+
switch (tip) {
|
|
253
|
+
case undefined:
|
|
254
|
+
case 'proposed':
|
|
255
|
+
case 'checkpointed':
|
|
256
|
+
return await this.blockSource.getCheckpointNumber();
|
|
257
|
+
case 'proven':
|
|
258
|
+
case 'finalized': {
|
|
259
|
+
const tips = await this.blockSource.getL2Tips();
|
|
260
|
+
return tip === 'proven' ? tips.proven.checkpoint.number : tips.finalized.checkpoint.number;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
private isChainTip(value: unknown): value is ChainTip {
|
|
266
|
+
return value === 'proposed' || value === 'checkpointed' || value === 'proven' || value === 'finalized';
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
private async resolveBlockParameter(
|
|
270
|
+
param: BlockParameter,
|
|
271
|
+
): Promise<{ number?: BlockNumber; hash?: BlockHash; archive?: Fr }> {
|
|
272
|
+
if (BlockHash.isBlockHash(param)) {
|
|
273
|
+
return { hash: param };
|
|
274
|
+
}
|
|
275
|
+
if (typeof param === 'number') {
|
|
276
|
+
return { number: param as BlockNumber };
|
|
277
|
+
}
|
|
278
|
+
if (param === 'latest') {
|
|
279
|
+
return { number: await this.blockSource.getBlockNumber() };
|
|
280
|
+
}
|
|
281
|
+
if (this.isChainTip(param)) {
|
|
282
|
+
return { number: await this.getBlockNumber(param) };
|
|
283
|
+
}
|
|
284
|
+
if (typeof param === 'object' && param !== null) {
|
|
285
|
+
if ('number' in param) {
|
|
286
|
+
return { number: param.number };
|
|
287
|
+
}
|
|
288
|
+
if ('hash' in param) {
|
|
289
|
+
return { hash: param.hash };
|
|
290
|
+
}
|
|
291
|
+
if ('archive' in param) {
|
|
292
|
+
return { archive: param.archive };
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
throw new BadRequestError(`Invalid BlockParameter: ${JSON.stringify(param)}`);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
private async resolveCheckpointParameter(
|
|
299
|
+
param: CheckpointParameter,
|
|
300
|
+
): Promise<{ number?: CheckpointNumber; slot?: SlotNumber }> {
|
|
301
|
+
if (typeof param === 'number') {
|
|
302
|
+
return { number: param as CheckpointNumber };
|
|
303
|
+
}
|
|
304
|
+
if (param === 'latest') {
|
|
305
|
+
return { number: await this.blockSource.getCheckpointNumber() };
|
|
306
|
+
}
|
|
307
|
+
if (this.isChainTip(param)) {
|
|
308
|
+
return { number: await this.getCheckpointNumber(param) };
|
|
309
|
+
}
|
|
310
|
+
if (typeof param === 'object' && param !== null) {
|
|
311
|
+
if ('number' in param) {
|
|
312
|
+
return { number: param.number };
|
|
313
|
+
}
|
|
314
|
+
if ('slot' in param) {
|
|
315
|
+
return { slot: param.slot };
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
throw new BadRequestError(`Invalid CheckpointParameter: ${JSON.stringify(param)}`);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
public async getBlock<Opts extends BlockIncludeOptions = {}>(
|
|
322
|
+
param: BlockParameter,
|
|
323
|
+
options: Opts = {} as Opts,
|
|
324
|
+
): Promise<BlockResponse<Opts> | undefined> {
|
|
325
|
+
const resolved = await this.resolveBlockParameter(param);
|
|
326
|
+
const wantTxs = !!options.includeTransactions;
|
|
327
|
+
const wantContext = !!options.includeL1PublishInfo || !!options.includeAttestations;
|
|
328
|
+
|
|
329
|
+
if (resolved.hash !== undefined) {
|
|
330
|
+
const initial = await this.#getInitialHeaderHash();
|
|
331
|
+
if (resolved.hash.equals(initial)) {
|
|
332
|
+
return (await this.buildGenesisBlockResponse(options)) as BlockResponse<Opts>;
|
|
333
|
+
}
|
|
334
|
+
if (wantTxs) {
|
|
335
|
+
const block = await this.blockSource.getL2BlockByHash(resolved.hash);
|
|
336
|
+
if (!block) {
|
|
337
|
+
return undefined;
|
|
338
|
+
}
|
|
339
|
+
const ctx = wantContext ? await this.blockSource.getBlockDataWithCheckpointContext(block.number) : undefined;
|
|
340
|
+
return (await blockResponseFromL2Block(block, options, ctx)) as BlockResponse<Opts>;
|
|
341
|
+
}
|
|
342
|
+
const data = await this.blockSource.getBlockHeaderByHash(resolved.hash);
|
|
343
|
+
if (!data) {
|
|
344
|
+
return undefined;
|
|
345
|
+
}
|
|
346
|
+
const blockNumber = data.globalVariables.blockNumber;
|
|
347
|
+
const ctx = wantContext ? await this.blockSource.getBlockDataWithCheckpointContext(blockNumber) : undefined;
|
|
348
|
+
if (ctx) {
|
|
349
|
+
return blockResponseFromBlockData(ctx.data, blockNumber, options, ctx) as BlockResponse<Opts>;
|
|
350
|
+
}
|
|
351
|
+
const blockData = await this.blockSource.getBlockData(blockNumber);
|
|
352
|
+
if (!blockData) {
|
|
353
|
+
return undefined;
|
|
354
|
+
}
|
|
355
|
+
return blockResponseFromBlockData(blockData, blockNumber, options) as BlockResponse<Opts>;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (resolved.archive !== undefined) {
|
|
359
|
+
if (wantTxs) {
|
|
360
|
+
const block = await this.blockSource.getL2BlockByArchive(resolved.archive);
|
|
361
|
+
if (!block) {
|
|
362
|
+
return undefined;
|
|
363
|
+
}
|
|
364
|
+
const ctx = wantContext ? await this.blockSource.getBlockDataWithCheckpointContext(block.number) : undefined;
|
|
365
|
+
return (await blockResponseFromL2Block(block, options, ctx)) as BlockResponse<Opts>;
|
|
366
|
+
}
|
|
367
|
+
const data = await this.blockSource.getBlockDataByArchive(resolved.archive);
|
|
368
|
+
if (!data) {
|
|
369
|
+
return undefined;
|
|
370
|
+
}
|
|
371
|
+
const blockNumber = data.header.globalVariables.blockNumber;
|
|
372
|
+
const ctx = wantContext ? await this.blockSource.getBlockDataWithCheckpointContext(blockNumber) : undefined;
|
|
373
|
+
return blockResponseFromBlockData(data, blockNumber, options, ctx) as BlockResponse<Opts>;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const blockNumber = resolved.number!;
|
|
377
|
+
if (blockNumber === BlockNumber.ZERO) {
|
|
378
|
+
return (await this.buildGenesisBlockResponse(options)) as BlockResponse<Opts>;
|
|
379
|
+
}
|
|
380
|
+
if (wantTxs) {
|
|
381
|
+
const block = await this.blockSource.getL2Block(blockNumber);
|
|
382
|
+
if (!block) {
|
|
383
|
+
return undefined;
|
|
384
|
+
}
|
|
385
|
+
const ctx = wantContext ? await this.blockSource.getBlockDataWithCheckpointContext(blockNumber) : undefined;
|
|
386
|
+
return (await blockResponseFromL2Block(block, options, ctx)) as BlockResponse<Opts>;
|
|
387
|
+
}
|
|
388
|
+
const ctx = await this.blockSource.getBlockDataWithCheckpointContext(blockNumber);
|
|
389
|
+
if (!ctx) {
|
|
390
|
+
return undefined;
|
|
391
|
+
}
|
|
392
|
+
return blockResponseFromBlockData(ctx.data, blockNumber, options, ctx) as BlockResponse<Opts>;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
public async getBlocks<Opts extends BlockIncludeOptions = {}>(
|
|
396
|
+
from: BlockNumber,
|
|
397
|
+
limit: number,
|
|
398
|
+
options: Opts = {} as Opts,
|
|
399
|
+
): Promise<BlockResponse<Opts>[]> {
|
|
400
|
+
const wantTxs = !!options.includeTransactions;
|
|
401
|
+
const wantContext = !!options.includeL1PublishInfo || !!options.includeAttestations;
|
|
402
|
+
if (wantTxs) {
|
|
403
|
+
const blocks = await this.blockSource.getBlocks(from, limit);
|
|
404
|
+
return (await Promise.all(
|
|
405
|
+
blocks.map(async block => {
|
|
406
|
+
const ctx = wantContext ? await this.blockSource.getBlockDataWithCheckpointContext(block.number) : undefined;
|
|
407
|
+
return blockResponseFromL2Block(block, options, ctx);
|
|
408
|
+
}),
|
|
409
|
+
)) as BlockResponse<Opts>[];
|
|
410
|
+
}
|
|
411
|
+
const results: BlockResponse<Opts>[] = [];
|
|
412
|
+
for (let i = 0; i < limit; i++) {
|
|
413
|
+
const blockNumber = BlockNumber(from + i);
|
|
414
|
+
const ctx = await this.blockSource.getBlockDataWithCheckpointContext(blockNumber);
|
|
415
|
+
if (!ctx) {
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
results.push(blockResponseFromBlockData(ctx.data, blockNumber, options, ctx) as BlockResponse<Opts>);
|
|
419
|
+
}
|
|
420
|
+
return results;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
public async getCheckpoint<Opts extends CheckpointIncludeOptions = {}>(
|
|
424
|
+
param: CheckpointParameter,
|
|
425
|
+
options: Opts = {} as Opts,
|
|
426
|
+
): Promise<CheckpointResponse<Opts> | undefined> {
|
|
427
|
+
const resolved = await this.resolveCheckpointParameter(param);
|
|
428
|
+
let checkpointNumber = resolved.number;
|
|
429
|
+
if (checkpointNumber === undefined && resolved.slot !== undefined) {
|
|
430
|
+
checkpointNumber = await this.blockSource.getCheckpointNumberBySlot(resolved.slot);
|
|
431
|
+
}
|
|
432
|
+
if (checkpointNumber === undefined) {
|
|
433
|
+
return undefined;
|
|
434
|
+
}
|
|
435
|
+
if (options.includeBlocks) {
|
|
436
|
+
const [checkpoint] = await this.blockSource.getCheckpoints(checkpointNumber, 1);
|
|
437
|
+
if (!checkpoint) {
|
|
438
|
+
return undefined;
|
|
439
|
+
}
|
|
440
|
+
return (await checkpointResponseFromPublishedCheckpoint(checkpoint, options)) as CheckpointResponse<Opts>;
|
|
441
|
+
}
|
|
442
|
+
const data = await this.blockSource.getCheckpointData(checkpointNumber);
|
|
443
|
+
if (!data) {
|
|
444
|
+
return undefined;
|
|
445
|
+
}
|
|
446
|
+
return checkpointResponseFromCheckpointData(data, options) as CheckpointResponse<Opts>;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
public async getCheckpoints<Opts extends CheckpointIncludeOptions = {}>(
|
|
450
|
+
from: CheckpointNumber,
|
|
451
|
+
limit: number,
|
|
452
|
+
options: Opts = {} as Opts,
|
|
453
|
+
): Promise<CheckpointResponse<Opts>[]> {
|
|
454
|
+
if (options.includeBlocks) {
|
|
455
|
+
const checkpoints = await this.blockSource.getCheckpoints(from, limit);
|
|
456
|
+
return (await Promise.all(
|
|
457
|
+
checkpoints.map(cp => checkpointResponseFromPublishedCheckpoint(cp, options)),
|
|
458
|
+
)) as CheckpointResponse<Opts>[];
|
|
459
|
+
}
|
|
460
|
+
const datas = await this.blockSource.getCheckpointDataRange(from, limit);
|
|
461
|
+
return datas.map(d => checkpointResponseFromCheckpointData(d, options)) as CheckpointResponse<Opts>[];
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
private async buildGenesisBlockResponse(options: BlockIncludeOptions): Promise<BlockResponse> {
|
|
465
|
+
const initial = this.worldStateSynchronizer.getCommitted().getInitialHeader();
|
|
466
|
+
const empty = L2Block.empty(initial);
|
|
467
|
+
const response: BlockResponse = {
|
|
468
|
+
header: empty.header,
|
|
469
|
+
archive: empty.archive,
|
|
470
|
+
hash: await this.#getInitialHeaderHash(),
|
|
471
|
+
checkpointNumber: empty.checkpointNumber,
|
|
472
|
+
indexWithinCheckpoint: empty.indexWithinCheckpoint,
|
|
473
|
+
number: empty.number,
|
|
474
|
+
};
|
|
475
|
+
if (options.includeTransactions) {
|
|
476
|
+
(response as BlockResponse).body = empty.body;
|
|
477
|
+
}
|
|
478
|
+
if (options.includeL1PublishInfo) {
|
|
479
|
+
(response as BlockResponse).l1 = { published: false };
|
|
480
|
+
}
|
|
481
|
+
if (options.includeAttestations) {
|
|
482
|
+
(response as BlockResponse).attestations = [];
|
|
483
|
+
}
|
|
484
|
+
return response;
|
|
485
|
+
}
|
|
486
|
+
|
|
204
487
|
/**
|
|
205
488
|
* initializes the Aztec Node, wait for component to sync.
|
|
206
489
|
* @param config - The configuration to be used by the aztec node.
|
|
@@ -736,71 +1019,6 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
736
1019
|
return nodeInfo;
|
|
737
1020
|
}
|
|
738
1021
|
|
|
739
|
-
/**
|
|
740
|
-
* Get a block specified by its block number, block hash, or 'latest'.
|
|
741
|
-
* @param block - The block parameter (block number, block hash, or 'latest').
|
|
742
|
-
* @returns The requested block.
|
|
743
|
-
*/
|
|
744
|
-
public async getBlock(block: BlockParameter): Promise<L2Block | undefined> {
|
|
745
|
-
if (BlockHash.isBlockHash(block)) {
|
|
746
|
-
return this.getBlockByHash(block);
|
|
747
|
-
}
|
|
748
|
-
const blockNumber = block === 'latest' ? await this.getBlockNumber() : (block as BlockNumber);
|
|
749
|
-
if (blockNumber === BlockNumber.ZERO) {
|
|
750
|
-
return this.buildInitialBlock();
|
|
751
|
-
}
|
|
752
|
-
return await this.blockSource.getL2Block(blockNumber);
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
/**
|
|
756
|
-
* Get a block specified by its hash.
|
|
757
|
-
* @param blockHash - The block hash being requested.
|
|
758
|
-
* @returns The requested block.
|
|
759
|
-
*/
|
|
760
|
-
public async getBlockByHash(blockHash: BlockHash): Promise<L2Block | undefined> {
|
|
761
|
-
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
762
|
-
if (blockHash.equals(initialBlockHash)) {
|
|
763
|
-
return this.buildInitialBlock();
|
|
764
|
-
}
|
|
765
|
-
return await this.blockSource.getL2BlockByHash(blockHash);
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
private buildInitialBlock(): L2Block {
|
|
769
|
-
const initialHeader = this.worldStateSynchronizer.getCommitted().getInitialHeader();
|
|
770
|
-
return L2Block.empty(initialHeader);
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
/**
|
|
774
|
-
* Get a block specified by its archive root.
|
|
775
|
-
* @param archive - The archive root being requested.
|
|
776
|
-
* @returns The requested block.
|
|
777
|
-
*/
|
|
778
|
-
public async getBlockByArchive(archive: Fr): Promise<L2Block | undefined> {
|
|
779
|
-
return await this.blockSource.getL2BlockByArchive(archive);
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
/**
|
|
783
|
-
* Method to request blocks. Will attempt to return all requested blocks but will return only those available.
|
|
784
|
-
* @param from - The start of the range of blocks to return.
|
|
785
|
-
* @param limit - The maximum number of blocks to obtain.
|
|
786
|
-
* @returns The blocks requested.
|
|
787
|
-
*/
|
|
788
|
-
public async getBlocks(from: BlockNumber, limit: number): Promise<L2Block[]> {
|
|
789
|
-
return (await this.blockSource.getBlocks(from, BlockNumber(limit))) ?? [];
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
public async getCheckpoints(from: CheckpointNumber, limit: number): Promise<PublishedCheckpoint[]> {
|
|
793
|
-
return (await this.blockSource.getCheckpoints(from, limit)) ?? [];
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
public async getCheckpointedBlocks(from: BlockNumber, limit: number) {
|
|
797
|
-
return (await this.blockSource.getCheckpointedBlocks(from, limit)) ?? [];
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
public getCheckpointsDataForEpoch(epochNumber: EpochNumber) {
|
|
801
|
-
return this.blockSource.getCheckpointsDataForEpoch(epochNumber);
|
|
802
|
-
}
|
|
803
|
-
|
|
804
1022
|
public async getCurrentMinFees(): Promise<GasFees> {
|
|
805
1023
|
return await this.feeProvider.getCurrentMinFees();
|
|
806
1024
|
}
|
|
@@ -818,26 +1036,6 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
818
1036
|
return GasFees.from({ feePerDaGas: 0n, feePerL2Gas: 0n });
|
|
819
1037
|
}
|
|
820
1038
|
|
|
821
|
-
/**
|
|
822
|
-
* Method to fetch the latest block number synchronized by the node.
|
|
823
|
-
* @returns The block number.
|
|
824
|
-
*/
|
|
825
|
-
public async getBlockNumber(): Promise<BlockNumber> {
|
|
826
|
-
return await this.blockSource.getBlockNumber();
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
public async getProvenBlockNumber(): Promise<BlockNumber> {
|
|
830
|
-
return await this.blockSource.getProvenBlockNumber();
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
public async getCheckpointedBlockNumber(): Promise<BlockNumber> {
|
|
834
|
-
return await this.blockSource.getCheckpointedL2BlockNumber();
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
public getCheckpointNumber(): Promise<CheckpointNumber> {
|
|
838
|
-
return this.blockSource.getCheckpointNumber();
|
|
839
|
-
}
|
|
840
|
-
|
|
841
1039
|
/**
|
|
842
1040
|
* Method to fetch the version of the package.
|
|
843
1041
|
* @returns The node package version
|
|
@@ -955,7 +1153,13 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
955
1153
|
throw new Error(`Invalid tx: ${reason}`);
|
|
956
1154
|
}
|
|
957
1155
|
|
|
958
|
-
|
|
1156
|
+
try {
|
|
1157
|
+
await this.p2pClient!.sendTx(tx);
|
|
1158
|
+
} catch (err) {
|
|
1159
|
+
this.metrics.receivedTx(timer.ms(), false);
|
|
1160
|
+
this.log.warn(`Mempool rejected tx ${txHash}: ${(err as Error).message}`, { txHash });
|
|
1161
|
+
throw err;
|
|
1162
|
+
}
|
|
959
1163
|
const duration = timer.ms();
|
|
960
1164
|
this.metrics.receivedTx(duration, true);
|
|
961
1165
|
this.log.info(`Received tx ${txHash} in ${duration}ms`, { txHash });
|
|
@@ -1274,41 +1478,6 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
1274
1478
|
return preimage.leaf.value;
|
|
1275
1479
|
}
|
|
1276
1480
|
|
|
1277
|
-
public async getBlockHeader(block: BlockParameter = 'latest'): Promise<BlockHeader | undefined> {
|
|
1278
|
-
if (BlockHash.isBlockHash(block)) {
|
|
1279
|
-
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
1280
|
-
if (block.equals(initialBlockHash)) {
|
|
1281
|
-
// Block source doesn't handle initial header so we need to handle the case separately.
|
|
1282
|
-
return this.worldStateSynchronizer.getCommitted().getInitialHeader();
|
|
1283
|
-
}
|
|
1284
|
-
return this.blockSource.getBlockHeaderByHash(block);
|
|
1285
|
-
} else {
|
|
1286
|
-
// Block source doesn't handle initial header so we need to handle the case separately.
|
|
1287
|
-
const blockNumber = block === 'latest' ? await this.getBlockNumber() : (block as BlockNumber);
|
|
1288
|
-
if (blockNumber === BlockNumber.ZERO) {
|
|
1289
|
-
return this.worldStateSynchronizer.getCommitted().getInitialHeader();
|
|
1290
|
-
}
|
|
1291
|
-
return this.blockSource.getBlockHeader(block);
|
|
1292
|
-
}
|
|
1293
|
-
}
|
|
1294
|
-
|
|
1295
|
-
/**
|
|
1296
|
-
* Get a block header specified by its archive root.
|
|
1297
|
-
* @param archive - The archive root being requested.
|
|
1298
|
-
* @returns The requested block header.
|
|
1299
|
-
*/
|
|
1300
|
-
public async getBlockHeaderByArchive(archive: Fr): Promise<BlockHeader | undefined> {
|
|
1301
|
-
return await this.blockSource.getBlockHeaderByArchive(archive);
|
|
1302
|
-
}
|
|
1303
|
-
|
|
1304
|
-
public getBlockData(number: BlockNumber): Promise<BlockData | undefined> {
|
|
1305
|
-
return this.blockSource.getBlockData(number);
|
|
1306
|
-
}
|
|
1307
|
-
|
|
1308
|
-
public getBlockDataByArchive(archive: Fr): Promise<BlockData | undefined> {
|
|
1309
|
-
return this.blockSource.getBlockDataByArchive(archive);
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
1481
|
/**
|
|
1313
1482
|
* Simulates the public part of a transaction with the current state.
|
|
1314
1483
|
* @param tx - The transaction to simulate.
|
|
@@ -1768,7 +1937,9 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
1768
1937
|
|
|
1769
1938
|
// Check it's within world state sync range
|
|
1770
1939
|
if (blockNumber > blockSyncedTo) {
|
|
1771
|
-
throw new Error(
|
|
1940
|
+
throw new Error(
|
|
1941
|
+
`Queried block ${inspectBlockParameter(block)} not yet synced by the node (node is synced upto ${blockSyncedTo}).`,
|
|
1942
|
+
);
|
|
1772
1943
|
}
|
|
1773
1944
|
this.log.debug(`Using snapshot for block ${blockNumber}, world state synced upto ${blockSyncedTo}`);
|
|
1774
1945
|
|
|
@@ -1788,23 +1959,31 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, AztecNodeDeb
|
|
|
1788
1959
|
return snapshot;
|
|
1789
1960
|
}
|
|
1790
1961
|
|
|
1791
|
-
/** Resolves
|
|
1962
|
+
/** Resolves any {@link BlockParameter} variant to a concrete block number. */
|
|
1792
1963
|
protected async resolveBlockNumber(block: BlockParameter): Promise<BlockNumber> {
|
|
1793
|
-
|
|
1794
|
-
|
|
1964
|
+
const resolved = await this.resolveBlockParameter(block);
|
|
1965
|
+
if (resolved.number !== undefined) {
|
|
1966
|
+
return resolved.number;
|
|
1795
1967
|
}
|
|
1796
|
-
if (
|
|
1968
|
+
if (resolved.hash !== undefined) {
|
|
1797
1969
|
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
1798
|
-
if (
|
|
1970
|
+
if (resolved.hash.equals(initialBlockHash)) {
|
|
1799
1971
|
return BlockNumber.ZERO;
|
|
1800
1972
|
}
|
|
1801
|
-
const header = await this.blockSource.getBlockHeaderByHash(
|
|
1973
|
+
const header = await this.blockSource.getBlockHeaderByHash(resolved.hash);
|
|
1974
|
+
if (!header) {
|
|
1975
|
+
throw new Error(`Block hash ${resolved.hash.toString()} not found.`);
|
|
1976
|
+
}
|
|
1977
|
+
return header.getBlockNumber();
|
|
1978
|
+
}
|
|
1979
|
+
if (resolved.archive !== undefined) {
|
|
1980
|
+
const header = await this.blockSource.getBlockHeaderByArchive(resolved.archive);
|
|
1802
1981
|
if (!header) {
|
|
1803
|
-
throw new Error(`Block
|
|
1982
|
+
throw new Error(`Block with archive ${resolved.archive.toString()} not found.`);
|
|
1804
1983
|
}
|
|
1805
1984
|
return header.getBlockNumber();
|
|
1806
1985
|
}
|
|
1807
|
-
|
|
1986
|
+
throw new BadRequestError(`Invalid BlockParameter: ${JSON.stringify(block)}`);
|
|
1808
1987
|
}
|
|
1809
1988
|
|
|
1810
1989
|
/**
|
package/src/sentinel/factory.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { createLogger } from '@aztec/foundation/log';
|
|
|
3
3
|
import { createStore } from '@aztec/kv-store/lmdb-v2';
|
|
4
4
|
import type { P2PClient } from '@aztec/p2p';
|
|
5
5
|
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
6
|
+
import type { ChainConfig } from '@aztec/stdlib/config';
|
|
6
7
|
import type { SlasherConfig } from '@aztec/stdlib/interfaces/server';
|
|
7
8
|
import type { DataStoreConfig } from '@aztec/stdlib/kv-store';
|
|
8
9
|
|
|
@@ -14,7 +15,7 @@ export async function createSentinel(
|
|
|
14
15
|
epochCache: EpochCache,
|
|
15
16
|
archiver: L2BlockSource,
|
|
16
17
|
p2p: P2PClient,
|
|
17
|
-
config: SentinelConfig & DataStoreConfig & SlasherConfig,
|
|
18
|
+
config: SentinelConfig & DataStoreConfig & SlasherConfig & Pick<ChainConfig, 'l1ChainId' | 'l1Contracts'>,
|
|
18
19
|
logger = createLogger('node:sentinel'),
|
|
19
20
|
): Promise<Sentinel | undefined> {
|
|
20
21
|
if (!config.sentinelEnabled) {
|