@aztec/archiver 3.0.0-nightly.20251107 → 3.0.0-nightly.20251108
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/archiver.d.ts +6 -3
- package/dest/archiver/archiver.d.ts.map +1 -1
- package/dest/archiver/archiver.js +85 -57
- package/dest/archiver/config.d.ts.map +1 -1
- package/dest/archiver/config.js +5 -0
- package/dest/archiver/data_retrieval.d.ts.map +1 -1
- package/dest/archiver/data_retrieval.js +2 -0
- package/package.json +13 -13
- package/src/archiver/archiver.ts +104 -66
- package/src/archiver/config.ts +5 -0
- package/src/archiver/data_retrieval.ts +2 -0
|
@@ -48,11 +48,12 @@ export declare class Archiver extends Archiver_base implements ArchiveSource, Tr
|
|
|
48
48
|
private config;
|
|
49
49
|
private readonly blobSinkClient;
|
|
50
50
|
private readonly epochCache;
|
|
51
|
+
private readonly dateProvider;
|
|
51
52
|
private readonly instrumentation;
|
|
52
53
|
private readonly l1constants;
|
|
53
54
|
private readonly log;
|
|
54
55
|
/** A loop in which we will be continually fetching new L2 blocks. */
|
|
55
|
-
private runningPromise
|
|
56
|
+
private runningPromise;
|
|
56
57
|
private rollup;
|
|
57
58
|
private inbox;
|
|
58
59
|
private store;
|
|
@@ -79,7 +80,8 @@ export declare class Archiver extends Archiver_base implements ArchiveSource, Tr
|
|
|
79
80
|
pollingIntervalMs: number;
|
|
80
81
|
batchSize: number;
|
|
81
82
|
skipValidateBlockAttestations?: boolean;
|
|
82
|
-
|
|
83
|
+
maxAllowedEthClientDriftSeconds: number;
|
|
84
|
+
}, blobSinkClient: BlobSinkClientInterface, epochCache: EpochCache, dateProvider: DateProvider, instrumentation: ArchiverInstrumentation, l1constants: L1RollupConstants & {
|
|
83
85
|
l1StartBlockHash: Buffer32;
|
|
84
86
|
genesisArchiveRoot: Fr;
|
|
85
87
|
}, log?: Logger);
|
|
@@ -100,7 +102,8 @@ export declare class Archiver extends Archiver_base implements ArchiveSource, Tr
|
|
|
100
102
|
start(blockUntilSynced: boolean): Promise<void>;
|
|
101
103
|
syncImmediate(): Promise<void>;
|
|
102
104
|
waitForInitialSync(): Promise<void>;
|
|
103
|
-
|
|
105
|
+
/** Checks that the ethereum node we are connected to has a latest timestamp no more than the allowed drift. Throw if not. */
|
|
106
|
+
private testEthereumNodeSynced;
|
|
104
107
|
/**
|
|
105
108
|
* Fetches logs from L1 contracts and processes them.
|
|
106
109
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"archiver.d.ts","sourceRoot":"","sources":["../../src/archiver/archiver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAGL,KAAK,SAAS,EAEd,KAAK,gBAAgB,EAEtB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAY,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAE9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAC9C,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"archiver.d.ts","sourceRoot":"","sources":["../../src/archiver/archiver.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,15 +13,14 @@ import { Fr } from '@aztec/foundation/fields';
|
|
|
13
13
|
import { createLogger } from '@aztec/foundation/log';
|
|
14
14
|
import { promiseWithResolvers } from '@aztec/foundation/promise';
|
|
15
15
|
import { RunningPromise, makeLoggingErrorHandler } from '@aztec/foundation/running-promise';
|
|
16
|
-
import { sleep } from '@aztec/foundation/sleep';
|
|
17
16
|
import { count } from '@aztec/foundation/string';
|
|
18
|
-
import { Timer, elapsed } from '@aztec/foundation/timer';
|
|
17
|
+
import { DateProvider, Timer, elapsed } from '@aztec/foundation/timer';
|
|
19
18
|
import { ContractClassPublishedEvent, PrivateFunctionBroadcastedEvent, UtilityFunctionBroadcastedEvent } from '@aztec/protocol-contracts/class-registry';
|
|
20
19
|
import { ContractInstancePublishedEvent, ContractInstanceUpdatedEvent } from '@aztec/protocol-contracts/instance-registry';
|
|
21
20
|
import { L2BlockSourceEvents } from '@aztec/stdlib/block';
|
|
22
21
|
import { computePublicBytecodeCommitment, isValidPrivateFunctionMembershipProof, isValidUtilityFunctionMembershipProof } from '@aztec/stdlib/contract';
|
|
23
22
|
import { getEpochAtSlot, getEpochNumberAtTimestamp, getSlotAtTimestamp, getSlotRangeForEpoch, getTimestampRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
|
|
24
|
-
import {
|
|
23
|
+
import { getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
|
|
25
24
|
import { EventEmitter } from 'events';
|
|
26
25
|
import groupBy from 'lodash.groupby';
|
|
27
26
|
import { createPublicClient, fallback, http } from 'viem';
|
|
@@ -33,7 +32,8 @@ function mapArchiverConfig(config) {
|
|
|
33
32
|
return {
|
|
34
33
|
pollingIntervalMs: config.archiverPollingIntervalMS,
|
|
35
34
|
batchSize: config.archiverBatchSize,
|
|
36
|
-
skipValidateBlockAttestations: config.skipValidateBlockAttestations
|
|
35
|
+
skipValidateBlockAttestations: config.skipValidateBlockAttestations,
|
|
36
|
+
maxAllowedEthClientDriftSeconds: config.maxAllowedEthClientDriftSeconds
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
@@ -47,6 +47,7 @@ function mapArchiverConfig(config) {
|
|
|
47
47
|
config;
|
|
48
48
|
blobSinkClient;
|
|
49
49
|
epochCache;
|
|
50
|
+
dateProvider;
|
|
50
51
|
instrumentation;
|
|
51
52
|
l1constants;
|
|
52
53
|
log;
|
|
@@ -68,13 +69,16 @@ function mapArchiverConfig(config) {
|
|
|
68
69
|
* @param pollingIntervalMs - The interval for polling for L1 logs (in milliseconds).
|
|
69
70
|
* @param store - An archiver data store for storage & retrieval of blocks, encrypted logs & contract data.
|
|
70
71
|
* @param log - A logger.
|
|
71
|
-
*/ constructor(publicClient, l1Addresses, dataStore, config, blobSinkClient, epochCache, instrumentation, l1constants, log = createLogger('archiver')){
|
|
72
|
-
super(), this.publicClient = publicClient, this.l1Addresses = l1Addresses, this.dataStore = dataStore, this.config = config, this.blobSinkClient = blobSinkClient, this.epochCache = epochCache, this.instrumentation = instrumentation, this.l1constants = l1constants, this.log = log, this.initialSyncComplete = false;
|
|
72
|
+
*/ constructor(publicClient, l1Addresses, dataStore, config, blobSinkClient, epochCache, dateProvider, instrumentation, l1constants, log = createLogger('archiver')){
|
|
73
|
+
super(), this.publicClient = publicClient, this.l1Addresses = l1Addresses, this.dataStore = dataStore, this.config = config, this.blobSinkClient = blobSinkClient, this.epochCache = epochCache, this.dateProvider = dateProvider, this.instrumentation = instrumentation, this.l1constants = l1constants, this.log = log, this.initialSyncComplete = false;
|
|
73
74
|
this.tracer = instrumentation.tracer;
|
|
74
75
|
this.store = new ArchiverStoreHelper(dataStore);
|
|
75
76
|
this.rollup = new RollupContract(publicClient, l1Addresses.rollupAddress);
|
|
76
77
|
this.inbox = new InboxContract(publicClient, l1Addresses.inboxAddress);
|
|
77
78
|
this.initialSyncPromise = promiseWithResolvers();
|
|
79
|
+
// Running promise starts with a small interval inbetween runs, so all iterations needed for the initial sync
|
|
80
|
+
// are done as fast as possible. This then gets updated once the initial sync completes.
|
|
81
|
+
this.runningPromise = new RunningPromise(()=>this.sync(), this.log, this.config.pollingIntervalMs / 10, makeLoggingErrorHandler(this.log, NoBlobBodiesFoundError, BlockTagTooOldError));
|
|
78
82
|
}
|
|
79
83
|
/**
|
|
80
84
|
* Creates a new instance of the Archiver and blocks until it syncs from chain.
|
|
@@ -113,11 +117,12 @@ function mapArchiverConfig(config) {
|
|
|
113
117
|
};
|
|
114
118
|
const opts = merge({
|
|
115
119
|
pollingIntervalMs: 10_000,
|
|
116
|
-
batchSize: 100
|
|
120
|
+
batchSize: 100,
|
|
121
|
+
maxAllowedEthClientDriftSeconds: 300
|
|
117
122
|
}, mapArchiverConfig(config));
|
|
118
123
|
const epochCache = deps.epochCache ?? await EpochCache.create(config.l1Contracts.rollupAddress, config, deps);
|
|
119
124
|
const telemetry = deps.telemetry ?? getTelemetryClient();
|
|
120
|
-
const archiver = new Archiver(publicClient, config.l1Contracts, archiverStore, opts, deps.blobSinkClient, epochCache, await ArchiverInstrumentation.new(telemetry, ()=>archiverStore.estimateSize()), l1Constants);
|
|
125
|
+
const archiver = new Archiver(publicClient, config.l1Contracts, archiverStore, opts, deps.blobSinkClient, epochCache, deps.dateProvider ?? new DateProvider(), await ArchiverInstrumentation.new(telemetry, ()=>archiverStore.estimateSize()), l1Constants);
|
|
121
126
|
await archiver.start(blockUntilSynced);
|
|
122
127
|
return archiver;
|
|
123
128
|
}
|
|
@@ -128,48 +133,48 @@ function mapArchiverConfig(config) {
|
|
|
128
133
|
* Starts sync process.
|
|
129
134
|
* @param blockUntilSynced - If true, blocks until the archiver has fully synced.
|
|
130
135
|
*/ async start(blockUntilSynced) {
|
|
131
|
-
if (this.runningPromise) {
|
|
136
|
+
if (this.runningPromise.isRunning()) {
|
|
132
137
|
throw new Error('Archiver is already running');
|
|
133
138
|
}
|
|
134
139
|
await this.blobSinkClient.testSources();
|
|
140
|
+
await this.testEthereumNodeSynced();
|
|
141
|
+
// Log initial state for the archiver
|
|
142
|
+
const { l1StartBlock } = this.l1constants;
|
|
143
|
+
const { blocksSynchedTo = l1StartBlock, messagesSynchedTo = l1StartBlock } = await this.store.getSynchPoint();
|
|
144
|
+
const currentL2Block = await this.getBlockNumber();
|
|
145
|
+
this.log.info(`Starting archiver sync to rollup contract ${this.l1Addresses.rollupAddress.toString()} from L1 block ${blocksSynchedTo} and L2 block ${currentL2Block}`, {
|
|
146
|
+
blocksSynchedTo,
|
|
147
|
+
messagesSynchedTo,
|
|
148
|
+
currentL2Block
|
|
149
|
+
});
|
|
150
|
+
// Start sync loop, and return the wait for initial sync if we are asked to block until synced
|
|
151
|
+
this.runningPromise.start();
|
|
135
152
|
if (blockUntilSynced) {
|
|
136
|
-
|
|
137
|
-
this.log.info(`Retrying initial archiver sync in ${this.config.pollingIntervalMs}ms`);
|
|
138
|
-
await sleep(this.config.pollingIntervalMs);
|
|
139
|
-
}
|
|
153
|
+
return this.waitForInitialSync();
|
|
140
154
|
}
|
|
141
|
-
this.runningPromise = new RunningPromise(()=>this.sync(false), this.log, this.config.pollingIntervalMs, makeLoggingErrorHandler(this.log, // Ignored errors will not log to the console
|
|
142
|
-
// We ignore NoBlobBodiesFound as the message may not have been passed to the blob sink yet
|
|
143
|
-
NoBlobBodiesFoundError));
|
|
144
|
-
this.runningPromise.start();
|
|
145
155
|
}
|
|
146
156
|
syncImmediate() {
|
|
147
|
-
if (!this.runningPromise) {
|
|
148
|
-
throw new Error('Archiver is not running');
|
|
149
|
-
}
|
|
150
157
|
return this.runningPromise.trigger();
|
|
151
158
|
}
|
|
152
159
|
waitForInitialSync() {
|
|
153
160
|
return this.initialSyncPromise.promise;
|
|
154
161
|
}
|
|
155
|
-
async
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
return
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
return false;
|
|
162
|
+
/** Checks that the ethereum node we are connected to has a latest timestamp no more than the allowed drift. Throw if not. */ async testEthereumNodeSynced() {
|
|
163
|
+
const maxAllowedDelay = this.config.maxAllowedEthClientDriftSeconds;
|
|
164
|
+
if (maxAllowedDelay === 0) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const { number, timestamp: l1Timestamp } = await this.publicClient.getBlock({
|
|
168
|
+
includeTransactions: false
|
|
169
|
+
});
|
|
170
|
+
const currentTime = BigInt(this.dateProvider.nowInSeconds());
|
|
171
|
+
if (currentTime - l1Timestamp > BigInt(maxAllowedDelay)) {
|
|
172
|
+
throw new Error(`Ethereum node is out of sync (last block synced ${number} at ${l1Timestamp} vs current time ${currentTime})`);
|
|
168
173
|
}
|
|
169
174
|
}
|
|
170
175
|
/**
|
|
171
176
|
* Fetches logs from L1 contracts and processes them.
|
|
172
|
-
*/ async sync(
|
|
177
|
+
*/ async sync() {
|
|
173
178
|
/**
|
|
174
179
|
* We keep track of three "pointers" to L1 blocks:
|
|
175
180
|
* 1. the last L1 block that published an L2 block
|
|
@@ -179,8 +184,6 @@ function mapArchiverConfig(config) {
|
|
|
179
184
|
* We do this to deal with L1 data providers that are eventually consistent (e.g. Infura).
|
|
180
185
|
* We guard against seeing block X with no data at one point, and later, the provider processes the block and it has data.
|
|
181
186
|
* The archiver will stay back, until there's data on L1 that will move the pointers forward.
|
|
182
|
-
*
|
|
183
|
-
* This code does not handle reorgs.
|
|
184
187
|
*/ const { l1StartBlock, l1StartBlockHash } = this.l1constants;
|
|
185
188
|
const { blocksSynchedTo = l1StartBlock, messagesSynchedTo = {
|
|
186
189
|
l1BlockNumber: l1StartBlock,
|
|
@@ -191,12 +194,12 @@ function mapArchiverConfig(config) {
|
|
|
191
194
|
});
|
|
192
195
|
const currentL1BlockNumber = currentL1Block.number;
|
|
193
196
|
const currentL1BlockHash = Buffer32.fromString(currentL1Block.hash);
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}
|
|
197
|
+
this.log.trace(`Starting new archiver sync iteration`, {
|
|
198
|
+
blocksSynchedTo,
|
|
199
|
+
messagesSynchedTo,
|
|
200
|
+
currentL1BlockNumber,
|
|
201
|
+
currentL1BlockHash
|
|
202
|
+
});
|
|
200
203
|
// ********** Ensuring Consistency of data pulled from L1 **********
|
|
201
204
|
/**
|
|
202
205
|
* There are a number of calls in this sync operation to L1 for retrieving
|
|
@@ -219,6 +222,17 @@ function mapArchiverConfig(config) {
|
|
|
219
222
|
const currentL1Timestamp = !this.l1Timestamp || !this.l1BlockNumber || this.l1BlockNumber !== currentL1BlockNumber ? (await this.publicClient.getBlock({
|
|
220
223
|
blockNumber: currentL1BlockNumber
|
|
221
224
|
})).timestamp : this.l1Timestamp;
|
|
225
|
+
// Warn if the latest L1 block timestamp is too old
|
|
226
|
+
const maxAllowedDelay = this.config.maxAllowedEthClientDriftSeconds;
|
|
227
|
+
const now = this.dateProvider.nowInSeconds();
|
|
228
|
+
if (maxAllowedDelay > 0 && Number(currentL1Timestamp) <= now - maxAllowedDelay) {
|
|
229
|
+
this.log.warn(`Latest L1 block ${currentL1BlockNumber} timestamp ${currentL1Timestamp} is too old. Make sure your Ethereum node is synced.`, {
|
|
230
|
+
currentL1BlockNumber,
|
|
231
|
+
currentL1Timestamp,
|
|
232
|
+
now,
|
|
233
|
+
maxAllowedDelay
|
|
234
|
+
});
|
|
235
|
+
}
|
|
222
236
|
// ********** Events that are processed per L2 block **********
|
|
223
237
|
if (currentL1BlockNumber > blocksSynchedTo) {
|
|
224
238
|
// First we retrieve new L2 blocks and store them in the DB. This will also update the
|
|
@@ -230,6 +244,12 @@ function mapArchiverConfig(config) {
|
|
|
230
244
|
// the chain locally before we start unwinding stuff. This can be optimized by figuring out
|
|
231
245
|
// up to which point we're pruning, and then requesting L2 blocks up to that point only.
|
|
232
246
|
const { rollupCanPrune } = await this.handleEpochPrune(rollupStatus.provenBlockNumber, currentL1BlockNumber, currentL1Timestamp);
|
|
247
|
+
// If the last block we processed had an invalid attestation, we manually advance the L1 syncpoint
|
|
248
|
+
// past it, since otherwise we'll keep downloading it and reprocessing it on every iteration until
|
|
249
|
+
// we get a valid block to advance the syncpoint.
|
|
250
|
+
if (!rollupStatus.validationResult?.valid && rollupStatus.lastL1BlockWithL2Blocks !== undefined) {
|
|
251
|
+
await this.store.setBlockSynchedL1BlockNumber(rollupStatus.lastL1BlockWithL2Blocks);
|
|
252
|
+
}
|
|
233
253
|
// And lastly we check if we are missing any L2 blocks behind us due to a possible L1 reorg.
|
|
234
254
|
// We only do this if rollup cant prune on the next submission. Otherwise we will end up
|
|
235
255
|
// re-syncing the blocks we have just unwound above. We also dont do this if the last block is invalid,
|
|
@@ -244,14 +264,17 @@ function mapArchiverConfig(config) {
|
|
|
244
264
|
// but the corresponding blocks have not been processed (see #12631).
|
|
245
265
|
this.l1Timestamp = currentL1Timestamp;
|
|
246
266
|
this.l1BlockNumber = currentL1BlockNumber;
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
if (
|
|
250
|
-
this.log.info(`Initial archiver sync to L1 block ${currentL1BlockNumber} complete
|
|
267
|
+
// We resolve the initial sync only once we've caught up with the latest L1 block number (with 1 block grace)
|
|
268
|
+
// so if the initial sync took too long, we still go for another iteration.
|
|
269
|
+
if (!this.initialSyncComplete && currentL1BlockNumber + 1n >= await this.publicClient.getBlockNumber()) {
|
|
270
|
+
this.log.info(`Initial archiver sync to L1 block ${currentL1BlockNumber} complete`, {
|
|
251
271
|
l1BlockNumber: currentL1BlockNumber,
|
|
252
272
|
syncPoint: await this.store.getSynchPoint(),
|
|
253
273
|
...await this.getL2Tips()
|
|
254
274
|
});
|
|
275
|
+
this.runningPromise.setPollingIntervalMS(this.config.pollingIntervalMs);
|
|
276
|
+
this.initialSyncComplete = true;
|
|
277
|
+
this.initialSyncPromise.resolve();
|
|
255
278
|
}
|
|
256
279
|
}
|
|
257
280
|
/** Queries the rollup contract on whether a prune can be executed on the immediate next L1 block. */ async canPrune(currentL1BlockNumber, currentL1Timestamp) {
|
|
@@ -334,7 +357,7 @@ function mapArchiverConfig(config) {
|
|
|
334
357
|
});
|
|
335
358
|
// Compare message count and rolling hash. If they match, no need to retrieve anything.
|
|
336
359
|
if (remoteMessagesState.totalMessagesInserted === localMessagesInserted && remoteMessagesState.messagesRollingHash.equals(localLastMessage?.rollingHash ?? Buffer16.ZERO)) {
|
|
337
|
-
this.log.
|
|
360
|
+
this.log.trace(`No L1 to L2 messages to query between L1 blocks ${messagesSyncPoint.l1BlockNumber} and ${currentL1BlockNumber}.`);
|
|
338
361
|
return;
|
|
339
362
|
}
|
|
340
363
|
// Check if our syncpoint is still valid. If not, there was an L1 reorg and we need to re-retrieve messages.
|
|
@@ -570,6 +593,10 @@ function mapArchiverConfig(config) {
|
|
|
570
593
|
break;
|
|
571
594
|
}
|
|
572
595
|
const archiveAtContract = await this.rollup.archiveAt(BigInt(candidateBlock.number));
|
|
596
|
+
this.log.trace(`Checking local block ${candidateBlock.number} with archive ${candidateBlock.archive.root}`, {
|
|
597
|
+
archiveAtContract,
|
|
598
|
+
archiveLocal: candidateBlock.archive.root.toString()
|
|
599
|
+
});
|
|
573
600
|
if (archiveAtContract === candidateBlock.archive.root.toString()) {
|
|
574
601
|
break;
|
|
575
602
|
}
|
|
@@ -585,6 +612,7 @@ function mapArchiverConfig(config) {
|
|
|
585
612
|
let searchStartBlock = blocksSynchedTo;
|
|
586
613
|
let searchEndBlock = blocksSynchedTo;
|
|
587
614
|
let lastRetrievedBlock;
|
|
615
|
+
let lastL1BlockWithL2Blocks = undefined;
|
|
588
616
|
do {
|
|
589
617
|
[searchStartBlock, searchEndBlock] = this.nextRange(searchEndBlock, currentL1BlockNumber);
|
|
590
618
|
this.log.trace(`Retrieving L2 blocks from L1 block ${searchStartBlock} to ${searchEndBlock}`);
|
|
@@ -596,8 +624,11 @@ function mapArchiverConfig(config) {
|
|
|
596
624
|
this.log.trace(`Retrieved no new L2 blocks from L1 block ${searchStartBlock} to ${searchEndBlock}`);
|
|
597
625
|
continue;
|
|
598
626
|
}
|
|
599
|
-
|
|
600
|
-
|
|
627
|
+
this.log.debug(`Retrieved ${retrievedBlocks.length} new L2 blocks between L1 blocks ${searchStartBlock} and ${searchEndBlock}`, {
|
|
628
|
+
lastProcessedL1Block: retrievedBlocks[retrievedBlocks.length - 1].l1,
|
|
629
|
+
searchStartBlock,
|
|
630
|
+
searchEndBlock
|
|
631
|
+
});
|
|
601
632
|
const publishedBlocks = await Promise.all(retrievedBlocks.map((b)=>retrievedBlockToPublishedL2Block(b)));
|
|
602
633
|
const validBlocks = [];
|
|
603
634
|
for (const block of publishedBlocks){
|
|
@@ -663,12 +694,14 @@ function mapArchiverConfig(config) {
|
|
|
663
694
|
});
|
|
664
695
|
}
|
|
665
696
|
lastRetrievedBlock = validBlocks.at(-1) ?? lastRetrievedBlock;
|
|
697
|
+
lastL1BlockWithL2Blocks = publishedBlocks.at(-1)?.l1.blockNumber ?? lastL1BlockWithL2Blocks;
|
|
666
698
|
}while (searchEndBlock < currentL1BlockNumber)
|
|
667
699
|
// Important that we update AFTER inserting the blocks.
|
|
668
700
|
await updateProvenBlock();
|
|
669
701
|
return {
|
|
670
702
|
...rollupStatus,
|
|
671
|
-
lastRetrievedBlock
|
|
703
|
+
lastRetrievedBlock,
|
|
704
|
+
lastL1BlockWithL2Blocks
|
|
672
705
|
};
|
|
673
706
|
}
|
|
674
707
|
async checkForNewBlocksBeforeL1SyncPoint(status, blocksSynchedTo, currentL1BlockNumber) {
|
|
@@ -701,9 +734,6 @@ function mapArchiverConfig(config) {
|
|
|
701
734
|
}
|
|
702
735
|
}
|
|
703
736
|
/** Resumes the archiver after a stop. */ resume() {
|
|
704
|
-
if (!this.runningPromise) {
|
|
705
|
-
throw new Error(`Archiver was never started`);
|
|
706
|
-
}
|
|
707
737
|
if (this.runningPromise.isRunning()) {
|
|
708
738
|
this.log.warn(`Archiver already running`);
|
|
709
739
|
}
|
|
@@ -715,7 +745,7 @@ function mapArchiverConfig(config) {
|
|
|
715
745
|
* @returns A promise signalling completion of the stop process.
|
|
716
746
|
*/ async stop() {
|
|
717
747
|
this.log.debug('Stopping...');
|
|
718
|
-
await this.runningPromise
|
|
748
|
+
await this.runningPromise.stop();
|
|
719
749
|
this.log.info('Stopped.');
|
|
720
750
|
return Promise.resolve();
|
|
721
751
|
}
|
|
@@ -1030,9 +1060,7 @@ function mapArchiverConfig(config) {
|
|
|
1030
1060
|
}
|
|
1031
1061
|
}
|
|
1032
1062
|
_ts_decorate([
|
|
1033
|
-
trackSpan('Archiver.sync'
|
|
1034
|
-
[Attributes.INITIAL_SYNC]: initialRun
|
|
1035
|
-
}))
|
|
1063
|
+
trackSpan('Archiver.sync')
|
|
1036
1064
|
], Archiver.prototype, "sync", null);
|
|
1037
1065
|
var Operation = /*#__PURE__*/ function(Operation) {
|
|
1038
1066
|
Operation[Operation["Store"] = 0] = "Store";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/archiver/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAyB,MAAM,yBAAyB,CAAC;AACrF,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,cAAc,EAIpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,kBAAkB,EAIxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,KAAK,WAAW,EAAuB,MAAM,sBAAsB,CAAC;AAC7E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAE9E;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,sBAAsB,GAAG,cAAc,GAAG,iBAAiB,GAAG,cAAc,GAAG,WAAW,CAAC;AAExH,eAAO,MAAM,sBAAsB,EAAE,kBAAkB,CAAC,cAAc,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/archiver/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAyB,MAAM,yBAAyB,CAAC;AACrF,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,cAAc,EAIpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,kBAAkB,EAIxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,KAAK,WAAW,EAAuB,MAAM,sBAAsB,CAAC;AAC7E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAE9E;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,sBAAsB,GAAG,cAAc,GAAG,iBAAiB,GAAG,cAAc,GAAG,WAAW,CAAC;AAExH,eAAO,MAAM,sBAAsB,EAAE,kBAAkB,CAAC,cAAc,CA2CrE,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,cAAc,CAEzD"}
|
package/dest/archiver/config.js
CHANGED
|
@@ -28,6 +28,11 @@ export const archiverConfigMappings = {
|
|
|
28
28
|
description: 'Whether to skip validating block attestations (use only for testing).',
|
|
29
29
|
...booleanConfigHelper(false)
|
|
30
30
|
},
|
|
31
|
+
maxAllowedEthClientDriftSeconds: {
|
|
32
|
+
env: 'MAX_ALLOWED_ETH_CLIENT_DRIFT_SECONDS',
|
|
33
|
+
description: 'Maximum allowed drift in seconds between the Ethereum client and current time.',
|
|
34
|
+
...numberConfigHelper(300)
|
|
35
|
+
},
|
|
31
36
|
...chainConfigMappings,
|
|
32
37
|
...l1ReaderConfigMappings,
|
|
33
38
|
viemPollingIntervalMS: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data_retrieval.d.ts","sourceRoot":"","sources":["../../src/archiver/data_retrieval.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,KAAK,EAEV,UAAU,EAGV,gBAAgB,EAEjB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAC9C,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,KAAK,QAAQ,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAQ,oBAAoB,EAA0B,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC3G,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,EAAmB,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEnE,OAAO,EAEL,KAAK,qBAAqB,EAC1B,KAAK,GAAG,EAKT,MAAM,MAAM,CAAC;AAGd,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,EAAE,CAAC;IAChB,cAAc,EAAE,cAAc,CAAC;IAC/B,MAAM,EAAE,gBAAgB,CAAC;IACzB,UAAU,EAAE,EAAE,EAAE,CAAC;IACjB,EAAE,EAAE,eAAe,CAAC;IACpB,OAAO,EAAE,EAAE,CAAC;IACZ,OAAO,EAAE,EAAE,CAAC;IACZ,YAAY,EAAE,oBAAoB,EAAE,CAAC;CACtC,CAAC;AAEF,wBAAsB,gCAAgC,CAAC,cAAc,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAqDlH;AAED;;;;;;;;GAQG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,qBAAqB,CAAC,OAAO,SAAS,EAAE,gBAAgB,CAAC,EACjE,YAAY,EAAE,gBAAgB,EAC9B,cAAc,EAAE,uBAAuB,EACvC,gBAAgB,EAAE,MAAM,EACxB,cAAc,EAAE,MAAM,EACtB,MAAM,GAAE,MAAiC,GACxC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAuD7B;AA6DD,wBAAsB,cAAc,CAAC,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGzG;
|
|
1
|
+
{"version":3,"file":"data_retrieval.d.ts","sourceRoot":"","sources":["../../src/archiver/data_retrieval.ts"],"names":[],"mappings":"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"}
|
|
@@ -191,6 +191,7 @@ export async function getL1BlockTime(publicClient, blockNumber) {
|
|
|
191
191
|
* @param l2BlockNumber - L2 block number.
|
|
192
192
|
* @returns L2 block from the calldata, deserialized
|
|
193
193
|
*/ async function getBlockFromRollupTx(publicClient, blobSinkClient, txHash, blobHashes, l2BlockNumber, rollupAddress, targetCommitteeSize, logger) {
|
|
194
|
+
logger.trace(`Fetching L2 block ${l2BlockNumber} from rollup tx ${txHash}`);
|
|
194
195
|
const { input: forwarderData, blockHash } = await publicClient.getTransaction({
|
|
195
196
|
hash: txHash
|
|
196
197
|
});
|
|
@@ -209,6 +210,7 @@ export async function getL1BlockTime(publicClient, blockNumber) {
|
|
|
209
210
|
archive: decodedArgs.archive,
|
|
210
211
|
stateReference: decodedArgs.stateReference,
|
|
211
212
|
header: decodedArgs.header,
|
|
213
|
+
l1BlockHash: blockHash,
|
|
212
214
|
blobHashes,
|
|
213
215
|
attestations,
|
|
214
216
|
packedAttestations,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/archiver",
|
|
3
|
-
"version": "3.0.0-nightly.
|
|
3
|
+
"version": "3.0.0-nightly.20251108",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dest/index.js",
|
|
@@ -66,18 +66,18 @@
|
|
|
66
66
|
]
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
|
-
"@aztec/blob-lib": "3.0.0-nightly.
|
|
70
|
-
"@aztec/blob-sink": "3.0.0-nightly.
|
|
71
|
-
"@aztec/constants": "3.0.0-nightly.
|
|
72
|
-
"@aztec/epoch-cache": "3.0.0-nightly.
|
|
73
|
-
"@aztec/ethereum": "3.0.0-nightly.
|
|
74
|
-
"@aztec/foundation": "3.0.0-nightly.
|
|
75
|
-
"@aztec/kv-store": "3.0.0-nightly.
|
|
76
|
-
"@aztec/l1-artifacts": "3.0.0-nightly.
|
|
77
|
-
"@aztec/noir-protocol-circuits-types": "3.0.0-nightly.
|
|
78
|
-
"@aztec/protocol-contracts": "3.0.0-nightly.
|
|
79
|
-
"@aztec/stdlib": "3.0.0-nightly.
|
|
80
|
-
"@aztec/telemetry-client": "3.0.0-nightly.
|
|
69
|
+
"@aztec/blob-lib": "3.0.0-nightly.20251108",
|
|
70
|
+
"@aztec/blob-sink": "3.0.0-nightly.20251108",
|
|
71
|
+
"@aztec/constants": "3.0.0-nightly.20251108",
|
|
72
|
+
"@aztec/epoch-cache": "3.0.0-nightly.20251108",
|
|
73
|
+
"@aztec/ethereum": "3.0.0-nightly.20251108",
|
|
74
|
+
"@aztec/foundation": "3.0.0-nightly.20251108",
|
|
75
|
+
"@aztec/kv-store": "3.0.0-nightly.20251108",
|
|
76
|
+
"@aztec/l1-artifacts": "3.0.0-nightly.20251108",
|
|
77
|
+
"@aztec/noir-protocol-circuits-types": "3.0.0-nightly.20251108",
|
|
78
|
+
"@aztec/protocol-contracts": "3.0.0-nightly.20251108",
|
|
79
|
+
"@aztec/stdlib": "3.0.0-nightly.20251108",
|
|
80
|
+
"@aztec/telemetry-client": "3.0.0-nightly.20251108",
|
|
81
81
|
"lodash.groupby": "^4.6.0",
|
|
82
82
|
"lodash.omit": "^4.5.0",
|
|
83
83
|
"tsc-watch": "^6.0.0",
|
package/src/archiver/archiver.ts
CHANGED
|
@@ -16,7 +16,6 @@ import { Fr } from '@aztec/foundation/fields';
|
|
|
16
16
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
17
17
|
import { type PromiseWithResolvers, promiseWithResolvers } from '@aztec/foundation/promise';
|
|
18
18
|
import { RunningPromise, makeLoggingErrorHandler } from '@aztec/foundation/running-promise';
|
|
19
|
-
import { sleep } from '@aztec/foundation/sleep';
|
|
20
19
|
import { count } from '@aztec/foundation/string';
|
|
21
20
|
import { DateProvider, Timer, elapsed } from '@aztec/foundation/timer';
|
|
22
21
|
import type { CustomRange } from '@aztec/kv-store';
|
|
@@ -65,7 +64,6 @@ import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
|
65
64
|
import { type BlockHeader, type IndexedTxEffect, TxHash, TxReceipt } from '@aztec/stdlib/tx';
|
|
66
65
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
67
66
|
import {
|
|
68
|
-
Attributes,
|
|
69
67
|
type TelemetryClient,
|
|
70
68
|
type Traceable,
|
|
71
69
|
type Tracer,
|
|
@@ -75,7 +73,7 @@ import {
|
|
|
75
73
|
|
|
76
74
|
import { EventEmitter } from 'events';
|
|
77
75
|
import groupBy from 'lodash.groupby';
|
|
78
|
-
import { type GetContractReturnType, createPublicClient, fallback, http } from 'viem';
|
|
76
|
+
import { type GetContractReturnType, type Hex, createPublicClient, fallback, http } from 'viem';
|
|
79
77
|
|
|
80
78
|
import type { ArchiverDataStore, ArchiverL1SynchPoint } from './archiver_store.js';
|
|
81
79
|
import type { ArchiverConfig } from './config.js';
|
|
@@ -108,9 +106,20 @@ function mapArchiverConfig(config: Partial<ArchiverConfig>) {
|
|
|
108
106
|
pollingIntervalMs: config.archiverPollingIntervalMS,
|
|
109
107
|
batchSize: config.archiverBatchSize,
|
|
110
108
|
skipValidateBlockAttestations: config.skipValidateBlockAttestations,
|
|
109
|
+
maxAllowedEthClientDriftSeconds: config.maxAllowedEthClientDriftSeconds,
|
|
111
110
|
};
|
|
112
111
|
}
|
|
113
112
|
|
|
113
|
+
type RollupStatus = {
|
|
114
|
+
provenBlockNumber: number;
|
|
115
|
+
provenArchive: Hex;
|
|
116
|
+
pendingBlockNumber: number;
|
|
117
|
+
pendingArchive: Hex;
|
|
118
|
+
validationResult: ValidateBlockResult | undefined;
|
|
119
|
+
lastRetrievedBlock?: PublishedL2Block;
|
|
120
|
+
lastL1BlockWithL2Blocks?: bigint;
|
|
121
|
+
};
|
|
122
|
+
|
|
114
123
|
/**
|
|
115
124
|
* Pulls L2 blocks in a non-blocking manner and provides interface for their retrieval.
|
|
116
125
|
* Responsible for handling robust L1 polling so that other components do not need to
|
|
@@ -118,7 +127,7 @@ function mapArchiverConfig(config: Partial<ArchiverConfig>) {
|
|
|
118
127
|
*/
|
|
119
128
|
export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implements ArchiveSource, Traceable {
|
|
120
129
|
/** A loop in which we will be continually fetching new L2 blocks. */
|
|
121
|
-
private runningPromise
|
|
130
|
+
private runningPromise: RunningPromise;
|
|
122
131
|
|
|
123
132
|
private rollup: RollupContract;
|
|
124
133
|
private inbox: InboxContract;
|
|
@@ -146,9 +155,15 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
146
155
|
private readonly publicClient: ViemPublicClient,
|
|
147
156
|
private readonly l1Addresses: { rollupAddress: EthAddress; inboxAddress: EthAddress; registryAddress: EthAddress },
|
|
148
157
|
readonly dataStore: ArchiverDataStore,
|
|
149
|
-
private config: {
|
|
158
|
+
private config: {
|
|
159
|
+
pollingIntervalMs: number;
|
|
160
|
+
batchSize: number;
|
|
161
|
+
skipValidateBlockAttestations?: boolean;
|
|
162
|
+
maxAllowedEthClientDriftSeconds: number;
|
|
163
|
+
},
|
|
150
164
|
private readonly blobSinkClient: BlobSinkClientInterface,
|
|
151
165
|
private readonly epochCache: EpochCache,
|
|
166
|
+
private readonly dateProvider: DateProvider,
|
|
152
167
|
private readonly instrumentation: ArchiverInstrumentation,
|
|
153
168
|
private readonly l1constants: L1RollupConstants & { l1StartBlockHash: Buffer32; genesisArchiveRoot: Fr },
|
|
154
169
|
private readonly log: Logger = createLogger('archiver'),
|
|
@@ -161,6 +176,15 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
161
176
|
this.rollup = new RollupContract(publicClient, l1Addresses.rollupAddress);
|
|
162
177
|
this.inbox = new InboxContract(publicClient, l1Addresses.inboxAddress);
|
|
163
178
|
this.initialSyncPromise = promiseWithResolvers();
|
|
179
|
+
|
|
180
|
+
// Running promise starts with a small interval inbetween runs, so all iterations needed for the initial sync
|
|
181
|
+
// are done as fast as possible. This then gets updated once the initial sync completes.
|
|
182
|
+
this.runningPromise = new RunningPromise(
|
|
183
|
+
() => this.sync(),
|
|
184
|
+
this.log,
|
|
185
|
+
this.config.pollingIntervalMs / 10,
|
|
186
|
+
makeLoggingErrorHandler(this.log, NoBlobBodiesFoundError, BlockTagTooOldError),
|
|
187
|
+
);
|
|
164
188
|
}
|
|
165
189
|
|
|
166
190
|
/**
|
|
@@ -209,7 +233,10 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
209
233
|
genesisArchiveRoot: Fr.fromHexString(genesisArchiveRoot),
|
|
210
234
|
};
|
|
211
235
|
|
|
212
|
-
const opts = merge(
|
|
236
|
+
const opts = merge(
|
|
237
|
+
{ pollingIntervalMs: 10_000, batchSize: 100, maxAllowedEthClientDriftSeconds: 300 },
|
|
238
|
+
mapArchiverConfig(config),
|
|
239
|
+
);
|
|
213
240
|
|
|
214
241
|
const epochCache = deps.epochCache ?? (await EpochCache.create(config.l1Contracts.rollupAddress, config, deps));
|
|
215
242
|
const telemetry = deps.telemetry ?? getTelemetryClient();
|
|
@@ -221,6 +248,7 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
221
248
|
opts,
|
|
222
249
|
deps.blobSinkClient,
|
|
223
250
|
epochCache,
|
|
251
|
+
deps.dateProvider ?? new DateProvider(),
|
|
224
252
|
await ArchiverInstrumentation.new(telemetry, () => archiverStore.estimateSize()),
|
|
225
253
|
l1Constants,
|
|
226
254
|
);
|
|
@@ -238,38 +266,30 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
238
266
|
* @param blockUntilSynced - If true, blocks until the archiver has fully synced.
|
|
239
267
|
*/
|
|
240
268
|
public async start(blockUntilSynced: boolean): Promise<void> {
|
|
241
|
-
if (this.runningPromise) {
|
|
269
|
+
if (this.runningPromise.isRunning()) {
|
|
242
270
|
throw new Error('Archiver is already running');
|
|
243
271
|
}
|
|
244
272
|
|
|
245
273
|
await this.blobSinkClient.testSources();
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
() => this.sync(false),
|
|
256
|
-
this.log,
|
|
257
|
-
this.config.pollingIntervalMs,
|
|
258
|
-
makeLoggingErrorHandler(
|
|
259
|
-
this.log,
|
|
260
|
-
// Ignored errors will not log to the console
|
|
261
|
-
// We ignore NoBlobBodiesFound as the message may not have been passed to the blob sink yet
|
|
262
|
-
NoBlobBodiesFoundError,
|
|
263
|
-
),
|
|
274
|
+
await this.testEthereumNodeSynced();
|
|
275
|
+
|
|
276
|
+
// Log initial state for the archiver
|
|
277
|
+
const { l1StartBlock } = this.l1constants;
|
|
278
|
+
const { blocksSynchedTo = l1StartBlock, messagesSynchedTo = l1StartBlock } = await this.store.getSynchPoint();
|
|
279
|
+
const currentL2Block = await this.getBlockNumber();
|
|
280
|
+
this.log.info(
|
|
281
|
+
`Starting archiver sync to rollup contract ${this.l1Addresses.rollupAddress.toString()} from L1 block ${blocksSynchedTo} and L2 block ${currentL2Block}`,
|
|
282
|
+
{ blocksSynchedTo, messagesSynchedTo, currentL2Block },
|
|
264
283
|
);
|
|
265
284
|
|
|
285
|
+
// Start sync loop, and return the wait for initial sync if we are asked to block until synced
|
|
266
286
|
this.runningPromise.start();
|
|
287
|
+
if (blockUntilSynced) {
|
|
288
|
+
return this.waitForInitialSync();
|
|
289
|
+
}
|
|
267
290
|
}
|
|
268
291
|
|
|
269
292
|
public syncImmediate() {
|
|
270
|
-
if (!this.runningPromise) {
|
|
271
|
-
throw new Error('Archiver is not running');
|
|
272
|
-
}
|
|
273
293
|
return this.runningPromise.trigger();
|
|
274
294
|
}
|
|
275
295
|
|
|
@@ -277,27 +297,26 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
277
297
|
return this.initialSyncPromise.promise;
|
|
278
298
|
}
|
|
279
299
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
return false;
|
|
300
|
+
/** Checks that the ethereum node we are connected to has a latest timestamp no more than the allowed drift. Throw if not. */
|
|
301
|
+
private async testEthereumNodeSynced() {
|
|
302
|
+
const maxAllowedDelay = this.config.maxAllowedEthClientDriftSeconds;
|
|
303
|
+
if (maxAllowedDelay === 0) {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
const { number, timestamp: l1Timestamp } = await this.publicClient.getBlock({ includeTransactions: false });
|
|
307
|
+
const currentTime = BigInt(this.dateProvider.nowInSeconds());
|
|
308
|
+
if (currentTime - l1Timestamp > BigInt(maxAllowedDelay)) {
|
|
309
|
+
throw new Error(
|
|
310
|
+
`Ethereum node is out of sync (last block synced ${number} at ${l1Timestamp} vs current time ${currentTime})`,
|
|
311
|
+
);
|
|
293
312
|
}
|
|
294
313
|
}
|
|
295
314
|
|
|
296
315
|
/**
|
|
297
316
|
* Fetches logs from L1 contracts and processes them.
|
|
298
317
|
*/
|
|
299
|
-
@trackSpan('Archiver.sync'
|
|
300
|
-
private async sync(
|
|
318
|
+
@trackSpan('Archiver.sync')
|
|
319
|
+
private async sync() {
|
|
301
320
|
/**
|
|
302
321
|
* We keep track of three "pointers" to L1 blocks:
|
|
303
322
|
* 1. the last L1 block that published an L2 block
|
|
@@ -307,8 +326,6 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
307
326
|
* We do this to deal with L1 data providers that are eventually consistent (e.g. Infura).
|
|
308
327
|
* We guard against seeing block X with no data at one point, and later, the provider processes the block and it has data.
|
|
309
328
|
* The archiver will stay back, until there's data on L1 that will move the pointers forward.
|
|
310
|
-
*
|
|
311
|
-
* This code does not handle reorgs.
|
|
312
329
|
*/
|
|
313
330
|
const { l1StartBlock, l1StartBlockHash } = this.l1constants;
|
|
314
331
|
const {
|
|
@@ -320,13 +337,12 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
320
337
|
const currentL1BlockNumber = currentL1Block.number;
|
|
321
338
|
const currentL1BlockHash = Buffer32.fromString(currentL1Block.hash);
|
|
322
339
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
}
|
|
340
|
+
this.log.trace(`Starting new archiver sync iteration`, {
|
|
341
|
+
blocksSynchedTo,
|
|
342
|
+
messagesSynchedTo,
|
|
343
|
+
currentL1BlockNumber,
|
|
344
|
+
currentL1BlockHash,
|
|
345
|
+
});
|
|
330
346
|
|
|
331
347
|
// ********** Ensuring Consistency of data pulled from L1 **********
|
|
332
348
|
|
|
@@ -356,6 +372,16 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
356
372
|
? (await this.publicClient.getBlock({ blockNumber: currentL1BlockNumber })).timestamp
|
|
357
373
|
: this.l1Timestamp;
|
|
358
374
|
|
|
375
|
+
// Warn if the latest L1 block timestamp is too old
|
|
376
|
+
const maxAllowedDelay = this.config.maxAllowedEthClientDriftSeconds;
|
|
377
|
+
const now = this.dateProvider.nowInSeconds();
|
|
378
|
+
if (maxAllowedDelay > 0 && Number(currentL1Timestamp) <= now - maxAllowedDelay) {
|
|
379
|
+
this.log.warn(
|
|
380
|
+
`Latest L1 block ${currentL1BlockNumber} timestamp ${currentL1Timestamp} is too old. Make sure your Ethereum node is synced.`,
|
|
381
|
+
{ currentL1BlockNumber, currentL1Timestamp, now, maxAllowedDelay },
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
|
|
359
385
|
// ********** Events that are processed per L2 block **********
|
|
360
386
|
if (currentL1BlockNumber > blocksSynchedTo) {
|
|
361
387
|
// First we retrieve new L2 blocks and store them in the DB. This will also update the
|
|
@@ -372,6 +398,13 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
372
398
|
currentL1Timestamp,
|
|
373
399
|
);
|
|
374
400
|
|
|
401
|
+
// If the last block we processed had an invalid attestation, we manually advance the L1 syncpoint
|
|
402
|
+
// past it, since otherwise we'll keep downloading it and reprocessing it on every iteration until
|
|
403
|
+
// we get a valid block to advance the syncpoint.
|
|
404
|
+
if (!rollupStatus.validationResult?.valid && rollupStatus.lastL1BlockWithL2Blocks !== undefined) {
|
|
405
|
+
await this.store.setBlockSynchedL1BlockNumber(rollupStatus.lastL1BlockWithL2Blocks);
|
|
406
|
+
}
|
|
407
|
+
|
|
375
408
|
// And lastly we check if we are missing any L2 blocks behind us due to a possible L1 reorg.
|
|
376
409
|
// We only do this if rollup cant prune on the next submission. Otherwise we will end up
|
|
377
410
|
// re-syncing the blocks we have just unwound above. We also dont do this if the last block is invalid,
|
|
@@ -388,15 +421,18 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
388
421
|
// but the corresponding blocks have not been processed (see #12631).
|
|
389
422
|
this.l1Timestamp = currentL1Timestamp;
|
|
390
423
|
this.l1BlockNumber = currentL1BlockNumber;
|
|
391
|
-
this.initialSyncComplete = true;
|
|
392
|
-
this.initialSyncPromise.resolve();
|
|
393
424
|
|
|
394
|
-
|
|
395
|
-
|
|
425
|
+
// We resolve the initial sync only once we've caught up with the latest L1 block number (with 1 block grace)
|
|
426
|
+
// so if the initial sync took too long, we still go for another iteration.
|
|
427
|
+
if (!this.initialSyncComplete && currentL1BlockNumber + 1n >= (await this.publicClient.getBlockNumber())) {
|
|
428
|
+
this.log.info(`Initial archiver sync to L1 block ${currentL1BlockNumber} complete`, {
|
|
396
429
|
l1BlockNumber: currentL1BlockNumber,
|
|
397
430
|
syncPoint: await this.store.getSynchPoint(),
|
|
398
431
|
...(await this.getL2Tips()),
|
|
399
432
|
});
|
|
433
|
+
this.runningPromise.setPollingIntervalMS(this.config.pollingIntervalMs);
|
|
434
|
+
this.initialSyncComplete = true;
|
|
435
|
+
this.initialSyncPromise.resolve();
|
|
400
436
|
}
|
|
401
437
|
}
|
|
402
438
|
|
|
@@ -497,7 +533,7 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
497
533
|
remoteMessagesState.totalMessagesInserted === localMessagesInserted &&
|
|
498
534
|
remoteMessagesState.messagesRollingHash.equals(localLastMessage?.rollingHash ?? Buffer16.ZERO)
|
|
499
535
|
) {
|
|
500
|
-
this.log.
|
|
536
|
+
this.log.trace(
|
|
501
537
|
`No L1 to L2 messages to query between L1 blocks ${messagesSyncPoint.l1BlockNumber} and ${currentL1BlockNumber}.`,
|
|
502
538
|
);
|
|
503
539
|
return;
|
|
@@ -629,7 +665,7 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
629
665
|
return Buffer32.fromString(block.hash);
|
|
630
666
|
}
|
|
631
667
|
|
|
632
|
-
private async handleL2blocks(blocksSynchedTo: bigint, currentL1BlockNumber: bigint) {
|
|
668
|
+
private async handleL2blocks(blocksSynchedTo: bigint, currentL1BlockNumber: bigint): Promise<RollupStatus> {
|
|
633
669
|
const localPendingBlockNumber = await this.getBlockNumber();
|
|
634
670
|
const initialValidationResult: ValidateBlockResult | undefined = await this.store.getPendingChainValidationStatus();
|
|
635
671
|
const [provenBlockNumber, provenArchive, pendingBlockNumber, pendingArchive, archiveForLocalPendingBlockNumber] =
|
|
@@ -759,7 +795,10 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
759
795
|
}
|
|
760
796
|
|
|
761
797
|
const archiveAtContract = await this.rollup.archiveAt(BigInt(candidateBlock.number));
|
|
762
|
-
|
|
798
|
+
this.log.trace(`Checking local block ${candidateBlock.number} with archive ${candidateBlock.archive.root}`, {
|
|
799
|
+
archiveAtContract,
|
|
800
|
+
archiveLocal: candidateBlock.archive.root.toString(),
|
|
801
|
+
});
|
|
763
802
|
if (archiveAtContract === candidateBlock.archive.root.toString()) {
|
|
764
803
|
break;
|
|
765
804
|
}
|
|
@@ -782,6 +821,7 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
782
821
|
let searchStartBlock: bigint = blocksSynchedTo;
|
|
783
822
|
let searchEndBlock: bigint = blocksSynchedTo;
|
|
784
823
|
let lastRetrievedBlock: PublishedL2Block | undefined;
|
|
824
|
+
let lastL1BlockWithL2Blocks: bigint | undefined = undefined;
|
|
785
825
|
|
|
786
826
|
do {
|
|
787
827
|
[searchStartBlock, searchEndBlock] = this.nextRange(searchEndBlock, currentL1BlockNumber);
|
|
@@ -805,9 +845,9 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
805
845
|
continue;
|
|
806
846
|
}
|
|
807
847
|
|
|
808
|
-
const lastProcessedL1BlockNumber = retrievedBlocks[retrievedBlocks.length - 1].l1.blockNumber;
|
|
809
848
|
this.log.debug(
|
|
810
|
-
`Retrieved ${retrievedBlocks.length} new L2 blocks between L1 blocks ${searchStartBlock} and ${searchEndBlock}
|
|
849
|
+
`Retrieved ${retrievedBlocks.length} new L2 blocks between L1 blocks ${searchStartBlock} and ${searchEndBlock}`,
|
|
850
|
+
{ lastProcessedL1Block: retrievedBlocks[retrievedBlocks.length - 1].l1, searchStartBlock, searchEndBlock },
|
|
811
851
|
);
|
|
812
852
|
|
|
813
853
|
const publishedBlocks = await Promise.all(retrievedBlocks.map(b => retrievedBlockToPublishedL2Block(b)));
|
|
@@ -900,12 +940,13 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
900
940
|
});
|
|
901
941
|
}
|
|
902
942
|
lastRetrievedBlock = validBlocks.at(-1) ?? lastRetrievedBlock;
|
|
943
|
+
lastL1BlockWithL2Blocks = publishedBlocks.at(-1)?.l1.blockNumber ?? lastL1BlockWithL2Blocks;
|
|
903
944
|
} while (searchEndBlock < currentL1BlockNumber);
|
|
904
945
|
|
|
905
946
|
// Important that we update AFTER inserting the blocks.
|
|
906
947
|
await updateProvenBlock();
|
|
907
948
|
|
|
908
|
-
return { ...rollupStatus, lastRetrievedBlock };
|
|
949
|
+
return { ...rollupStatus, lastRetrievedBlock, lastL1BlockWithL2Blocks };
|
|
909
950
|
}
|
|
910
951
|
|
|
911
952
|
private async checkForNewBlocksBeforeL1SyncPoint(
|
|
@@ -955,9 +996,6 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
955
996
|
|
|
956
997
|
/** Resumes the archiver after a stop. */
|
|
957
998
|
public resume() {
|
|
958
|
-
if (!this.runningPromise) {
|
|
959
|
-
throw new Error(`Archiver was never started`);
|
|
960
|
-
}
|
|
961
999
|
if (this.runningPromise.isRunning()) {
|
|
962
1000
|
this.log.warn(`Archiver already running`);
|
|
963
1001
|
}
|
|
@@ -971,7 +1009,7 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
971
1009
|
*/
|
|
972
1010
|
public async stop(): Promise<void> {
|
|
973
1011
|
this.log.debug('Stopping...');
|
|
974
|
-
await this.runningPromise
|
|
1012
|
+
await this.runningPromise.stop();
|
|
975
1013
|
|
|
976
1014
|
this.log.info('Stopped.');
|
|
977
1015
|
return Promise.resolve();
|
package/src/archiver/config.ts
CHANGED
|
@@ -50,6 +50,11 @@ export const archiverConfigMappings: ConfigMappingsType<ArchiverConfig> = {
|
|
|
50
50
|
description: 'Whether to skip validating block attestations (use only for testing).',
|
|
51
51
|
...booleanConfigHelper(false),
|
|
52
52
|
},
|
|
53
|
+
maxAllowedEthClientDriftSeconds: {
|
|
54
|
+
env: 'MAX_ALLOWED_ETH_CLIENT_DRIFT_SECONDS',
|
|
55
|
+
description: 'Maximum allowed drift in seconds between the Ethereum client and current time.',
|
|
56
|
+
...numberConfigHelper(300),
|
|
57
|
+
},
|
|
53
58
|
...chainConfigMappings,
|
|
54
59
|
...l1ReaderConfigMappings,
|
|
55
60
|
viemPollingIntervalMS: {
|
|
@@ -309,6 +309,7 @@ async function getBlockFromRollupTx(
|
|
|
309
309
|
targetCommitteeSize: number,
|
|
310
310
|
logger: Logger,
|
|
311
311
|
): Promise<Omit<RetrievedL2Block, 'l1' | 'chainId' | 'version'>> {
|
|
312
|
+
logger.trace(`Fetching L2 block ${l2BlockNumber} from rollup tx ${txHash}`);
|
|
312
313
|
const { input: forwarderData, blockHash } = await publicClient.getTransaction({ hash: txHash });
|
|
313
314
|
|
|
314
315
|
const rollupData = extractRollupProposeCalldata(forwarderData, rollupAddress);
|
|
@@ -344,6 +345,7 @@ async function getBlockFromRollupTx(
|
|
|
344
345
|
archive: decodedArgs.archive,
|
|
345
346
|
stateReference: decodedArgs.stateReference,
|
|
346
347
|
header: decodedArgs.header,
|
|
348
|
+
l1BlockHash: blockHash,
|
|
347
349
|
blobHashes,
|
|
348
350
|
attestations,
|
|
349
351
|
packedAttestations,
|