@aztec/archiver 0.0.1-commit.0dc957cde → 0.0.1-commit.0ec55a70b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/archiver.d.ts +15 -9
- package/dest/archiver.d.ts.map +1 -1
- package/dest/archiver.js +85 -53
- package/dest/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +2 -2
- package/dest/errors.d.ts +16 -5
- package/dest/errors.d.ts.map +1 -1
- package/dest/errors.js +29 -6
- package/dest/factory.d.ts +4 -4
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +11 -9
- package/dest/index.d.ts +8 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +7 -1
- package/dest/l1/calldata_retriever.d.ts +2 -1
- package/dest/l1/calldata_retriever.d.ts.map +1 -1
- package/dest/l1/calldata_retriever.js +9 -4
- package/dest/modules/contract_data_source_adapter.d.ts +25 -0
- package/dest/modules/contract_data_source_adapter.d.ts.map +1 -0
- package/dest/modules/contract_data_source_adapter.js +42 -0
- package/dest/modules/data_source_base.d.ts +16 -10
- package/dest/modules/data_source_base.d.ts.map +1 -1
- package/dest/modules/data_source_base.js +71 -60
- package/dest/modules/data_store_updater.d.ts +6 -6
- package/dest/modules/data_store_updater.d.ts.map +1 -1
- package/dest/modules/data_store_updater.js +42 -40
- package/dest/modules/l1_synchronizer.d.ts +5 -4
- package/dest/modules/l1_synchronizer.d.ts.map +1 -1
- package/dest/modules/l1_synchronizer.js +79 -54
- package/dest/modules/validation.d.ts +4 -3
- package/dest/modules/validation.d.ts.map +1 -1
- package/dest/modules/validation.js +4 -4
- package/dest/store/block_store.d.ts +58 -27
- package/dest/store/block_store.d.ts.map +1 -1
- package/dest/store/block_store.js +152 -75
- package/dest/store/contract_class_store.d.ts +17 -3
- package/dest/store/contract_class_store.d.ts.map +1 -1
- package/dest/store/contract_class_store.js +17 -1
- package/dest/store/contract_instance_store.d.ts +28 -1
- package/dest/store/contract_instance_store.d.ts.map +1 -1
- package/dest/store/contract_instance_store.js +31 -0
- package/dest/store/data_stores.d.ts +68 -0
- package/dest/store/data_stores.d.ts.map +1 -0
- package/dest/store/data_stores.js +50 -0
- package/dest/store/function_names_cache.d.ts +17 -0
- package/dest/store/function_names_cache.d.ts.map +1 -0
- package/dest/store/function_names_cache.js +30 -0
- package/dest/store/l2_tips_cache.js +1 -1
- package/dest/test/fake_l1_state.d.ts +2 -1
- package/dest/test/fake_l1_state.d.ts.map +1 -1
- package/dest/test/fake_l1_state.js +25 -8
- package/dest/test/mock_l2_block_source.d.ts +12 -3
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +24 -2
- package/dest/test/noop_l1_archiver.d.ts +4 -4
- package/dest/test/noop_l1_archiver.d.ts.map +1 -1
- package/dest/test/noop_l1_archiver.js +5 -5
- package/package.json +13 -13
- package/src/archiver.ts +91 -49
- package/src/config.ts +2 -1
- package/src/errors.ts +41 -8
- package/src/factory.ts +10 -10
- package/src/index.ts +15 -1
- package/src/l1/calldata_retriever.ts +15 -4
- package/src/modules/contract_data_source_adapter.ts +59 -0
- package/src/modules/data_source_base.ts +75 -57
- package/src/modules/data_store_updater.ts +46 -38
- package/src/modules/l1_synchronizer.ts +92 -60
- package/src/modules/validation.ts +8 -7
- package/src/store/block_store.ts +159 -80
- package/src/store/contract_class_store.ts +28 -2
- package/src/store/contract_instance_store.ts +43 -0
- package/src/store/data_stores.ts +108 -0
- package/src/store/function_names_cache.ts +37 -0
- package/src/store/l2_tips_cache.ts +1 -1
- package/src/test/fake_l1_state.ts +24 -14
- package/src/test/mock_l2_block_source.ts +23 -2
- package/src/test/noop_l1_archiver.ts +6 -6
- package/dest/store/kv_archiver_store.d.ts +0 -383
- package/dest/store/kv_archiver_store.d.ts.map +0 -1
- package/dest/store/kv_archiver_store.js +0 -501
- package/src/store/kv_archiver_store.ts +0 -728
|
@@ -247,6 +247,27 @@ import { TxExecutionResult, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
|
247
247
|
indexWithinCheckpoint: block.indexWithinCheckpoint
|
|
248
248
|
};
|
|
249
249
|
}
|
|
250
|
+
getCheckpointData(_n) {
|
|
251
|
+
return Promise.resolve(undefined);
|
|
252
|
+
}
|
|
253
|
+
getCheckpointDataRange(_from, _limit) {
|
|
254
|
+
return Promise.resolve([]);
|
|
255
|
+
}
|
|
256
|
+
getCheckpointNumberBySlot(_slot) {
|
|
257
|
+
return Promise.resolve(undefined);
|
|
258
|
+
}
|
|
259
|
+
async getBlockDataWithCheckpointContext(number) {
|
|
260
|
+
const data = await this.getBlockData(number);
|
|
261
|
+
if (!data) {
|
|
262
|
+
return undefined;
|
|
263
|
+
}
|
|
264
|
+
return {
|
|
265
|
+
data,
|
|
266
|
+
checkpoint: undefined,
|
|
267
|
+
l1: undefined,
|
|
268
|
+
attestations: []
|
|
269
|
+
};
|
|
270
|
+
}
|
|
250
271
|
async getBlockDataByArchive(archive) {
|
|
251
272
|
const block = this.l2Blocks.find((b)=>b.archive.root.equals(archive));
|
|
252
273
|
if (!block) {
|
|
@@ -275,6 +296,7 @@ import { TxExecutionResult, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
|
275
296
|
checkpointOutHash: computeCheckpointOutHash(checkpoint.blocks.map((b)=>b.body.txEffects.map((tx)=>tx.l2ToL1Msgs))),
|
|
276
297
|
startBlock: checkpoint.blocks[0].number,
|
|
277
298
|
blockCount: checkpoint.blocks.length,
|
|
299
|
+
feeAssetPriceModifier: checkpoint.feeAssetPriceModifier,
|
|
278
300
|
attestations: [],
|
|
279
301
|
l1: this.mockL1DataForCheckpoint(checkpoint)
|
|
280
302
|
})));
|
|
@@ -437,10 +459,10 @@ import { TxExecutionResult, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
|
437
459
|
valid: true
|
|
438
460
|
});
|
|
439
461
|
}
|
|
440
|
-
|
|
462
|
+
getLastCheckpoint() {
|
|
441
463
|
return Promise.resolve(undefined);
|
|
442
464
|
}
|
|
443
|
-
|
|
465
|
+
getLastProposedCheckpoint() {
|
|
444
466
|
return Promise.resolve(undefined);
|
|
445
467
|
}
|
|
446
468
|
/** Returns checkpoints whose slot falls within the given epoch. */ getCheckpointsInEpoch(epochNumber) {
|
|
@@ -4,14 +4,14 @@ import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
|
|
|
4
4
|
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
5
5
|
import { Archiver } from '../archiver.js';
|
|
6
6
|
import { ArchiverInstrumentation } from '../modules/instrumentation.js';
|
|
7
|
-
import type {
|
|
7
|
+
import type { ArchiverDataStores } from '../store/data_stores.js';
|
|
8
8
|
/**
|
|
9
9
|
* Archiver with mocked L1 connectivity for testing.
|
|
10
10
|
* Uses mock L1 clients and a noop synchronizer, enabling tests that
|
|
11
11
|
* don't require real Ethereum connectivity.
|
|
12
12
|
*/
|
|
13
13
|
export declare class NoopL1Archiver extends Archiver {
|
|
14
|
-
constructor(
|
|
14
|
+
constructor(dataStores: ArchiverDataStores, l1Constants: L1RollupConstants & {
|
|
15
15
|
genesisArchiveRoot: Fr;
|
|
16
16
|
}, instrumentation: ArchiverInstrumentation);
|
|
17
17
|
/** Override start to skip L1 validation checks. */
|
|
@@ -20,7 +20,7 @@ export declare class NoopL1Archiver extends Archiver {
|
|
|
20
20
|
getSyncedL2SlotNumber(): Promise<SlotNumber | undefined>;
|
|
21
21
|
}
|
|
22
22
|
/** Creates an archiver with mocked L1 connectivity for testing. */
|
|
23
|
-
export declare function createNoopL1Archiver(
|
|
23
|
+
export declare function createNoopL1Archiver(dataStores: ArchiverDataStores, l1Constants: L1RollupConstants & {
|
|
24
24
|
genesisArchiveRoot: Fr;
|
|
25
25
|
}, telemetry?: TelemetryClient): Promise<NoopL1Archiver>;
|
|
26
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
26
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9vcF9sMV9hcmNoaXZlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Rlc3Qvbm9vcF9sMV9hcmNoaXZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFHQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFFN0QsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBSXBELE9BQU8sS0FBSyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDckUsT0FBTyxFQUFFLEtBQUssZUFBZSxFQUFtQyxNQUFNLHlCQUF5QixDQUFDO0FBS2hHLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUMxQyxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUV4RSxPQUFPLEtBQUssRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBeUJsRTs7OztHQUlHO0FBQ0gscUJBQWEsY0FBZSxTQUFRLFFBQVE7SUFDMUMsWUFDRSxVQUFVLEVBQUUsa0JBQWtCLEVBQzlCLFdBQVcsRUFBRSxpQkFBaUIsR0FBRztRQUFFLGtCQUFrQixFQUFFLEVBQUUsQ0FBQTtLQUFFLEVBQzNELGVBQWUsRUFBRSx1QkFBdUIsRUF5Q3pDO0lBRUQsbURBQW1EO0lBQ25DLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLE9BQU8sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBSWhFO0lBRUQsNkVBQTZFO0lBQzdELHFCQUFxQixJQUFJLE9BQU8sQ0FBQyxVQUFVLEdBQUcsU0FBUyxDQUFDLENBRXZFO0NBQ0Y7QUFFRCxtRUFBbUU7QUFDbkUsd0JBQXNCLG9CQUFvQixDQUN4QyxVQUFVLEVBQUUsa0JBQWtCLEVBQzlCLFdBQVcsRUFBRSxpQkFBaUIsR0FBRztJQUFFLGtCQUFrQixFQUFFLEVBQUUsQ0FBQTtDQUFFLEVBQzNELFNBQVMsR0FBRSxlQUFzQyxHQUNoRCxPQUFPLENBQUMsY0FBYyxDQUFDLENBR3pCIn0=
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"noop_l1_archiver.d.ts","sourceRoot":"","sources":["../../src/test/noop_l1_archiver.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAE7D,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAIpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,KAAK,eAAe,EAAmC,MAAM,yBAAyB,CAAC;AAKhG,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAExE,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"noop_l1_archiver.d.ts","sourceRoot":"","sources":["../../src/test/noop_l1_archiver.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAE7D,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAIpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,KAAK,eAAe,EAAmC,MAAM,yBAAyB,CAAC;AAKhG,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAExE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAyBlE;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,QAAQ;IAC1C,YACE,UAAU,EAAE,kBAAkB,EAC9B,WAAW,EAAE,iBAAiB,GAAG;QAAE,kBAAkB,EAAE,EAAE,CAAA;KAAE,EAC3D,eAAe,EAAE,uBAAuB,EAyCzC;IAED,mDAAmD;IACnC,KAAK,CAAC,iBAAiB,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhE;IAED,6EAA6E;IAC7D,qBAAqB,IAAI,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAEvE;CACF;AAED,mEAAmE;AACnE,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,kBAAkB,EAC9B,WAAW,EAAE,iBAAiB,GAAG;IAAE,kBAAkB,EAAE,EAAE,CAAA;CAAE,EAC3D,SAAS,GAAE,eAAsC,GAChD,OAAO,CAAC,cAAc,CAAC,CAGzB"}
|
|
@@ -30,7 +30,7 @@ import { ArchiverInstrumentation } from '../modules/instrumentation.js';
|
|
|
30
30
|
* Uses mock L1 clients and a noop synchronizer, enabling tests that
|
|
31
31
|
* don't require real Ethereum connectivity.
|
|
32
32
|
*/ export class NoopL1Archiver extends Archiver {
|
|
33
|
-
constructor(
|
|
33
|
+
constructor(dataStores, l1Constants, instrumentation){
|
|
34
34
|
// Create mocks for L1 clients
|
|
35
35
|
const publicClient = mock();
|
|
36
36
|
const debugClient = mock();
|
|
@@ -47,7 +47,7 @@ import { ArchiverInstrumentation } from '../modules/instrumentation.js';
|
|
|
47
47
|
inboxAddress: EthAddress.ZERO,
|
|
48
48
|
governanceProposerAddress: EthAddress.ZERO,
|
|
49
49
|
slashingProposerAddress: EthAddress.ZERO
|
|
50
|
-
},
|
|
50
|
+
}, dataStores, {
|
|
51
51
|
pollingIntervalMs: 1000,
|
|
52
52
|
batchSize: 100,
|
|
53
53
|
skipValidateCheckpointAttestations: true,
|
|
@@ -68,7 +68,7 @@ import { ArchiverInstrumentation } from '../modules/instrumentation.js';
|
|
|
68
68
|
return Promise.resolve(SlotNumber(Number.MAX_SAFE_INTEGER));
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
-
/** Creates an archiver with mocked L1 connectivity for testing. */ export async function createNoopL1Archiver(
|
|
72
|
-
const instrumentation = await ArchiverInstrumentation.new(telemetry, ()=>
|
|
73
|
-
return new NoopL1Archiver(
|
|
71
|
+
/** Creates an archiver with mocked L1 connectivity for testing. */ export async function createNoopL1Archiver(dataStores, l1Constants, telemetry = getTelemetryClient()) {
|
|
72
|
+
const instrumentation = await ArchiverInstrumentation.new(telemetry, ()=>dataStores.db.estimateSize());
|
|
73
|
+
return new NoopL1Archiver(dataStores, l1Constants, instrumentation);
|
|
74
74
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/archiver",
|
|
3
|
-
"version": "0.0.1-commit.
|
|
3
|
+
"version": "0.0.1-commit.0ec55a70b",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dest/index.js",
|
|
@@ -65,18 +65,18 @@
|
|
|
65
65
|
]
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@aztec/blob-client": "0.0.1-commit.
|
|
69
|
-
"@aztec/blob-lib": "0.0.1-commit.
|
|
70
|
-
"@aztec/constants": "0.0.1-commit.
|
|
71
|
-
"@aztec/epoch-cache": "0.0.1-commit.
|
|
72
|
-
"@aztec/ethereum": "0.0.1-commit.
|
|
73
|
-
"@aztec/foundation": "0.0.1-commit.
|
|
74
|
-
"@aztec/kv-store": "0.0.1-commit.
|
|
75
|
-
"@aztec/l1-artifacts": "0.0.1-commit.
|
|
76
|
-
"@aztec/noir-protocol-circuits-types": "0.0.1-commit.
|
|
77
|
-
"@aztec/protocol-contracts": "0.0.1-commit.
|
|
78
|
-
"@aztec/stdlib": "0.0.1-commit.
|
|
79
|
-
"@aztec/telemetry-client": "0.0.1-commit.
|
|
68
|
+
"@aztec/blob-client": "0.0.1-commit.0ec55a70b",
|
|
69
|
+
"@aztec/blob-lib": "0.0.1-commit.0ec55a70b",
|
|
70
|
+
"@aztec/constants": "0.0.1-commit.0ec55a70b",
|
|
71
|
+
"@aztec/epoch-cache": "0.0.1-commit.0ec55a70b",
|
|
72
|
+
"@aztec/ethereum": "0.0.1-commit.0ec55a70b",
|
|
73
|
+
"@aztec/foundation": "0.0.1-commit.0ec55a70b",
|
|
74
|
+
"@aztec/kv-store": "0.0.1-commit.0ec55a70b",
|
|
75
|
+
"@aztec/l1-artifacts": "0.0.1-commit.0ec55a70b",
|
|
76
|
+
"@aztec/noir-protocol-circuits-types": "0.0.1-commit.0ec55a70b",
|
|
77
|
+
"@aztec/protocol-contracts": "0.0.1-commit.0ec55a70b",
|
|
78
|
+
"@aztec/stdlib": "0.0.1-commit.0ec55a70b",
|
|
79
|
+
"@aztec/telemetry-client": "0.0.1-commit.0ec55a70b",
|
|
80
80
|
"lodash.groupby": "^4.6.0",
|
|
81
81
|
"lodash.omit": "^4.5.0",
|
|
82
82
|
"tslib": "^2.5.0",
|
package/src/archiver.ts
CHANGED
|
@@ -25,19 +25,20 @@ import {
|
|
|
25
25
|
getEpochAtSlot,
|
|
26
26
|
getSlotAtNextL1Block,
|
|
27
27
|
getSlotRangeForEpoch,
|
|
28
|
+
getTimestampForSlot,
|
|
28
29
|
getTimestampRangeForEpoch,
|
|
29
30
|
} from '@aztec/stdlib/epoch-helpers';
|
|
30
31
|
import { type TelemetryClient, type Traceable, type Tracer, trackSpan } from '@aztec/telemetry-client';
|
|
31
32
|
|
|
32
33
|
import { type ArchiverConfig, mapArchiverConfig } from './config.js';
|
|
33
|
-
import { BlockAlreadyCheckpointedError, NoBlobBodiesFoundError } from './errors.js';
|
|
34
|
+
import { BlockAlreadyCheckpointedError, BlockOrCheckpointSlotExpiredError, NoBlobBodiesFoundError } from './errors.js';
|
|
34
35
|
import { validateAndLogHistoricalLogsAvailability } from './l1/validate_historical_logs.js';
|
|
35
36
|
import { validateAndLogTraceAvailability } from './l1/validate_trace.js';
|
|
36
37
|
import { ArchiverDataSourceBase } from './modules/data_source_base.js';
|
|
37
38
|
import { ArchiverDataStoreUpdater } from './modules/data_store_updater.js';
|
|
38
39
|
import type { ArchiverInstrumentation } from './modules/instrumentation.js';
|
|
39
40
|
import type { ArchiverL1Synchronizer } from './modules/l1_synchronizer.js';
|
|
40
|
-
import type
|
|
41
|
+
import { type ArchiverDataStores, backupArchiverDataStores, getArchiverSynchPoint } from './store/data_stores.js';
|
|
41
42
|
import { L2TipsCache } from './store/l2_tips_cache.js';
|
|
42
43
|
|
|
43
44
|
/** Export ArchiverEmitter for use in factory and tests. */
|
|
@@ -45,11 +46,20 @@ export type { ArchiverEmitter };
|
|
|
45
46
|
|
|
46
47
|
/** Request to add a block to the archiver, queued for processing by the sync loop. */
|
|
47
48
|
type AddBlockRequest = {
|
|
49
|
+
type: 'block';
|
|
48
50
|
block: L2Block;
|
|
49
51
|
resolve: () => void;
|
|
50
52
|
reject: (err: Error) => void;
|
|
51
53
|
};
|
|
52
54
|
|
|
55
|
+
/** Request to add a proposed checkpoint to the archiver, queued for processing by the sync loop. */
|
|
56
|
+
type AddProposedCheckpointRequest = {
|
|
57
|
+
type: 'checkpoint';
|
|
58
|
+
checkpoint: ProposedCheckpointInput;
|
|
59
|
+
resolve: () => void;
|
|
60
|
+
reject: (err: Error) => void;
|
|
61
|
+
};
|
|
62
|
+
|
|
53
63
|
export type ArchiverDeps = {
|
|
54
64
|
telemetry?: TelemetryClient;
|
|
55
65
|
blobClient: BlobClientInterface;
|
|
@@ -75,8 +85,8 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
75
85
|
private initialSyncComplete: boolean = false;
|
|
76
86
|
private initialSyncPromise: PromiseWithResolvers<void>;
|
|
77
87
|
|
|
78
|
-
/** Queue of blocks to be added to the store, processed by the sync loop. */
|
|
79
|
-
private
|
|
88
|
+
/** Queue of blocks and checkpoints to be added to the store, processed by the sync loop. */
|
|
89
|
+
private inboundQueue: (AddBlockRequest | AddProposedCheckpointRequest)[] = [];
|
|
80
90
|
|
|
81
91
|
/** Helper to handle updates to the store */
|
|
82
92
|
private readonly updater: ArchiverDataStoreUpdater;
|
|
@@ -95,7 +105,7 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
95
105
|
* @param rollup - Rollup contract instance.
|
|
96
106
|
* @param inbox - Inbox contract instance.
|
|
97
107
|
* @param l1Addresses - L1 contract addresses (registry, governance proposer, slashing proposer).
|
|
98
|
-
* @param
|
|
108
|
+
* @param dataStores - Archiver substores for storage & retrieval of blocks, encrypted logs & contract data.
|
|
99
109
|
* @param config - Archiver configuration options.
|
|
100
110
|
* @param blobClient - Client for retrieving blob data.
|
|
101
111
|
* @param dateProvider - Provider for current date/time.
|
|
@@ -113,7 +123,7 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
113
123
|
> & {
|
|
114
124
|
slashingProposerAddress: EthAddress;
|
|
115
125
|
},
|
|
116
|
-
readonly
|
|
126
|
+
readonly dataStores: ArchiverDataStores,
|
|
117
127
|
private config: {
|
|
118
128
|
pollingIntervalMs: number;
|
|
119
129
|
batchSize: number;
|
|
@@ -133,15 +143,15 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
133
143
|
l2TipsCache?: L2TipsCache,
|
|
134
144
|
private readonly log: Logger = createLogger('archiver'),
|
|
135
145
|
) {
|
|
136
|
-
super(
|
|
146
|
+
super(dataStores, l1Constants);
|
|
137
147
|
|
|
138
148
|
this.tracer = instrumentation.tracer;
|
|
139
149
|
this.instrumentation = instrumentation;
|
|
140
150
|
this.initialSyncPromise = promiseWithResolvers();
|
|
141
151
|
this.synchronizer = synchronizer;
|
|
142
152
|
this.events = events;
|
|
143
|
-
this.l2TipsCache = l2TipsCache ?? new L2TipsCache(this.
|
|
144
|
-
this.updater = new ArchiverDataStoreUpdater(this.
|
|
153
|
+
this.l2TipsCache = l2TipsCache ?? new L2TipsCache(this.dataStores.blocks);
|
|
154
|
+
this.updater = new ArchiverDataStoreUpdater(this.dataStores, this.l2TipsCache, {
|
|
145
155
|
rollupManaLimit: l1Constants.rollupManaLimit,
|
|
146
156
|
});
|
|
147
157
|
|
|
@@ -191,7 +201,9 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
191
201
|
|
|
192
202
|
// Log initial state for the archiver
|
|
193
203
|
const { l1StartBlock } = this.l1Constants;
|
|
194
|
-
const { blocksSynchedTo = l1StartBlock, messagesSynchedTo = l1StartBlock } = await
|
|
204
|
+
const { blocksSynchedTo = l1StartBlock, messagesSynchedTo = l1StartBlock } = await getArchiverSynchPoint(
|
|
205
|
+
this.stores,
|
|
206
|
+
);
|
|
195
207
|
const currentL2Checkpoint = await this.getSynchedCheckpointNumber();
|
|
196
208
|
this.log.info(
|
|
197
209
|
`Starting archiver sync to rollup contract ${this.rollup.address} from L1 block ${blocksSynchedTo} and L2 checkpoint ${currentL2Checkpoint}`,
|
|
@@ -209,6 +221,14 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
209
221
|
return this.runningPromise.trigger();
|
|
210
222
|
}
|
|
211
223
|
|
|
224
|
+
public trySyncImmediate() {
|
|
225
|
+
try {
|
|
226
|
+
return this.syncImmediate();
|
|
227
|
+
} catch (err) {
|
|
228
|
+
this.log.error(`Failed to trigger immediate archiver sync: ${err}`, err);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
212
232
|
/**
|
|
213
233
|
* Queues a block to be added to the archiver store and triggers processing.
|
|
214
234
|
* The block will be processed by the sync loop.
|
|
@@ -217,63 +237,85 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
217
237
|
* @returns A promise that resolves when the block has been added to the store, or rejects on error.
|
|
218
238
|
*/
|
|
219
239
|
public addBlock(block: L2Block): Promise<void> {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
this.log.error(`Sync immediate call failed: ${err}`);
|
|
226
|
-
});
|
|
227
|
-
});
|
|
240
|
+
const promise = promiseWithResolvers<void>();
|
|
241
|
+
this.inboundQueue.push({ block, ...promise, type: 'block' });
|
|
242
|
+
this.log.debug(`Queued block ${block.number} for processing`);
|
|
243
|
+
void this.trySyncImmediate();
|
|
244
|
+
return promise.promise;
|
|
228
245
|
}
|
|
229
246
|
|
|
230
|
-
|
|
231
|
-
|
|
247
|
+
/**
|
|
248
|
+
* Queues a new proposed checkpoint into the archiver store.
|
|
249
|
+
* Checks that the checkpoint is not for an L2 slot already synced from L1.
|
|
250
|
+
* Resolves once the checkpoint has been processed.
|
|
251
|
+
*/
|
|
252
|
+
public addProposedCheckpoint(pending: ProposedCheckpointInput): Promise<void> {
|
|
253
|
+
const promise = promiseWithResolvers<void>();
|
|
254
|
+
this.inboundQueue.push({ checkpoint: pending, ...promise, type: 'checkpoint' });
|
|
255
|
+
this.log.debug(`Queued checkpoint ${pending.checkpointNumber} for processing`);
|
|
256
|
+
void this.trySyncImmediate();
|
|
257
|
+
return promise.promise;
|
|
232
258
|
}
|
|
233
259
|
|
|
234
260
|
/**
|
|
235
|
-
* Processes all queued blocks, adding them to the store.
|
|
261
|
+
* Processes all queued blocks and checkpoints, adding them to the store.
|
|
236
262
|
* Called at the beginning of each sync iteration.
|
|
237
|
-
*
|
|
263
|
+
* Items are processed in the order they were queued.
|
|
238
264
|
*/
|
|
239
|
-
private async
|
|
240
|
-
if (this.
|
|
265
|
+
private async processInboundQueue(): Promise<void> {
|
|
266
|
+
if (this.inboundQueue.length === 0) {
|
|
241
267
|
return;
|
|
242
268
|
}
|
|
243
269
|
|
|
244
|
-
// Take all
|
|
245
|
-
const queuedItems = this.
|
|
246
|
-
this.log.debug(`Processing ${queuedItems.length} queued
|
|
270
|
+
// Take all items from the queue
|
|
271
|
+
const queuedItems = this.inboundQueue.splice(0, this.inboundQueue.length);
|
|
272
|
+
this.log.debug(`Processing ${queuedItems.length} queued inbound items`);
|
|
247
273
|
|
|
248
274
|
// Calculate slot threshold for validation
|
|
249
275
|
const l1Timestamp = this.synchronizer.getL1Timestamp();
|
|
250
276
|
const slotAtNextL1Block =
|
|
251
277
|
l1Timestamp === undefined ? undefined : getSlotAtNextL1Block(l1Timestamp, this.l1Constants);
|
|
252
278
|
|
|
253
|
-
//
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
279
|
+
// Helpers for manipulating blocks and checkpoints in the queue
|
|
280
|
+
const getSlot: (item: AddBlockRequest | AddProposedCheckpointRequest) => SlotNumber = item =>
|
|
281
|
+
item.type === 'block' ? item.block.header.globalVariables.slotNumber : item.checkpoint.header.slotNumber;
|
|
282
|
+
const getNumber: (item: AddBlockRequest | AddProposedCheckpointRequest) => number = item =>
|
|
283
|
+
item.type === 'block' ? item.block.number : item.checkpoint.checkpointNumber;
|
|
284
|
+
|
|
285
|
+
// Process each item individually to properly resolve/reject each promise
|
|
286
|
+
for (const item of queuedItems) {
|
|
287
|
+
const { resolve, reject, type } = item;
|
|
288
|
+
const itemSlot = getSlot(item);
|
|
289
|
+
const itemNumber = getNumber(item);
|
|
290
|
+
if (slotAtNextL1Block !== undefined && itemSlot < slotAtNextL1Block) {
|
|
291
|
+
const nextSlotTimestamp = getTimestampForSlot(slotAtNextL1Block, this.l1Constants);
|
|
257
292
|
this.log.warn(
|
|
258
|
-
`Rejecting proposed
|
|
259
|
-
{
|
|
293
|
+
`Rejecting proposed ${type} ${itemNumber} for past slot ${itemSlot} (current ${slotAtNextL1Block})`,
|
|
294
|
+
{ number: itemNumber, type, l1Timestamp, slotAtNextL1Block, nextSlotTimestamp },
|
|
260
295
|
);
|
|
261
|
-
reject(new
|
|
296
|
+
reject(new BlockOrCheckpointSlotExpiredError(itemSlot, nextSlotTimestamp, l1Timestamp));
|
|
262
297
|
continue;
|
|
263
298
|
}
|
|
264
299
|
|
|
265
300
|
try {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
301
|
+
if (type === 'block') {
|
|
302
|
+
const [durationMs] = await elapsed(() => this.updater.addProposedBlock(item.block));
|
|
303
|
+
this.instrumentation.processNewProposedBlock(durationMs, item.block);
|
|
304
|
+
} else {
|
|
305
|
+
await this.updater.addProposedCheckpoint(item.checkpoint);
|
|
306
|
+
}
|
|
307
|
+
this.log.debug(`Added ${type} ${itemNumber} to store`);
|
|
269
308
|
resolve();
|
|
270
309
|
} catch (err: any) {
|
|
271
310
|
if (err instanceof BlockAlreadyCheckpointedError) {
|
|
272
|
-
this.log.debug(`Proposed block ${
|
|
311
|
+
this.log.debug(`Proposed block ${itemNumber} matches already checkpointed block, ignoring late proposal`);
|
|
273
312
|
resolve();
|
|
274
313
|
continue;
|
|
275
314
|
}
|
|
276
|
-
this.log.error(`Failed to add
|
|
315
|
+
this.log.error(`Failed to add ${type} ${itemNumber} to store: ${err.message}`, err, {
|
|
316
|
+
number: itemNumber,
|
|
317
|
+
type,
|
|
318
|
+
});
|
|
277
319
|
reject(err);
|
|
278
320
|
}
|
|
279
321
|
}
|
|
@@ -289,7 +331,7 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
289
331
|
@trackSpan('Archiver.sync')
|
|
290
332
|
private async sync() {
|
|
291
333
|
// Process any queued blocks first, before doing L1 sync
|
|
292
|
-
await this.
|
|
334
|
+
await this.processInboundQueue();
|
|
293
335
|
// Now perform L1 sync
|
|
294
336
|
await this.syncFromL1();
|
|
295
337
|
}
|
|
@@ -305,7 +347,7 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
305
347
|
if (currentL1BlockNumber + 1n >= l1BlockNumberAtEnd) {
|
|
306
348
|
this.log.info(`Initial archiver sync to L1 block ${currentL1BlockNumber} complete`, {
|
|
307
349
|
l1BlockNumber: currentL1BlockNumber,
|
|
308
|
-
syncPoint: await this.
|
|
350
|
+
syncPoint: await getArchiverSynchPoint(this.stores),
|
|
309
351
|
...(await this.getL2Tips()),
|
|
310
352
|
});
|
|
311
353
|
this.runningPromise.setPollingIntervalMS(this.config.pollingIntervalMs);
|
|
@@ -337,7 +379,7 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
337
379
|
}
|
|
338
380
|
|
|
339
381
|
public backupTo(destPath: string): Promise<string> {
|
|
340
|
-
return this.
|
|
382
|
+
return backupArchiverDataStores(this.dataStores, destPath);
|
|
341
383
|
}
|
|
342
384
|
|
|
343
385
|
public getL1Constants(): Promise<L1RollupConstants> {
|
|
@@ -379,9 +421,9 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
379
421
|
}
|
|
380
422
|
|
|
381
423
|
let slotFromCheckpoint: SlotNumber | undefined;
|
|
382
|
-
const latestCheckpointNumber = await this.
|
|
424
|
+
const latestCheckpointNumber = await this.stores.blocks.getLatestCheckpointNumber();
|
|
383
425
|
if (latestCheckpointNumber > 0) {
|
|
384
|
-
const checkpointData = await this.
|
|
426
|
+
const checkpointData = await this.stores.blocks.getCheckpointData(latestCheckpointNumber);
|
|
385
427
|
if (checkpointData) {
|
|
386
428
|
slotFromCheckpoint = checkpointData.header.slotNumber;
|
|
387
429
|
}
|
|
@@ -470,14 +512,14 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
470
512
|
if (targetL2BlockNumber >= currentL2Block) {
|
|
471
513
|
throw new Error(`Target L2 block ${targetL2BlockNumber} must be less than current L2 block ${currentL2Block}`);
|
|
472
514
|
}
|
|
473
|
-
const targetL2Block = await this.
|
|
515
|
+
const targetL2Block = await this.stores.blocks.getCheckpointedBlock(targetL2BlockNumber);
|
|
474
516
|
if (!targetL2Block) {
|
|
475
517
|
throw new Error(`Target L2 block ${targetL2BlockNumber} not found`);
|
|
476
518
|
}
|
|
477
519
|
const targetCheckpointNumber = targetL2Block.checkpointNumber;
|
|
478
520
|
|
|
479
521
|
// Rollback operates at checkpoint granularity: the target block must be the last block of its checkpoint.
|
|
480
|
-
const checkpointData = await this.
|
|
522
|
+
const checkpointData = await this.stores.blocks.getCheckpointData(targetCheckpointNumber);
|
|
481
523
|
if (checkpointData) {
|
|
482
524
|
const lastBlockInCheckpoint = BlockNumber(checkpointData.startBlock + checkpointData.blockCount - 1);
|
|
483
525
|
if (targetL2BlockNumber !== lastBlockInCheckpoint) {
|
|
@@ -506,10 +548,10 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
506
548
|
);
|
|
507
549
|
await this.updater.removeCheckpointsAfter(targetCheckpointNumber);
|
|
508
550
|
this.log.info(`Rolling back L1 to L2 messages to checkpoint ${targetCheckpointNumber}`);
|
|
509
|
-
await this.
|
|
551
|
+
await this.stores.messages.rollbackL1ToL2MessagesToCheckpoint(targetCheckpointNumber);
|
|
510
552
|
this.log.info(`Setting L1 syncpoints to ${targetL1BlockNumber}`);
|
|
511
|
-
await this.
|
|
512
|
-
await this.
|
|
553
|
+
await this.stores.blocks.setSynchedL1BlockNumber(targetL1BlockNumber);
|
|
554
|
+
await this.stores.messages.setMessageSyncState(
|
|
513
555
|
{ l1BlockNumber: targetL1BlockNumber, l1BlockHash: targetL1BlockHash },
|
|
514
556
|
undefined,
|
|
515
557
|
);
|
package/src/config.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
booleanConfigHelper,
|
|
8
8
|
getConfigFromMappings,
|
|
9
9
|
numberConfigHelper,
|
|
10
|
+
optionalNumberConfigHelper,
|
|
10
11
|
} from '@aztec/foundation/config';
|
|
11
12
|
import {
|
|
12
13
|
type ChainConfig,
|
|
@@ -50,7 +51,7 @@ export const archiverConfigMappings: ConfigMappingsType<ArchiverConfig> = {
|
|
|
50
51
|
},
|
|
51
52
|
archiverStoreMapSizeKb: {
|
|
52
53
|
env: 'ARCHIVER_STORE_MAP_SIZE_KB',
|
|
53
|
-
|
|
54
|
+
...optionalNumberConfigHelper(),
|
|
54
55
|
description: 'The maximum possible size of the archiver DB in KB. Overwrites the general dataStoreMapSizeKb.',
|
|
55
56
|
},
|
|
56
57
|
skipValidateCheckpointAttestations: {
|
package/src/errors.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
+
import type { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
1
2
|
import type { Fr } from '@aztec/foundation/schemas';
|
|
2
3
|
|
|
3
4
|
export class NoBlobBodiesFoundError extends Error {
|
|
4
5
|
constructor(l2BlockNum: number) {
|
|
5
6
|
super(`No blob bodies found for block ${l2BlockNum}`);
|
|
7
|
+
this.name = 'NoBlobBodiesFoundError';
|
|
6
8
|
}
|
|
7
9
|
}
|
|
8
10
|
|
|
9
11
|
export class BlockNumberNotSequentialError extends Error {
|
|
10
12
|
constructor(newBlockNumber: number, previous: number | undefined) {
|
|
11
13
|
super(`Cannot insert new block ${newBlockNumber} given previous block number is ${previous ?? 'undefined'}`);
|
|
14
|
+
this.name = 'BlockNumberNotSequentialError';
|
|
12
15
|
}
|
|
13
16
|
}
|
|
14
17
|
|
|
@@ -22,18 +25,29 @@ export class InitialCheckpointNumberNotSequentialError extends Error {
|
|
|
22
25
|
previousCheckpointNumber ?? 'undefined'
|
|
23
26
|
}`,
|
|
24
27
|
);
|
|
28
|
+
this.name = 'InitialCheckpointNumberNotSequentialError';
|
|
25
29
|
}
|
|
26
30
|
}
|
|
27
31
|
|
|
28
|
-
export class
|
|
32
|
+
export class BlockCheckpointNumberNotSequentialError extends Error {
|
|
29
33
|
constructor(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
blockNumber: BlockNumber,
|
|
35
|
+
blockCheckpointNumber: CheckpointNumber,
|
|
36
|
+
previous: CheckpointNumber | undefined,
|
|
33
37
|
) {
|
|
34
38
|
super(
|
|
35
|
-
`Cannot insert new
|
|
39
|
+
`Cannot insert new block ${blockNumber} for checkpoint ${blockCheckpointNumber} given previous checkpoint number is ${previous ?? 'undefined'}`,
|
|
40
|
+
);
|
|
41
|
+
this.name = 'BlockCheckpointNumberNotSequentialError';
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class CheckpointNumberNotSequentialError extends Error {
|
|
46
|
+
constructor(newCheckpointNumber: CheckpointNumber, previous: CheckpointNumber | undefined) {
|
|
47
|
+
super(
|
|
48
|
+
`Cannot insert new checkpoint ${newCheckpointNumber} given previous checkpoint number is ${previous ?? 'undefined'}`,
|
|
36
49
|
);
|
|
50
|
+
this.name = 'CheckpointNumberNotSequentialError';
|
|
37
51
|
}
|
|
38
52
|
}
|
|
39
53
|
|
|
@@ -42,6 +56,7 @@ export class BlockIndexNotSequentialError extends Error {
|
|
|
42
56
|
super(
|
|
43
57
|
`Cannot insert new block at checkpoint index ${newBlockIndex} given previous block index is ${previousBlockIndex ?? 'undefined'}`,
|
|
44
58
|
);
|
|
59
|
+
this.name = 'BlockIndexNotSequentialError';
|
|
45
60
|
}
|
|
46
61
|
}
|
|
47
62
|
|
|
@@ -55,18 +70,21 @@ export class BlockArchiveNotConsistentError extends Error {
|
|
|
55
70
|
super(
|
|
56
71
|
`Cannot insert new block number ${newBlockNumber} with archive ${newBlockArchive.toString()} previous block number is ${previousBlockNumber ?? 'undefined'}, previous archive is ${previousBlockArchive?.toString() ?? 'undefined'}`,
|
|
57
72
|
);
|
|
73
|
+
this.name = 'BlockArchiveNotConsistentError';
|
|
58
74
|
}
|
|
59
75
|
}
|
|
60
76
|
|
|
61
77
|
export class CheckpointNotFoundError extends Error {
|
|
62
78
|
constructor(checkpointNumber: number) {
|
|
63
79
|
super(`Failed to find expected checkpoint number ${checkpointNumber}`);
|
|
80
|
+
this.name = 'CheckpointNotFoundError';
|
|
64
81
|
}
|
|
65
82
|
}
|
|
66
83
|
|
|
67
84
|
export class BlockNotFoundError extends Error {
|
|
68
85
|
constructor(blockNumber: number) {
|
|
69
86
|
super(`Failed to find expected block number ${blockNumber}`);
|
|
87
|
+
this.name = 'BlockNotFoundError';
|
|
70
88
|
}
|
|
71
89
|
}
|
|
72
90
|
|
|
@@ -119,19 +137,34 @@ export class ProposedCheckpointStaleError extends Error {
|
|
|
119
137
|
}
|
|
120
138
|
}
|
|
121
139
|
|
|
122
|
-
/** Thrown when a proposed checkpoint number is not the expected
|
|
140
|
+
/** Thrown when a proposed checkpoint number is not the expected latestTip + 1. */
|
|
123
141
|
export class ProposedCheckpointNotSequentialError extends Error {
|
|
124
142
|
constructor(
|
|
125
143
|
public readonly proposedCheckpointNumber: number,
|
|
126
|
-
public readonly
|
|
144
|
+
public readonly latestTipNumber: number,
|
|
127
145
|
) {
|
|
128
146
|
super(
|
|
129
|
-
`Proposed checkpoint ${proposedCheckpointNumber} is not sequential: expected ${
|
|
147
|
+
`Proposed checkpoint ${proposedCheckpointNumber} is not sequential: expected ${latestTipNumber + 1} (latest tip + 1, where tip is highest of confirmed or pending)`,
|
|
130
148
|
);
|
|
131
149
|
this.name = 'ProposedCheckpointNotSequentialError';
|
|
132
150
|
}
|
|
133
151
|
}
|
|
134
152
|
|
|
153
|
+
/** Thrown when a proposed checkpoint or block L2 slot has already expired on L1. */
|
|
154
|
+
export class BlockOrCheckpointSlotExpiredError extends Error {
|
|
155
|
+
constructor(
|
|
156
|
+
public readonly slot: number,
|
|
157
|
+
public readonly nextSlotStart: bigint,
|
|
158
|
+
public readonly l1TimestampSynced: bigint | undefined,
|
|
159
|
+
) {
|
|
160
|
+
super(
|
|
161
|
+
`Checkpoint or block for slot ${slot} is expired: L1 synced to ${l1TimestampSynced} which is past the next slot start ${nextSlotStart}. ` +
|
|
162
|
+
`If the checkpoint still lands via a late L1 tx, the archiver will pick it up via normal L1-sync (not the pending-queue shortcut).`,
|
|
163
|
+
);
|
|
164
|
+
this.name = 'BlockOrCheckpointSlotExpiredError';
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
135
168
|
/** Thrown when attempting to promote a proposed checkpoint but no proposed checkpoint exists in the store. */
|
|
136
169
|
export class NoProposedCheckpointToPromoteError extends Error {
|
|
137
170
|
constructor() {
|