@aztec/archiver 0.0.1-commit.9593d84 → 0.0.1-commit.96bb3f7
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 +14 -14
- package/dest/archiver/archiver.d.ts +105 -85
- package/dest/archiver/archiver.d.ts.map +1 -1
- package/dest/archiver/archiver.js +949 -255
- package/dest/archiver/archiver_store.d.ts +109 -49
- package/dest/archiver/archiver_store.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.d.ts +1 -1
- package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.js +1871 -390
- package/dest/archiver/config.d.ts +5 -4
- package/dest/archiver/config.d.ts.map +1 -1
- package/dest/archiver/config.js +12 -5
- package/dest/archiver/errors.d.ts +25 -1
- package/dest/archiver/errors.d.ts.map +1 -1
- package/dest/archiver/errors.js +37 -0
- package/dest/archiver/index.d.ts +2 -2
- package/dest/archiver/index.d.ts.map +1 -1
- package/dest/archiver/instrumentation.d.ts +3 -1
- package/dest/archiver/instrumentation.d.ts.map +1 -1
- package/dest/archiver/instrumentation.js +22 -59
- package/dest/archiver/kv_archiver_store/block_store.d.ts +60 -20
- package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/block_store.js +345 -89
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +2 -2
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/contract_class_store.js +1 -1
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +2 -2
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +49 -58
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.js +68 -48
- package/dest/archiver/kv_archiver_store/log_store.d.ts +12 -16
- package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/log_store.js +149 -84
- package/dest/archiver/kv_archiver_store/message_store.d.ts +6 -5
- package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/message_store.js +15 -14
- package/dest/archiver/l1/bin/retrieve-calldata.d.ts +3 -0
- package/dest/archiver/l1/bin/retrieve-calldata.d.ts.map +1 -0
- package/dest/archiver/l1/bin/retrieve-calldata.js +149 -0
- package/dest/archiver/l1/calldata_retriever.d.ts +112 -0
- package/dest/archiver/l1/calldata_retriever.d.ts.map +1 -0
- package/dest/archiver/l1/calldata_retriever.js +471 -0
- package/dest/archiver/l1/data_retrieval.d.ts +90 -0
- package/dest/archiver/l1/data_retrieval.d.ts.map +1 -0
- package/dest/archiver/{data_retrieval.js → l1/data_retrieval.js} +52 -107
- package/dest/archiver/l1/debug_tx.d.ts +19 -0
- package/dest/archiver/l1/debug_tx.d.ts.map +1 -0
- package/dest/archiver/l1/debug_tx.js +73 -0
- package/dest/archiver/l1/spire_proposer.d.ts +70 -0
- package/dest/archiver/l1/spire_proposer.d.ts.map +1 -0
- package/dest/archiver/l1/spire_proposer.js +157 -0
- package/dest/archiver/l1/trace_tx.d.ts +97 -0
- package/dest/archiver/l1/trace_tx.d.ts.map +1 -0
- package/dest/archiver/l1/trace_tx.js +91 -0
- package/dest/archiver/l1/types.d.ts +12 -0
- package/dest/archiver/l1/types.d.ts.map +1 -0
- package/dest/archiver/l1/types.js +3 -0
- package/dest/archiver/l1/validate_trace.d.ts +29 -0
- package/dest/archiver/l1/validate_trace.d.ts.map +1 -0
- package/dest/archiver/l1/validate_trace.js +150 -0
- package/dest/archiver/structs/inbox_message.d.ts +4 -4
- package/dest/archiver/structs/inbox_message.d.ts.map +1 -1
- package/dest/archiver/structs/inbox_message.js +6 -5
- package/dest/archiver/structs/published.d.ts +1 -2
- package/dest/archiver/structs/published.d.ts.map +1 -1
- package/dest/archiver/validation.d.ts +4 -4
- package/dest/archiver/validation.d.ts.map +1 -1
- package/dest/archiver/validation.js +1 -1
- package/dest/factory.d.ts +2 -2
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +4 -3
- package/dest/index.d.ts +2 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -1
- package/dest/test/mock_archiver.d.ts +16 -8
- package/dest/test/mock_archiver.d.ts.map +1 -1
- package/dest/test/mock_archiver.js +19 -14
- package/dest/test/mock_l1_to_l2_message_source.d.ts +7 -6
- package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
- package/dest/test/mock_l1_to_l2_message_source.js +21 -11
- package/dest/test/mock_l2_block_source.d.ts +23 -8
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +95 -35
- package/dest/test/mock_structs.d.ts +3 -2
- package/dest/test/mock_structs.d.ts.map +1 -1
- package/dest/test/mock_structs.js +9 -8
- package/package.json +17 -16
- package/src/archiver/archiver.ts +751 -344
- package/src/archiver/archiver_store.ts +123 -48
- package/src/archiver/archiver_store_test_suite.ts +1943 -365
- package/src/archiver/config.ts +17 -12
- package/src/archiver/errors.ts +64 -0
- package/src/archiver/index.ts +1 -1
- package/src/archiver/instrumentation.ts +24 -59
- package/src/archiver/kv_archiver_store/block_store.ts +475 -106
- package/src/archiver/kv_archiver_store/contract_class_store.ts +1 -1
- package/src/archiver/kv_archiver_store/contract_instance_store.ts +1 -1
- package/src/archiver/kv_archiver_store/kv_archiver_store.ts +92 -72
- package/src/archiver/kv_archiver_store/log_store.ts +209 -99
- package/src/archiver/kv_archiver_store/message_store.ts +21 -18
- package/src/archiver/l1/README.md +98 -0
- package/src/archiver/l1/bin/retrieve-calldata.ts +182 -0
- package/src/archiver/l1/calldata_retriever.ts +641 -0
- package/src/archiver/{data_retrieval.ts → l1/data_retrieval.ts} +101 -165
- package/src/archiver/l1/debug_tx.ts +99 -0
- package/src/archiver/l1/spire_proposer.ts +160 -0
- package/src/archiver/l1/trace_tx.ts +128 -0
- package/src/archiver/l1/types.ts +13 -0
- package/src/archiver/l1/validate_trace.ts +211 -0
- package/src/archiver/structs/inbox_message.ts +8 -8
- package/src/archiver/structs/published.ts +0 -1
- package/src/archiver/validation.ts +6 -6
- package/src/factory.ts +4 -3
- package/src/index.ts +1 -1
- package/src/test/fixtures/debug_traceTransaction-multicall3.json +88 -0
- package/src/test/fixtures/debug_traceTransaction-multiplePropose.json +153 -0
- package/src/test/fixtures/debug_traceTransaction-proxied.json +122 -0
- package/src/test/fixtures/trace_transaction-multicall3.json +65 -0
- package/src/test/fixtures/trace_transaction-multiplePropose.json +319 -0
- package/src/test/fixtures/trace_transaction-proxied.json +128 -0
- package/src/test/fixtures/trace_transaction-randomRevert.json +216 -0
- package/src/test/mock_archiver.ts +22 -16
- package/src/test/mock_l1_to_l2_message_source.ts +18 -11
- package/src/test/mock_l2_block_source.ts +115 -37
- package/src/test/mock_structs.ts +10 -9
- package/dest/archiver/data_retrieval.d.ts +0 -79
- package/dest/archiver/data_retrieval.d.ts.map +0 -1
package/src/archiver/archiver.ts
CHANGED
|
@@ -1,24 +1,23 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BlobClientInterface } from '@aztec/blob-client/client';
|
|
2
|
+
import { GENESIS_BLOCK_HEADER_HASH, INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
2
3
|
import { EpochCache } from '@aztec/epoch-cache';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
type ViemPublicClient,
|
|
9
|
-
createEthereumChain,
|
|
10
|
-
} from '@aztec/ethereum';
|
|
4
|
+
import { createEthereumChain } from '@aztec/ethereum/chain';
|
|
5
|
+
import { BlockTagTooOldError, InboxContract, RollupContract } from '@aztec/ethereum/contracts';
|
|
6
|
+
import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
|
|
7
|
+
import type { L1BlockId } from '@aztec/ethereum/l1-types';
|
|
8
|
+
import type { ViemPublicClient, ViemPublicDebugClient } from '@aztec/ethereum/types';
|
|
11
9
|
import { maxBigint } from '@aztec/foundation/bigint';
|
|
12
|
-
import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
10
|
+
import { BlockNumber, CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
13
11
|
import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
|
|
14
12
|
import { merge, pick } from '@aztec/foundation/collection';
|
|
13
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
15
14
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
16
|
-
import { Fr } from '@aztec/foundation/fields';
|
|
17
15
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
18
16
|
import { type PromiseWithResolvers, promiseWithResolvers } from '@aztec/foundation/promise';
|
|
19
17
|
import { RunningPromise, makeLoggingErrorHandler } from '@aztec/foundation/running-promise';
|
|
20
18
|
import { count } from '@aztec/foundation/string';
|
|
21
19
|
import { DateProvider, Timer, elapsed } from '@aztec/foundation/timer';
|
|
20
|
+
import { isDefined } from '@aztec/foundation/types';
|
|
22
21
|
import type { CustomRange } from '@aztec/kv-store';
|
|
23
22
|
import { RollupAbi } from '@aztec/l1-artifacts';
|
|
24
23
|
import {
|
|
@@ -34,14 +33,19 @@ import type { FunctionSelector } from '@aztec/stdlib/abi';
|
|
|
34
33
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
35
34
|
import {
|
|
36
35
|
type ArchiverEmitter,
|
|
36
|
+
type CheckpointId,
|
|
37
|
+
CheckpointedL2Block,
|
|
38
|
+
CommitteeAttestation,
|
|
39
|
+
GENESIS_CHECKPOINT_HEADER_HASH,
|
|
37
40
|
L2Block,
|
|
38
|
-
|
|
41
|
+
L2BlockNew,
|
|
42
|
+
type L2BlockSink,
|
|
39
43
|
type L2BlockSource,
|
|
40
44
|
L2BlockSourceEvents,
|
|
41
45
|
type L2Tips,
|
|
42
46
|
PublishedL2Block,
|
|
43
47
|
} from '@aztec/stdlib/block';
|
|
44
|
-
import
|
|
48
|
+
import { Checkpoint, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
45
49
|
import {
|
|
46
50
|
type ContractClassPublic,
|
|
47
51
|
type ContractDataSource,
|
|
@@ -62,8 +66,16 @@ import {
|
|
|
62
66
|
} from '@aztec/stdlib/epoch-helpers';
|
|
63
67
|
import type { GetContractClassLogsResponse, GetPublicLogsResponse } from '@aztec/stdlib/interfaces/client';
|
|
64
68
|
import type { L2LogsSource } from '@aztec/stdlib/interfaces/server';
|
|
65
|
-
import {
|
|
66
|
-
|
|
69
|
+
import {
|
|
70
|
+
ContractClassLog,
|
|
71
|
+
type LogFilter,
|
|
72
|
+
type PrivateLog,
|
|
73
|
+
type PublicLog,
|
|
74
|
+
type SiloedTag,
|
|
75
|
+
Tag,
|
|
76
|
+
TxScopedL2Log,
|
|
77
|
+
} from '@aztec/stdlib/logs';
|
|
78
|
+
import { type L1ToL2MessageSource, computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
|
|
67
79
|
import type { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
68
80
|
import { type BlockHeader, type IndexedTxEffect, TxHash, TxReceipt } from '@aztec/stdlib/tx';
|
|
69
81
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
@@ -71,6 +83,7 @@ import {
|
|
|
71
83
|
type TelemetryClient,
|
|
72
84
|
type Traceable,
|
|
73
85
|
type Tracer,
|
|
86
|
+
execInSpan,
|
|
74
87
|
getTelemetryClient,
|
|
75
88
|
trackSpan,
|
|
76
89
|
} from '@aztec/telemetry-client';
|
|
@@ -81,25 +94,34 @@ import { type GetContractReturnType, type Hex, createPublicClient, fallback, htt
|
|
|
81
94
|
|
|
82
95
|
import type { ArchiverDataStore, ArchiverL1SynchPoint } from './archiver_store.js';
|
|
83
96
|
import type { ArchiverConfig } from './config.js';
|
|
97
|
+
import { InitialCheckpointNumberNotSequentialError, NoBlobBodiesFoundError } from './errors.js';
|
|
98
|
+
import { ArchiverInstrumentation } from './instrumentation.js';
|
|
99
|
+
import type { CheckpointData } from './kv_archiver_store/block_store.js';
|
|
84
100
|
import {
|
|
85
101
|
retrieveCheckpointsFromRollup,
|
|
86
102
|
retrieveL1ToL2Message,
|
|
87
103
|
retrieveL1ToL2Messages,
|
|
88
104
|
retrievedToPublishedCheckpoint,
|
|
89
|
-
} from './data_retrieval.js';
|
|
90
|
-
import {
|
|
91
|
-
import { ArchiverInstrumentation } from './instrumentation.js';
|
|
105
|
+
} from './l1/data_retrieval.js';
|
|
106
|
+
import { validateAndLogTraceAvailability } from './l1/validate_trace.js';
|
|
92
107
|
import type { InboxMessage } from './structs/inbox_message.js';
|
|
93
|
-
import { type
|
|
108
|
+
import { type ValidateCheckpointResult, validateCheckpointAttestations } from './validation.js';
|
|
94
109
|
|
|
95
110
|
/**
|
|
96
111
|
* Helper interface to combine all sources this archiver implementation provides.
|
|
97
112
|
*/
|
|
98
113
|
export type ArchiveSource = L2BlockSource & L2LogsSource & ContractDataSource & L1ToL2MessageSource;
|
|
99
114
|
|
|
115
|
+
/** Request to add a block to the archiver, queued for processing by the sync loop. */
|
|
116
|
+
type AddBlockRequest = {
|
|
117
|
+
block: L2BlockNew;
|
|
118
|
+
resolve: () => void;
|
|
119
|
+
reject: (err: Error) => void;
|
|
120
|
+
};
|
|
121
|
+
|
|
100
122
|
export type ArchiverDeps = {
|
|
101
123
|
telemetry?: TelemetryClient;
|
|
102
|
-
|
|
124
|
+
blobClient: BlobClientInterface;
|
|
103
125
|
epochCache?: EpochCache;
|
|
104
126
|
dateProvider?: DateProvider;
|
|
105
127
|
};
|
|
@@ -108,17 +130,18 @@ function mapArchiverConfig(config: Partial<ArchiverConfig>) {
|
|
|
108
130
|
return {
|
|
109
131
|
pollingIntervalMs: config.archiverPollingIntervalMS,
|
|
110
132
|
batchSize: config.archiverBatchSize,
|
|
111
|
-
|
|
133
|
+
skipValidateCheckpointAttestations: config.skipValidateCheckpointAttestations,
|
|
112
134
|
maxAllowedEthClientDriftSeconds: config.maxAllowedEthClientDriftSeconds,
|
|
135
|
+
ethereumAllowNoDebugHosts: config.ethereumAllowNoDebugHosts,
|
|
113
136
|
};
|
|
114
137
|
}
|
|
115
138
|
|
|
116
139
|
type RollupStatus = {
|
|
117
|
-
provenCheckpointNumber:
|
|
140
|
+
provenCheckpointNumber: CheckpointNumber;
|
|
118
141
|
provenArchive: Hex;
|
|
119
|
-
pendingCheckpointNumber:
|
|
142
|
+
pendingCheckpointNumber: CheckpointNumber;
|
|
120
143
|
pendingArchive: Hex;
|
|
121
|
-
validationResult:
|
|
144
|
+
validationResult: ValidateCheckpointResult | undefined;
|
|
122
145
|
lastRetrievedCheckpoint?: PublishedCheckpoint;
|
|
123
146
|
lastL1BlockWithCheckpoint?: bigint;
|
|
124
147
|
};
|
|
@@ -128,7 +151,10 @@ type RollupStatus = {
|
|
|
128
151
|
* Responsible for handling robust L1 polling so that other components do not need to
|
|
129
152
|
* concern themselves with it.
|
|
130
153
|
*/
|
|
131
|
-
export class Archiver
|
|
154
|
+
export class Archiver
|
|
155
|
+
extends (EventEmitter as new () => ArchiverEmitter)
|
|
156
|
+
implements ArchiveSource, L2BlockSink, Traceable
|
|
157
|
+
{
|
|
132
158
|
/** A loop in which we will be continually fetching new checkpoints. */
|
|
133
159
|
private runningPromise: RunningPromise;
|
|
134
160
|
|
|
@@ -142,11 +168,15 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
142
168
|
private initialSyncComplete: boolean = false;
|
|
143
169
|
private initialSyncPromise: PromiseWithResolvers<void>;
|
|
144
170
|
|
|
171
|
+
/** Queue of blocks to be added to the store, processed by the sync loop. */
|
|
172
|
+
private blockQueue: AddBlockRequest[] = [];
|
|
173
|
+
|
|
145
174
|
public readonly tracer: Tracer;
|
|
146
175
|
|
|
147
176
|
/**
|
|
148
177
|
* Creates a new instance of the Archiver.
|
|
149
178
|
* @param publicClient - A client for interacting with the Ethereum node.
|
|
179
|
+
* @param debugClient - A client for interacting with the Ethereum node for debug/trace methods.
|
|
150
180
|
* @param rollupAddress - Ethereum address of the rollup contract.
|
|
151
181
|
* @param inboxAddress - Ethereum address of the inbox contract.
|
|
152
182
|
* @param registryAddress - Ethereum address of the registry contract.
|
|
@@ -156,15 +186,20 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
156
186
|
*/
|
|
157
187
|
constructor(
|
|
158
188
|
private readonly publicClient: ViemPublicClient,
|
|
159
|
-
private readonly
|
|
189
|
+
private readonly debugClient: ViemPublicDebugClient,
|
|
190
|
+
private readonly l1Addresses: Pick<
|
|
191
|
+
L1ContractAddresses,
|
|
192
|
+
'rollupAddress' | 'inboxAddress' | 'registryAddress' | 'governanceProposerAddress' | 'slashFactoryAddress'
|
|
193
|
+
> & { slashingProposerAddress: EthAddress },
|
|
160
194
|
readonly dataStore: ArchiverDataStore,
|
|
161
195
|
private config: {
|
|
162
196
|
pollingIntervalMs: number;
|
|
163
197
|
batchSize: number;
|
|
164
|
-
|
|
198
|
+
skipValidateCheckpointAttestations?: boolean;
|
|
165
199
|
maxAllowedEthClientDriftSeconds: number;
|
|
200
|
+
ethereumAllowNoDebugHosts?: boolean;
|
|
166
201
|
},
|
|
167
|
-
private readonly
|
|
202
|
+
private readonly blobClient: BlobClientInterface,
|
|
168
203
|
private readonly epochCache: EpochCache,
|
|
169
204
|
private readonly dateProvider: DateProvider,
|
|
170
205
|
private readonly instrumentation: ArchiverInstrumentation,
|
|
@@ -206,18 +241,28 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
206
241
|
const chain = createEthereumChain(config.l1RpcUrls, config.l1ChainId);
|
|
207
242
|
const publicClient = createPublicClient({
|
|
208
243
|
chain: chain.chainInfo,
|
|
209
|
-
transport: fallback(config.l1RpcUrls.map(url => http(url))),
|
|
244
|
+
transport: fallback(config.l1RpcUrls.map(url => http(url, { batch: false }))),
|
|
210
245
|
pollingInterval: config.viemPollingIntervalMS,
|
|
211
246
|
});
|
|
212
247
|
|
|
248
|
+
// Create debug client using debug RPC URLs if available, otherwise fall back to regular RPC URLs
|
|
249
|
+
const debugRpcUrls = config.l1DebugRpcUrls.length > 0 ? config.l1DebugRpcUrls : config.l1RpcUrls;
|
|
250
|
+
const debugClient = createPublicClient({
|
|
251
|
+
chain: chain.chainInfo,
|
|
252
|
+
transport: fallback(debugRpcUrls.map(url => http(url, { batch: false }))),
|
|
253
|
+
pollingInterval: config.viemPollingIntervalMS,
|
|
254
|
+
}) as ViemPublicDebugClient;
|
|
255
|
+
|
|
213
256
|
const rollup = new RollupContract(publicClient, config.l1Contracts.rollupAddress);
|
|
214
257
|
|
|
215
|
-
const [l1StartBlock, l1GenesisTime, proofSubmissionEpochs, genesisArchiveRoot] =
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
258
|
+
const [l1StartBlock, l1GenesisTime, proofSubmissionEpochs, genesisArchiveRoot, slashingProposerAddress] =
|
|
259
|
+
await Promise.all([
|
|
260
|
+
rollup.getL1StartBlock(),
|
|
261
|
+
rollup.getL1GenesisTime(),
|
|
262
|
+
rollup.getProofSubmissionEpochs(),
|
|
263
|
+
rollup.getGenesisArchiveTreeRoot(),
|
|
264
|
+
rollup.getSlashingProposerAddress(),
|
|
265
|
+
] as const);
|
|
221
266
|
|
|
222
267
|
const l1StartBlockHash = await publicClient
|
|
223
268
|
.getBlock({ blockNumber: l1StartBlock, includeTransactions: false })
|
|
@@ -233,11 +278,16 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
233
278
|
slotDuration,
|
|
234
279
|
ethereumSlotDuration,
|
|
235
280
|
proofSubmissionEpochs: Number(proofSubmissionEpochs),
|
|
236
|
-
genesisArchiveRoot: Fr.
|
|
281
|
+
genesisArchiveRoot: Fr.fromString(genesisArchiveRoot.toString()),
|
|
237
282
|
};
|
|
238
283
|
|
|
239
284
|
const opts = merge(
|
|
240
|
-
{
|
|
285
|
+
{
|
|
286
|
+
pollingIntervalMs: 10_000,
|
|
287
|
+
batchSize: 100,
|
|
288
|
+
maxAllowedEthClientDriftSeconds: 300,
|
|
289
|
+
ethereumAllowNoDebugHosts: false,
|
|
290
|
+
},
|
|
241
291
|
mapArchiverConfig(config),
|
|
242
292
|
);
|
|
243
293
|
|
|
@@ -246,10 +296,11 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
246
296
|
|
|
247
297
|
const archiver = new Archiver(
|
|
248
298
|
publicClient,
|
|
249
|
-
|
|
299
|
+
debugClient,
|
|
300
|
+
{ ...config.l1Contracts, slashingProposerAddress },
|
|
250
301
|
archiverStore,
|
|
251
302
|
opts,
|
|
252
|
-
deps.
|
|
303
|
+
deps.blobClient,
|
|
253
304
|
epochCache,
|
|
254
305
|
deps.dateProvider ?? new DateProvider(),
|
|
255
306
|
await ArchiverInstrumentation.new(telemetry, () => archiverStore.estimateSize()),
|
|
@@ -273,16 +324,17 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
273
324
|
throw new Error('Archiver is already running');
|
|
274
325
|
}
|
|
275
326
|
|
|
276
|
-
await this.
|
|
327
|
+
await this.blobClient.testSources();
|
|
277
328
|
await this.testEthereumNodeSynced();
|
|
329
|
+
await validateAndLogTraceAvailability(this.debugClient, this.config.ethereumAllowNoDebugHosts ?? false);
|
|
278
330
|
|
|
279
331
|
// Log initial state for the archiver
|
|
280
332
|
const { l1StartBlock } = this.l1constants;
|
|
281
333
|
const { blocksSynchedTo = l1StartBlock, messagesSynchedTo = l1StartBlock } = await this.store.getSynchPoint();
|
|
282
|
-
const
|
|
334
|
+
const currentL2Checkpoint = await this.getSynchedCheckpointNumber();
|
|
283
335
|
this.log.info(
|
|
284
|
-
`Starting archiver sync to rollup contract ${this.l1Addresses.rollupAddress.toString()} from L1 block ${blocksSynchedTo} and L2
|
|
285
|
-
{ blocksSynchedTo, messagesSynchedTo,
|
|
336
|
+
`Starting archiver sync to rollup contract ${this.l1Addresses.rollupAddress.toString()} from L1 block ${blocksSynchedTo} and L2 checkpoint ${currentL2Checkpoint}`,
|
|
337
|
+
{ blocksSynchedTo, messagesSynchedTo, currentL2Checkpoint },
|
|
286
338
|
);
|
|
287
339
|
|
|
288
340
|
// Start sync loop, and return the wait for initial sync if we are asked to block until synced
|
|
@@ -296,6 +348,51 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
296
348
|
return this.runningPromise.trigger();
|
|
297
349
|
}
|
|
298
350
|
|
|
351
|
+
/**
|
|
352
|
+
* Queues a block to be added to the archiver store and triggers processing.
|
|
353
|
+
* The block will be processed by the sync loop.
|
|
354
|
+
* Implements the L2BlockSink interface.
|
|
355
|
+
* @param block - The L2 block to add.
|
|
356
|
+
* @returns A promise that resolves when the block has been added to the store, or rejects on error.
|
|
357
|
+
*/
|
|
358
|
+
public addBlock(block: L2BlockNew): Promise<void> {
|
|
359
|
+
return new Promise<void>((resolve, reject) => {
|
|
360
|
+
this.blockQueue.push({ block, resolve, reject });
|
|
361
|
+
this.log.debug(`Queued block ${block.number} for processing`);
|
|
362
|
+
// Trigger an immediate sync, but don't wait for it - the promise resolves when the block is processed
|
|
363
|
+
this.syncImmediate().catch(err => {
|
|
364
|
+
this.log.error(`Sync immediate call failed: ${err}`);
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Processes all queued blocks, adding them to the store.
|
|
371
|
+
* Called at the beginning of each sync iteration.
|
|
372
|
+
* Blocks are processed in the order they were queued.
|
|
373
|
+
*/
|
|
374
|
+
private async processQueuedBlocks(): Promise<void> {
|
|
375
|
+
if (this.blockQueue.length === 0) {
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Take all blocks from the queue
|
|
380
|
+
const queuedItems = this.blockQueue.splice(0, this.blockQueue.length);
|
|
381
|
+
this.log.debug(`Processing ${queuedItems.length} queued block(s)`);
|
|
382
|
+
|
|
383
|
+
// Process each block individually to properly resolve/reject each promise
|
|
384
|
+
for (const { block, resolve, reject } of queuedItems) {
|
|
385
|
+
try {
|
|
386
|
+
await this.store.addBlocks([block]);
|
|
387
|
+
this.log.debug(`Added block ${block.number} to store`);
|
|
388
|
+
resolve();
|
|
389
|
+
} catch (err: any) {
|
|
390
|
+
this.log.error(`Failed to add block ${block.number} to store: ${err.message}`);
|
|
391
|
+
reject(err);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
299
396
|
public waitForInitialSync() {
|
|
300
397
|
return this.initialSyncPromise.promise;
|
|
301
398
|
}
|
|
@@ -315,11 +412,8 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
315
412
|
}
|
|
316
413
|
}
|
|
317
414
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
*/
|
|
321
|
-
@trackSpan('Archiver.sync')
|
|
322
|
-
private async sync() {
|
|
415
|
+
@trackSpan('Archiver.syncFromL1')
|
|
416
|
+
private async syncFromL1() {
|
|
323
417
|
/**
|
|
324
418
|
* We keep track of three "pointers" to L1 blocks:
|
|
325
419
|
* 1. the last L1 block that published an L2 block
|
|
@@ -405,7 +499,7 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
405
499
|
// past it, since otherwise we'll keep downloading it and reprocessing it on every iteration until
|
|
406
500
|
// we get a valid checkpoint to advance the syncpoint.
|
|
407
501
|
if (!rollupStatus.validationResult?.valid && rollupStatus.lastL1BlockWithCheckpoint !== undefined) {
|
|
408
|
-
await this.store.
|
|
502
|
+
await this.store.setCheckpointSynchedL1BlockNumber(rollupStatus.lastL1BlockWithCheckpoint);
|
|
409
503
|
}
|
|
410
504
|
|
|
411
505
|
// And lastly we check if we are missing any checkpoints behind us due to a possible L1 reorg.
|
|
@@ -439,6 +533,17 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
439
533
|
}
|
|
440
534
|
}
|
|
441
535
|
|
|
536
|
+
/**
|
|
537
|
+
* Fetches logs from L1 contracts and processes them.
|
|
538
|
+
*/
|
|
539
|
+
@trackSpan('Archiver.sync')
|
|
540
|
+
private async sync() {
|
|
541
|
+
// Process any queued blocks first, before doing L1 sync
|
|
542
|
+
await this.processQueuedBlocks();
|
|
543
|
+
// Now perform L1 sync
|
|
544
|
+
await this.syncFromL1();
|
|
545
|
+
}
|
|
546
|
+
|
|
442
547
|
/** Queries the rollup contract on whether a prune can be executed on the immediate next L1 block. */
|
|
443
548
|
private async canPrune(currentL1BlockNumber: bigint, currentL1Timestamp: bigint) {
|
|
444
549
|
const time = (currentL1Timestamp ?? 0n) + BigInt(this.l1constants.ethereumSlotDuration);
|
|
@@ -454,8 +559,9 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
454
559
|
}
|
|
455
560
|
|
|
456
561
|
/** Checks if there'd be a reorg for the next checkpoint submission and start pruning now. */
|
|
562
|
+
@trackSpan('Archiver.handleEpochPrune')
|
|
457
563
|
private async handleEpochPrune(
|
|
458
|
-
provenCheckpointNumber:
|
|
564
|
+
provenCheckpointNumber: CheckpointNumber,
|
|
459
565
|
currentL1BlockNumber: bigint,
|
|
460
566
|
currentL1Timestamp: bigint,
|
|
461
567
|
) {
|
|
@@ -465,9 +571,9 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
465
571
|
|
|
466
572
|
if (canPrune) {
|
|
467
573
|
const timer = new Timer();
|
|
468
|
-
const pruneFrom = provenCheckpointNumber + 1;
|
|
574
|
+
const pruneFrom = CheckpointNumber(provenCheckpointNumber + 1);
|
|
469
575
|
|
|
470
|
-
const header = await this.getCheckpointHeader(
|
|
576
|
+
const header = await this.getCheckpointHeader(pruneFrom);
|
|
471
577
|
if (header === undefined) {
|
|
472
578
|
throw new Error(`Missing checkpoint header ${pruneFrom}`);
|
|
473
579
|
}
|
|
@@ -477,13 +583,23 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
477
583
|
|
|
478
584
|
const checkpointsToUnwind = localPendingCheckpointNumber - provenCheckpointNumber;
|
|
479
585
|
|
|
480
|
-
const
|
|
586
|
+
const checkpointPromises = Array.from({ length: checkpointsToUnwind })
|
|
587
|
+
.fill(0)
|
|
588
|
+
.map((_, i) => this.store.getCheckpointData(CheckpointNumber(i + pruneFrom)));
|
|
589
|
+
const checkpoints = await Promise.all(checkpointPromises);
|
|
590
|
+
|
|
591
|
+
const blockPromises = await Promise.all(
|
|
592
|
+
checkpoints
|
|
593
|
+
.filter(isDefined)
|
|
594
|
+
.map(cp => this.store.getBlocksForCheckpoint(CheckpointNumber(cp.checkpointNumber))),
|
|
595
|
+
);
|
|
596
|
+
const newBlocks = blockPromises.filter(isDefined).flat();
|
|
481
597
|
|
|
482
598
|
// Emit an event for listening services to react to the chain prune
|
|
483
599
|
this.emit(L2BlockSourceEvents.L2PruneDetected, {
|
|
484
600
|
type: L2BlockSourceEvents.L2PruneDetected,
|
|
485
601
|
epochNumber: pruneFromEpochNumber,
|
|
486
|
-
blocks:
|
|
602
|
+
blocks: newBlocks,
|
|
487
603
|
});
|
|
488
604
|
|
|
489
605
|
this.log.debug(
|
|
@@ -514,6 +630,7 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
514
630
|
return [nextStart, nextEnd];
|
|
515
631
|
}
|
|
516
632
|
|
|
633
|
+
@trackSpan('Archiver.handleL1ToL2Messages')
|
|
517
634
|
private async handleL1ToL2Messages(
|
|
518
635
|
messagesSyncPoint: L1BlockId,
|
|
519
636
|
currentL1BlockNumber: bigint,
|
|
@@ -594,7 +711,7 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
594
711
|
// Log stats for messages retrieved (if any).
|
|
595
712
|
if (messageCount > 0) {
|
|
596
713
|
this.log.info(
|
|
597
|
-
`Retrieved ${messageCount} new L1 to L2 messages up to message with index ${lastMessage?.index} for
|
|
714
|
+
`Retrieved ${messageCount} new L1 to L2 messages up to message with index ${lastMessage?.index} for checkpoint ${lastMessage?.checkpointNumber}`,
|
|
598
715
|
{ lastMessage, messageCount },
|
|
599
716
|
);
|
|
600
717
|
}
|
|
@@ -672,23 +789,25 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
672
789
|
return Buffer32.fromString(block.hash);
|
|
673
790
|
}
|
|
674
791
|
|
|
792
|
+
@trackSpan('Archiver.handleCheckpoints')
|
|
675
793
|
private async handleCheckpoints(blocksSynchedTo: bigint, currentL1BlockNumber: bigint): Promise<RollupStatus> {
|
|
676
794
|
const localPendingCheckpointNumber = await this.getSynchedCheckpointNumber();
|
|
677
|
-
const initialValidationResult:
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
provenArchive,
|
|
681
|
-
rollupPendingCheckpointNumber,
|
|
682
|
-
pendingArchive,
|
|
683
|
-
archiveForLocalPendingCheckpointNumber,
|
|
684
|
-
] = await this.rollup.status(BigInt(localPendingCheckpointNumber), { blockNumber: currentL1BlockNumber });
|
|
685
|
-
const provenCheckpointNumber = Number(rollupProvenCheckpointNumber);
|
|
686
|
-
const pendingCheckpointNumber = Number(rollupPendingCheckpointNumber);
|
|
687
|
-
const rollupStatus = {
|
|
795
|
+
const initialValidationResult: ValidateCheckpointResult | undefined =
|
|
796
|
+
await this.store.getPendingChainValidationStatus();
|
|
797
|
+
const {
|
|
688
798
|
provenCheckpointNumber,
|
|
689
799
|
provenArchive,
|
|
690
800
|
pendingCheckpointNumber,
|
|
691
801
|
pendingArchive,
|
|
802
|
+
archiveOfMyCheckpoint: archiveForLocalPendingCheckpointNumber,
|
|
803
|
+
} = await execInSpan(this.tracer, 'Archiver.getRollupStatus', () =>
|
|
804
|
+
this.rollup.status(localPendingCheckpointNumber, { blockNumber: currentL1BlockNumber }),
|
|
805
|
+
);
|
|
806
|
+
const rollupStatus: RollupStatus = {
|
|
807
|
+
provenCheckpointNumber,
|
|
808
|
+
provenArchive: provenArchive.toString(),
|
|
809
|
+
pendingCheckpointNumber,
|
|
810
|
+
pendingArchive: pendingArchive.toString(),
|
|
692
811
|
validationResult: initialValidationResult,
|
|
693
812
|
};
|
|
694
813
|
this.log.trace(`Retrieved rollup status at current L1 block ${currentL1BlockNumber}.`, {
|
|
@@ -711,17 +830,18 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
711
830
|
}
|
|
712
831
|
}
|
|
713
832
|
|
|
714
|
-
const localCheckpointForDestinationProvenCheckpointNumber =
|
|
833
|
+
const localCheckpointForDestinationProvenCheckpointNumber =
|
|
834
|
+
await this.store.getCheckpointData(provenCheckpointNumber);
|
|
715
835
|
|
|
716
836
|
// Sanity check. I've hit what seems to be a state where the proven checkpoint is set to a value greater than the latest
|
|
717
837
|
// synched checkpoint when requesting L2Tips from the archiver. This is the only place where the proven checkpoint is set.
|
|
718
838
|
const synched = await this.getSynchedCheckpointNumber();
|
|
719
839
|
if (
|
|
720
840
|
localCheckpointForDestinationProvenCheckpointNumber &&
|
|
721
|
-
synched < localCheckpointForDestinationProvenCheckpointNumber.
|
|
841
|
+
synched < localCheckpointForDestinationProvenCheckpointNumber.checkpointNumber
|
|
722
842
|
) {
|
|
723
843
|
this.log.error(
|
|
724
|
-
`Hit local checkpoint greater than last synched checkpoint: ${localCheckpointForDestinationProvenCheckpointNumber.
|
|
844
|
+
`Hit local checkpoint greater than last synched checkpoint: ${localCheckpointForDestinationProvenCheckpointNumber.checkpointNumber} > ${synched}`,
|
|
725
845
|
);
|
|
726
846
|
}
|
|
727
847
|
|
|
@@ -731,38 +851,39 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
731
851
|
}`,
|
|
732
852
|
);
|
|
733
853
|
|
|
734
|
-
const lastProvenBlockNumber = await this.getLastBlockNumberInCheckpoint(provenCheckpointNumber);
|
|
735
854
|
if (
|
|
736
855
|
localCheckpointForDestinationProvenCheckpointNumber &&
|
|
737
|
-
provenArchive
|
|
856
|
+
provenArchive.equals(localCheckpointForDestinationProvenCheckpointNumber.archive.root)
|
|
738
857
|
) {
|
|
739
858
|
const localProvenCheckpointNumber = await this.getProvenCheckpointNumber();
|
|
740
859
|
if (localProvenCheckpointNumber !== provenCheckpointNumber) {
|
|
741
860
|
await this.setProvenCheckpointNumber(provenCheckpointNumber);
|
|
742
|
-
this.log.info(`Updated proven chain to checkpoint ${provenCheckpointNumber}`, {
|
|
743
|
-
provenCheckpointNumber,
|
|
744
|
-
});
|
|
861
|
+
this.log.info(`Updated proven chain to checkpoint ${provenCheckpointNumber}`, { provenCheckpointNumber });
|
|
745
862
|
const provenSlotNumber = localCheckpointForDestinationProvenCheckpointNumber.header.slotNumber;
|
|
746
863
|
const provenEpochNumber: EpochNumber = getEpochAtSlot(provenSlotNumber, this.l1constants);
|
|
864
|
+
const lastBlockNumberInCheckpoint =
|
|
865
|
+
localCheckpointForDestinationProvenCheckpointNumber.startBlock +
|
|
866
|
+
localCheckpointForDestinationProvenCheckpointNumber.numBlocks -
|
|
867
|
+
1;
|
|
747
868
|
|
|
748
869
|
this.emit(L2BlockSourceEvents.L2BlockProven, {
|
|
749
870
|
type: L2BlockSourceEvents.L2BlockProven,
|
|
750
|
-
blockNumber:
|
|
871
|
+
blockNumber: BlockNumber(lastBlockNumberInCheckpoint),
|
|
751
872
|
slotNumber: provenSlotNumber,
|
|
752
873
|
epochNumber: provenEpochNumber,
|
|
753
874
|
});
|
|
875
|
+
this.instrumentation.updateLastProvenBlock(lastBlockNumberInCheckpoint);
|
|
754
876
|
} else {
|
|
755
877
|
this.log.trace(`Proven checkpoint ${provenCheckpointNumber} already stored.`);
|
|
756
878
|
}
|
|
757
879
|
}
|
|
758
|
-
this.instrumentation.updateLastProvenBlock(lastProvenBlockNumber);
|
|
759
880
|
};
|
|
760
881
|
|
|
761
882
|
// This is an edge case that we only hit if there are no proposed checkpoints.
|
|
762
883
|
// If we have 0 checkpoints locally and there are no checkpoints onchain there is nothing to do.
|
|
763
884
|
const noCheckpoints = localPendingCheckpointNumber === 0 && pendingCheckpointNumber === 0;
|
|
764
885
|
if (noCheckpoints) {
|
|
765
|
-
await this.store.
|
|
886
|
+
await this.store.setCheckpointSynchedL1BlockNumber(currentL1BlockNumber);
|
|
766
887
|
this.log.debug(
|
|
767
888
|
`No checkpoints to retrieve from ${blocksSynchedTo + 1n} to ${currentL1BlockNumber}, no checkpoints on chain`,
|
|
768
889
|
);
|
|
@@ -774,13 +895,13 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
774
895
|
// Related to the L2 reorgs of the pending chain. We are only interested in actually addressing a reorg if there
|
|
775
896
|
// are any state that could be impacted by it. If we have no checkpoints, there is no impact.
|
|
776
897
|
if (localPendingCheckpointNumber > 0) {
|
|
777
|
-
const localPendingCheckpoint = await this.
|
|
898
|
+
const localPendingCheckpoint = await this.store.getCheckpointData(localPendingCheckpointNumber);
|
|
778
899
|
if (localPendingCheckpoint === undefined) {
|
|
779
900
|
throw new Error(`Missing checkpoint ${localPendingCheckpointNumber}`);
|
|
780
901
|
}
|
|
781
902
|
|
|
782
903
|
const localPendingArchiveRoot = localPendingCheckpoint.archive.root.toString();
|
|
783
|
-
const noCheckpointSinceLast = localPendingCheckpoint && pendingArchive === localPendingArchiveRoot;
|
|
904
|
+
const noCheckpointSinceLast = localPendingCheckpoint && pendingArchive.toString() === localPendingArchiveRoot;
|
|
784
905
|
if (noCheckpointSinceLast) {
|
|
785
906
|
// We believe the following line causes a problem when we encounter L1 re-orgs.
|
|
786
907
|
// Basically, by setting the synched L1 block number here, we are saying that we have
|
|
@@ -794,7 +915,9 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
794
915
|
return rollupStatus;
|
|
795
916
|
}
|
|
796
917
|
|
|
797
|
-
const localPendingCheckpointInChain = archiveForLocalPendingCheckpointNumber
|
|
918
|
+
const localPendingCheckpointInChain = archiveForLocalPendingCheckpointNumber.equals(
|
|
919
|
+
localPendingCheckpoint.archive.root,
|
|
920
|
+
);
|
|
798
921
|
if (!localPendingCheckpointInChain) {
|
|
799
922
|
// If our local pending checkpoint tip is not in the chain on L1 a "prune" must have happened
|
|
800
923
|
// or the L1 have reorged.
|
|
@@ -807,20 +930,20 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
807
930
|
|
|
808
931
|
let tipAfterUnwind = localPendingCheckpointNumber;
|
|
809
932
|
while (true) {
|
|
810
|
-
const candidateCheckpoint = await this.
|
|
933
|
+
const candidateCheckpoint = await this.store.getCheckpointData(tipAfterUnwind);
|
|
811
934
|
if (candidateCheckpoint === undefined) {
|
|
812
935
|
break;
|
|
813
936
|
}
|
|
814
937
|
|
|
815
|
-
const archiveAtContract = await this.rollup.archiveAt(
|
|
938
|
+
const archiveAtContract = await this.rollup.archiveAt(candidateCheckpoint.checkpointNumber);
|
|
816
939
|
this.log.trace(
|
|
817
|
-
`Checking local checkpoint ${candidateCheckpoint.
|
|
940
|
+
`Checking local checkpoint ${candidateCheckpoint.checkpointNumber} with archive ${candidateCheckpoint.archive.root}`,
|
|
818
941
|
{
|
|
819
942
|
archiveAtContract,
|
|
820
943
|
archiveLocal: candidateCheckpoint.archive.root.toString(),
|
|
821
944
|
},
|
|
822
945
|
);
|
|
823
|
-
if (archiveAtContract
|
|
946
|
+
if (archiveAtContract.equals(candidateCheckpoint.archive.root)) {
|
|
824
947
|
break;
|
|
825
948
|
}
|
|
826
949
|
tipAfterUnwind--;
|
|
@@ -849,14 +972,20 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
849
972
|
|
|
850
973
|
this.log.trace(`Retrieving checkpoints from L1 block ${searchStartBlock} to ${searchEndBlock}`);
|
|
851
974
|
|
|
852
|
-
// TODO(md): Retrieve from blob
|
|
853
|
-
const retrievedCheckpoints = await retrieveCheckpointsFromRollup(
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
975
|
+
// TODO(md): Retrieve from blob client then from consensus client, then from peers
|
|
976
|
+
const retrievedCheckpoints = await execInSpan(this.tracer, 'Archiver.retrieveCheckpointsFromRollup', () =>
|
|
977
|
+
retrieveCheckpointsFromRollup(
|
|
978
|
+
this.rollup.getContract() as GetContractReturnType<typeof RollupAbi, ViemPublicClient>,
|
|
979
|
+
this.publicClient,
|
|
980
|
+
this.debugClient,
|
|
981
|
+
this.blobClient,
|
|
982
|
+
searchStartBlock, // TODO(palla/reorg): If the L2 reorg was due to an L1 reorg, we need to start search earlier
|
|
983
|
+
searchEndBlock,
|
|
984
|
+
this.l1Addresses,
|
|
985
|
+
this.instrumentation,
|
|
986
|
+
this.log,
|
|
987
|
+
!this.initialSyncComplete, // isHistoricalSync
|
|
988
|
+
),
|
|
860
989
|
);
|
|
861
990
|
|
|
862
991
|
if (retrievedCheckpoints.length === 0) {
|
|
@@ -879,7 +1008,7 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
879
1008
|
const validCheckpoints: PublishedCheckpoint[] = [];
|
|
880
1009
|
|
|
881
1010
|
for (const published of publishedCheckpoints) {
|
|
882
|
-
const validationResult = this.config.
|
|
1011
|
+
const validationResult = this.config.skipValidateCheckpointAttestations
|
|
883
1012
|
? { valid: true as const }
|
|
884
1013
|
: await validateCheckpointAttestations(published, this.epochCache, this.l1constants, this.log);
|
|
885
1014
|
|
|
@@ -892,7 +1021,7 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
892
1021
|
rollupStatus.validationResult?.valid !== validationResult.valid ||
|
|
893
1022
|
(!rollupStatus.validationResult.valid &&
|
|
894
1023
|
!validationResult.valid &&
|
|
895
|
-
rollupStatus.validationResult.
|
|
1024
|
+
rollupStatus.validationResult.checkpoint.checkpointNumber === validationResult.checkpoint.checkpointNumber)
|
|
896
1025
|
) {
|
|
897
1026
|
rollupStatus.validationResult = validationResult;
|
|
898
1027
|
}
|
|
@@ -904,9 +1033,9 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
904
1033
|
...pick(validationResult, 'reason'),
|
|
905
1034
|
});
|
|
906
1035
|
|
|
907
|
-
// Emit event for invalid
|
|
908
|
-
this.emit(L2BlockSourceEvents.
|
|
909
|
-
type: L2BlockSourceEvents.
|
|
1036
|
+
// Emit event for invalid checkpoint detection
|
|
1037
|
+
this.emit(L2BlockSourceEvents.InvalidAttestationsCheckpointDetected, {
|
|
1038
|
+
type: L2BlockSourceEvents.InvalidAttestationsCheckpointDetected,
|
|
910
1039
|
validationResult,
|
|
911
1040
|
});
|
|
912
1041
|
|
|
@@ -916,6 +1045,25 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
916
1045
|
continue;
|
|
917
1046
|
}
|
|
918
1047
|
|
|
1048
|
+
// Check the inHash of the checkpoint against the l1->l2 messages.
|
|
1049
|
+
// The messages should've been synced up to the currentL1BlockNumber and must be available for the published
|
|
1050
|
+
// checkpoints we just retrieved.
|
|
1051
|
+
const l1ToL2Messages = await this.getL1ToL2Messages(published.checkpoint.number);
|
|
1052
|
+
const computedInHash = computeInHashFromL1ToL2Messages(l1ToL2Messages);
|
|
1053
|
+
const publishedInHash = published.checkpoint.header.inHash;
|
|
1054
|
+
if (!computedInHash.equals(publishedInHash)) {
|
|
1055
|
+
this.log.fatal(`Mismatch inHash for checkpoint ${published.checkpoint.number}`, {
|
|
1056
|
+
checkpointHash: published.checkpoint.hash(),
|
|
1057
|
+
l1BlockNumber: published.l1.blockNumber,
|
|
1058
|
+
computedInHash,
|
|
1059
|
+
publishedInHash,
|
|
1060
|
+
});
|
|
1061
|
+
// Throwing an error since this is most likely caused by a bug.
|
|
1062
|
+
throw new Error(
|
|
1063
|
+
`Mismatch inHash for checkpoint ${published.checkpoint.number}. Expected ${computedInHash} but got ${publishedInHash}`,
|
|
1064
|
+
);
|
|
1065
|
+
}
|
|
1066
|
+
|
|
919
1067
|
validCheckpoints.push(published);
|
|
920
1068
|
this.log.debug(
|
|
921
1069
|
`Ingesting new checkpoint ${published.checkpoint.number} with ${published.checkpoint.blocks.length} blocks`,
|
|
@@ -931,25 +1079,28 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
931
1079
|
try {
|
|
932
1080
|
const updatedValidationResult =
|
|
933
1081
|
rollupStatus.validationResult === initialValidationResult ? undefined : rollupStatus.validationResult;
|
|
934
|
-
const [processDuration] = await elapsed(() =>
|
|
1082
|
+
const [processDuration] = await elapsed(() =>
|
|
1083
|
+
execInSpan(this.tracer, 'Archiver.addCheckpoints', () =>
|
|
1084
|
+
this.addCheckpoints(validCheckpoints, updatedValidationResult),
|
|
1085
|
+
),
|
|
1086
|
+
);
|
|
935
1087
|
this.instrumentation.processNewBlocks(
|
|
936
1088
|
processDuration / validCheckpoints.length,
|
|
937
1089
|
validCheckpoints.flatMap(c => c.checkpoint.blocks),
|
|
938
1090
|
);
|
|
939
1091
|
} catch (err) {
|
|
940
|
-
if (err instanceof
|
|
941
|
-
const {
|
|
942
|
-
const
|
|
943
|
-
? await this.store.
|
|
1092
|
+
if (err instanceof InitialCheckpointNumberNotSequentialError) {
|
|
1093
|
+
const { previousCheckpointNumber, newCheckpointNumber } = err;
|
|
1094
|
+
const previousCheckpoint = previousCheckpointNumber
|
|
1095
|
+
? await this.store.getCheckpointData(CheckpointNumber(previousCheckpointNumber))
|
|
944
1096
|
: undefined;
|
|
945
|
-
const updatedL1SyncPoint =
|
|
1097
|
+
const updatedL1SyncPoint = previousCheckpoint?.l1.blockNumber ?? this.l1constants.l1StartBlock;
|
|
946
1098
|
await this.store.setBlockSynchedL1BlockNumber(updatedL1SyncPoint);
|
|
947
1099
|
this.log.warn(
|
|
948
|
-
`Attempting to insert
|
|
1100
|
+
`Attempting to insert checkpoint ${newCheckpointNumber} with previous block ${previousCheckpointNumber}. Rolling back L1 sync point to ${updatedL1SyncPoint} to try and fetch the missing blocks.`,
|
|
949
1101
|
{
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
newBlockNumber,
|
|
1102
|
+
previousCheckpointNumber,
|
|
1103
|
+
newCheckpointNumber,
|
|
953
1104
|
updatedL1SyncPoint,
|
|
954
1105
|
},
|
|
955
1106
|
);
|
|
@@ -969,7 +1120,7 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
969
1120
|
});
|
|
970
1121
|
}
|
|
971
1122
|
lastRetrievedCheckpoint = validCheckpoints.at(-1) ?? lastRetrievedCheckpoint;
|
|
972
|
-
lastL1BlockWithCheckpoint =
|
|
1123
|
+
lastL1BlockWithCheckpoint = retrievedCheckpoints.at(-1)?.l1.blockNumber ?? lastL1BlockWithCheckpoint;
|
|
973
1124
|
} while (searchEndBlock < currentL1BlockNumber);
|
|
974
1125
|
|
|
975
1126
|
// Important that we update AFTER inserting the blocks.
|
|
@@ -994,13 +1145,16 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
994
1145
|
// We suspect an L1 reorg that added checkpoints *behind* us. If that is the case, it must have happened between
|
|
995
1146
|
// the last checkpoint we saw and the current one, so we reset the last synched L1 block number. In the edge case
|
|
996
1147
|
// we don't have one, we go back 2 L1 epochs, which is the deepest possible reorg (assuming Casper is working).
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1148
|
+
let latestLocalCheckpointArchive: string | undefined = undefined;
|
|
1149
|
+
let targetL1BlockNumber = maxBigint(currentL1BlockNumber - 64n, 0n);
|
|
1150
|
+
if (lastRetrievedCheckpoint) {
|
|
1151
|
+
latestLocalCheckpointArchive = lastRetrievedCheckpoint.checkpoint.archive.root.toString();
|
|
1152
|
+
targetL1BlockNumber = lastRetrievedCheckpoint.l1.blockNumber;
|
|
1153
|
+
} else if (latestLocalCheckpointNumber > 0) {
|
|
1154
|
+
const checkpoint = await this.store.getRangeOfCheckpoints(latestLocalCheckpointNumber, 1).then(([c]) => c);
|
|
1155
|
+
latestLocalCheckpointArchive = checkpoint.archive.root.toString();
|
|
1156
|
+
targetL1BlockNumber = checkpoint.l1.blockNumber;
|
|
1157
|
+
}
|
|
1004
1158
|
this.log.warn(
|
|
1005
1159
|
`Failed to reach checkpoint ${pendingCheckpointNumber} at ${currentL1BlockNumber} (latest is ${latestLocalCheckpointNumber}). ` +
|
|
1006
1160
|
`Rolling back last synched L1 block number to ${targetL1BlockNumber}.`,
|
|
@@ -1086,15 +1240,22 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
1086
1240
|
const [start, end] = getSlotRangeForEpoch(epochNumber, this.l1constants);
|
|
1087
1241
|
const blocks: L2Block[] = [];
|
|
1088
1242
|
|
|
1089
|
-
// Walk the list of
|
|
1090
|
-
// We'll typically ask for
|
|
1091
|
-
let
|
|
1092
|
-
const slot = (b:
|
|
1093
|
-
while (
|
|
1094
|
-
if (slot(
|
|
1095
|
-
blocks
|
|
1243
|
+
// Walk the list of checkpoints backwards and filter by slots matching the requested epoch.
|
|
1244
|
+
// We'll typically ask for checkpoints for a very recent epoch, so we shouldn't need an index here.
|
|
1245
|
+
let checkpoint = await this.store.getCheckpointData(await this.store.getSynchedCheckpointNumber());
|
|
1246
|
+
const slot = (b: CheckpointData) => b.header.slotNumber;
|
|
1247
|
+
while (checkpoint && slot(checkpoint) >= start) {
|
|
1248
|
+
if (slot(checkpoint) <= end) {
|
|
1249
|
+
// push the blocks on backwards
|
|
1250
|
+
const endBlock = checkpoint.startBlock + checkpoint.numBlocks - 1;
|
|
1251
|
+
for (let i = endBlock; i >= checkpoint.startBlock; i--) {
|
|
1252
|
+
const block = await this.getBlock(BlockNumber(i));
|
|
1253
|
+
if (block) {
|
|
1254
|
+
blocks.push(block);
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1096
1257
|
}
|
|
1097
|
-
|
|
1258
|
+
checkpoint = await this.store.getCheckpointData(CheckpointNumber(checkpoint.checkpointNumber - 1));
|
|
1098
1259
|
}
|
|
1099
1260
|
|
|
1100
1261
|
return blocks.reverse();
|
|
@@ -1104,16 +1265,22 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
1104
1265
|
const [start, end] = getSlotRangeForEpoch(epochNumber, this.l1constants);
|
|
1105
1266
|
const blocks: BlockHeader[] = [];
|
|
1106
1267
|
|
|
1107
|
-
// Walk the list of
|
|
1108
|
-
// We'll typically ask for
|
|
1109
|
-
let
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1268
|
+
// Walk the list of checkpoints backwards and filter by slots matching the requested epoch.
|
|
1269
|
+
// We'll typically ask for checkpoints for a very recent epoch, so we shouldn't need an index here.
|
|
1270
|
+
let checkpoint = await this.store.getCheckpointData(await this.store.getSynchedCheckpointNumber());
|
|
1271
|
+
const slot = (b: CheckpointData) => b.header.slotNumber;
|
|
1272
|
+
while (checkpoint && slot(checkpoint) >= start) {
|
|
1273
|
+
if (slot(checkpoint) <= end) {
|
|
1274
|
+
// push the blocks on backwards
|
|
1275
|
+
const endBlock = checkpoint.startBlock + checkpoint.numBlocks - 1;
|
|
1276
|
+
for (let i = endBlock; i >= checkpoint.startBlock; i--) {
|
|
1277
|
+
const block = await this.getBlockHeader(BlockNumber(i));
|
|
1278
|
+
if (block) {
|
|
1279
|
+
blocks.push(block);
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1115
1282
|
}
|
|
1116
|
-
|
|
1283
|
+
checkpoint = await this.store.getCheckpointData(CheckpointNumber(checkpoint.checkpointNumber - 1));
|
|
1117
1284
|
}
|
|
1118
1285
|
return blocks.reverse();
|
|
1119
1286
|
}
|
|
@@ -1151,102 +1318,53 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
1151
1318
|
return this.initialSyncComplete;
|
|
1152
1319
|
}
|
|
1153
1320
|
|
|
1154
|
-
public async
|
|
1155
|
-
|
|
1156
|
-
return blocks.map(b => b.toPublishedCheckpoint());
|
|
1157
|
-
}
|
|
1158
|
-
|
|
1159
|
-
public async getCheckpoints(from: number, limit: number, proven?: boolean): Promise<Checkpoint[]> {
|
|
1160
|
-
const published = await this.getPublishedCheckpoints(from, limit, proven);
|
|
1161
|
-
return published.map(p => p.checkpoint);
|
|
1162
|
-
}
|
|
1163
|
-
|
|
1164
|
-
public async getCheckpoint(number: number): Promise<Checkpoint | undefined> {
|
|
1165
|
-
if (number < 0) {
|
|
1321
|
+
public async getCheckpointHeader(number: CheckpointNumber | 'latest'): Promise<CheckpointHeader | undefined> {
|
|
1322
|
+
if (number === 'latest') {
|
|
1166
1323
|
number = await this.getSynchedCheckpointNumber();
|
|
1167
1324
|
}
|
|
1168
1325
|
if (number === 0) {
|
|
1169
1326
|
return undefined;
|
|
1170
1327
|
}
|
|
1171
|
-
const
|
|
1172
|
-
|
|
1173
|
-
}
|
|
1174
|
-
|
|
1175
|
-
public async getCheckpointHeader(number: number | 'latest'): Promise<CheckpointHeader | undefined> {
|
|
1176
|
-
if (number === 'latest') {
|
|
1177
|
-
number = await this.getSynchedCheckpointNumber();
|
|
1178
|
-
}
|
|
1179
|
-
if (number === 0) {
|
|
1328
|
+
const checkpoint = await this.store.getCheckpointData(number);
|
|
1329
|
+
if (!checkpoint) {
|
|
1180
1330
|
return undefined;
|
|
1181
1331
|
}
|
|
1182
|
-
|
|
1183
|
-
return checkpoint?.header;
|
|
1332
|
+
return checkpoint.header;
|
|
1184
1333
|
}
|
|
1185
1334
|
|
|
1186
|
-
public getCheckpointNumber(): Promise<
|
|
1335
|
+
public getCheckpointNumber(): Promise<CheckpointNumber> {
|
|
1187
1336
|
return this.getSynchedCheckpointNumber();
|
|
1188
1337
|
}
|
|
1189
1338
|
|
|
1190
|
-
public getSynchedCheckpointNumber(): Promise<
|
|
1191
|
-
|
|
1192
|
-
return this.store.getSynchedL2BlockNumber();
|
|
1339
|
+
public getSynchedCheckpointNumber(): Promise<CheckpointNumber> {
|
|
1340
|
+
return this.store.getSynchedCheckpointNumber();
|
|
1193
1341
|
}
|
|
1194
1342
|
|
|
1195
|
-
public getProvenCheckpointNumber(): Promise<
|
|
1196
|
-
|
|
1197
|
-
return this.store.getProvenL2BlockNumber();
|
|
1343
|
+
public getProvenCheckpointNumber(): Promise<CheckpointNumber> {
|
|
1344
|
+
return this.store.getProvenCheckpointNumber();
|
|
1198
1345
|
}
|
|
1199
1346
|
|
|
1200
|
-
public setProvenCheckpointNumber(checkpointNumber:
|
|
1201
|
-
|
|
1202
|
-
return this.store.setProvenL2BlockNumber(checkpointNumber);
|
|
1347
|
+
public setProvenCheckpointNumber(checkpointNumber: CheckpointNumber): Promise<void> {
|
|
1348
|
+
return this.store.setProvenCheckpointNumber(checkpointNumber);
|
|
1203
1349
|
}
|
|
1204
1350
|
|
|
1205
|
-
public unwindCheckpoints(from:
|
|
1206
|
-
|
|
1207
|
-
return this.store.unwindBlocks(from, checkpointsToUnwind);
|
|
1351
|
+
public unwindCheckpoints(from: CheckpointNumber, checkpointsToUnwind: number): Promise<boolean> {
|
|
1352
|
+
return this.store.unwindCheckpoints(from, checkpointsToUnwind);
|
|
1208
1353
|
}
|
|
1209
1354
|
|
|
1210
|
-
public getLastBlockNumberInCheckpoint(checkpointNumber:
|
|
1211
|
-
|
|
1212
|
-
|
|
1355
|
+
public async getLastBlockNumberInCheckpoint(checkpointNumber: CheckpointNumber): Promise<BlockNumber | undefined> {
|
|
1356
|
+
const checkpointData = await this.store.getCheckpointData(checkpointNumber);
|
|
1357
|
+
if (!checkpointData) {
|
|
1358
|
+
return undefined;
|
|
1359
|
+
}
|
|
1360
|
+
return BlockNumber(checkpointData.startBlock + checkpointData.numBlocks - 1);
|
|
1213
1361
|
}
|
|
1214
1362
|
|
|
1215
1363
|
public addCheckpoints(
|
|
1216
1364
|
checkpoints: PublishedCheckpoint[],
|
|
1217
|
-
pendingChainValidationStatus?:
|
|
1365
|
+
pendingChainValidationStatus?: ValidateCheckpointResult,
|
|
1218
1366
|
): Promise<boolean> {
|
|
1219
|
-
return this.store.
|
|
1220
|
-
checkpoints.map(p => PublishedL2Block.fromPublishedCheckpoint(p)),
|
|
1221
|
-
pendingChainValidationStatus,
|
|
1222
|
-
);
|
|
1223
|
-
}
|
|
1224
|
-
|
|
1225
|
-
/**
|
|
1226
|
-
* Gets up to `limit` amount of L2 blocks starting from `from`.
|
|
1227
|
-
* @param from - Number of the first block to return (inclusive).
|
|
1228
|
-
* @param limit - The number of blocks to return.
|
|
1229
|
-
* @param proven - If true, only return blocks that have been proven.
|
|
1230
|
-
* @returns The requested L2 blocks.
|
|
1231
|
-
*/
|
|
1232
|
-
public getBlocks(from: number, limit: number, proven?: boolean): Promise<L2Block[]> {
|
|
1233
|
-
return this.getPublishedBlocks(from, limit, proven).then(blocks => blocks.map(b => b.block));
|
|
1234
|
-
}
|
|
1235
|
-
|
|
1236
|
-
/** Equivalent to getBlocks but includes publish data. */
|
|
1237
|
-
public async getPublishedBlocks(from: number, limit: number, proven?: boolean): Promise<PublishedL2Block[]> {
|
|
1238
|
-
const limitWithProven = proven
|
|
1239
|
-
? Math.min(limit, Math.max((await this.store.getProvenL2BlockNumber()) - from + 1, 0))
|
|
1240
|
-
: limit;
|
|
1241
|
-
return limitWithProven === 0 ? [] : await this.store.getPublishedBlocks(from, limitWithProven);
|
|
1242
|
-
}
|
|
1243
|
-
|
|
1244
|
-
public getPublishedBlockByHash(blockHash: Fr): Promise<PublishedL2Block | undefined> {
|
|
1245
|
-
return this.store.getPublishedBlockByHash(blockHash);
|
|
1246
|
-
}
|
|
1247
|
-
|
|
1248
|
-
public getPublishedBlockByArchive(archive: Fr): Promise<PublishedL2Block | undefined> {
|
|
1249
|
-
return this.store.getPublishedBlockByArchive(archive);
|
|
1367
|
+
return this.store.addCheckpoints(checkpoints, pendingChainValidationStatus);
|
|
1250
1368
|
}
|
|
1251
1369
|
|
|
1252
1370
|
public getBlockHeaderByHash(blockHash: Fr): Promise<BlockHeader | undefined> {
|
|
@@ -1262,7 +1380,7 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
1262
1380
|
* @param number - The block number to return.
|
|
1263
1381
|
* @returns The requested L2 block.
|
|
1264
1382
|
*/
|
|
1265
|
-
public async
|
|
1383
|
+
public async getL2BlockNew(number: BlockNumber): Promise<L2BlockNew | undefined> {
|
|
1266
1384
|
// If the number provided is -ve, then return the latest block.
|
|
1267
1385
|
if (number < 0) {
|
|
1268
1386
|
number = await this.store.getSynchedL2BlockNumber();
|
|
@@ -1270,11 +1388,21 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
1270
1388
|
if (number === 0) {
|
|
1271
1389
|
return undefined;
|
|
1272
1390
|
}
|
|
1273
|
-
const publishedBlock = await this.store.
|
|
1274
|
-
return publishedBlock
|
|
1391
|
+
const publishedBlock = await this.store.store.getBlock(number);
|
|
1392
|
+
return publishedBlock;
|
|
1275
1393
|
}
|
|
1276
1394
|
|
|
1277
|
-
public async
|
|
1395
|
+
public async getL2BlocksNew(from: BlockNumber, limit: number, proven?: boolean): Promise<L2BlockNew[]> {
|
|
1396
|
+
const blocks = await this.store.store.getBlocks(from, limit);
|
|
1397
|
+
|
|
1398
|
+
if (proven === true) {
|
|
1399
|
+
const provenBlockNumber = await this.store.getProvenBlockNumber();
|
|
1400
|
+
return blocks.filter(b => b.number <= provenBlockNumber);
|
|
1401
|
+
}
|
|
1402
|
+
return blocks;
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
public async getBlockHeader(number: BlockNumber | 'latest'): Promise<BlockHeader | undefined> {
|
|
1278
1406
|
if (number === 'latest') {
|
|
1279
1407
|
number = await this.store.getSynchedL2BlockNumber();
|
|
1280
1408
|
}
|
|
@@ -1285,6 +1413,38 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
1285
1413
|
return headers.length === 0 ? undefined : headers[0];
|
|
1286
1414
|
}
|
|
1287
1415
|
|
|
1416
|
+
getCheckpointedBlock(number: BlockNumber): Promise<CheckpointedL2Block | undefined> {
|
|
1417
|
+
return this.store.getCheckpointedBlock(number);
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
public async getCheckpointedBlocks(
|
|
1421
|
+
from: BlockNumber,
|
|
1422
|
+
limit: number,
|
|
1423
|
+
proven?: boolean,
|
|
1424
|
+
): Promise<CheckpointedL2Block[]> {
|
|
1425
|
+
const blocks = await this.store.store.getCheckpointedBlocks(from, limit);
|
|
1426
|
+
|
|
1427
|
+
if (proven === true) {
|
|
1428
|
+
const provenBlockNumber = await this.store.getProvenBlockNumber();
|
|
1429
|
+
return blocks.filter(b => b.block.number <= provenBlockNumber);
|
|
1430
|
+
}
|
|
1431
|
+
return blocks;
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
getCheckpointedBlockByHash(blockHash: Fr): Promise<CheckpointedL2Block | undefined> {
|
|
1435
|
+
return this.store.getCheckpointedBlockByHash(blockHash);
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
getProvenBlockNumber(): Promise<BlockNumber> {
|
|
1439
|
+
return this.store.getProvenBlockNumber();
|
|
1440
|
+
}
|
|
1441
|
+
getCheckpointedBlockNumber(): Promise<BlockNumber> {
|
|
1442
|
+
return this.store.getCheckpointedL2BlockNumber();
|
|
1443
|
+
}
|
|
1444
|
+
getCheckpointedBlockByArchive(archive: Fr): Promise<CheckpointedL2Block | undefined> {
|
|
1445
|
+
return this.store.getCheckpointedBlockByArchive(archive);
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1288
1448
|
public getTxEffect(txHash: TxHash) {
|
|
1289
1449
|
return this.store.getTxEffect(txHash);
|
|
1290
1450
|
}
|
|
@@ -1293,24 +1453,12 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
1293
1453
|
return this.store.getSettledTxReceipt(txHash);
|
|
1294
1454
|
}
|
|
1295
1455
|
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
* @param from - The block number from which to begin retrieving logs.
|
|
1299
|
-
* @param limit - The maximum number of blocks to retrieve logs from.
|
|
1300
|
-
* @returns An array of private logs from the specified range of blocks.
|
|
1301
|
-
*/
|
|
1302
|
-
public getPrivateLogs(from: number, limit: number): Promise<PrivateLog[]> {
|
|
1303
|
-
return this.store.getPrivateLogs(from, limit);
|
|
1456
|
+
getPrivateLogsByTags(tags: SiloedTag[]): Promise<TxScopedL2Log[][]> {
|
|
1457
|
+
return this.store.getPrivateLogsByTags(tags);
|
|
1304
1458
|
}
|
|
1305
1459
|
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
* @param tags - The tags to filter the logs by.
|
|
1309
|
-
* @returns For each received tag, an array of matching logs is returned. An empty array implies no logs match
|
|
1310
|
-
* that tag.
|
|
1311
|
-
*/
|
|
1312
|
-
getLogsByTags(tags: Fr[]): Promise<TxScopedL2Log[][]> {
|
|
1313
|
-
return this.store.getLogsByTags(tags);
|
|
1460
|
+
getPublicLogsByTagsFromContract(contractAddress: AztecAddress, tags: Tag[]): Promise<TxScopedL2Log[][]> {
|
|
1461
|
+
return this.store.getPublicLogsByTagsFromContract(contractAddress, tags);
|
|
1314
1462
|
}
|
|
1315
1463
|
|
|
1316
1464
|
/**
|
|
@@ -1333,19 +1481,11 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
1333
1481
|
|
|
1334
1482
|
/**
|
|
1335
1483
|
* Gets the number of the latest L2 block processed by the block source implementation.
|
|
1484
|
+
* This includes both checkpointed and uncheckpointed blocks.
|
|
1336
1485
|
* @returns The number of the latest L2 block processed by the block source implementation.
|
|
1337
1486
|
*/
|
|
1338
|
-
public getBlockNumber(): Promise<
|
|
1339
|
-
return this.store.
|
|
1340
|
-
}
|
|
1341
|
-
|
|
1342
|
-
public getProvenBlockNumber(): Promise<number> {
|
|
1343
|
-
return this.store.getProvenL2BlockNumber();
|
|
1344
|
-
}
|
|
1345
|
-
|
|
1346
|
-
/** Forcefully updates the last proven block number. Use for testing. */
|
|
1347
|
-
public setProvenBlockNumber(blockNumber: number): Promise<void> {
|
|
1348
|
-
return this.store.setProvenL2BlockNumber(blockNumber);
|
|
1487
|
+
public getBlockNumber(): Promise<BlockNumber> {
|
|
1488
|
+
return this.store.getLatestBlockNumber();
|
|
1349
1489
|
}
|
|
1350
1490
|
|
|
1351
1491
|
public getContractClass(id: Fr): Promise<ContractClassPublic | undefined> {
|
|
@@ -1373,12 +1513,12 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
1373
1513
|
}
|
|
1374
1514
|
|
|
1375
1515
|
/**
|
|
1376
|
-
* Gets L1 to L2 message (to be) included in a given
|
|
1377
|
-
* @param
|
|
1516
|
+
* Gets L1 to L2 message (to be) included in a given checkpoint.
|
|
1517
|
+
* @param checkpointNumber - Checkpoint number to get messages for.
|
|
1378
1518
|
* @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found).
|
|
1379
1519
|
*/
|
|
1380
|
-
getL1ToL2Messages(
|
|
1381
|
-
return this.store.getL1ToL2Messages(
|
|
1520
|
+
getL1ToL2Messages(checkpointNumber: CheckpointNumber): Promise<Fr[]> {
|
|
1521
|
+
return this.store.getL1ToL2Messages(checkpointNumber);
|
|
1382
1522
|
}
|
|
1383
1523
|
|
|
1384
1524
|
/**
|
|
@@ -1402,7 +1542,7 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
1402
1542
|
return this.store.getDebugFunctionName(address, selector);
|
|
1403
1543
|
}
|
|
1404
1544
|
|
|
1405
|
-
async getPendingChainValidationStatus(): Promise<
|
|
1545
|
+
async getPendingChainValidationStatus(): Promise<ValidateCheckpointResult> {
|
|
1406
1546
|
return (await this.store.getPendingChainValidationStatus()) ?? { valid: true };
|
|
1407
1547
|
}
|
|
1408
1548
|
|
|
@@ -1411,84 +1551,145 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
1411
1551
|
}
|
|
1412
1552
|
|
|
1413
1553
|
async getL2Tips(): Promise<L2Tips> {
|
|
1414
|
-
const [latestBlockNumber, provenBlockNumber] = await Promise.all([
|
|
1554
|
+
const [latestBlockNumber, provenBlockNumber, checkpointedBlockNumber] = await Promise.all([
|
|
1415
1555
|
this.getBlockNumber(),
|
|
1416
1556
|
this.getProvenBlockNumber(),
|
|
1557
|
+
this.getCheckpointedBlockNumber(),
|
|
1417
1558
|
] as const);
|
|
1418
1559
|
|
|
1419
1560
|
// TODO(#13569): Compute proper finalized block number based on L1 finalized block.
|
|
1420
1561
|
// We just force it 2 epochs worth of proven data for now.
|
|
1421
1562
|
// NOTE: update end-to-end/src/e2e_epochs/epochs_empty_blocks.test.ts as that uses finalized blocks in computations
|
|
1422
|
-
const finalizedBlockNumber = Math.max(provenBlockNumber - this.l1constants.epochDuration * 2, 0);
|
|
1423
|
-
|
|
1424
|
-
const
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1563
|
+
const finalizedBlockNumber = BlockNumber(Math.max(provenBlockNumber - this.l1constants.epochDuration * 2, 0));
|
|
1564
|
+
|
|
1565
|
+
const beforeInitialblockNumber = BlockNumber(INITIAL_L2_BLOCK_NUM - 1);
|
|
1566
|
+
|
|
1567
|
+
// Get the latest block header and checkpointed blocks for proven, finalised and checkpointed blocks
|
|
1568
|
+
const [latestBlockHeader, provenCheckpointedBlock, finalizedCheckpointedBlock, checkpointedBlock] =
|
|
1569
|
+
await Promise.all([
|
|
1570
|
+
latestBlockNumber > beforeInitialblockNumber ? this.getBlockHeader(latestBlockNumber) : undefined,
|
|
1571
|
+
provenBlockNumber > beforeInitialblockNumber ? this.getCheckpointedBlock(provenBlockNumber) : undefined,
|
|
1572
|
+
finalizedBlockNumber > beforeInitialblockNumber ? this.getCheckpointedBlock(finalizedBlockNumber) : undefined,
|
|
1573
|
+
checkpointedBlockNumber > beforeInitialblockNumber
|
|
1574
|
+
? this.getCheckpointedBlock(checkpointedBlockNumber)
|
|
1575
|
+
: undefined,
|
|
1576
|
+
] as const);
|
|
1577
|
+
|
|
1578
|
+
if (latestBlockNumber > beforeInitialblockNumber && !latestBlockHeader) {
|
|
1431
1579
|
throw new Error(`Failed to retrieve latest block header for block ${latestBlockNumber}`);
|
|
1432
1580
|
}
|
|
1433
1581
|
|
|
1434
|
-
if
|
|
1582
|
+
// Checkpointed blocks must exist for proven, finalized and checkpointed tips if they are beyond the initial block number.
|
|
1583
|
+
if (checkpointedBlockNumber > beforeInitialblockNumber && !checkpointedBlock?.block.header) {
|
|
1584
|
+
throw new Error(
|
|
1585
|
+
`Failed to retrieve checkpointed block header for block ${checkpointedBlockNumber} (latest block is ${latestBlockNumber})`,
|
|
1586
|
+
);
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
if (provenBlockNumber > beforeInitialblockNumber && !provenCheckpointedBlock?.block.header) {
|
|
1435
1590
|
throw new Error(
|
|
1436
|
-
`Failed to retrieve proven
|
|
1591
|
+
`Failed to retrieve proven checkpointed for block ${provenBlockNumber} (latest block is ${latestBlockNumber})`,
|
|
1437
1592
|
);
|
|
1438
1593
|
}
|
|
1439
1594
|
|
|
1440
|
-
if (finalizedBlockNumber >
|
|
1595
|
+
if (finalizedBlockNumber > beforeInitialblockNumber && !finalizedCheckpointedBlock?.block.header) {
|
|
1441
1596
|
throw new Error(
|
|
1442
1597
|
`Failed to retrieve finalized block header for block ${finalizedBlockNumber} (latest block is ${latestBlockNumber})`,
|
|
1443
1598
|
);
|
|
1444
1599
|
}
|
|
1445
1600
|
|
|
1446
|
-
const latestBlockHeaderHash = await latestBlockHeader?.hash();
|
|
1447
|
-
const provenBlockHeaderHash = await
|
|
1448
|
-
const finalizedBlockHeaderHash =
|
|
1601
|
+
const latestBlockHeaderHash = (await latestBlockHeader?.hash()) ?? GENESIS_BLOCK_HEADER_HASH;
|
|
1602
|
+
const provenBlockHeaderHash = (await provenCheckpointedBlock?.block.header?.hash()) ?? GENESIS_BLOCK_HEADER_HASH;
|
|
1603
|
+
const finalizedBlockHeaderHash =
|
|
1604
|
+
(await finalizedCheckpointedBlock?.block.header?.hash()) ?? GENESIS_BLOCK_HEADER_HASH;
|
|
1605
|
+
const checkpointedBlockHeaderHash = (await checkpointedBlock?.block.header?.hash()) ?? GENESIS_BLOCK_HEADER_HASH;
|
|
1606
|
+
|
|
1607
|
+
// Now attempt to retrieve checkpoints for proven, finalised and checkpointed blocks
|
|
1608
|
+
const [[provenBlockCheckpoint], [finalizedBlockCheckpoint], [checkpointedBlockCheckpoint]] = await Promise.all([
|
|
1609
|
+
provenCheckpointedBlock !== undefined
|
|
1610
|
+
? await this.getPublishedCheckpoints(provenCheckpointedBlock?.checkpointNumber, 1)
|
|
1611
|
+
: [undefined],
|
|
1612
|
+
finalizedCheckpointedBlock !== undefined
|
|
1613
|
+
? await this.getPublishedCheckpoints(finalizedCheckpointedBlock?.checkpointNumber, 1)
|
|
1614
|
+
: [undefined],
|
|
1615
|
+
checkpointedBlock !== undefined
|
|
1616
|
+
? await this.getPublishedCheckpoints(checkpointedBlock?.checkpointNumber, 1)
|
|
1617
|
+
: [undefined],
|
|
1618
|
+
]);
|
|
1619
|
+
|
|
1620
|
+
const initialcheckpointId: CheckpointId = {
|
|
1621
|
+
number: CheckpointNumber.ZERO,
|
|
1622
|
+
hash: GENESIS_CHECKPOINT_HEADER_HASH.toString(),
|
|
1623
|
+
};
|
|
1624
|
+
|
|
1625
|
+
const makeCheckpointId = (checkpoint: PublishedCheckpoint | undefined) => {
|
|
1626
|
+
if (checkpoint === undefined) {
|
|
1627
|
+
return initialcheckpointId;
|
|
1628
|
+
}
|
|
1629
|
+
return {
|
|
1630
|
+
number: checkpoint.checkpoint.number,
|
|
1631
|
+
hash: checkpoint.checkpoint.hash().toString(),
|
|
1632
|
+
};
|
|
1633
|
+
};
|
|
1449
1634
|
|
|
1450
|
-
|
|
1451
|
-
|
|
1635
|
+
const l2Tips: L2Tips = {
|
|
1636
|
+
proposed: {
|
|
1452
1637
|
number: latestBlockNumber,
|
|
1453
|
-
hash: latestBlockHeaderHash
|
|
1454
|
-
}
|
|
1638
|
+
hash: latestBlockHeaderHash.toString(),
|
|
1639
|
+
},
|
|
1455
1640
|
proven: {
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1641
|
+
block: {
|
|
1642
|
+
number: provenBlockNumber,
|
|
1643
|
+
hash: provenBlockHeaderHash.toString(),
|
|
1644
|
+
},
|
|
1645
|
+
checkpoint: makeCheckpointId(provenBlockCheckpoint),
|
|
1646
|
+
},
|
|
1459
1647
|
finalized: {
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1648
|
+
block: {
|
|
1649
|
+
number: finalizedBlockNumber,
|
|
1650
|
+
hash: finalizedBlockHeaderHash.toString(),
|
|
1651
|
+
},
|
|
1652
|
+
checkpoint: makeCheckpointId(finalizedBlockCheckpoint),
|
|
1653
|
+
},
|
|
1654
|
+
checkpointed: {
|
|
1655
|
+
block: {
|
|
1656
|
+
number: checkpointedBlockNumber,
|
|
1657
|
+
hash: checkpointedBlockHeaderHash.toString(),
|
|
1658
|
+
},
|
|
1659
|
+
checkpoint: makeCheckpointId(checkpointedBlockCheckpoint),
|
|
1660
|
+
},
|
|
1463
1661
|
};
|
|
1662
|
+
|
|
1663
|
+
return l2Tips;
|
|
1464
1664
|
}
|
|
1465
1665
|
|
|
1466
|
-
public async rollbackTo(targetL2BlockNumber:
|
|
1666
|
+
public async rollbackTo(targetL2BlockNumber: BlockNumber): Promise<void> {
|
|
1667
|
+
// TODO(pw/mbps): This still assumes 1 block per checkpoint
|
|
1467
1668
|
const currentBlocks = await this.getL2Tips();
|
|
1468
|
-
const currentL2Block = currentBlocks.
|
|
1469
|
-
const currentProvenBlock = currentBlocks.proven.number;
|
|
1470
|
-
// const currentFinalizedBlock = currentBlocks.finalized.number;
|
|
1669
|
+
const currentL2Block = currentBlocks.proposed.number;
|
|
1670
|
+
const currentProvenBlock = currentBlocks.proven.block.number;
|
|
1471
1671
|
|
|
1472
1672
|
if (targetL2BlockNumber >= currentL2Block) {
|
|
1473
1673
|
throw new Error(`Target L2 block ${targetL2BlockNumber} must be less than current L2 block ${currentL2Block}`);
|
|
1474
1674
|
}
|
|
1475
1675
|
const blocksToUnwind = currentL2Block - targetL2BlockNumber;
|
|
1476
|
-
const targetL2Block = await this.store.
|
|
1676
|
+
const targetL2Block = await this.store.getCheckpointedBlock(targetL2BlockNumber);
|
|
1477
1677
|
if (!targetL2Block) {
|
|
1478
1678
|
throw new Error(`Target L2 block ${targetL2BlockNumber} not found`);
|
|
1479
1679
|
}
|
|
1480
1680
|
const targetL1BlockNumber = targetL2Block.l1.blockNumber;
|
|
1681
|
+
const targetCheckpointNumber = CheckpointNumber.fromBlockNumber(targetL2BlockNumber);
|
|
1481
1682
|
const targetL1BlockHash = await this.getL1BlockHash(targetL1BlockNumber);
|
|
1482
|
-
this.log.info(`Unwinding ${blocksToUnwind}
|
|
1483
|
-
await this.store.
|
|
1484
|
-
this.log.info(`Unwinding L1 to L2 messages to ${
|
|
1485
|
-
await this.store.
|
|
1683
|
+
this.log.info(`Unwinding ${blocksToUnwind} checkpoints from L2 block ${currentL2Block}`);
|
|
1684
|
+
await this.store.unwindCheckpoints(CheckpointNumber(currentL2Block), blocksToUnwind);
|
|
1685
|
+
this.log.info(`Unwinding L1 to L2 messages to checkpoint ${targetCheckpointNumber}`);
|
|
1686
|
+
await this.store.rollbackL1ToL2MessagesToCheckpoint(targetCheckpointNumber);
|
|
1486
1687
|
this.log.info(`Setting L1 syncpoints to ${targetL1BlockNumber}`);
|
|
1487
1688
|
await this.store.setBlockSynchedL1BlockNumber(targetL1BlockNumber);
|
|
1488
1689
|
await this.store.setMessageSynchedL1Block({ l1BlockNumber: targetL1BlockNumber, l1BlockHash: targetL1BlockHash });
|
|
1489
1690
|
if (targetL2BlockNumber < currentProvenBlock) {
|
|
1490
1691
|
this.log.info(`Clearing proven L2 block number`);
|
|
1491
|
-
await this.store.
|
|
1692
|
+
await this.store.setProvenCheckpointNumber(CheckpointNumber.ZERO);
|
|
1492
1693
|
}
|
|
1493
1694
|
// TODO(palla/reorg): Set the finalized block when we add support for it.
|
|
1494
1695
|
// if (targetL2BlockNumber < currentFinalizedBlock) {
|
|
@@ -1496,6 +1697,150 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
1496
1697
|
// await this.store.setFinalizedL2BlockNumber(0);
|
|
1497
1698
|
// }
|
|
1498
1699
|
}
|
|
1700
|
+
|
|
1701
|
+
public async getPublishedCheckpoints(
|
|
1702
|
+
checkpointNumber: CheckpointNumber,
|
|
1703
|
+
limit: number,
|
|
1704
|
+
): Promise<PublishedCheckpoint[]> {
|
|
1705
|
+
const checkpoints = await this.store.getRangeOfCheckpoints(checkpointNumber, limit);
|
|
1706
|
+
const blocks = (
|
|
1707
|
+
await Promise.all(checkpoints.map(ch => this.store.getBlocksForCheckpoint(ch.checkpointNumber)))
|
|
1708
|
+
).filter(isDefined);
|
|
1709
|
+
|
|
1710
|
+
const fullCheckpoints: PublishedCheckpoint[] = [];
|
|
1711
|
+
for (let i = 0; i < checkpoints.length; i++) {
|
|
1712
|
+
const blocksForCheckpoint = blocks[i];
|
|
1713
|
+
const checkpoint = checkpoints[i];
|
|
1714
|
+
const fullCheckpoint = new Checkpoint(
|
|
1715
|
+
checkpoint.archive,
|
|
1716
|
+
checkpoint.header,
|
|
1717
|
+
blocksForCheckpoint,
|
|
1718
|
+
checkpoint.checkpointNumber,
|
|
1719
|
+
);
|
|
1720
|
+
const publishedCheckpoint = new PublishedCheckpoint(
|
|
1721
|
+
fullCheckpoint,
|
|
1722
|
+
checkpoint.l1,
|
|
1723
|
+
checkpoint.attestations.map(x => CommitteeAttestation.fromBuffer(x)),
|
|
1724
|
+
);
|
|
1725
|
+
fullCheckpoints.push(publishedCheckpoint);
|
|
1726
|
+
}
|
|
1727
|
+
return fullCheckpoints;
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
public async getCheckpointsForEpoch(epochNumber: EpochNumber): Promise<Checkpoint[]> {
|
|
1731
|
+
const [start, end] = getSlotRangeForEpoch(epochNumber, this.l1constants);
|
|
1732
|
+
const checkpoints: Checkpoint[] = [];
|
|
1733
|
+
|
|
1734
|
+
// Walk the list of checkpoints backwards and filter by slots matching the requested epoch.
|
|
1735
|
+
// We'll typically ask for checkpoints for a very recent epoch, so we shouldn't need an index here.
|
|
1736
|
+
let checkpointData = await this.store.getCheckpointData(await this.store.getSynchedCheckpointNumber());
|
|
1737
|
+
const slot = (b: CheckpointData) => b.header.slotNumber;
|
|
1738
|
+
while (checkpointData && slot(checkpointData) >= start) {
|
|
1739
|
+
if (slot(checkpointData) <= end) {
|
|
1740
|
+
// push the checkpoints on backwards
|
|
1741
|
+
const [checkpoint] = await this.getPublishedCheckpoints(checkpointData.checkpointNumber, 1);
|
|
1742
|
+
checkpoints.push(checkpoint.checkpoint);
|
|
1743
|
+
}
|
|
1744
|
+
checkpointData = await this.store.getCheckpointData(CheckpointNumber(checkpointData.checkpointNumber - 1));
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
return checkpoints.reverse();
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
/* Legacy APIs */
|
|
1751
|
+
|
|
1752
|
+
public async getPublishedBlockByHash(blockHash: Fr): Promise<PublishedL2Block | undefined> {
|
|
1753
|
+
const checkpointedBlock = await this.store.getCheckpointedBlockByHash(blockHash);
|
|
1754
|
+
return this.buildOldBlockFromCheckpointedBlock(checkpointedBlock);
|
|
1755
|
+
}
|
|
1756
|
+
public async getPublishedBlockByArchive(archive: Fr): Promise<PublishedL2Block | undefined> {
|
|
1757
|
+
const checkpointedBlock = await this.store.getCheckpointedBlockByArchive(archive);
|
|
1758
|
+
return this.buildOldBlockFromCheckpointedBlock(checkpointedBlock);
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
/**
|
|
1762
|
+
* Gets up to `limit` amount of L2 blocks starting from `from`.
|
|
1763
|
+
* @param from - Number of the first block to return (inclusive).
|
|
1764
|
+
* @param limit - The number of blocks to return.
|
|
1765
|
+
* @param proven - If true, only return blocks that have been proven.
|
|
1766
|
+
* @returns The requested L2 blocks.
|
|
1767
|
+
*/
|
|
1768
|
+
public async getBlocks(from: BlockNumber, limit: number, proven?: boolean): Promise<L2Block[]> {
|
|
1769
|
+
const publishedBlocks = await this.getPublishedBlocks(from, limit, proven);
|
|
1770
|
+
return publishedBlocks.map(x => x.block);
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
public async getPublishedBlocks(from: BlockNumber, limit: number, proven?: boolean): Promise<PublishedL2Block[]> {
|
|
1774
|
+
const checkpoints = await this.store.getRangeOfCheckpoints(CheckpointNumber(from), limit);
|
|
1775
|
+
const provenCheckpointNumber = await this.getProvenCheckpointNumber();
|
|
1776
|
+
const blocks = (
|
|
1777
|
+
await Promise.all(checkpoints.map(ch => this.store.getBlocksForCheckpoint(ch.checkpointNumber)))
|
|
1778
|
+
).filter(isDefined);
|
|
1779
|
+
|
|
1780
|
+
const olbBlocks: PublishedL2Block[] = [];
|
|
1781
|
+
for (let i = 0; i < checkpoints.length; i++) {
|
|
1782
|
+
const blockForCheckpoint = blocks[i][0];
|
|
1783
|
+
const checkpoint = checkpoints[i];
|
|
1784
|
+
if (checkpoint.checkpointNumber > provenCheckpointNumber && proven === true) {
|
|
1785
|
+
// this checkpointisn't proven and we only want proven
|
|
1786
|
+
continue;
|
|
1787
|
+
}
|
|
1788
|
+
const oldCheckpoint = new Checkpoint(
|
|
1789
|
+
blockForCheckpoint.archive,
|
|
1790
|
+
checkpoint.header,
|
|
1791
|
+
[blockForCheckpoint],
|
|
1792
|
+
checkpoint.checkpointNumber,
|
|
1793
|
+
);
|
|
1794
|
+
const oldBlock = L2Block.fromCheckpoint(oldCheckpoint);
|
|
1795
|
+
const publishedBlock = new PublishedL2Block(
|
|
1796
|
+
oldBlock,
|
|
1797
|
+
checkpoint.l1,
|
|
1798
|
+
checkpoint.attestations.map(x => CommitteeAttestation.fromBuffer(x)),
|
|
1799
|
+
);
|
|
1800
|
+
olbBlocks.push(publishedBlock);
|
|
1801
|
+
}
|
|
1802
|
+
return olbBlocks;
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
private async buildOldBlockFromCheckpointedBlock(
|
|
1806
|
+
checkpointedBlock: CheckpointedL2Block | undefined,
|
|
1807
|
+
): Promise<PublishedL2Block | undefined> {
|
|
1808
|
+
if (!checkpointedBlock) {
|
|
1809
|
+
return undefined;
|
|
1810
|
+
}
|
|
1811
|
+
const checkpoint = await this.store.getCheckpointData(checkpointedBlock.checkpointNumber);
|
|
1812
|
+
if (!checkpoint) {
|
|
1813
|
+
return checkpoint;
|
|
1814
|
+
}
|
|
1815
|
+
const fullCheckpoint = new Checkpoint(
|
|
1816
|
+
checkpointedBlock?.block.archive,
|
|
1817
|
+
checkpoint?.header,
|
|
1818
|
+
[checkpointedBlock.block],
|
|
1819
|
+
checkpoint.checkpointNumber,
|
|
1820
|
+
);
|
|
1821
|
+
const oldBlock = L2Block.fromCheckpoint(fullCheckpoint);
|
|
1822
|
+
const published = new PublishedL2Block(
|
|
1823
|
+
oldBlock,
|
|
1824
|
+
checkpoint.l1,
|
|
1825
|
+
checkpoint.attestations.map(x => CommitteeAttestation.fromBuffer(x)),
|
|
1826
|
+
);
|
|
1827
|
+
return published;
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
public async getBlock(number: BlockNumber): Promise<L2Block | undefined> {
|
|
1831
|
+
// If the number provided is -ve, then return the latest block.
|
|
1832
|
+
if (number < 0) {
|
|
1833
|
+
number = await this.store.getSynchedL2BlockNumber();
|
|
1834
|
+
}
|
|
1835
|
+
if (number === 0) {
|
|
1836
|
+
return undefined;
|
|
1837
|
+
}
|
|
1838
|
+
const publishedBlocks = await this.getPublishedBlocks(number, 1);
|
|
1839
|
+
if (publishedBlocks.length === 0) {
|
|
1840
|
+
return undefined;
|
|
1841
|
+
}
|
|
1842
|
+
return publishedBlocks[0].block;
|
|
1843
|
+
}
|
|
1499
1844
|
}
|
|
1500
1845
|
|
|
1501
1846
|
enum Operation {
|
|
@@ -1526,17 +1871,20 @@ export class ArchiverStoreHelper
|
|
|
1526
1871
|
| 'close'
|
|
1527
1872
|
| 'transactionAsync'
|
|
1528
1873
|
| 'addBlocks'
|
|
1874
|
+
| 'getBlock'
|
|
1875
|
+
| 'getBlocks'
|
|
1876
|
+
| 'getCheckpointedBlocks'
|
|
1529
1877
|
>
|
|
1530
1878
|
{
|
|
1531
1879
|
#log = createLogger('archiver:block-helper');
|
|
1532
1880
|
|
|
1533
|
-
constructor(
|
|
1881
|
+
constructor(public readonly store: ArchiverDataStore) {}
|
|
1534
1882
|
|
|
1535
1883
|
/**
|
|
1536
1884
|
* Extracts and stores contract classes out of ContractClassPublished events emitted by the class registry contract.
|
|
1537
1885
|
* @param allLogs - All logs emitted in a bunch of blocks.
|
|
1538
1886
|
*/
|
|
1539
|
-
async #updatePublishedContractClasses(allLogs: ContractClassLog[], blockNum:
|
|
1887
|
+
async #updatePublishedContractClasses(allLogs: ContractClassLog[], blockNum: BlockNumber, operation: Operation) {
|
|
1540
1888
|
const contractClassPublishedEvents = allLogs
|
|
1541
1889
|
.filter(log => ContractClassPublishedEvent.isContractClassPublishedEvent(log))
|
|
1542
1890
|
.map(log => ContractClassPublishedEvent.fromLog(log));
|
|
@@ -1561,7 +1909,7 @@ export class ArchiverStoreHelper
|
|
|
1561
1909
|
* Extracts and stores contract instances out of ContractInstancePublished events emitted by the canonical deployer contract.
|
|
1562
1910
|
* @param allLogs - All logs emitted in a bunch of blocks.
|
|
1563
1911
|
*/
|
|
1564
|
-
async #updateDeployedContractInstances(allLogs: PrivateLog[], blockNum:
|
|
1912
|
+
async #updateDeployedContractInstances(allLogs: PrivateLog[], blockNum: BlockNumber, operation: Operation) {
|
|
1565
1913
|
const contractInstances = allLogs
|
|
1566
1914
|
.filter(log => ContractInstancePublishedEvent.isContractInstancePublishedEvent(log))
|
|
1567
1915
|
.map(log => ContractInstancePublishedEvent.fromLog(log))
|
|
@@ -1614,7 +1962,7 @@ export class ArchiverStoreHelper
|
|
|
1614
1962
|
* @param _blockNum - The block number
|
|
1615
1963
|
* @returns
|
|
1616
1964
|
*/
|
|
1617
|
-
async #storeBroadcastedIndividualFunctions(allLogs: ContractClassLog[], _blockNum:
|
|
1965
|
+
async #storeBroadcastedIndividualFunctions(allLogs: ContractClassLog[], _blockNum: BlockNumber) {
|
|
1618
1966
|
// Filter out private and utility function broadcast events
|
|
1619
1967
|
const privateFnEvents = allLogs
|
|
1620
1968
|
.filter(log => PrivateFunctionBroadcastedEvent.isPrivateFunctionBroadcastedEvent(log))
|
|
@@ -1668,7 +2016,23 @@ export class ArchiverStoreHelper
|
|
|
1668
2016
|
return true;
|
|
1669
2017
|
}
|
|
1670
2018
|
|
|
1671
|
-
|
|
2019
|
+
private async addBlockDataToDB(block: L2BlockNew) {
|
|
2020
|
+
const contractClassLogs = block.body.txEffects.flatMap(txEffect => txEffect.contractClassLogs);
|
|
2021
|
+
// ContractInstancePublished event logs are broadcast in privateLogs.
|
|
2022
|
+
const privateLogs = block.body.txEffects.flatMap(txEffect => txEffect.privateLogs);
|
|
2023
|
+
const publicLogs = block.body.txEffects.flatMap(txEffect => txEffect.publicLogs);
|
|
2024
|
+
|
|
2025
|
+
return (
|
|
2026
|
+
await Promise.all([
|
|
2027
|
+
this.#updatePublishedContractClasses(contractClassLogs, block.number, Operation.Store),
|
|
2028
|
+
this.#updateDeployedContractInstances(privateLogs, block.number, Operation.Store),
|
|
2029
|
+
this.#updateUpdatedContractInstances(publicLogs, block.header.globalVariables.timestamp, Operation.Store),
|
|
2030
|
+
this.#storeBroadcastedIndividualFunctions(contractClassLogs, block.number),
|
|
2031
|
+
])
|
|
2032
|
+
).every(Boolean);
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
public addBlocks(blocks: L2BlockNew[], pendingChainValidationStatus?: ValidateCheckpointResult): Promise<boolean> {
|
|
1672
2036
|
// Add the blocks to the store. Store will throw if the blocks are not in order, there are gaps,
|
|
1673
2037
|
// or if the previous block is not in the store.
|
|
1674
2038
|
return this.store.transactionAsync(async () => {
|
|
@@ -1678,25 +2042,10 @@ export class ArchiverStoreHelper
|
|
|
1678
2042
|
// Update the pending chain validation status if provided
|
|
1679
2043
|
pendingChainValidationStatus && this.store.setPendingChainValidationStatus(pendingChainValidationStatus),
|
|
1680
2044
|
// Add any logs emitted during the retrieved blocks
|
|
1681
|
-
this.store.addLogs(blocks
|
|
2045
|
+
this.store.addLogs(blocks),
|
|
1682
2046
|
// Unroll all logs emitted during the retrieved blocks and extract any contract classes and instances from them
|
|
1683
|
-
...blocks.map(
|
|
1684
|
-
|
|
1685
|
-
// ContractInstancePublished event logs are broadcast in privateLogs.
|
|
1686
|
-
const privateLogs = block.block.body.txEffects.flatMap(txEffect => txEffect.privateLogs);
|
|
1687
|
-
const publicLogs = block.block.body.txEffects.flatMap(txEffect => txEffect.publicLogs);
|
|
1688
|
-
return (
|
|
1689
|
-
await Promise.all([
|
|
1690
|
-
this.#updatePublishedContractClasses(contractClassLogs, block.block.number, Operation.Store),
|
|
1691
|
-
this.#updateDeployedContractInstances(privateLogs, block.block.number, Operation.Store),
|
|
1692
|
-
this.#updateUpdatedContractInstances(
|
|
1693
|
-
publicLogs,
|
|
1694
|
-
block.block.header.globalVariables.timestamp,
|
|
1695
|
-
Operation.Store,
|
|
1696
|
-
),
|
|
1697
|
-
this.#storeBroadcastedIndividualFunctions(contractClassLogs, block.block.number),
|
|
1698
|
-
])
|
|
1699
|
-
).every(Boolean);
|
|
2047
|
+
...blocks.map(block => {
|
|
2048
|
+
return this.addBlockDataToDB(block);
|
|
1700
2049
|
}),
|
|
1701
2050
|
]);
|
|
1702
2051
|
|
|
@@ -1704,61 +2053,104 @@ export class ArchiverStoreHelper
|
|
|
1704
2053
|
});
|
|
1705
2054
|
}
|
|
1706
2055
|
|
|
1707
|
-
public
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
2056
|
+
public addCheckpoints(
|
|
2057
|
+
checkpoints: PublishedCheckpoint[],
|
|
2058
|
+
pendingChainValidationStatus?: ValidateCheckpointResult,
|
|
2059
|
+
): Promise<boolean> {
|
|
2060
|
+
// Add the blocks to the store. Store will throw if the blocks are not in order, there are gaps,
|
|
2061
|
+
// or if the previous block is not in the store.
|
|
2062
|
+
return this.store.transactionAsync(async () => {
|
|
2063
|
+
await this.store.addCheckpoints(checkpoints);
|
|
2064
|
+
const allBlocks = checkpoints.flatMap((ch: PublishedCheckpoint) => ch.checkpoint.blocks);
|
|
2065
|
+
|
|
2066
|
+
const opResults = await Promise.all([
|
|
2067
|
+
// Update the pending chain validation status if provided
|
|
2068
|
+
pendingChainValidationStatus && this.store.setPendingChainValidationStatus(pendingChainValidationStatus),
|
|
2069
|
+
// Add any logs emitted during the retrieved blocks
|
|
2070
|
+
this.store.addLogs(allBlocks),
|
|
2071
|
+
// Unroll all logs emitted during the retrieved blocks and extract any contract classes and instances from them
|
|
2072
|
+
...allBlocks.map(block => {
|
|
2073
|
+
return this.addBlockDataToDB(block);
|
|
2074
|
+
}),
|
|
2075
|
+
]);
|
|
2076
|
+
|
|
2077
|
+
return opResults.every(Boolean);
|
|
2078
|
+
});
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
public async unwindCheckpoints(from: CheckpointNumber, checkpointsToUnwind: number): Promise<boolean> {
|
|
2082
|
+
if (checkpointsToUnwind <= 0) {
|
|
2083
|
+
throw new Error(`Cannot unwind ${checkpointsToUnwind} blocks`);
|
|
1711
2084
|
}
|
|
1712
|
-
|
|
1713
|
-
|
|
2085
|
+
|
|
2086
|
+
const last = await this.getSynchedCheckpointNumber();
|
|
2087
|
+
if (from != last) {
|
|
2088
|
+
throw new Error(`Cannot unwind checkpoints from checkpoint ${from} when the last checkpoint is ${last}`);
|
|
1714
2089
|
}
|
|
1715
2090
|
|
|
1716
|
-
|
|
1717
|
-
const
|
|
2091
|
+
const blocks = [];
|
|
2092
|
+
const lastCheckpointNumber = from + checkpointsToUnwind - 1;
|
|
2093
|
+
for (let checkpointNumber = from; checkpointNumber <= lastCheckpointNumber; checkpointNumber++) {
|
|
2094
|
+
const blocksForCheckpoint = await this.store.getBlocksForCheckpoint(checkpointNumber);
|
|
2095
|
+
if (!blocksForCheckpoint) {
|
|
2096
|
+
continue;
|
|
2097
|
+
}
|
|
2098
|
+
blocks.push(...blocksForCheckpoint);
|
|
2099
|
+
}
|
|
1718
2100
|
|
|
1719
2101
|
const opResults = await Promise.all([
|
|
1720
2102
|
// Prune rolls back to the last proven block, which is by definition valid
|
|
1721
2103
|
this.store.setPendingChainValidationStatus({ valid: true }),
|
|
1722
2104
|
// Unroll all logs emitted during the retrieved blocks and extract any contract classes and instances from them
|
|
1723
2105
|
...blocks.map(async block => {
|
|
1724
|
-
const contractClassLogs = block.
|
|
2106
|
+
const contractClassLogs = block.body.txEffects.flatMap(txEffect => txEffect.contractClassLogs);
|
|
1725
2107
|
// ContractInstancePublished event logs are broadcast in privateLogs.
|
|
1726
|
-
const privateLogs = block.
|
|
1727
|
-
const publicLogs = block.
|
|
2108
|
+
const privateLogs = block.body.txEffects.flatMap(txEffect => txEffect.privateLogs);
|
|
2109
|
+
const publicLogs = block.body.txEffects.flatMap(txEffect => txEffect.publicLogs);
|
|
1728
2110
|
|
|
1729
2111
|
return (
|
|
1730
2112
|
await Promise.all([
|
|
1731
|
-
this.#updatePublishedContractClasses(contractClassLogs, block.
|
|
1732
|
-
this.#updateDeployedContractInstances(privateLogs, block.
|
|
1733
|
-
this.#updateUpdatedContractInstances(
|
|
1734
|
-
publicLogs,
|
|
1735
|
-
block.block.header.globalVariables.timestamp,
|
|
1736
|
-
Operation.Delete,
|
|
1737
|
-
),
|
|
2113
|
+
this.#updatePublishedContractClasses(contractClassLogs, block.number, Operation.Delete),
|
|
2114
|
+
this.#updateDeployedContractInstances(privateLogs, block.number, Operation.Delete),
|
|
2115
|
+
this.#updateUpdatedContractInstances(publicLogs, block.header.globalVariables.timestamp, Operation.Delete),
|
|
1738
2116
|
])
|
|
1739
2117
|
).every(Boolean);
|
|
1740
2118
|
}),
|
|
1741
2119
|
|
|
1742
|
-
this.store.deleteLogs(blocks
|
|
1743
|
-
this.store.
|
|
2120
|
+
this.store.deleteLogs(blocks),
|
|
2121
|
+
this.store.unwindCheckpoints(from, checkpointsToUnwind),
|
|
1744
2122
|
]);
|
|
1745
2123
|
|
|
1746
2124
|
return opResults.every(Boolean);
|
|
1747
2125
|
}
|
|
1748
2126
|
|
|
1749
|
-
|
|
1750
|
-
return this.store.
|
|
2127
|
+
getCheckpointData(checkpointNumber: CheckpointNumber): Promise<CheckpointData | undefined> {
|
|
2128
|
+
return this.store.getCheckpointData(checkpointNumber);
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
getRangeOfCheckpoints(from: CheckpointNumber, limit: number): Promise<CheckpointData[]> {
|
|
2132
|
+
return this.store.getRangeOfCheckpoints(from, limit);
|
|
2133
|
+
}
|
|
2134
|
+
|
|
2135
|
+
getCheckpointedL2BlockNumber(): Promise<BlockNumber> {
|
|
2136
|
+
return this.store.getCheckpointedL2BlockNumber();
|
|
2137
|
+
}
|
|
2138
|
+
getSynchedCheckpointNumber(): Promise<CheckpointNumber> {
|
|
2139
|
+
return this.store.getSynchedCheckpointNumber();
|
|
1751
2140
|
}
|
|
1752
|
-
|
|
1753
|
-
return this.store.
|
|
2141
|
+
setCheckpointSynchedL1BlockNumber(l1BlockNumber: bigint): Promise<void> {
|
|
2142
|
+
return this.store.setCheckpointSynchedL1BlockNumber(l1BlockNumber);
|
|
1754
2143
|
}
|
|
1755
|
-
|
|
1756
|
-
return this.store.
|
|
2144
|
+
getCheckpointedBlock(number: BlockNumber): Promise<CheckpointedL2Block | undefined> {
|
|
2145
|
+
return this.store.getCheckpointedBlock(number);
|
|
1757
2146
|
}
|
|
1758
|
-
|
|
1759
|
-
return this.store.
|
|
2147
|
+
getCheckpointedBlockByHash(blockHash: Fr): Promise<CheckpointedL2Block | undefined> {
|
|
2148
|
+
return this.store.getCheckpointedBlockByHash(blockHash);
|
|
1760
2149
|
}
|
|
1761
|
-
|
|
2150
|
+
getCheckpointedBlockByArchive(archive: Fr): Promise<CheckpointedL2Block | undefined> {
|
|
2151
|
+
return this.store.getCheckpointedBlockByArchive(archive);
|
|
2152
|
+
}
|
|
2153
|
+
getBlockHeaders(from: BlockNumber, limit: number): Promise<BlockHeader[]> {
|
|
1762
2154
|
return this.store.getBlockHeaders(from, limit);
|
|
1763
2155
|
}
|
|
1764
2156
|
getBlockHeaderByHash(blockHash: Fr): Promise<BlockHeader | undefined> {
|
|
@@ -1767,6 +2159,18 @@ export class ArchiverStoreHelper
|
|
|
1767
2159
|
getBlockHeaderByArchive(archive: Fr): Promise<BlockHeader | undefined> {
|
|
1768
2160
|
return this.store.getBlockHeaderByArchive(archive);
|
|
1769
2161
|
}
|
|
2162
|
+
getBlockByHash(blockHash: Fr): Promise<L2BlockNew | undefined> {
|
|
2163
|
+
return this.store.getBlockByHash(blockHash);
|
|
2164
|
+
}
|
|
2165
|
+
getBlockByArchive(archive: Fr): Promise<L2BlockNew | undefined> {
|
|
2166
|
+
return this.store.getBlockByArchive(archive);
|
|
2167
|
+
}
|
|
2168
|
+
getLatestBlockNumber(): Promise<BlockNumber> {
|
|
2169
|
+
return this.store.getLatestBlockNumber();
|
|
2170
|
+
}
|
|
2171
|
+
getBlocksForCheckpoint(checkpointNumber: CheckpointNumber): Promise<L2BlockNew[] | undefined> {
|
|
2172
|
+
return this.store.getBlocksForCheckpoint(checkpointNumber);
|
|
2173
|
+
}
|
|
1770
2174
|
getTxEffect(txHash: TxHash): Promise<IndexedTxEffect | undefined> {
|
|
1771
2175
|
return this.store.getTxEffect(txHash);
|
|
1772
2176
|
}
|
|
@@ -1776,17 +2180,17 @@ export class ArchiverStoreHelper
|
|
|
1776
2180
|
addL1ToL2Messages(messages: InboxMessage[]): Promise<void> {
|
|
1777
2181
|
return this.store.addL1ToL2Messages(messages);
|
|
1778
2182
|
}
|
|
1779
|
-
getL1ToL2Messages(
|
|
1780
|
-
return this.store.getL1ToL2Messages(
|
|
2183
|
+
getL1ToL2Messages(checkpointNumber: CheckpointNumber): Promise<Fr[]> {
|
|
2184
|
+
return this.store.getL1ToL2Messages(checkpointNumber);
|
|
1781
2185
|
}
|
|
1782
2186
|
getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise<bigint | undefined> {
|
|
1783
2187
|
return this.store.getL1ToL2MessageIndex(l1ToL2Message);
|
|
1784
2188
|
}
|
|
1785
|
-
|
|
1786
|
-
return this.store.
|
|
2189
|
+
getPrivateLogsByTags(tags: SiloedTag[]): Promise<TxScopedL2Log[][]> {
|
|
2190
|
+
return this.store.getPrivateLogsByTags(tags);
|
|
1787
2191
|
}
|
|
1788
|
-
|
|
1789
|
-
return this.store.
|
|
2192
|
+
getPublicLogsByTagsFromContract(contractAddress: AztecAddress, tags: Tag[]): Promise<TxScopedL2Log[][]> {
|
|
2193
|
+
return this.store.getPublicLogsByTagsFromContract(contractAddress, tags);
|
|
1790
2194
|
}
|
|
1791
2195
|
getPublicLogs(filter: LogFilter): Promise<GetPublicLogsResponse> {
|
|
1792
2196
|
return this.store.getPublicLogs(filter);
|
|
@@ -1794,17 +2198,20 @@ export class ArchiverStoreHelper
|
|
|
1794
2198
|
getContractClassLogs(filter: LogFilter): Promise<GetContractClassLogsResponse> {
|
|
1795
2199
|
return this.store.getContractClassLogs(filter);
|
|
1796
2200
|
}
|
|
1797
|
-
getSynchedL2BlockNumber(): Promise<
|
|
1798
|
-
return this.store.
|
|
2201
|
+
getSynchedL2BlockNumber(): Promise<BlockNumber> {
|
|
2202
|
+
return this.store.getLatestBlockNumber();
|
|
2203
|
+
}
|
|
2204
|
+
getProvenCheckpointNumber(): Promise<CheckpointNumber> {
|
|
2205
|
+
return this.store.getProvenCheckpointNumber();
|
|
1799
2206
|
}
|
|
1800
|
-
|
|
1801
|
-
return this.store.
|
|
2207
|
+
getProvenBlockNumber(): Promise<BlockNumber> {
|
|
2208
|
+
return this.store.getProvenBlockNumber();
|
|
1802
2209
|
}
|
|
1803
|
-
|
|
1804
|
-
return this.store.
|
|
2210
|
+
setProvenCheckpointNumber(checkpointNumber: CheckpointNumber): Promise<void> {
|
|
2211
|
+
return this.store.setProvenCheckpointNumber(checkpointNumber);
|
|
1805
2212
|
}
|
|
1806
2213
|
setBlockSynchedL1BlockNumber(l1BlockNumber: bigint): Promise<void> {
|
|
1807
|
-
return this.store.
|
|
2214
|
+
return this.store.setCheckpointSynchedL1BlockNumber(l1BlockNumber);
|
|
1808
2215
|
}
|
|
1809
2216
|
setMessageSynchedL1Block(l1Block: L1BlockId): Promise<void> {
|
|
1810
2217
|
return this.store.setMessageSynchedL1Block(l1Block);
|
|
@@ -1836,8 +2243,8 @@ export class ArchiverStoreHelper
|
|
|
1836
2243
|
estimateSize(): Promise<{ mappingSize: number; physicalFileSize: number; actualSize: number; numItems: number }> {
|
|
1837
2244
|
return this.store.estimateSize();
|
|
1838
2245
|
}
|
|
1839
|
-
|
|
1840
|
-
return this.store.
|
|
2246
|
+
rollbackL1ToL2MessagesToCheckpoint(targetCheckpointNumber: CheckpointNumber): Promise<void> {
|
|
2247
|
+
return this.store.rollbackL1ToL2MessagesToCheckpoint(targetCheckpointNumber);
|
|
1841
2248
|
}
|
|
1842
2249
|
iterateL1ToL2Messages(range: CustomRange<bigint> = {}): AsyncIterableIterator<InboxMessage> {
|
|
1843
2250
|
return this.store.iterateL1ToL2Messages(range);
|
|
@@ -1848,10 +2255,10 @@ export class ArchiverStoreHelper
|
|
|
1848
2255
|
getLastL1ToL2Message(): Promise<InboxMessage | undefined> {
|
|
1849
2256
|
return this.store.getLastL1ToL2Message();
|
|
1850
2257
|
}
|
|
1851
|
-
getPendingChainValidationStatus(): Promise<
|
|
2258
|
+
getPendingChainValidationStatus(): Promise<ValidateCheckpointResult | undefined> {
|
|
1852
2259
|
return this.store.getPendingChainValidationStatus();
|
|
1853
2260
|
}
|
|
1854
|
-
setPendingChainValidationStatus(status:
|
|
2261
|
+
setPendingChainValidationStatus(status: ValidateCheckpointResult | undefined): Promise<void> {
|
|
1855
2262
|
this.#log.debug(`Setting pending chain validation status to valid ${status?.valid}`, status);
|
|
1856
2263
|
return this.store.setPendingChainValidationStatus(status);
|
|
1857
2264
|
}
|