@aztec/archiver 0.0.1-commit.e558bd1c → 0.0.1-commit.e5a3663dd
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/README.md +12 -6
- package/dest/archiver.d.ts +26 -15
- package/dest/archiver.d.ts.map +1 -1
- package/dest/archiver.js +161 -153
- package/dest/config.d.ts +5 -3
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +16 -4
- package/dest/errors.d.ts +61 -10
- package/dest/errors.d.ts.map +1 -1
- package/dest/errors.js +88 -14
- package/dest/factory.d.ts +6 -7
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +40 -32
- package/dest/index.d.ts +11 -3
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +10 -2
- package/dest/l1/bin/retrieve-calldata.js +32 -28
- package/dest/l1/calldata_retriever.d.ts +74 -50
- package/dest/l1/calldata_retriever.d.ts.map +1 -1
- package/dest/l1/calldata_retriever.js +197 -260
- package/dest/l1/data_retrieval.d.ts +26 -17
- package/dest/l1/data_retrieval.d.ts.map +1 -1
- package/dest/l1/data_retrieval.js +42 -47
- package/dest/l1/spire_proposer.d.ts +5 -5
- package/dest/l1/spire_proposer.d.ts.map +1 -1
- package/dest/l1/spire_proposer.js +9 -17
- package/dest/l1/validate_historical_logs.d.ts +23 -0
- package/dest/l1/validate_historical_logs.d.ts.map +1 -0
- package/dest/l1/validate_historical_logs.js +108 -0
- package/dest/modules/contract_data_source_adapter.d.ts +25 -0
- package/dest/modules/contract_data_source_adapter.d.ts.map +1 -0
- package/dest/modules/contract_data_source_adapter.js +42 -0
- package/dest/modules/data_source_base.d.ts +27 -14
- package/dest/modules/data_source_base.d.ts.map +1 -1
- package/dest/modules/data_source_base.js +98 -125
- package/dest/modules/data_store_updater.d.ts +37 -17
- package/dest/modules/data_store_updater.d.ts.map +1 -1
- package/dest/modules/data_store_updater.js +155 -112
- package/dest/modules/instrumentation.d.ts +21 -3
- package/dest/modules/instrumentation.d.ts.map +1 -1
- package/dest/modules/instrumentation.js +41 -8
- package/dest/modules/l1_synchronizer.d.ts +13 -11
- package/dest/modules/l1_synchronizer.d.ts.map +1 -1
- package/dest/modules/l1_synchronizer.js +355 -182
- package/dest/modules/validation.d.ts +4 -3
- package/dest/modules/validation.d.ts.map +1 -1
- package/dest/modules/validation.js +6 -6
- package/dest/store/block_store.d.ts +107 -31
- package/dest/store/block_store.d.ts.map +1 -1
- package/dest/store/block_store.js +477 -141
- package/dest/store/contract_class_store.d.ts +17 -4
- package/dest/store/contract_class_store.d.ts.map +1 -1
- package/dest/store/contract_class_store.js +24 -68
- package/dest/store/contract_instance_store.d.ts +28 -1
- package/dest/store/contract_instance_store.d.ts.map +1 -1
- package/dest/store/contract_instance_store.js +37 -2
- package/dest/store/data_stores.d.ts +68 -0
- package/dest/store/data_stores.d.ts.map +1 -0
- package/dest/store/data_stores.js +50 -0
- package/dest/store/function_names_cache.d.ts +17 -0
- package/dest/store/function_names_cache.d.ts.map +1 -0
- package/dest/store/function_names_cache.js +30 -0
- package/dest/store/l2_tips_cache.d.ts +20 -0
- package/dest/store/l2_tips_cache.d.ts.map +1 -0
- package/dest/store/l2_tips_cache.js +109 -0
- package/dest/store/log_store.d.ts +6 -3
- package/dest/store/log_store.d.ts.map +1 -1
- package/dest/store/log_store.js +95 -20
- package/dest/store/message_store.d.ts +11 -1
- package/dest/store/message_store.d.ts.map +1 -1
- package/dest/store/message_store.js +51 -9
- package/dest/test/fake_l1_state.d.ts +25 -1
- package/dest/test/fake_l1_state.d.ts.map +1 -1
- package/dest/test/fake_l1_state.js +166 -32
- 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_l1_to_l2_message_source.d.ts +1 -1
- package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
- package/dest/test/mock_l1_to_l2_message_source.js +2 -1
- package/dest/test/mock_l2_block_source.d.ts +35 -5
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +182 -89
- package/dest/test/mock_structs.d.ts +4 -1
- package/dest/test/mock_structs.d.ts.map +1 -1
- package/dest/test/mock_structs.js +13 -1
- package/dest/test/noop_l1_archiver.d.ts +7 -4
- package/dest/test/noop_l1_archiver.d.ts.map +1 -1
- package/dest/test/noop_l1_archiver.js +14 -8
- package/package.json +13 -13
- package/src/archiver.ts +199 -174
- package/src/config.ts +23 -2
- package/src/errors.ts +133 -22
- package/src/factory.ts +53 -30
- package/src/index.ts +18 -2
- package/src/l1/README.md +25 -68
- package/src/l1/bin/retrieve-calldata.ts +40 -27
- package/src/l1/calldata_retriever.ts +261 -379
- package/src/l1/data_retrieval.ts +58 -69
- package/src/l1/spire_proposer.ts +7 -15
- package/src/l1/validate_historical_logs.ts +140 -0
- package/src/modules/contract_data_source_adapter.ts +59 -0
- package/src/modules/data_source_base.ts +142 -144
- package/src/modules/data_store_updater.ts +187 -141
- package/src/modules/instrumentation.ts +56 -9
- package/src/modules/l1_synchronizer.ts +463 -218
- package/src/modules/validation.ts +10 -9
- package/src/store/block_store.ts +587 -177
- package/src/store/contract_class_store.ts +31 -103
- package/src/store/contract_instance_store.ts +51 -5
- package/src/store/data_stores.ts +108 -0
- package/src/store/function_names_cache.ts +37 -0
- package/src/store/l2_tips_cache.ts +134 -0
- package/src/store/log_store.ts +128 -32
- package/src/store/message_store.ts +60 -10
- package/src/structs/inbox_message.ts +1 -1
- package/src/test/fake_l1_state.ts +213 -42
- package/src/test/mock_archiver.ts +3 -2
- package/src/test/mock_l1_to_l2_message_source.ts +1 -0
- package/src/test/mock_l2_block_source.ts +230 -82
- package/src/test/mock_structs.ts +20 -6
- package/src/test/noop_l1_archiver.ts +16 -8
- package/dest/store/kv_archiver_store.d.ts +0 -340
- package/dest/store/kv_archiver_store.d.ts.map +0 -1
- package/dest/store/kv_archiver_store.js +0 -446
- package/src/store/kv_archiver_store.ts +0 -639
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';
|
|
@@ -12,46 +11,55 @@ import { EthAddress } from '@aztec/foundation/eth-address';
|
|
|
12
11
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
13
12
|
import { type PromiseWithResolvers, promiseWithResolvers } from '@aztec/foundation/promise';
|
|
14
13
|
import { RunningPromise, makeLoggingErrorHandler } from '@aztec/foundation/running-promise';
|
|
15
|
-
import { DateProvider } from '@aztec/foundation/timer';
|
|
14
|
+
import { DateProvider, elapsed } 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,
|
|
23
20
|
type ValidateCheckpointResult,
|
|
24
21
|
} from '@aztec/stdlib/block';
|
|
25
|
-
import { PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
22
|
+
import { type ProposedCheckpointInput, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
26
23
|
import {
|
|
27
24
|
type L1RollupConstants,
|
|
28
|
-
|
|
25
|
+
getEpochAtSlot,
|
|
29
26
|
getSlotAtNextL1Block,
|
|
30
|
-
getSlotAtTimestamp,
|
|
31
27
|
getSlotRangeForEpoch,
|
|
28
|
+
getTimestampForSlot,
|
|
32
29
|
getTimestampRangeForEpoch,
|
|
33
30
|
} from '@aztec/stdlib/epoch-helpers';
|
|
34
31
|
import { type TelemetryClient, type Traceable, type Tracer, trackSpan } from '@aztec/telemetry-client';
|
|
35
32
|
|
|
36
33
|
import { type ArchiverConfig, mapArchiverConfig } from './config.js';
|
|
37
|
-
import { NoBlobBodiesFoundError } from './errors.js';
|
|
34
|
+
import { BlockAlreadyCheckpointedError, BlockOrCheckpointSlotExpiredError, NoBlobBodiesFoundError } from './errors.js';
|
|
35
|
+
import { validateAndLogHistoricalLogsAvailability } from './l1/validate_historical_logs.js';
|
|
38
36
|
import { validateAndLogTraceAvailability } from './l1/validate_trace.js';
|
|
39
37
|
import { ArchiverDataSourceBase } from './modules/data_source_base.js';
|
|
40
38
|
import { ArchiverDataStoreUpdater } from './modules/data_store_updater.js';
|
|
41
39
|
import type { ArchiverInstrumentation } from './modules/instrumentation.js';
|
|
42
40
|
import type { ArchiverL1Synchronizer } from './modules/l1_synchronizer.js';
|
|
43
|
-
import type
|
|
41
|
+
import { type ArchiverDataStores, backupArchiverDataStores, getArchiverSynchPoint } from './store/data_stores.js';
|
|
42
|
+
import { L2TipsCache } from './store/l2_tips_cache.js';
|
|
44
43
|
|
|
45
44
|
/** Export ArchiverEmitter for use in factory and tests. */
|
|
46
45
|
export type { ArchiverEmitter };
|
|
47
46
|
|
|
48
47
|
/** Request to add a block to the archiver, queued for processing by the sync loop. */
|
|
49
48
|
type AddBlockRequest = {
|
|
49
|
+
type: 'block';
|
|
50
50
|
block: L2Block;
|
|
51
51
|
resolve: () => void;
|
|
52
52
|
reject: (err: Error) => void;
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
+
/** Request to add a proposed checkpoint to the archiver, queued for processing by the sync loop. */
|
|
56
|
+
type AddProposedCheckpointRequest = {
|
|
57
|
+
type: 'checkpoint';
|
|
58
|
+
checkpoint: ProposedCheckpointInput;
|
|
59
|
+
resolve: () => void;
|
|
60
|
+
reject: (err: Error) => void;
|
|
61
|
+
};
|
|
62
|
+
|
|
55
63
|
export type ArchiverDeps = {
|
|
56
64
|
telemetry?: TelemetryClient;
|
|
57
65
|
blobClient: BlobClientInterface;
|
|
@@ -77,25 +85,29 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
77
85
|
private initialSyncComplete: boolean = false;
|
|
78
86
|
private initialSyncPromise: PromiseWithResolvers<void>;
|
|
79
87
|
|
|
80
|
-
/** Queue of blocks to be added to the store, processed by the sync loop. */
|
|
81
|
-
private
|
|
88
|
+
/** Queue of blocks and checkpoints to be added to the store, processed by the sync loop. */
|
|
89
|
+
private inboundQueue: (AddBlockRequest | AddProposedCheckpointRequest)[] = [];
|
|
82
90
|
|
|
83
91
|
/** Helper to handle updates to the store */
|
|
84
92
|
private readonly updater: ArchiverDataStoreUpdater;
|
|
85
93
|
|
|
94
|
+
/** In-memory cache for L2 chain tips. */
|
|
95
|
+
private readonly l2TipsCache: L2TipsCache;
|
|
96
|
+
|
|
86
97
|
public readonly tracer: Tracer;
|
|
87
98
|
|
|
99
|
+
private readonly instrumentation: ArchiverInstrumentation;
|
|
100
|
+
|
|
88
101
|
/**
|
|
89
102
|
* Creates a new instance of the Archiver.
|
|
90
103
|
* @param publicClient - A client for interacting with the Ethereum node.
|
|
91
104
|
* @param debugClient - A client for interacting with the Ethereum node for debug/trace methods.
|
|
92
105
|
* @param rollup - Rollup contract instance.
|
|
93
106
|
* @param inbox - Inbox contract instance.
|
|
94
|
-
* @param l1Addresses - L1 contract addresses (registry, governance proposer,
|
|
95
|
-
* @param
|
|
107
|
+
* @param l1Addresses - L1 contract addresses (registry, governance proposer, slashing proposer).
|
|
108
|
+
* @param dataStores - Archiver substores for storage & retrieval of blocks, encrypted logs & contract data.
|
|
96
109
|
* @param config - Archiver configuration options.
|
|
97
110
|
* @param blobClient - Client for retrieving blob data.
|
|
98
|
-
* @param epochCache - Cache for epoch-related data.
|
|
99
111
|
* @param dateProvider - Provider for current date/time.
|
|
100
112
|
* @param instrumentation - Instrumentation for metrics and tracing.
|
|
101
113
|
* @param l1Constants - L1 rollup constants.
|
|
@@ -107,30 +119,41 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
107
119
|
private readonly rollup: RollupContract,
|
|
108
120
|
private readonly l1Addresses: Pick<
|
|
109
121
|
L1ContractAddresses,
|
|
110
|
-
'registryAddress' | '
|
|
111
|
-
> & {
|
|
112
|
-
|
|
122
|
+
'rollupAddress' | 'registryAddress' | 'inboxAddress' | 'governanceProposerAddress'
|
|
123
|
+
> & {
|
|
124
|
+
slashingProposerAddress: EthAddress;
|
|
125
|
+
},
|
|
126
|
+
readonly dataStores: ArchiverDataStores,
|
|
113
127
|
private config: {
|
|
114
128
|
pollingIntervalMs: number;
|
|
115
129
|
batchSize: number;
|
|
116
130
|
skipValidateCheckpointAttestations?: boolean;
|
|
117
131
|
maxAllowedEthClientDriftSeconds: number;
|
|
118
132
|
ethereumAllowNoDebugHosts?: boolean;
|
|
133
|
+
skipHistoricalLogsCheck?: boolean;
|
|
119
134
|
},
|
|
120
135
|
private readonly blobClient: BlobClientInterface,
|
|
121
136
|
instrumentation: ArchiverInstrumentation,
|
|
122
|
-
protected override readonly l1Constants: L1RollupConstants & {
|
|
137
|
+
protected override readonly l1Constants: L1RollupConstants & {
|
|
138
|
+
l1StartBlockHash: Buffer32;
|
|
139
|
+
genesisArchiveRoot: Fr;
|
|
140
|
+
},
|
|
123
141
|
synchronizer: ArchiverL1Synchronizer,
|
|
124
142
|
events: ArchiverEmitter,
|
|
143
|
+
l2TipsCache?: L2TipsCache,
|
|
125
144
|
private readonly log: Logger = createLogger('archiver'),
|
|
126
145
|
) {
|
|
127
|
-
super(
|
|
146
|
+
super(dataStores, l1Constants);
|
|
128
147
|
|
|
129
148
|
this.tracer = instrumentation.tracer;
|
|
149
|
+
this.instrumentation = instrumentation;
|
|
130
150
|
this.initialSyncPromise = promiseWithResolvers();
|
|
131
151
|
this.synchronizer = synchronizer;
|
|
132
152
|
this.events = events;
|
|
133
|
-
this.
|
|
153
|
+
this.l2TipsCache = l2TipsCache ?? new L2TipsCache(this.dataStores.blocks);
|
|
154
|
+
this.updater = new ArchiverDataStoreUpdater(this.dataStores, this.l2TipsCache, {
|
|
155
|
+
rollupManaLimit: l1Constants.rollupManaLimit,
|
|
156
|
+
});
|
|
134
157
|
|
|
135
158
|
// Running promise starts with a small interval inbetween runs, so all iterations needed for the initial sync
|
|
136
159
|
// are done as fast as possible. This then gets updated once the initial sync completes.
|
|
@@ -164,10 +187,23 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
164
187
|
this.config.ethereumAllowNoDebugHosts ?? false,
|
|
165
188
|
this.log.getBindings(),
|
|
166
189
|
);
|
|
190
|
+
await validateAndLogHistoricalLogsAvailability(
|
|
191
|
+
this.publicClient,
|
|
192
|
+
{
|
|
193
|
+
rollupAddress: this.l1Addresses.rollupAddress,
|
|
194
|
+
inboxAddress: this.l1Addresses.inboxAddress,
|
|
195
|
+
registryAddress: this.l1Addresses.registryAddress,
|
|
196
|
+
governanceProposerAddress: this.l1Addresses.governanceProposerAddress,
|
|
197
|
+
},
|
|
198
|
+
this.config.skipHistoricalLogsCheck ?? false,
|
|
199
|
+
this.log.getBindings(),
|
|
200
|
+
);
|
|
167
201
|
|
|
168
202
|
// Log initial state for the archiver
|
|
169
203
|
const { l1StartBlock } = this.l1Constants;
|
|
170
|
-
const { blocksSynchedTo = l1StartBlock, messagesSynchedTo = l1StartBlock } = await
|
|
204
|
+
const { blocksSynchedTo = l1StartBlock, messagesSynchedTo = l1StartBlock } = await getArchiverSynchPoint(
|
|
205
|
+
this.stores,
|
|
206
|
+
);
|
|
171
207
|
const currentL2Checkpoint = await this.getSynchedCheckpointNumber();
|
|
172
208
|
this.log.info(
|
|
173
209
|
`Starting archiver sync to rollup contract ${this.rollup.address} from L1 block ${blocksSynchedTo} and L2 checkpoint ${currentL2Checkpoint}`,
|
|
@@ -185,6 +221,14 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
185
221
|
return this.runningPromise.trigger();
|
|
186
222
|
}
|
|
187
223
|
|
|
224
|
+
public trySyncImmediate() {
|
|
225
|
+
try {
|
|
226
|
+
return this.syncImmediate();
|
|
227
|
+
} catch (err) {
|
|
228
|
+
this.log.error(`Failed to trigger immediate archiver sync: ${err}`, err);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
188
232
|
/**
|
|
189
233
|
* Queues a block to be added to the archiver store and triggers processing.
|
|
190
234
|
* The block will be processed by the sync loop.
|
|
@@ -193,53 +237,85 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
193
237
|
* @returns A promise that resolves when the block has been added to the store, or rejects on error.
|
|
194
238
|
*/
|
|
195
239
|
public addBlock(block: L2Block): Promise<void> {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
this.log.error(`Sync immediate call failed: ${err}`);
|
|
202
|
-
});
|
|
203
|
-
});
|
|
240
|
+
const promise = promiseWithResolvers<void>();
|
|
241
|
+
this.inboundQueue.push({ block, ...promise, type: 'block' });
|
|
242
|
+
this.log.debug(`Queued block ${block.number} for processing`);
|
|
243
|
+
void this.trySyncImmediate();
|
|
244
|
+
return promise.promise;
|
|
204
245
|
}
|
|
205
246
|
|
|
206
247
|
/**
|
|
207
|
-
*
|
|
248
|
+
* Queues a new proposed checkpoint into the archiver store.
|
|
249
|
+
* Checks that the checkpoint is not for an L2 slot already synced from L1.
|
|
250
|
+
* Resolves once the checkpoint has been processed.
|
|
251
|
+
*/
|
|
252
|
+
public addProposedCheckpoint(pending: ProposedCheckpointInput): Promise<void> {
|
|
253
|
+
const promise = promiseWithResolvers<void>();
|
|
254
|
+
this.inboundQueue.push({ checkpoint: pending, ...promise, type: 'checkpoint' });
|
|
255
|
+
this.log.debug(`Queued checkpoint ${pending.checkpointNumber} for processing`);
|
|
256
|
+
void this.trySyncImmediate();
|
|
257
|
+
return promise.promise;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Processes all queued blocks and checkpoints, adding them to the store.
|
|
208
262
|
* Called at the beginning of each sync iteration.
|
|
209
|
-
*
|
|
263
|
+
* Items are processed in the order they were queued.
|
|
210
264
|
*/
|
|
211
|
-
private async
|
|
212
|
-
if (this.
|
|
265
|
+
private async processInboundQueue(): Promise<void> {
|
|
266
|
+
if (this.inboundQueue.length === 0) {
|
|
213
267
|
return;
|
|
214
268
|
}
|
|
215
269
|
|
|
216
|
-
// Take all
|
|
217
|
-
const queuedItems = this.
|
|
218
|
-
this.log.debug(`Processing ${queuedItems.length} queued
|
|
270
|
+
// Take all items from the queue
|
|
271
|
+
const queuedItems = this.inboundQueue.splice(0, this.inboundQueue.length);
|
|
272
|
+
this.log.debug(`Processing ${queuedItems.length} queued inbound items`);
|
|
219
273
|
|
|
220
274
|
// Calculate slot threshold for validation
|
|
221
275
|
const l1Timestamp = this.synchronizer.getL1Timestamp();
|
|
222
276
|
const slotAtNextL1Block =
|
|
223
277
|
l1Timestamp === undefined ? undefined : getSlotAtNextL1Block(l1Timestamp, this.l1Constants);
|
|
224
278
|
|
|
225
|
-
//
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
279
|
+
// Helpers for manipulating blocks and checkpoints in the queue
|
|
280
|
+
const getSlot: (item: AddBlockRequest | AddProposedCheckpointRequest) => SlotNumber = item =>
|
|
281
|
+
item.type === 'block' ? item.block.header.globalVariables.slotNumber : item.checkpoint.header.slotNumber;
|
|
282
|
+
const getNumber: (item: AddBlockRequest | AddProposedCheckpointRequest) => number = item =>
|
|
283
|
+
item.type === 'block' ? item.block.number : item.checkpoint.checkpointNumber;
|
|
284
|
+
|
|
285
|
+
// Process each item individually to properly resolve/reject each promise
|
|
286
|
+
for (const item of queuedItems) {
|
|
287
|
+
const { resolve, reject, type } = item;
|
|
288
|
+
const itemSlot = getSlot(item);
|
|
289
|
+
const itemNumber = getNumber(item);
|
|
290
|
+
if (slotAtNextL1Block !== undefined && itemSlot < slotAtNextL1Block) {
|
|
291
|
+
const nextSlotTimestamp = getTimestampForSlot(slotAtNextL1Block, this.l1Constants);
|
|
229
292
|
this.log.warn(
|
|
230
|
-
`Rejecting proposed
|
|
231
|
-
{
|
|
293
|
+
`Rejecting proposed ${type} ${itemNumber} for past slot ${itemSlot} (current ${slotAtNextL1Block})`,
|
|
294
|
+
{ number: itemNumber, type, l1Timestamp, slotAtNextL1Block, nextSlotTimestamp },
|
|
232
295
|
);
|
|
233
|
-
reject(new
|
|
296
|
+
reject(new BlockOrCheckpointSlotExpiredError(itemSlot, nextSlotTimestamp, l1Timestamp));
|
|
234
297
|
continue;
|
|
235
298
|
}
|
|
236
299
|
|
|
237
300
|
try {
|
|
238
|
-
|
|
239
|
-
|
|
301
|
+
if (type === 'block') {
|
|
302
|
+
const [durationMs] = await elapsed(() => this.updater.addProposedBlock(item.block));
|
|
303
|
+
this.instrumentation.processNewProposedBlock(durationMs, item.block);
|
|
304
|
+
} else {
|
|
305
|
+
await this.updater.addProposedCheckpoint(item.checkpoint);
|
|
306
|
+
}
|
|
307
|
+
this.log.debug(`Added ${type} ${itemNumber} to store`);
|
|
240
308
|
resolve();
|
|
241
309
|
} catch (err: any) {
|
|
242
|
-
|
|
310
|
+
if (err instanceof BlockAlreadyCheckpointedError) {
|
|
311
|
+
this.log.debug(`Proposed block ${itemNumber} matches already checkpointed block, ignoring late proposal`);
|
|
312
|
+
resolve();
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
this.log.error(`Failed to add ${type} ${itemNumber} to store: ${err.message}`, err, {
|
|
316
|
+
number: itemNumber,
|
|
317
|
+
type,
|
|
318
|
+
});
|
|
243
319
|
reject(err);
|
|
244
320
|
}
|
|
245
321
|
}
|
|
@@ -255,7 +331,7 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
255
331
|
@trackSpan('Archiver.sync')
|
|
256
332
|
private async sync() {
|
|
257
333
|
// Process any queued blocks first, before doing L1 sync
|
|
258
|
-
await this.
|
|
334
|
+
await this.processInboundQueue();
|
|
259
335
|
// Now perform L1 sync
|
|
260
336
|
await this.syncFromL1();
|
|
261
337
|
}
|
|
@@ -271,7 +347,7 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
271
347
|
if (currentL1BlockNumber + 1n >= l1BlockNumberAtEnd) {
|
|
272
348
|
this.log.info(`Initial archiver sync to L1 block ${currentL1BlockNumber} complete`, {
|
|
273
349
|
l1BlockNumber: currentL1BlockNumber,
|
|
274
|
-
syncPoint: await this.
|
|
350
|
+
syncPoint: await getArchiverSynchPoint(this.stores),
|
|
275
351
|
...(await this.getL2Tips()),
|
|
276
352
|
});
|
|
277
353
|
this.runningPromise.setPollingIntervalMS(this.config.pollingIntervalMs);
|
|
@@ -303,7 +379,7 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
303
379
|
}
|
|
304
380
|
|
|
305
381
|
public backupTo(destPath: string): Promise<string> {
|
|
306
|
-
return this.
|
|
382
|
+
return backupArchiverDataStores(this.dataStores, destPath);
|
|
307
383
|
}
|
|
308
384
|
|
|
309
385
|
public getL1Constants(): Promise<L1RollupConstants> {
|
|
@@ -330,16 +406,49 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
330
406
|
return Promise.resolve(this.synchronizer.getL1Timestamp());
|
|
331
407
|
}
|
|
332
408
|
|
|
333
|
-
public
|
|
409
|
+
public async getSyncedL2SlotNumber(): Promise<SlotNumber | undefined> {
|
|
410
|
+
// The synced L2 slot is the latest slot for which we have all L1 data,
|
|
411
|
+
// either because we have seen all L1 blocks for that slot, or because
|
|
412
|
+
// we have seen the corresponding checkpoint.
|
|
413
|
+
|
|
414
|
+
let slotFromL1Sync: SlotNumber | undefined;
|
|
334
415
|
const l1Timestamp = this.synchronizer.getL1Timestamp();
|
|
335
|
-
|
|
416
|
+
if (l1Timestamp !== undefined) {
|
|
417
|
+
const nextL1BlockSlot = getSlotAtNextL1Block(l1Timestamp, this.l1Constants);
|
|
418
|
+
if (Number(nextL1BlockSlot) > 0) {
|
|
419
|
+
slotFromL1Sync = SlotNumber.add(nextL1BlockSlot, -1);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
let slotFromCheckpoint: SlotNumber | undefined;
|
|
424
|
+
const latestCheckpointNumber = await this.stores.blocks.getLatestCheckpointNumber();
|
|
425
|
+
if (latestCheckpointNumber > 0) {
|
|
426
|
+
const checkpointData = await this.stores.blocks.getCheckpointData(latestCheckpointNumber);
|
|
427
|
+
if (checkpointData) {
|
|
428
|
+
slotFromCheckpoint = checkpointData.header.slotNumber;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
if (slotFromL1Sync === undefined && slotFromCheckpoint === undefined) {
|
|
433
|
+
return undefined;
|
|
434
|
+
}
|
|
435
|
+
return SlotNumber(Math.max(slotFromL1Sync ?? 0, slotFromCheckpoint ?? 0));
|
|
336
436
|
}
|
|
337
437
|
|
|
338
|
-
public
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
438
|
+
public async getSyncedL2EpochNumber(): Promise<EpochNumber | undefined> {
|
|
439
|
+
const syncedSlot = await this.getSyncedL2SlotNumber();
|
|
440
|
+
if (syncedSlot === undefined) {
|
|
441
|
+
return undefined;
|
|
442
|
+
}
|
|
443
|
+
// An epoch is fully synced when all its slots are synced.
|
|
444
|
+
// We check if syncedSlot is the last slot of its epoch; if so, that epoch is fully synced.
|
|
445
|
+
// Otherwise, only the previous epoch is fully synced.
|
|
446
|
+
const epoch = getEpochAtSlot(syncedSlot, this.l1Constants);
|
|
447
|
+
const [, endSlot] = getSlotRangeForEpoch(epoch, this.l1Constants);
|
|
448
|
+
if (syncedSlot >= endSlot) {
|
|
449
|
+
return epoch;
|
|
450
|
+
}
|
|
451
|
+
return Number(epoch) > 0 ? EpochNumber(Number(epoch) - 1) : undefined;
|
|
343
452
|
}
|
|
344
453
|
|
|
345
454
|
public async isEpochComplete(epochNumber: EpochNumber): Promise<boolean> {
|
|
@@ -391,115 +500,11 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
391
500
|
return true;
|
|
392
501
|
}
|
|
393
502
|
|
|
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;
|
|
503
|
+
public getL2Tips(): Promise<L2Tips> {
|
|
504
|
+
return this.l2TipsCache.getL2Tips();
|
|
499
505
|
}
|
|
500
506
|
|
|
501
507
|
public async rollbackTo(targetL2BlockNumber: BlockNumber): Promise<void> {
|
|
502
|
-
// TODO(pw/mbps): This still assumes 1 block per checkpoint
|
|
503
508
|
const currentBlocks = await this.getL2Tips();
|
|
504
509
|
const currentL2Block = currentBlocks.proposed.number;
|
|
505
510
|
const currentProvenBlock = currentBlocks.proven.block.number;
|
|
@@ -507,12 +512,29 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
507
512
|
if (targetL2BlockNumber >= currentL2Block) {
|
|
508
513
|
throw new Error(`Target L2 block ${targetL2BlockNumber} must be less than current L2 block ${currentL2Block}`);
|
|
509
514
|
}
|
|
510
|
-
const targetL2Block = await this.
|
|
515
|
+
const targetL2Block = await this.stores.blocks.getCheckpointedBlock(targetL2BlockNumber);
|
|
511
516
|
if (!targetL2Block) {
|
|
512
517
|
throw new Error(`Target L2 block ${targetL2BlockNumber} not found`);
|
|
513
518
|
}
|
|
514
|
-
const targetL1BlockNumber = targetL2Block.l1.blockNumber;
|
|
515
519
|
const targetCheckpointNumber = targetL2Block.checkpointNumber;
|
|
520
|
+
|
|
521
|
+
// Rollback operates at checkpoint granularity: the target block must be the last block of its checkpoint.
|
|
522
|
+
const checkpointData = await this.stores.blocks.getCheckpointData(targetCheckpointNumber);
|
|
523
|
+
if (checkpointData) {
|
|
524
|
+
const lastBlockInCheckpoint = BlockNumber(checkpointData.startBlock + checkpointData.blockCount - 1);
|
|
525
|
+
if (targetL2BlockNumber !== lastBlockInCheckpoint) {
|
|
526
|
+
const previousCheckpointBoundary =
|
|
527
|
+
checkpointData.startBlock > 1 ? BlockNumber(checkpointData.startBlock - 1) : BlockNumber(0);
|
|
528
|
+
throw new Error(
|
|
529
|
+
`Target L2 block ${targetL2BlockNumber} is not at a checkpoint boundary. ` +
|
|
530
|
+
`Checkpoint ${targetCheckpointNumber} spans blocks ${checkpointData.startBlock} to ${lastBlockInCheckpoint}. ` +
|
|
531
|
+
`Use block ${lastBlockInCheckpoint} to roll back to this checkpoint, ` +
|
|
532
|
+
`or block ${previousCheckpointBoundary} to roll back to the previous one.`,
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
const targetL1BlockNumber = targetL2Block.l1.blockNumber;
|
|
516
538
|
const targetL1Block = await this.publicClient.getBlock({
|
|
517
539
|
blockNumber: targetL1BlockNumber,
|
|
518
540
|
includeTransactions: false,
|
|
@@ -526,18 +548,21 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
526
548
|
);
|
|
527
549
|
await this.updater.removeCheckpointsAfter(targetCheckpointNumber);
|
|
528
550
|
this.log.info(`Rolling back L1 to L2 messages to checkpoint ${targetCheckpointNumber}`);
|
|
529
|
-
await this.
|
|
551
|
+
await this.stores.messages.rollbackL1ToL2MessagesToCheckpoint(targetCheckpointNumber);
|
|
530
552
|
this.log.info(`Setting L1 syncpoints to ${targetL1BlockNumber}`);
|
|
531
|
-
await this.
|
|
532
|
-
await this.
|
|
553
|
+
await this.stores.blocks.setSynchedL1BlockNumber(targetL1BlockNumber);
|
|
554
|
+
await this.stores.messages.setMessageSyncState(
|
|
555
|
+
{ l1BlockNumber: targetL1BlockNumber, l1BlockHash: targetL1BlockHash },
|
|
556
|
+
undefined,
|
|
557
|
+
);
|
|
533
558
|
if (targetL2BlockNumber < currentProvenBlock) {
|
|
534
|
-
this.log.info(`
|
|
535
|
-
await this.
|
|
559
|
+
this.log.info(`Rolling back proven L2 checkpoint to ${targetCheckpointNumber}`);
|
|
560
|
+
await this.updater.setProvenCheckpointNumber(targetCheckpointNumber);
|
|
561
|
+
}
|
|
562
|
+
const currentFinalizedBlock = currentBlocks.finalized.block.number;
|
|
563
|
+
if (targetL2BlockNumber < currentFinalizedBlock) {
|
|
564
|
+
this.log.info(`Rolling back finalized L2 checkpoint to ${targetCheckpointNumber}`);
|
|
565
|
+
await this.updater.setFinalizedCheckpointNumber(targetCheckpointNumber);
|
|
536
566
|
}
|
|
537
|
-
// TODO(palla/reorg): Set the finalized block when we add support for it.
|
|
538
|
-
// if (targetL2BlockNumber < currentFinalizedBlock) {
|
|
539
|
-
// this.log.info(`Clearing finalized L2 block number`);
|
|
540
|
-
// await this.store.setFinalizedL2BlockNumber(0);
|
|
541
|
-
// }
|
|
542
567
|
}
|
|
543
568
|
}
|
package/src/config.ts
CHANGED
|
@@ -7,8 +7,14 @@ import {
|
|
|
7
7
|
booleanConfigHelper,
|
|
8
8
|
getConfigFromMappings,
|
|
9
9
|
numberConfigHelper,
|
|
10
|
+
optionalNumberConfigHelper,
|
|
10
11
|
} from '@aztec/foundation/config';
|
|
11
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
type ChainConfig,
|
|
14
|
+
type PipelineConfig,
|
|
15
|
+
chainConfigMappings,
|
|
16
|
+
pipelineConfigMappings,
|
|
17
|
+
} from '@aztec/stdlib/config';
|
|
12
18
|
import type { ArchiverSpecificConfig } from '@aztec/stdlib/interfaces/server';
|
|
13
19
|
|
|
14
20
|
/**
|
|
@@ -21,11 +27,13 @@ import type { ArchiverSpecificConfig } from '@aztec/stdlib/interfaces/server';
|
|
|
21
27
|
export type ArchiverConfig = ArchiverSpecificConfig &
|
|
22
28
|
L1ReaderConfig &
|
|
23
29
|
L1ContractsConfig &
|
|
30
|
+
PipelineConfig & // required to pass through to epoch cache
|
|
24
31
|
BlobClientConfig &
|
|
25
32
|
ChainConfig;
|
|
26
33
|
|
|
27
34
|
export const archiverConfigMappings: ConfigMappingsType<ArchiverConfig> = {
|
|
28
35
|
...blobClientConfigMapping,
|
|
36
|
+
...pipelineConfigMappings,
|
|
29
37
|
archiverPollingIntervalMS: {
|
|
30
38
|
env: 'ARCHIVER_POLLING_INTERVAL_MS',
|
|
31
39
|
description: 'The polling interval in ms for retrieving new L2 blocks and encrypted logs.',
|
|
@@ -43,13 +51,17 @@ export const archiverConfigMappings: ConfigMappingsType<ArchiverConfig> = {
|
|
|
43
51
|
},
|
|
44
52
|
archiverStoreMapSizeKb: {
|
|
45
53
|
env: 'ARCHIVER_STORE_MAP_SIZE_KB',
|
|
46
|
-
|
|
54
|
+
...optionalNumberConfigHelper(),
|
|
47
55
|
description: 'The maximum possible size of the archiver DB in KB. Overwrites the general dataStoreMapSizeKb.',
|
|
48
56
|
},
|
|
49
57
|
skipValidateCheckpointAttestations: {
|
|
50
58
|
description: 'Skip validating checkpoint attestations (for testing purposes only)',
|
|
51
59
|
...booleanConfigHelper(false),
|
|
52
60
|
},
|
|
61
|
+
skipPromoteProposedCheckpointDuringL1Sync: {
|
|
62
|
+
description: 'Skip promoting proposed checkpoints during L1 sync (for testing purposes only)',
|
|
63
|
+
...booleanConfigHelper(false),
|
|
64
|
+
},
|
|
53
65
|
maxAllowedEthClientDriftSeconds: {
|
|
54
66
|
env: 'MAX_ALLOWED_ETH_CLIENT_DRIFT_SECONDS',
|
|
55
67
|
description: 'Maximum allowed drift in seconds between the Ethereum client and current time.',
|
|
@@ -60,6 +72,13 @@ export const archiverConfigMappings: ConfigMappingsType<ArchiverConfig> = {
|
|
|
60
72
|
description: 'Whether to allow starting the archiver without debug/trace method support on Ethereum hosts',
|
|
61
73
|
...booleanConfigHelper(true),
|
|
62
74
|
},
|
|
75
|
+
archiverSkipHistoricalLogsCheck: {
|
|
76
|
+
env: 'ARCHIVER_SKIP_HISTORICAL_LOGS_CHECK',
|
|
77
|
+
description:
|
|
78
|
+
'Skip the startup check that probes the L1 RPC for historical Rollup contract logs. ' +
|
|
79
|
+
'Set to true to bypass the check when the connected RPC node is known to prune old logs.',
|
|
80
|
+
...booleanConfigHelper(false),
|
|
81
|
+
},
|
|
63
82
|
...chainConfigMappings,
|
|
64
83
|
...l1ReaderConfigMappings,
|
|
65
84
|
viemPollingIntervalMS: {
|
|
@@ -89,7 +108,9 @@ export function mapArchiverConfig(config: Partial<ArchiverConfig>) {
|
|
|
89
108
|
pollingIntervalMs: config.archiverPollingIntervalMS,
|
|
90
109
|
batchSize: config.archiverBatchSize,
|
|
91
110
|
skipValidateCheckpointAttestations: config.skipValidateCheckpointAttestations,
|
|
111
|
+
skipPromoteProposedCheckpointDuringL1Sync: config.skipPromoteProposedCheckpointDuringL1Sync,
|
|
92
112
|
maxAllowedEthClientDriftSeconds: config.maxAllowedEthClientDriftSeconds,
|
|
93
113
|
ethereumAllowNoDebugHosts: config.ethereumAllowNoDebugHosts,
|
|
114
|
+
skipHistoricalLogsCheck: config.archiverSkipHistoricalLogsCheck,
|
|
94
115
|
};
|
|
95
116
|
}
|