@aztec/archiver 0.0.1-commit.6d63667d → 0.0.1-commit.7ac86ea28
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/archiver.d.ts +5 -2
- package/dest/archiver.d.ts.map +1 -1
- package/dest/archiver.js +9 -91
- package/dest/factory.d.ts +1 -1
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +9 -4
- package/dest/index.d.ts +2 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -0
- package/dest/l1/calldata_retriever.d.ts +7 -1
- package/dest/l1/calldata_retriever.d.ts.map +1 -1
- package/dest/l1/calldata_retriever.js +17 -4
- package/dest/l1/data_retrieval.d.ts +3 -2
- package/dest/l1/data_retrieval.d.ts.map +1 -1
- package/dest/l1/data_retrieval.js +3 -2
- package/dest/modules/data_source_base.d.ts +8 -3
- package/dest/modules/data_source_base.d.ts.map +1 -1
- package/dest/modules/data_source_base.js +28 -72
- package/dest/modules/data_store_updater.d.ts +9 -2
- package/dest/modules/data_store_updater.d.ts.map +1 -1
- package/dest/modules/data_store_updater.js +40 -19
- package/dest/modules/instrumentation.d.ts +4 -2
- package/dest/modules/instrumentation.d.ts.map +1 -1
- package/dest/modules/instrumentation.js +9 -2
- package/dest/modules/l1_synchronizer.d.ts +3 -2
- package/dest/modules/l1_synchronizer.d.ts.map +1 -1
- package/dest/modules/l1_synchronizer.js +6 -6
- package/dest/store/block_store.d.ts +18 -14
- package/dest/store/block_store.d.ts.map +1 -1
- package/dest/store/block_store.js +69 -17
- package/dest/store/kv_archiver_store.d.ts +18 -4
- package/dest/store/kv_archiver_store.d.ts.map +1 -1
- package/dest/store/kv_archiver_store.js +18 -0
- package/dest/store/l2_tips_cache.d.ts +19 -0
- package/dest/store/l2_tips_cache.d.ts.map +1 -0
- package/dest/store/l2_tips_cache.js +89 -0
- package/dest/test/fake_l1_state.d.ts +4 -1
- package/dest/test/fake_l1_state.d.ts.map +1 -1
- package/dest/test/fake_l1_state.js +15 -9
- package/dest/test/mock_archiver.d.ts +1 -1
- package/dest/test/mock_archiver.d.ts.map +1 -1
- package/dest/test/mock_archiver.js +3 -2
- package/dest/test/mock_l2_block_source.d.ts +18 -3
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +125 -82
- package/package.json +13 -13
- package/src/archiver.ts +10 -110
- package/src/factory.ts +23 -8
- package/src/index.ts +1 -0
- package/src/l1/calldata_retriever.ts +25 -3
- package/src/l1/data_retrieval.ts +3 -0
- package/src/modules/data_source_base.ts +53 -92
- package/src/modules/data_store_updater.ts +43 -18
- package/src/modules/instrumentation.ts +9 -2
- package/src/modules/l1_synchronizer.ts +7 -5
- package/src/store/block_store.ts +85 -36
- package/src/store/kv_archiver_store.ts +35 -3
- package/src/store/l2_tips_cache.ts +89 -0
- package/src/test/fake_l1_state.ts +17 -9
- package/src/test/mock_archiver.ts +3 -2
- package/src/test/mock_l2_block_source.ts +158 -78
package/src/archiver.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { BlobClientInterface } from '@aztec/blob-client/client';
|
|
2
|
-
import { GENESIS_BLOCK_HEADER_HASH, INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
3
2
|
import { EpochCache } from '@aztec/epoch-cache';
|
|
4
3
|
import { BlockTagTooOldError, RollupContract } from '@aztec/ethereum/contracts';
|
|
5
4
|
import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
|
|
@@ -15,8 +14,6 @@ import { RunningPromise, makeLoggingErrorHandler } from '@aztec/foundation/runni
|
|
|
15
14
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
16
15
|
import {
|
|
17
16
|
type ArchiverEmitter,
|
|
18
|
-
type CheckpointId,
|
|
19
|
-
GENESIS_CHECKPOINT_HEADER_HASH,
|
|
20
17
|
L2Block,
|
|
21
18
|
type L2BlockSink,
|
|
22
19
|
type L2Tips,
|
|
@@ -41,6 +38,7 @@ import { ArchiverDataStoreUpdater } from './modules/data_store_updater.js';
|
|
|
41
38
|
import type { ArchiverInstrumentation } from './modules/instrumentation.js';
|
|
42
39
|
import type { ArchiverL1Synchronizer } from './modules/l1_synchronizer.js';
|
|
43
40
|
import type { KVArchiverDataStore } from './store/kv_archiver_store.js';
|
|
41
|
+
import { L2TipsCache } from './store/l2_tips_cache.js';
|
|
44
42
|
|
|
45
43
|
/** Export ArchiverEmitter for use in factory and tests. */
|
|
46
44
|
export type { ArchiverEmitter };
|
|
@@ -83,6 +81,9 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
83
81
|
/** Helper to handle updates to the store */
|
|
84
82
|
private readonly updater: ArchiverDataStoreUpdater;
|
|
85
83
|
|
|
84
|
+
/** In-memory cache for L2 chain tips. */
|
|
85
|
+
private readonly l2TipsCache: L2TipsCache;
|
|
86
|
+
|
|
86
87
|
public readonly tracer: Tracer;
|
|
87
88
|
|
|
88
89
|
/**
|
|
@@ -122,6 +123,7 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
122
123
|
protected override readonly l1Constants: L1RollupConstants & { l1StartBlockHash: Buffer32; genesisArchiveRoot: Fr },
|
|
123
124
|
synchronizer: ArchiverL1Synchronizer,
|
|
124
125
|
events: ArchiverEmitter,
|
|
126
|
+
l2TipsCache?: L2TipsCache,
|
|
125
127
|
private readonly log: Logger = createLogger('archiver'),
|
|
126
128
|
) {
|
|
127
129
|
super(dataStore, l1Constants);
|
|
@@ -130,7 +132,8 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
130
132
|
this.initialSyncPromise = promiseWithResolvers();
|
|
131
133
|
this.synchronizer = synchronizer;
|
|
132
134
|
this.events = events;
|
|
133
|
-
this.
|
|
135
|
+
this.l2TipsCache = l2TipsCache ?? new L2TipsCache(this.dataStore.blockStore);
|
|
136
|
+
this.updater = new ArchiverDataStoreUpdater(this.dataStore, this.l2TipsCache);
|
|
134
137
|
|
|
135
138
|
// Running promise starts with a small interval inbetween runs, so all iterations needed for the initial sync
|
|
136
139
|
// are done as fast as possible. This then gets updated once the initial sync completes.
|
|
@@ -391,111 +394,8 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
391
394
|
return true;
|
|
392
395
|
}
|
|
393
396
|
|
|
394
|
-
public
|
|
395
|
-
|
|
396
|
-
this.getBlockNumber(),
|
|
397
|
-
this.getProvenBlockNumber(),
|
|
398
|
-
this.getCheckpointedL2BlockNumber(),
|
|
399
|
-
this.getFinalizedL2BlockNumber(),
|
|
400
|
-
] as const);
|
|
401
|
-
|
|
402
|
-
const beforeInitialblockNumber = BlockNumber(INITIAL_L2_BLOCK_NUM - 1);
|
|
403
|
-
|
|
404
|
-
// Get the latest block header and checkpointed blocks for proven, finalised and checkpointed blocks
|
|
405
|
-
const [latestBlockHeader, provenCheckpointedBlock, finalizedCheckpointedBlock, checkpointedBlock] =
|
|
406
|
-
await Promise.all([
|
|
407
|
-
latestBlockNumber > beforeInitialblockNumber ? this.getBlockHeader(latestBlockNumber) : undefined,
|
|
408
|
-
provenBlockNumber > beforeInitialblockNumber ? this.getCheckpointedBlock(provenBlockNumber) : undefined,
|
|
409
|
-
finalizedBlockNumber > beforeInitialblockNumber ? this.getCheckpointedBlock(finalizedBlockNumber) : undefined,
|
|
410
|
-
checkpointedBlockNumber > beforeInitialblockNumber
|
|
411
|
-
? this.getCheckpointedBlock(checkpointedBlockNumber)
|
|
412
|
-
: undefined,
|
|
413
|
-
] as const);
|
|
414
|
-
|
|
415
|
-
if (latestBlockNumber > beforeInitialblockNumber && !latestBlockHeader) {
|
|
416
|
-
throw new Error(`Failed to retrieve latest block header for block ${latestBlockNumber}`);
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
// Checkpointed blocks must exist for proven, finalized and checkpointed tips if they are beyond the initial block number.
|
|
420
|
-
if (checkpointedBlockNumber > beforeInitialblockNumber && !checkpointedBlock?.block.header) {
|
|
421
|
-
throw new Error(
|
|
422
|
-
`Failed to retrieve checkpointed block header for block ${checkpointedBlockNumber} (latest block is ${latestBlockNumber})`,
|
|
423
|
-
);
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
if (provenBlockNumber > beforeInitialblockNumber && !provenCheckpointedBlock?.block.header) {
|
|
427
|
-
throw new Error(
|
|
428
|
-
`Failed to retrieve proven checkpointed for block ${provenBlockNumber} (latest block is ${latestBlockNumber})`,
|
|
429
|
-
);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
if (finalizedBlockNumber > beforeInitialblockNumber && !finalizedCheckpointedBlock?.block.header) {
|
|
433
|
-
throw new Error(
|
|
434
|
-
`Failed to retrieve finalized block header for block ${finalizedBlockNumber} (latest block is ${latestBlockNumber})`,
|
|
435
|
-
);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
const latestBlockHeaderHash = (await latestBlockHeader?.hash()) ?? GENESIS_BLOCK_HEADER_HASH;
|
|
439
|
-
const provenBlockHeaderHash = (await provenCheckpointedBlock?.block.header?.hash()) ?? GENESIS_BLOCK_HEADER_HASH;
|
|
440
|
-
const finalizedBlockHeaderHash =
|
|
441
|
-
(await finalizedCheckpointedBlock?.block.header?.hash()) ?? GENESIS_BLOCK_HEADER_HASH;
|
|
442
|
-
const checkpointedBlockHeaderHash = (await checkpointedBlock?.block.header?.hash()) ?? GENESIS_BLOCK_HEADER_HASH;
|
|
443
|
-
|
|
444
|
-
// Now attempt to retrieve checkpoints for proven, finalised and checkpointed blocks
|
|
445
|
-
const [[provenBlockCheckpoint], [finalizedBlockCheckpoint], [checkpointedBlockCheckpoint]] = await Promise.all([
|
|
446
|
-
provenCheckpointedBlock !== undefined
|
|
447
|
-
? await this.getCheckpoints(provenCheckpointedBlock?.checkpointNumber, 1)
|
|
448
|
-
: [undefined],
|
|
449
|
-
finalizedCheckpointedBlock !== undefined
|
|
450
|
-
? await this.getCheckpoints(finalizedCheckpointedBlock?.checkpointNumber, 1)
|
|
451
|
-
: [undefined],
|
|
452
|
-
checkpointedBlock !== undefined ? await this.getCheckpoints(checkpointedBlock?.checkpointNumber, 1) : [undefined],
|
|
453
|
-
]);
|
|
454
|
-
|
|
455
|
-
const initialcheckpointId: CheckpointId = {
|
|
456
|
-
number: CheckpointNumber.ZERO,
|
|
457
|
-
hash: GENESIS_CHECKPOINT_HEADER_HASH.toString(),
|
|
458
|
-
};
|
|
459
|
-
|
|
460
|
-
const makeCheckpointId = (checkpoint: PublishedCheckpoint | undefined) => {
|
|
461
|
-
if (checkpoint === undefined) {
|
|
462
|
-
return initialcheckpointId;
|
|
463
|
-
}
|
|
464
|
-
return {
|
|
465
|
-
number: checkpoint.checkpoint.number,
|
|
466
|
-
hash: checkpoint.checkpoint.hash().toString(),
|
|
467
|
-
};
|
|
468
|
-
};
|
|
469
|
-
|
|
470
|
-
const l2Tips: L2Tips = {
|
|
471
|
-
proposed: {
|
|
472
|
-
number: latestBlockNumber,
|
|
473
|
-
hash: latestBlockHeaderHash.toString(),
|
|
474
|
-
},
|
|
475
|
-
proven: {
|
|
476
|
-
block: {
|
|
477
|
-
number: provenBlockNumber,
|
|
478
|
-
hash: provenBlockHeaderHash.toString(),
|
|
479
|
-
},
|
|
480
|
-
checkpoint: makeCheckpointId(provenBlockCheckpoint),
|
|
481
|
-
},
|
|
482
|
-
finalized: {
|
|
483
|
-
block: {
|
|
484
|
-
number: finalizedBlockNumber,
|
|
485
|
-
hash: finalizedBlockHeaderHash.toString(),
|
|
486
|
-
},
|
|
487
|
-
checkpoint: makeCheckpointId(finalizedBlockCheckpoint),
|
|
488
|
-
},
|
|
489
|
-
checkpointed: {
|
|
490
|
-
block: {
|
|
491
|
-
number: checkpointedBlockNumber,
|
|
492
|
-
hash: checkpointedBlockHeaderHash.toString(),
|
|
493
|
-
},
|
|
494
|
-
checkpoint: makeCheckpointId(checkpointedBlockCheckpoint),
|
|
495
|
-
},
|
|
496
|
-
};
|
|
497
|
-
|
|
498
|
-
return l2Tips;
|
|
397
|
+
public getL2Tips(): Promise<L2Tips> {
|
|
398
|
+
return this.l2TipsCache.getL2Tips();
|
|
499
399
|
}
|
|
500
400
|
|
|
501
401
|
public async rollbackTo(targetL2BlockNumber: BlockNumber): Promise<void> {
|
|
@@ -532,7 +432,7 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
532
432
|
await this.store.setMessageSynchedL1Block({ l1BlockNumber: targetL1BlockNumber, l1BlockHash: targetL1BlockHash });
|
|
533
433
|
if (targetL2BlockNumber < currentProvenBlock) {
|
|
534
434
|
this.log.info(`Clearing proven L2 block number`);
|
|
535
|
-
await this.
|
|
435
|
+
await this.updater.setProvenCheckpointNumber(CheckpointNumber.ZERO);
|
|
536
436
|
}
|
|
537
437
|
// TODO(palla/reorg): Set the finalized block when we add support for it.
|
|
538
438
|
// if (targetL2BlockNumber < currentFinalizedBlock) {
|
package/src/factory.ts
CHANGED
|
@@ -25,6 +25,7 @@ import { type ArchiverConfig, mapArchiverConfig } from './config.js';
|
|
|
25
25
|
import { ArchiverInstrumentation } from './modules/instrumentation.js';
|
|
26
26
|
import { ArchiverL1Synchronizer } from './modules/l1_synchronizer.js';
|
|
27
27
|
import { ARCHIVER_DB_VERSION, KVArchiverDataStore } from './store/kv_archiver_store.js';
|
|
28
|
+
import { L2TipsCache } from './store/l2_tips_cache.js';
|
|
28
29
|
|
|
29
30
|
export const ARCHIVER_STORE_NAME = 'archiver';
|
|
30
31
|
|
|
@@ -77,14 +78,21 @@ export async function createArchiver(
|
|
|
77
78
|
const inbox = new InboxContract(publicClient, config.l1Contracts.inboxAddress);
|
|
78
79
|
|
|
79
80
|
// Fetch L1 constants from rollup contract
|
|
80
|
-
const [
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
81
|
+
const [
|
|
82
|
+
l1StartBlock,
|
|
83
|
+
l1GenesisTime,
|
|
84
|
+
proofSubmissionEpochs,
|
|
85
|
+
genesisArchiveRoot,
|
|
86
|
+
slashingProposerAddress,
|
|
87
|
+
targetCommitteeSize,
|
|
88
|
+
] = await Promise.all([
|
|
89
|
+
rollup.getL1StartBlock(),
|
|
90
|
+
rollup.getL1GenesisTime(),
|
|
91
|
+
rollup.getProofSubmissionEpochs(),
|
|
92
|
+
rollup.getGenesisArchiveTreeRoot(),
|
|
93
|
+
rollup.getSlashingProposerAddress(),
|
|
94
|
+
rollup.getTargetCommitteeSize(),
|
|
95
|
+
] as const);
|
|
88
96
|
|
|
89
97
|
const l1StartBlockHash = await publicClient
|
|
90
98
|
.getBlock({ blockNumber: l1StartBlock, includeTransactions: false })
|
|
@@ -100,6 +108,7 @@ export async function createArchiver(
|
|
|
100
108
|
slotDuration,
|
|
101
109
|
ethereumSlotDuration,
|
|
102
110
|
proofSubmissionEpochs: Number(proofSubmissionEpochs),
|
|
111
|
+
targetCommitteeSize,
|
|
103
112
|
genesisArchiveRoot: Fr.fromString(genesisArchiveRoot.toString()),
|
|
104
113
|
};
|
|
105
114
|
|
|
@@ -120,6 +129,9 @@ export async function createArchiver(
|
|
|
120
129
|
// Create the event emitter that will be shared by archiver and synchronizer
|
|
121
130
|
const events = new EventEmitter() as ArchiverEmitter;
|
|
122
131
|
|
|
132
|
+
// Create L2 tips cache shared by archiver and synchronizer
|
|
133
|
+
const l2TipsCache = new L2TipsCache(archiverStore.blockStore);
|
|
134
|
+
|
|
123
135
|
// Create the L1 synchronizer
|
|
124
136
|
const synchronizer = new ArchiverL1Synchronizer(
|
|
125
137
|
publicClient,
|
|
@@ -136,6 +148,8 @@ export async function createArchiver(
|
|
|
136
148
|
l1Constants,
|
|
137
149
|
events,
|
|
138
150
|
instrumentation.tracer,
|
|
151
|
+
l2TipsCache,
|
|
152
|
+
undefined, // log (use default)
|
|
139
153
|
);
|
|
140
154
|
|
|
141
155
|
const archiver = new Archiver(
|
|
@@ -150,6 +164,7 @@ export async function createArchiver(
|
|
|
150
164
|
l1Constants,
|
|
151
165
|
synchronizer,
|
|
152
166
|
events,
|
|
167
|
+
l2TipsCache,
|
|
153
168
|
);
|
|
154
169
|
|
|
155
170
|
await archiver.start(opts.blockUntilSync);
|
package/src/index.ts
CHANGED
|
@@ -8,5 +8,6 @@ export * from './config.js';
|
|
|
8
8
|
export { type L1PublishedData } from './structs/published.js';
|
|
9
9
|
export { KVArchiverDataStore, ARCHIVER_DB_VERSION } from './store/kv_archiver_store.js';
|
|
10
10
|
export { ContractInstanceStore } from './store/contract_instance_store.js';
|
|
11
|
+
export { L2TipsCache } from './store/l2_tips_cache.js';
|
|
11
12
|
|
|
12
13
|
export { retrieveCheckpointsFromRollup, retrieveL2ProofVerifiedEvents } from './l1/data_retrieval.js';
|
|
@@ -39,6 +39,14 @@ import type { CallInfo } from './types.js';
|
|
|
39
39
|
* in order to reconstruct an L2 block header.
|
|
40
40
|
*/
|
|
41
41
|
export class CalldataRetriever {
|
|
42
|
+
/** Tx hashes we've already logged for trace+debug failure (log once per tx per process). */
|
|
43
|
+
private static readonly traceFailureWarnedTxHashes = new Set<string>();
|
|
44
|
+
|
|
45
|
+
/** Clears the trace-failure warned set. For testing only. */
|
|
46
|
+
static resetTraceFailureWarnedForTesting(): void {
|
|
47
|
+
CalldataRetriever.traceFailureWarnedTxHashes.clear();
|
|
48
|
+
}
|
|
49
|
+
|
|
42
50
|
/** Pre-computed valid contract calls for validation */
|
|
43
51
|
private readonly validContractCalls: ValidContractCall[];
|
|
44
52
|
|
|
@@ -84,6 +92,7 @@ export class CalldataRetriever {
|
|
|
84
92
|
header: CheckpointHeader;
|
|
85
93
|
attestations: CommitteeAttestation[];
|
|
86
94
|
blockHash: string;
|
|
95
|
+
feeAssetPriceModifier: bigint;
|
|
87
96
|
}> {
|
|
88
97
|
this.logger.trace(`Fetching checkpoint ${checkpointNumber} from rollup tx ${txHash}`, {
|
|
89
98
|
willValidateHashes: !!expectedHashes.attestationsHash || !!expectedHashes.payloadDigest,
|
|
@@ -313,7 +322,8 @@ export class CalldataRetriever {
|
|
|
313
322
|
this.logger.debug(`Successfully traced using trace_transaction, found ${calls.length} calls`);
|
|
314
323
|
} catch (err) {
|
|
315
324
|
const traceError = err instanceof Error ? err : new Error(String(err));
|
|
316
|
-
this.logger.verbose(`Failed trace_transaction for ${txHash}
|
|
325
|
+
this.logger.verbose(`Failed trace_transaction for ${txHash}: ${traceError.message}`);
|
|
326
|
+
this.logger.debug(`Trace failure details for ${txHash}`, { traceError });
|
|
317
327
|
|
|
318
328
|
try {
|
|
319
329
|
// Fall back to debug_traceTransaction (Geth RPC)
|
|
@@ -322,7 +332,16 @@ export class CalldataRetriever {
|
|
|
322
332
|
this.logger.debug(`Successfully traced using debug_traceTransaction, found ${calls.length} calls`);
|
|
323
333
|
} catch (debugErr) {
|
|
324
334
|
const debugError = debugErr instanceof Error ? debugErr : new Error(String(debugErr));
|
|
325
|
-
|
|
335
|
+
// Log once per tx so we don't spam on every sync cycle when sync point doesn't advance
|
|
336
|
+
if (!CalldataRetriever.traceFailureWarnedTxHashes.has(txHash)) {
|
|
337
|
+
CalldataRetriever.traceFailureWarnedTxHashes.add(txHash);
|
|
338
|
+
this.logger.warn(
|
|
339
|
+
`Cannot decode L1 tx ${txHash}: trace and debug RPC failed or unavailable. ` +
|
|
340
|
+
`trace_transaction: ${traceError.message}; debug_traceTransaction: ${debugError.message}`,
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
// Full error objects can be very long; keep at debug only
|
|
344
|
+
this.logger.debug(`Trace/debug failure details for tx ${txHash}`, {
|
|
326
345
|
traceError,
|
|
327
346
|
debugError,
|
|
328
347
|
txHash,
|
|
@@ -403,6 +422,7 @@ export class CalldataRetriever {
|
|
|
403
422
|
header: CheckpointHeader;
|
|
404
423
|
attestations: CommitteeAttestation[];
|
|
405
424
|
blockHash: string;
|
|
425
|
+
feeAssetPriceModifier: bigint;
|
|
406
426
|
} {
|
|
407
427
|
const { functionName: rollupFunctionName, args: rollupArgs } = decodeFunctionData({
|
|
408
428
|
abi: RollupAbi,
|
|
@@ -458,7 +478,8 @@ export class CalldataRetriever {
|
|
|
458
478
|
if (expectedHashes.payloadDigest) {
|
|
459
479
|
// Use ConsensusPayload to compute the digest - this ensures we match the exact logic
|
|
460
480
|
// used by the network for signing and verification
|
|
461
|
-
const
|
|
481
|
+
const feeAssetPriceModifier = decodedArgs.oracleInput.feeAssetPriceModifier;
|
|
482
|
+
const consensusPayload = new ConsensusPayload(header, archiveRoot, feeAssetPriceModifier);
|
|
462
483
|
const payloadToSign = consensusPayload.getPayloadToSign(SignatureDomainSeparator.checkpointAttestation);
|
|
463
484
|
const computedPayloadDigest = keccak256(payloadToSign);
|
|
464
485
|
|
|
@@ -495,6 +516,7 @@ export class CalldataRetriever {
|
|
|
495
516
|
header,
|
|
496
517
|
attestations,
|
|
497
518
|
blockHash,
|
|
519
|
+
feeAssetPriceModifier: decodedArgs.oracleInput.feeAssetPriceModifier,
|
|
498
520
|
};
|
|
499
521
|
}
|
|
500
522
|
}
|
package/src/l1/data_retrieval.ts
CHANGED
|
@@ -38,6 +38,7 @@ import { CalldataRetriever } from './calldata_retriever.js';
|
|
|
38
38
|
export type RetrievedCheckpoint = {
|
|
39
39
|
checkpointNumber: CheckpointNumber;
|
|
40
40
|
archiveRoot: Fr;
|
|
41
|
+
feeAssetPriceModifier: bigint;
|
|
41
42
|
header: CheckpointHeader;
|
|
42
43
|
checkpointBlobData: CheckpointBlobData;
|
|
43
44
|
l1: L1PublishedData;
|
|
@@ -49,6 +50,7 @@ export type RetrievedCheckpoint = {
|
|
|
49
50
|
export async function retrievedToPublishedCheckpoint({
|
|
50
51
|
checkpointNumber,
|
|
51
52
|
archiveRoot,
|
|
53
|
+
feeAssetPriceModifier,
|
|
52
54
|
header: checkpointHeader,
|
|
53
55
|
checkpointBlobData,
|
|
54
56
|
l1,
|
|
@@ -128,6 +130,7 @@ export async function retrievedToPublishedCheckpoint({
|
|
|
128
130
|
header: checkpointHeader,
|
|
129
131
|
blocks: l2Blocks,
|
|
130
132
|
number: checkpointNumber,
|
|
133
|
+
feeAssetPriceModifier: feeAssetPriceModifier,
|
|
131
134
|
});
|
|
132
135
|
|
|
133
136
|
return PublishedCheckpoint.from({ checkpoint, l1, attestations });
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
+
import { range } from '@aztec/foundation/array';
|
|
1
2
|
import { BlockNumber, CheckpointNumber, type EpochNumber, type SlotNumber } from '@aztec/foundation/branded-types';
|
|
2
3
|
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
4
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
4
5
|
import { isDefined } from '@aztec/foundation/types';
|
|
5
6
|
import type { FunctionSelector } from '@aztec/stdlib/abi';
|
|
6
7
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
7
|
-
import { type BlockHash, CheckpointedL2Block,
|
|
8
|
-
import { Checkpoint, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
8
|
+
import { type BlockData, type BlockHash, CheckpointedL2Block, L2Block, type L2Tips } from '@aztec/stdlib/block';
|
|
9
|
+
import { Checkpoint, type CheckpointData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
9
10
|
import type { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
|
|
10
11
|
import { type L1RollupConstants, getSlotRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
|
|
11
12
|
import type { GetContractClassLogsResponse, GetPublicLogsResponse } from '@aztec/stdlib/interfaces/client';
|
|
@@ -17,7 +18,6 @@ import type { BlockHeader, IndexedTxEffect, TxHash, TxReceipt } from '@aztec/std
|
|
|
17
18
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
18
19
|
|
|
19
20
|
import type { ArchiverDataSource } from '../interfaces.js';
|
|
20
|
-
import type { CheckpointData } from '../store/block_store.js';
|
|
21
21
|
import type { KVArchiverDataStore } from '../store/kv_archiver_store.js';
|
|
22
22
|
import type { ValidateCheckpointResult } from './validation.js';
|
|
23
23
|
|
|
@@ -114,7 +114,7 @@ export abstract class ArchiverDataSourceBase
|
|
|
114
114
|
if (!checkpointData) {
|
|
115
115
|
return undefined;
|
|
116
116
|
}
|
|
117
|
-
return BlockNumber(checkpointData.startBlock + checkpointData.
|
|
117
|
+
return BlockNumber(checkpointData.startBlock + checkpointData.blockCount - 1);
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
public getCheckpointedBlocks(from: BlockNumber, limit: number): Promise<CheckpointedL2Block[]> {
|
|
@@ -129,6 +129,14 @@ export abstract class ArchiverDataSourceBase
|
|
|
129
129
|
return this.store.getBlockHeaderByArchive(archive);
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
public getBlockData(number: BlockNumber): Promise<BlockData | undefined> {
|
|
133
|
+
return this.store.getBlockData(number);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
public getBlockDataByArchive(archive: Fr): Promise<BlockData | undefined> {
|
|
137
|
+
return this.store.getBlockDataByArchive(archive);
|
|
138
|
+
}
|
|
139
|
+
|
|
132
140
|
public async getL2Block(number: BlockNumber): Promise<L2Block | undefined> {
|
|
133
141
|
// If the number provided is -ve, then return the latest block.
|
|
134
142
|
if (number < 0) {
|
|
@@ -223,28 +231,21 @@ export abstract class ArchiverDataSourceBase
|
|
|
223
231
|
|
|
224
232
|
public async getCheckpoints(checkpointNumber: CheckpointNumber, limit: number): Promise<PublishedCheckpoint[]> {
|
|
225
233
|
const checkpoints = await this.store.getRangeOfCheckpoints(checkpointNumber, limit);
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const checkpoint = checkpoints[i];
|
|
234
|
-
const fullCheckpoint = new Checkpoint(
|
|
235
|
-
checkpoint.archive,
|
|
236
|
-
checkpoint.header,
|
|
237
|
-
blocksForCheckpoint,
|
|
238
|
-
checkpoint.checkpointNumber,
|
|
239
|
-
);
|
|
240
|
-
const publishedCheckpoint = new PublishedCheckpoint(
|
|
241
|
-
fullCheckpoint,
|
|
242
|
-
checkpoint.l1,
|
|
243
|
-
checkpoint.attestations.map(x => CommitteeAttestation.fromBuffer(x)),
|
|
244
|
-
);
|
|
245
|
-
fullCheckpoints.push(publishedCheckpoint);
|
|
234
|
+
return Promise.all(checkpoints.map(ch => this.getPublishedCheckpointFromCheckpointData(ch)));
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
private async getPublishedCheckpointFromCheckpointData(checkpoint: CheckpointData): Promise<PublishedCheckpoint> {
|
|
238
|
+
const blocksForCheckpoint = await this.store.getBlocksForCheckpoint(checkpoint.checkpointNumber);
|
|
239
|
+
if (!blocksForCheckpoint) {
|
|
240
|
+
throw new Error(`Blocks for checkpoint ${checkpoint.checkpointNumber} not found`);
|
|
246
241
|
}
|
|
247
|
-
|
|
242
|
+
const fullCheckpoint = new Checkpoint(
|
|
243
|
+
checkpoint.archive,
|
|
244
|
+
checkpoint.header,
|
|
245
|
+
blocksForCheckpoint,
|
|
246
|
+
checkpoint.checkpointNumber,
|
|
247
|
+
);
|
|
248
|
+
return new PublishedCheckpoint(fullCheckpoint, checkpoint.l1, checkpoint.attestations);
|
|
248
249
|
}
|
|
249
250
|
|
|
250
251
|
public getBlocksForSlot(slotNumber: SlotNumber): Promise<L2Block[]> {
|
|
@@ -252,84 +253,44 @@ export abstract class ArchiverDataSourceBase
|
|
|
252
253
|
}
|
|
253
254
|
|
|
254
255
|
public async getCheckpointedBlocksForEpoch(epochNumber: EpochNumber): Promise<CheckpointedL2Block[]> {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
let checkpoint = await this.store.getCheckpointData(await this.store.getSynchedCheckpointNumber());
|
|
265
|
-
const slot = (b: CheckpointData) => b.header.slotNumber;
|
|
266
|
-
while (checkpoint && slot(checkpoint) >= start) {
|
|
267
|
-
if (slot(checkpoint) <= end) {
|
|
268
|
-
// push the blocks on backwards
|
|
269
|
-
const endBlock = checkpoint.startBlock + checkpoint.numBlocks - 1;
|
|
270
|
-
for (let i = endBlock; i >= checkpoint.startBlock; i--) {
|
|
271
|
-
const checkpointedBlock = await this.getCheckpointedBlock(BlockNumber(i));
|
|
272
|
-
if (checkpointedBlock) {
|
|
273
|
-
blocks.push(checkpointedBlock);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
checkpoint = await this.store.getCheckpointData(CheckpointNumber(checkpoint.checkpointNumber - 1));
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
return blocks.reverse();
|
|
256
|
+
const checkpointsData = await this.getCheckpointsDataForEpoch(epochNumber);
|
|
257
|
+
const blocks = await Promise.all(
|
|
258
|
+
checkpointsData.flatMap(checkpoint =>
|
|
259
|
+
range(checkpoint.blockCount, checkpoint.startBlock).map(blockNumber =>
|
|
260
|
+
this.getCheckpointedBlock(BlockNumber(blockNumber)),
|
|
261
|
+
),
|
|
262
|
+
),
|
|
263
|
+
);
|
|
264
|
+
return blocks.filter(isDefined);
|
|
281
265
|
}
|
|
282
266
|
|
|
283
267
|
public async getCheckpointedBlockHeadersForEpoch(epochNumber: EpochNumber): Promise<BlockHeader[]> {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
let checkpoint = await this.store.getCheckpointData(await this.store.getSynchedCheckpointNumber());
|
|
294
|
-
const slot = (b: CheckpointData) => b.header.slotNumber;
|
|
295
|
-
while (checkpoint && slot(checkpoint) >= start) {
|
|
296
|
-
if (slot(checkpoint) <= end) {
|
|
297
|
-
// push the blocks on backwards
|
|
298
|
-
const endBlock = checkpoint.startBlock + checkpoint.numBlocks - 1;
|
|
299
|
-
for (let i = endBlock; i >= checkpoint.startBlock; i--) {
|
|
300
|
-
const block = await this.getBlockHeader(BlockNumber(i));
|
|
301
|
-
if (block) {
|
|
302
|
-
blocks.push(block);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
checkpoint = await this.store.getCheckpointData(CheckpointNumber(checkpoint.checkpointNumber - 1));
|
|
307
|
-
}
|
|
308
|
-
return blocks.reverse();
|
|
268
|
+
const checkpointsData = await this.getCheckpointsDataForEpoch(epochNumber);
|
|
269
|
+
const blocks = await Promise.all(
|
|
270
|
+
checkpointsData.flatMap(checkpoint =>
|
|
271
|
+
range(checkpoint.blockCount, checkpoint.startBlock).map(blockNumber =>
|
|
272
|
+
this.getBlockHeader(BlockNumber(blockNumber)),
|
|
273
|
+
),
|
|
274
|
+
),
|
|
275
|
+
);
|
|
276
|
+
return blocks.filter(isDefined);
|
|
309
277
|
}
|
|
310
278
|
|
|
311
279
|
public async getCheckpointsForEpoch(epochNumber: EpochNumber): Promise<Checkpoint[]> {
|
|
280
|
+
const checkpointsData = await this.getCheckpointsDataForEpoch(epochNumber);
|
|
281
|
+
return Promise.all(
|
|
282
|
+
checkpointsData.map(data => this.getPublishedCheckpointFromCheckpointData(data).then(p => p.checkpoint)),
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/** Returns checkpoint data for all checkpoints whose slot falls within the given epoch. */
|
|
287
|
+
public getCheckpointsDataForEpoch(epochNumber: EpochNumber): Promise<CheckpointData[]> {
|
|
312
288
|
if (!this.l1Constants) {
|
|
313
289
|
throw new Error('L1 constants not set');
|
|
314
290
|
}
|
|
315
291
|
|
|
316
292
|
const [start, end] = getSlotRangeForEpoch(epochNumber, this.l1Constants);
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
// Walk the list of checkpoints backwards and filter by slots matching the requested epoch.
|
|
320
|
-
// We'll typically ask for checkpoints for a very recent epoch, so we shouldn't need an index here.
|
|
321
|
-
let checkpointData = await this.store.getCheckpointData(await this.store.getSynchedCheckpointNumber());
|
|
322
|
-
const slot = (b: CheckpointData) => b.header.slotNumber;
|
|
323
|
-
while (checkpointData && slot(checkpointData) >= start) {
|
|
324
|
-
if (slot(checkpointData) <= end) {
|
|
325
|
-
// push the checkpoints on backwards
|
|
326
|
-
const [checkpoint] = await this.getCheckpoints(checkpointData.checkpointNumber, 1);
|
|
327
|
-
checkpoints.push(checkpoint.checkpoint);
|
|
328
|
-
}
|
|
329
|
-
checkpointData = await this.store.getCheckpointData(CheckpointNumber(checkpointData.checkpointNumber - 1));
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
return checkpoints.reverse();
|
|
293
|
+
return this.store.getCheckpointDataForSlotRange(start, end);
|
|
333
294
|
}
|
|
334
295
|
|
|
335
296
|
public async getBlock(number: BlockNumber): Promise<L2Block | undefined> {
|