@aztec/archiver 0.0.1-commit.fcb71a6 → 0.0.1-commit.fffb133c
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 +156 -22
- package/dest/archiver.d.ts +135 -0
- package/dest/archiver.d.ts.map +1 -0
- package/dest/archiver.js +768 -0
- package/dest/{archiver/config.d.ts → config.d.ts} +9 -1
- package/dest/config.d.ts.map +1 -0
- package/dest/{archiver/config.js → config.js} +11 -2
- package/dest/errors.d.ts +41 -0
- package/dest/errors.d.ts.map +1 -0
- package/dest/{archiver/errors.js → errors.js} +8 -0
- package/dest/factory.d.ts +7 -7
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +87 -8
- package/dest/index.d.ts +10 -4
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +8 -3
- package/dest/interfaces.d.ts +9 -0
- package/dest/interfaces.d.ts.map +1 -0
- package/dest/interfaces.js +3 -0
- package/dest/{archiver/l1 → l1}/bin/retrieve-calldata.d.ts +1 -1
- package/dest/l1/bin/retrieve-calldata.d.ts.map +1 -0
- package/dest/{archiver/l1 → l1}/bin/retrieve-calldata.js +2 -2
- package/dest/{archiver/l1 → l1}/calldata_retriever.d.ts +3 -3
- package/dest/l1/calldata_retriever.d.ts.map +1 -0
- package/dest/{archiver/l1 → l1}/calldata_retriever.js +2 -2
- package/dest/l1/data_retrieval.d.ts +88 -0
- package/dest/l1/data_retrieval.d.ts.map +1 -0
- package/dest/{archiver/l1 → l1}/data_retrieval.js +35 -54
- package/dest/{archiver/l1 → l1}/debug_tx.d.ts +1 -1
- package/dest/l1/debug_tx.d.ts.map +1 -0
- package/dest/{archiver/l1 → l1}/spire_proposer.d.ts +1 -1
- package/dest/l1/spire_proposer.d.ts.map +1 -0
- package/dest/{archiver/l1 → l1}/trace_tx.d.ts +1 -1
- package/dest/l1/trace_tx.d.ts.map +1 -0
- package/dest/l1/types.d.ts +12 -0
- package/dest/l1/types.d.ts.map +1 -0
- package/dest/{archiver/l1 → l1}/validate_trace.d.ts +1 -1
- package/dest/l1/validate_trace.d.ts.map +1 -0
- package/dest/{archiver/l1 → l1}/validate_trace.js +1 -1
- package/dest/modules/data_source_base.d.ts +84 -0
- package/dest/modules/data_source_base.d.ts.map +1 -0
- package/dest/modules/data_source_base.js +260 -0
- package/dest/modules/data_store_updater.d.ts +73 -0
- package/dest/modules/data_store_updater.d.ts.map +1 -0
- package/dest/modules/data_store_updater.js +302 -0
- package/dest/modules/instrumentation.d.ts +37 -0
- package/dest/modules/instrumentation.d.ts.map +1 -0
- package/dest/{archiver → modules}/instrumentation.js +15 -63
- package/dest/modules/l1_synchronizer.d.ts +75 -0
- package/dest/modules/l1_synchronizer.d.ts.map +1 -0
- package/dest/modules/l1_synchronizer.js +1113 -0
- package/dest/modules/validation.d.ts +17 -0
- package/dest/modules/validation.d.ts.map +1 -0
- package/dest/{archiver → modules}/validation.js +7 -1
- package/dest/store/block_store.d.ts +192 -0
- package/dest/store/block_store.d.ts.map +1 -0
- package/dest/{archiver/kv_archiver_store → store}/block_store.js +162 -48
- package/dest/store/contract_class_store.d.ts +18 -0
- package/dest/store/contract_class_store.d.ts.map +1 -0
- package/dest/{archiver/kv_archiver_store → store}/contract_class_store.js +1 -1
- package/dest/store/contract_instance_store.d.ts +24 -0
- package/dest/store/contract_instance_store.d.ts.map +1 -0
- package/dest/{archiver/kv_archiver_store → store}/contract_instance_store.js +1 -1
- package/dest/store/kv_archiver_store.d.ts +340 -0
- package/dest/store/kv_archiver_store.d.ts.map +1 -0
- package/dest/store/kv_archiver_store.js +447 -0
- package/dest/store/log_store.d.ts +54 -0
- package/dest/store/log_store.d.ts.map +1 -0
- package/dest/{archiver/kv_archiver_store → store}/log_store.js +89 -54
- package/dest/{archiver/kv_archiver_store → store}/message_store.d.ts +1 -1
- package/dest/store/message_store.d.ts.map +1 -0
- package/dest/{archiver/structs → structs}/data_retrieval.d.ts +1 -1
- package/dest/structs/data_retrieval.d.ts.map +1 -0
- package/dest/structs/inbox_message.d.ts +15 -0
- package/dest/structs/inbox_message.d.ts.map +1 -0
- package/dest/{archiver/structs → structs}/published.d.ts +1 -1
- package/dest/structs/published.d.ts.map +1 -0
- package/dest/test/fake_l1_state.d.ts +190 -0
- package/dest/test/fake_l1_state.d.ts.map +1 -0
- package/dest/test/fake_l1_state.js +383 -0
- package/dest/test/index.d.ts +2 -1
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/index.js +1 -0
- package/dest/test/mock_archiver.d.ts +2 -2
- package/dest/test/mock_archiver.d.ts.map +1 -1
- package/dest/test/mock_archiver.js +1 -2
- package/dest/test/mock_l1_to_l2_message_source.d.ts +2 -2
- package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
- package/dest/test/mock_l1_to_l2_message_source.js +12 -3
- package/dest/test/mock_l2_block_source.d.ts +22 -15
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +163 -57
- package/dest/test/mock_structs.d.ts +76 -2
- package/dest/test/mock_structs.d.ts.map +1 -1
- package/dest/test/mock_structs.js +133 -2
- package/package.json +15 -17
- package/src/archiver.ts +523 -0
- package/src/{archiver/config.ts → config.ts} +13 -2
- package/src/{archiver/errors.ts → errors.ts} +12 -0
- package/src/factory.ts +122 -8
- package/src/index.ts +10 -3
- package/src/interfaces.ts +9 -0
- package/src/{archiver/l1 → l1}/bin/retrieve-calldata.ts +7 -2
- package/src/{archiver/l1 → l1}/calldata_retriever.ts +3 -3
- package/src/{archiver/l1 → l1}/data_retrieval.ts +56 -73
- package/src/{archiver/l1 → l1}/validate_trace.ts +1 -1
- package/src/modules/data_source_base.ts +367 -0
- package/src/modules/data_store_updater.ts +423 -0
- package/src/{archiver → modules}/instrumentation.ts +16 -65
- package/src/modules/l1_synchronizer.ts +931 -0
- package/src/{archiver → modules}/validation.ts +11 -6
- package/src/{archiver/kv_archiver_store → store}/block_store.ts +210 -66
- package/src/{archiver/kv_archiver_store → store}/contract_class_store.ts +1 -1
- package/src/{archiver/kv_archiver_store → store}/contract_instance_store.ts +1 -1
- package/src/{archiver/kv_archiver_store → store}/kv_archiver_store.ts +236 -35
- package/src/{archiver/kv_archiver_store → store}/log_store.ts +145 -86
- package/src/test/fake_l1_state.ts +599 -0
- package/src/test/index.ts +1 -0
- package/src/test/mock_archiver.ts +2 -2
- package/src/test/mock_l1_to_l2_message_source.ts +10 -4
- package/src/test/mock_l2_block_source.ts +173 -67
- package/src/test/mock_structs.ts +247 -2
- package/dest/archiver/archiver.d.ts +0 -304
- package/dest/archiver/archiver.d.ts.map +0 -1
- package/dest/archiver/archiver.js +0 -1645
- package/dest/archiver/archiver_store.d.ts +0 -308
- package/dest/archiver/archiver_store.d.ts.map +0 -1
- package/dest/archiver/archiver_store.js +0 -4
- package/dest/archiver/archiver_store_test_suite.d.ts +0 -8
- package/dest/archiver/archiver_store_test_suite.d.ts.map +0 -1
- package/dest/archiver/archiver_store_test_suite.js +0 -2770
- package/dest/archiver/config.d.ts.map +0 -1
- package/dest/archiver/errors.d.ts +0 -36
- package/dest/archiver/errors.d.ts.map +0 -1
- package/dest/archiver/index.d.ts +0 -7
- package/dest/archiver/index.d.ts.map +0 -1
- package/dest/archiver/index.js +0 -4
- package/dest/archiver/instrumentation.d.ts +0 -37
- package/dest/archiver/instrumentation.d.ts.map +0 -1
- package/dest/archiver/kv_archiver_store/block_store.d.ts +0 -157
- package/dest/archiver/kv_archiver_store/block_store.d.ts.map +0 -1
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +0 -18
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +0 -1
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +0 -24
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +0 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +0 -158
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +0 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.js +0 -313
- package/dest/archiver/kv_archiver_store/log_store.d.ts +0 -45
- package/dest/archiver/kv_archiver_store/log_store.d.ts.map +0 -1
- package/dest/archiver/kv_archiver_store/message_store.d.ts.map +0 -1
- package/dest/archiver/l1/bin/retrieve-calldata.d.ts.map +0 -1
- package/dest/archiver/l1/calldata_retriever.d.ts.map +0 -1
- package/dest/archiver/l1/data_retrieval.d.ts +0 -90
- package/dest/archiver/l1/data_retrieval.d.ts.map +0 -1
- package/dest/archiver/l1/debug_tx.d.ts.map +0 -1
- package/dest/archiver/l1/spire_proposer.d.ts.map +0 -1
- package/dest/archiver/l1/trace_tx.d.ts.map +0 -1
- package/dest/archiver/l1/types.d.ts +0 -12
- package/dest/archiver/l1/types.d.ts.map +0 -1
- package/dest/archiver/l1/validate_trace.d.ts.map +0 -1
- package/dest/archiver/structs/data_retrieval.d.ts.map +0 -1
- package/dest/archiver/structs/inbox_message.d.ts +0 -15
- package/dest/archiver/structs/inbox_message.d.ts.map +0 -1
- package/dest/archiver/structs/published.d.ts.map +0 -1
- package/dest/archiver/validation.d.ts +0 -17
- package/dest/archiver/validation.d.ts.map +0 -1
- package/dest/rpc/index.d.ts +0 -9
- package/dest/rpc/index.d.ts.map +0 -1
- package/dest/rpc/index.js +0 -15
- package/src/archiver/archiver.ts +0 -2157
- package/src/archiver/archiver_store.ts +0 -372
- package/src/archiver/archiver_store_test_suite.ts +0 -2843
- package/src/archiver/index.ts +0 -6
- package/src/rpc/index.ts +0 -16
- /package/dest/{archiver/l1 → l1}/debug_tx.js +0 -0
- /package/dest/{archiver/l1 → l1}/spire_proposer.js +0 -0
- /package/dest/{archiver/l1 → l1}/trace_tx.js +0 -0
- /package/dest/{archiver/l1 → l1}/types.js +0 -0
- /package/dest/{archiver/kv_archiver_store → store}/message_store.js +0 -0
- /package/dest/{archiver/structs → structs}/data_retrieval.js +0 -0
- /package/dest/{archiver/structs → structs}/inbox_message.js +0 -0
- /package/dest/{archiver/structs → structs}/published.js +0 -0
- /package/src/{archiver/l1 → l1}/README.md +0 -0
- /package/src/{archiver/l1 → l1}/debug_tx.ts +0 -0
- /package/src/{archiver/l1 → l1}/spire_proposer.ts +0 -0
- /package/src/{archiver/l1 → l1}/trace_tx.ts +0 -0
- /package/src/{archiver/l1 → l1}/types.ts +0 -0
- /package/src/{archiver/kv_archiver_store → store}/message_store.ts +0 -0
- /package/src/{archiver/structs → structs}/data_retrieval.ts +0 -0
- /package/src/{archiver/structs → structs}/inbox_message.ts +0 -0
- /package/src/{archiver/structs → structs}/published.ts +0 -0
|
@@ -4,15 +4,15 @@ import { compactArray } from '@aztec/foundation/collection';
|
|
|
4
4
|
import type { Logger } from '@aztec/foundation/log';
|
|
5
5
|
import {
|
|
6
6
|
type AttestationInfo,
|
|
7
|
-
type
|
|
8
|
-
type
|
|
7
|
+
type ValidateCheckpointNegativeResult,
|
|
8
|
+
type ValidateCheckpointResult,
|
|
9
9
|
getAttestationInfoFromPayload,
|
|
10
10
|
} from '@aztec/stdlib/block';
|
|
11
11
|
import type { PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
12
12
|
import { type L1RollupConstants, getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
|
|
13
13
|
import { ConsensusPayload } from '@aztec/stdlib/p2p';
|
|
14
14
|
|
|
15
|
-
export type {
|
|
15
|
+
export type { ValidateCheckpointResult };
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Extracts attestation information from a published checkpoint.
|
|
@@ -35,7 +35,7 @@ export async function validateCheckpointAttestations(
|
|
|
35
35
|
epochCache: EpochCache,
|
|
36
36
|
constants: Pick<L1RollupConstants, 'epochDuration'>,
|
|
37
37
|
logger?: Logger,
|
|
38
|
-
): Promise<
|
|
38
|
+
): Promise<ValidateCheckpointResult> {
|
|
39
39
|
const attestorInfos = getAttestationInfoFromPublishedCheckpoint(publishedCheckpoint);
|
|
40
40
|
const attestors = compactArray(attestorInfos.map(info => ('address' in info ? info.address : undefined)));
|
|
41
41
|
const { checkpoint, attestations } = publishedCheckpoint;
|
|
@@ -61,12 +61,17 @@ export async function validateCheckpointAttestations(
|
|
|
61
61
|
return { valid: true };
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
if (await epochCache.isEscapeHatchOpen(epoch)) {
|
|
65
|
+
logger?.warn(`Escape hatch open for epoch ${epoch} at slot ${slot}, skipping checkpoint validation`);
|
|
66
|
+
return { valid: true };
|
|
67
|
+
}
|
|
68
|
+
|
|
64
69
|
const requiredAttestationCount = Math.floor((committee.length * 2) / 3) + 1;
|
|
65
70
|
|
|
66
|
-
const failedValidationResult = <TReason extends
|
|
71
|
+
const failedValidationResult = <TReason extends ValidateCheckpointNegativeResult['reason']>(reason: TReason) => ({
|
|
67
72
|
valid: false as const,
|
|
68
73
|
reason,
|
|
69
|
-
|
|
74
|
+
checkpoint: checkpoint.toCheckpointInfo(),
|
|
70
75
|
committee,
|
|
71
76
|
seed,
|
|
72
77
|
epoch,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { INITIAL_CHECKPOINT_NUMBER, INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
2
|
-
import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
2
|
+
import { BlockNumber, CheckpointNumber, IndexWithinCheckpoint, SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
3
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
4
|
import { toArray } from '@aztec/foundation/iterable';
|
|
5
5
|
import { createLogger } from '@aztec/foundation/log';
|
|
@@ -12,13 +12,14 @@ import {
|
|
|
12
12
|
Body,
|
|
13
13
|
CheckpointedL2Block,
|
|
14
14
|
CommitteeAttestation,
|
|
15
|
+
L2Block,
|
|
15
16
|
L2BlockHash,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
serializeValidateBlockResult,
|
|
17
|
+
type ValidateCheckpointResult,
|
|
18
|
+
deserializeValidateCheckpointResult,
|
|
19
|
+
serializeValidateCheckpointResult,
|
|
20
20
|
} from '@aztec/stdlib/block';
|
|
21
21
|
import { L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
22
|
+
import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
|
|
22
23
|
import { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
23
24
|
import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
|
|
24
25
|
import {
|
|
@@ -27,6 +28,7 @@ import {
|
|
|
27
28
|
TxEffect,
|
|
28
29
|
TxHash,
|
|
29
30
|
TxReceipt,
|
|
31
|
+
TxStatus,
|
|
30
32
|
deserializeIndexedTxEffect,
|
|
31
33
|
serializeIndexedTxEffect,
|
|
32
34
|
} from '@aztec/stdlib/tx';
|
|
@@ -36,6 +38,7 @@ import {
|
|
|
36
38
|
BlockIndexNotSequentialError,
|
|
37
39
|
BlockNotFoundError,
|
|
38
40
|
BlockNumberNotSequentialError,
|
|
41
|
+
CannotOverwriteCheckpointedBlockError,
|
|
39
42
|
CheckpointNotFoundError,
|
|
40
43
|
CheckpointNumberNotConsistentError,
|
|
41
44
|
CheckpointNumberNotSequentialError,
|
|
@@ -75,8 +78,10 @@ export type CheckpointData = {
|
|
|
75
78
|
attestations: Buffer[];
|
|
76
79
|
};
|
|
77
80
|
|
|
81
|
+
export type RemoveCheckpointsResult = { blocksRemoved: L2Block[] | undefined };
|
|
82
|
+
|
|
78
83
|
/**
|
|
79
|
-
* LMDB
|
|
84
|
+
* LMDB-based block storage for the archiver.
|
|
80
85
|
*/
|
|
81
86
|
export class BlockStore {
|
|
82
87
|
/** Map block number to block data */
|
|
@@ -111,7 +116,10 @@ export class BlockStore {
|
|
|
111
116
|
|
|
112
117
|
#log = createLogger('archiver:block_store');
|
|
113
118
|
|
|
114
|
-
constructor(
|
|
119
|
+
constructor(
|
|
120
|
+
private db: AztecAsyncKVStore,
|
|
121
|
+
private l1Constants: Pick<L1RollupConstants, 'epochDuration'>,
|
|
122
|
+
) {
|
|
115
123
|
this.#blocks = db.openMap('archiver_blocks');
|
|
116
124
|
this.#blockTxs = db.openMap('archiver_block_txs');
|
|
117
125
|
this.#txEffects = db.openMap('archiver_tx_effects');
|
|
@@ -125,11 +133,25 @@ export class BlockStore {
|
|
|
125
133
|
}
|
|
126
134
|
|
|
127
135
|
/**
|
|
128
|
-
*
|
|
129
|
-
*
|
|
136
|
+
* Computes the finalized block number based on the proven block number.
|
|
137
|
+
* A block is considered finalized when it's 2 epochs behind the proven block.
|
|
138
|
+
* TODO(#13569): Compute proper finalized block number based on L1 finalized block.
|
|
139
|
+
* TODO(palla/mbps): Even the provisional computation is wrong, since it should subtract checkpoints, not blocks
|
|
140
|
+
* @returns The finalized block number.
|
|
141
|
+
*/
|
|
142
|
+
async getFinalizedL2BlockNumber(): Promise<BlockNumber> {
|
|
143
|
+
const provenBlockNumber = await this.getProvenBlockNumber();
|
|
144
|
+
return BlockNumber(Math.max(provenBlockNumber - this.l1Constants.epochDuration * 2, 0));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Append new proposed blocks to the store's list. All blocks must be for the 'current' checkpoint.
|
|
149
|
+
* These are uncheckpointed blocks that have been proposed by the sequencer but not yet included in a checkpoint on L1.
|
|
150
|
+
* For checkpointed blocks (already published to L1), use addCheckpoints() instead.
|
|
151
|
+
* @param blocks - The proposed L2 blocks to be added to the store.
|
|
130
152
|
* @returns True if the operation is successful.
|
|
131
153
|
*/
|
|
132
|
-
async
|
|
154
|
+
async addProposedBlocks(blocks: L2Block[], opts: { force?: boolean } = {}): Promise<boolean> {
|
|
133
155
|
if (blocks.length === 0) {
|
|
134
156
|
return true;
|
|
135
157
|
}
|
|
@@ -145,6 +167,12 @@ export class BlockStore {
|
|
|
145
167
|
const previousBlockNumber = await this.getLatestBlockNumber();
|
|
146
168
|
const previousCheckpointNumber = await this.getLatestCheckpointNumber();
|
|
147
169
|
|
|
170
|
+
// Verify we're not overwriting checkpointed blocks
|
|
171
|
+
const lastCheckpointedBlockNumber = await this.getCheckpointedL2BlockNumber();
|
|
172
|
+
if (!opts.force && firstBlockNumber <= lastCheckpointedBlockNumber) {
|
|
173
|
+
throw new CannotOverwriteCheckpointedBlockError(firstBlockNumber, lastCheckpointedBlockNumber);
|
|
174
|
+
}
|
|
175
|
+
|
|
148
176
|
// Check that the first block number is the expected one
|
|
149
177
|
if (!opts.force && previousBlockNumber !== firstBlockNumber - 1) {
|
|
150
178
|
throw new InitialBlockNumberNotSequentialError(firstBlockNumber, previousBlockNumber);
|
|
@@ -182,7 +210,7 @@ export class BlockStore {
|
|
|
182
210
|
}
|
|
183
211
|
|
|
184
212
|
// Iterate over blocks array and insert them, checking that the block numbers and indexes are sequential. Also check they are for the correct checkpoint.
|
|
185
|
-
let previousBlock:
|
|
213
|
+
let previousBlock: L2Block | undefined = undefined;
|
|
186
214
|
for (const block of blocks) {
|
|
187
215
|
if (!opts.force && previousBlock) {
|
|
188
216
|
if (previousBlock.number + 1 !== block.number) {
|
|
@@ -241,7 +269,7 @@ export class BlockStore {
|
|
|
241
269
|
}
|
|
242
270
|
|
|
243
271
|
let previousBlockNumber: BlockNumber | undefined = undefined;
|
|
244
|
-
let previousBlock:
|
|
272
|
+
let previousBlock: L2Block | undefined = undefined;
|
|
245
273
|
|
|
246
274
|
// If we have a previous checkpoint then we need to get the previous block number
|
|
247
275
|
if (previousCheckpointData !== undefined) {
|
|
@@ -322,7 +350,7 @@ export class BlockStore {
|
|
|
322
350
|
});
|
|
323
351
|
}
|
|
324
352
|
|
|
325
|
-
private async addBlockToDatabase(block:
|
|
353
|
+
private async addBlockToDatabase(block: L2Block, checkpointNumber: number, indexWithinCheckpoint: number) {
|
|
326
354
|
const blockHash = L2BlockHash.fromField(await block.hash());
|
|
327
355
|
|
|
328
356
|
await this.#blocks.set(block.number, {
|
|
@@ -350,57 +378,66 @@ export class BlockStore {
|
|
|
350
378
|
await this.#blockArchiveIndex.set(block.archive.root.toString(), block.number);
|
|
351
379
|
}
|
|
352
380
|
|
|
381
|
+
/** Deletes a block and all associated data (tx effects, indices). */
|
|
382
|
+
private async deleteBlock(block: L2Block): Promise<void> {
|
|
383
|
+
// Delete the block from the main blocks map
|
|
384
|
+
await this.#blocks.delete(block.number);
|
|
385
|
+
|
|
386
|
+
// Delete all tx effects for this block
|
|
387
|
+
await Promise.all(block.body.txEffects.map(tx => this.#txEffects.delete(tx.txHash.toString())));
|
|
388
|
+
|
|
389
|
+
// Delete block txs mapping
|
|
390
|
+
const blockHash = (await block.hash()).toString();
|
|
391
|
+
await this.#blockTxs.delete(blockHash);
|
|
392
|
+
|
|
393
|
+
// Clean up indices
|
|
394
|
+
await this.#blockHashIndex.delete(blockHash);
|
|
395
|
+
await this.#blockArchiveIndex.delete(block.archive.root.toString());
|
|
396
|
+
}
|
|
397
|
+
|
|
353
398
|
/**
|
|
354
|
-
*
|
|
355
|
-
*
|
|
356
|
-
*
|
|
357
|
-
* @param checkpointsToUnwind - The number of checkpoints we are to unwind
|
|
358
|
-
* @returns True if the operation is successful
|
|
399
|
+
* Removes all checkpoints with checkpoint number > checkpointNumber.
|
|
400
|
+
* Also removes ALL blocks (both checkpointed and uncheckpointed) after the last block of the given checkpoint.
|
|
401
|
+
* @param checkpointNumber - Remove all checkpoints strictly after this one.
|
|
359
402
|
*/
|
|
360
|
-
async
|
|
403
|
+
async removeCheckpointsAfter(checkpointNumber: CheckpointNumber): Promise<RemoveCheckpointsResult> {
|
|
361
404
|
return await this.db.transactionAsync(async () => {
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
|
|
405
|
+
const latestCheckpointNumber = await this.getLatestCheckpointNumber();
|
|
406
|
+
|
|
407
|
+
if (checkpointNumber >= latestCheckpointNumber) {
|
|
408
|
+
this.#log.warn(`No checkpoints to remove after ${checkpointNumber} (latest is ${latestCheckpointNumber})`);
|
|
409
|
+
return { blocksRemoved: undefined };
|
|
365
410
|
}
|
|
366
411
|
|
|
412
|
+
// If the proven checkpoint is beyond the target, update it
|
|
367
413
|
const proven = await this.getProvenCheckpointNumber();
|
|
368
|
-
if (
|
|
369
|
-
|
|
414
|
+
if (proven > checkpointNumber) {
|
|
415
|
+
this.#log.warn(`Updating proven checkpoint ${proven} to last valid checkpoint ${checkpointNumber}`);
|
|
416
|
+
await this.setProvenCheckpointNumber(checkpointNumber);
|
|
370
417
|
}
|
|
371
418
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
419
|
+
// Find the last block number to keep (last block of the given checkpoint, or 0 if no checkpoint)
|
|
420
|
+
let lastBlockToKeep: BlockNumber;
|
|
421
|
+
if (checkpointNumber <= 0) {
|
|
422
|
+
lastBlockToKeep = BlockNumber(INITIAL_L2_BLOCK_NUM - 1);
|
|
423
|
+
} else {
|
|
424
|
+
const targetCheckpoint = await this.#checkpoints.getAsync(checkpointNumber);
|
|
425
|
+
if (!targetCheckpoint) {
|
|
426
|
+
throw new Error(`Target checkpoint ${checkpointNumber} not found in store`);
|
|
379
427
|
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
for (let blockNumber = checkpoint.startBlock; blockNumber <= maxBlock; blockNumber++) {
|
|
384
|
-
const block = await this.getBlock(BlockNumber(blockNumber));
|
|
385
|
-
|
|
386
|
-
if (block === undefined) {
|
|
387
|
-
this.#log.warn(`Cannot remove block ${blockNumber} from the store since we don't have it`);
|
|
388
|
-
continue;
|
|
389
|
-
}
|
|
390
|
-
await this.#blocks.delete(block.number);
|
|
391
|
-
await Promise.all(block.body.txEffects.map(tx => this.#txEffects.delete(tx.txHash.toString())));
|
|
392
|
-
const blockHash = (await block.hash()).toString();
|
|
393
|
-
await this.#blockTxs.delete(blockHash);
|
|
428
|
+
lastBlockToKeep = BlockNumber(targetCheckpoint.startBlock + targetCheckpoint.numBlocks - 1);
|
|
429
|
+
}
|
|
394
430
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
await this.#blockArchiveIndex.delete(block.archive.root.toString());
|
|
431
|
+
// Remove all blocks after lastBlockToKeep (both checkpointed and uncheckpointed)
|
|
432
|
+
const blocksRemoved = await this.removeBlocksAfter(lastBlockToKeep);
|
|
398
433
|
|
|
399
|
-
|
|
400
|
-
|
|
434
|
+
// Remove all checkpoints after the target
|
|
435
|
+
for (let c = latestCheckpointNumber; c > checkpointNumber; c = CheckpointNumber(c - 1)) {
|
|
436
|
+
await this.#checkpoints.delete(c);
|
|
437
|
+
this.#log.debug(`Removed checkpoint ${c}`);
|
|
401
438
|
}
|
|
402
439
|
|
|
403
|
-
return
|
|
440
|
+
return { blocksRemoved };
|
|
404
441
|
});
|
|
405
442
|
}
|
|
406
443
|
|
|
@@ -437,7 +474,7 @@ export class BlockStore {
|
|
|
437
474
|
return data;
|
|
438
475
|
}
|
|
439
476
|
|
|
440
|
-
async getBlocksForCheckpoint(checkpointNumber: CheckpointNumber): Promise<
|
|
477
|
+
async getBlocksForCheckpoint(checkpointNumber: CheckpointNumber): Promise<L2Block[] | undefined> {
|
|
441
478
|
const checkpoint = await this.#checkpoints.getAsync(checkpointNumber);
|
|
442
479
|
if (!checkpoint) {
|
|
443
480
|
return undefined;
|
|
@@ -454,6 +491,62 @@ export class BlockStore {
|
|
|
454
491
|
return converted.filter(isDefined);
|
|
455
492
|
}
|
|
456
493
|
|
|
494
|
+
/**
|
|
495
|
+
* Gets all blocks that have the given slot number.
|
|
496
|
+
* Iterates backwards through blocks for efficiency since we usually query for the last slot.
|
|
497
|
+
* @param slotNumber - The slot number to search for.
|
|
498
|
+
* @returns All blocks with the given slot number, in ascending block number order.
|
|
499
|
+
*/
|
|
500
|
+
async getBlocksForSlot(slotNumber: SlotNumber): Promise<L2Block[]> {
|
|
501
|
+
const blocks: L2Block[] = [];
|
|
502
|
+
|
|
503
|
+
// Iterate backwards through all blocks and filter by slot number
|
|
504
|
+
// This is more efficient since we usually query for the most recent slot
|
|
505
|
+
for await (const [blockNumber, blockStorage] of this.#blocks.entriesAsync({ reverse: true })) {
|
|
506
|
+
const block = await this.getBlockFromBlockStorage(blockNumber, blockStorage);
|
|
507
|
+
const blockSlot = block?.header.globalVariables.slotNumber;
|
|
508
|
+
if (block && blockSlot === slotNumber) {
|
|
509
|
+
blocks.push(block);
|
|
510
|
+
} else if (blockSlot && blockSlot < slotNumber) {
|
|
511
|
+
break; // Blocks are stored in slot ascending order, so we can stop searching
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// Reverse to return blocks in ascending order (block number order)
|
|
516
|
+
return blocks.reverse();
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* Removes all blocks with block number > blockNumber.
|
|
521
|
+
* Does not remove any associated checkpoints.
|
|
522
|
+
* @param blockNumber - The block number to remove after.
|
|
523
|
+
* @returns The removed blocks (for event emission).
|
|
524
|
+
*/
|
|
525
|
+
async removeBlocksAfter(blockNumber: BlockNumber): Promise<L2Block[]> {
|
|
526
|
+
return await this.db.transactionAsync(async () => {
|
|
527
|
+
const removedBlocks: L2Block[] = [];
|
|
528
|
+
|
|
529
|
+
// Get the latest block number to determine the range
|
|
530
|
+
const latestBlockNumber = await this.getLatestBlockNumber();
|
|
531
|
+
|
|
532
|
+
// Iterate from blockNumber + 1 to latestBlockNumber
|
|
533
|
+
for (let bn = blockNumber + 1; bn <= latestBlockNumber; bn++) {
|
|
534
|
+
const block = await this.getBlock(BlockNumber(bn));
|
|
535
|
+
|
|
536
|
+
if (block === undefined) {
|
|
537
|
+
this.#log.warn(`Cannot remove block ${bn} from the store since we don't have it`);
|
|
538
|
+
continue;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
removedBlocks.push(block);
|
|
542
|
+
await this.deleteBlock(block);
|
|
543
|
+
this.#log.debug(`Removed block ${bn} ${(await block.hash()).toString()}`);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
return removedBlocks;
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
|
|
457
550
|
async getProvenBlockNumber(): Promise<BlockNumber> {
|
|
458
551
|
const provenCheckpointNumber = await this.getProvenCheckpointNumber();
|
|
459
552
|
if (provenCheckpointNumber === INITIAL_CHECKPOINT_NUMBER - 1) {
|
|
@@ -503,6 +596,34 @@ export class BlockStore {
|
|
|
503
596
|
);
|
|
504
597
|
}
|
|
505
598
|
|
|
599
|
+
/**
|
|
600
|
+
* Gets up to `limit` amount of Checkpointed L2 blocks starting from `from`.
|
|
601
|
+
* @param start - Number of the first block to return (inclusive).
|
|
602
|
+
* @param limit - The number of blocks to return.
|
|
603
|
+
* @returns The requested L2 blocks
|
|
604
|
+
*/
|
|
605
|
+
async *getCheckpointedBlocks(start: BlockNumber, limit: number): AsyncIterableIterator<CheckpointedL2Block> {
|
|
606
|
+
const checkpointCache = new Map<CheckpointNumber, CheckpointStorage>();
|
|
607
|
+
for await (const [blockNumber, blockStorage] of this.getBlockStorages(start, limit)) {
|
|
608
|
+
const block = await this.getBlockFromBlockStorage(blockNumber, blockStorage);
|
|
609
|
+
if (block) {
|
|
610
|
+
const checkpoint =
|
|
611
|
+
checkpointCache.get(CheckpointNumber(blockStorage.checkpointNumber)) ??
|
|
612
|
+
(await this.#checkpoints.getAsync(blockStorage.checkpointNumber));
|
|
613
|
+
if (checkpoint) {
|
|
614
|
+
checkpointCache.set(CheckpointNumber(blockStorage.checkpointNumber), checkpoint);
|
|
615
|
+
const checkpointedBlock = new CheckpointedL2Block(
|
|
616
|
+
CheckpointNumber(checkpoint.checkpointNumber),
|
|
617
|
+
block,
|
|
618
|
+
L1PublishedData.fromBuffer(checkpoint.l1),
|
|
619
|
+
checkpoint.attestations.map(buf => CommitteeAttestation.fromBuffer(buf)),
|
|
620
|
+
);
|
|
621
|
+
yield checkpointedBlock;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
|
|
506
627
|
async getCheckpointedBlockByHash(blockHash: Fr): Promise<CheckpointedL2Block | undefined> {
|
|
507
628
|
const blockNumber = await this.#blockHashIndex.getAsync(blockHash.toString());
|
|
508
629
|
if (blockNumber === undefined) {
|
|
@@ -510,6 +631,7 @@ export class BlockStore {
|
|
|
510
631
|
}
|
|
511
632
|
return this.getCheckpointedBlock(BlockNumber(blockNumber));
|
|
512
633
|
}
|
|
634
|
+
|
|
513
635
|
async getCheckpointedBlockByArchive(archive: Fr): Promise<CheckpointedL2Block | undefined> {
|
|
514
636
|
const blockNumber = await this.#blockArchiveIndex.getAsync(archive.toString());
|
|
515
637
|
if (blockNumber === undefined) {
|
|
@@ -524,7 +646,7 @@ export class BlockStore {
|
|
|
524
646
|
* @param limit - The number of blocks to return.
|
|
525
647
|
* @returns The requested L2 blocks
|
|
526
648
|
*/
|
|
527
|
-
async *getBlocks(start: BlockNumber, limit: number): AsyncIterableIterator<
|
|
649
|
+
async *getBlocks(start: BlockNumber, limit: number): AsyncIterableIterator<L2Block> {
|
|
528
650
|
for await (const [blockNumber, blockStorage] of this.getBlockStorages(start, limit)) {
|
|
529
651
|
const block = await this.getBlockFromBlockStorage(blockNumber, blockStorage);
|
|
530
652
|
if (block) {
|
|
@@ -538,7 +660,7 @@ export class BlockStore {
|
|
|
538
660
|
* @param blockNumber - The number of the block to return.
|
|
539
661
|
* @returns The requested L2 block.
|
|
540
662
|
*/
|
|
541
|
-
async getBlock(blockNumber: BlockNumber): Promise<
|
|
663
|
+
async getBlock(blockNumber: BlockNumber): Promise<L2Block | undefined> {
|
|
542
664
|
const blockStorage = await this.#blocks.getAsync(blockNumber);
|
|
543
665
|
if (!blockStorage || !blockStorage.header) {
|
|
544
666
|
return Promise.resolve(undefined);
|
|
@@ -551,7 +673,7 @@ export class BlockStore {
|
|
|
551
673
|
* @param blockHash - The hash of the block to return.
|
|
552
674
|
* @returns The requested L2 block.
|
|
553
675
|
*/
|
|
554
|
-
async getBlockByHash(blockHash: L2BlockHash): Promise<
|
|
676
|
+
async getBlockByHash(blockHash: L2BlockHash): Promise<L2Block | undefined> {
|
|
555
677
|
const blockNumber = await this.#blockHashIndex.getAsync(blockHash.toString());
|
|
556
678
|
if (blockNumber === undefined) {
|
|
557
679
|
return undefined;
|
|
@@ -564,7 +686,7 @@ export class BlockStore {
|
|
|
564
686
|
* @param archive - The archive root of the block to return.
|
|
565
687
|
* @returns The requested L2 block.
|
|
566
688
|
*/
|
|
567
|
-
async getBlockByArchive(archive: Fr): Promise<
|
|
689
|
+
async getBlockByArchive(archive: Fr): Promise<L2Block | undefined> {
|
|
568
690
|
const blockNumber = await this.#blockArchiveIndex.getAsync(archive.toString());
|
|
569
691
|
if (blockNumber === undefined) {
|
|
570
692
|
return undefined;
|
|
@@ -640,10 +762,11 @@ export class BlockStore {
|
|
|
640
762
|
private async getBlockFromBlockStorage(
|
|
641
763
|
blockNumber: number,
|
|
642
764
|
blockStorage: BlockStorage,
|
|
643
|
-
): Promise<
|
|
765
|
+
): Promise<L2Block | undefined> {
|
|
644
766
|
const header = BlockHeader.fromBuffer(blockStorage.header);
|
|
645
767
|
const archive = AppendOnlyTreeSnapshot.fromBuffer(blockStorage.archive);
|
|
646
768
|
const blockHash = blockStorage.blockHash;
|
|
769
|
+
header.setHash(Fr.fromBuffer(blockHash));
|
|
647
770
|
const blockHashString = bufferToHex(blockHash);
|
|
648
771
|
const blockTxsBuffer = await this.#blockTxs.getAsync(blockHashString);
|
|
649
772
|
if (blockTxsBuffer === undefined) {
|
|
@@ -663,12 +786,12 @@ export class BlockStore {
|
|
|
663
786
|
txEffects.push(deserializeIndexedTxEffect(txEffect).data);
|
|
664
787
|
}
|
|
665
788
|
const body = new Body(txEffects);
|
|
666
|
-
const block = new
|
|
789
|
+
const block = new L2Block(
|
|
667
790
|
archive,
|
|
668
791
|
header,
|
|
669
792
|
body,
|
|
670
793
|
CheckpointNumber(blockStorage.checkpointNumber!),
|
|
671
|
-
blockStorage.indexWithinCheckpoint,
|
|
794
|
+
IndexWithinCheckpoint(blockStorage.indexWithinCheckpoint),
|
|
672
795
|
);
|
|
673
796
|
|
|
674
797
|
if (block.number !== blockNumber) {
|
|
@@ -705,13 +828,34 @@ export class BlockStore {
|
|
|
705
828
|
return undefined;
|
|
706
829
|
}
|
|
707
830
|
|
|
831
|
+
const blockNumber = BlockNumber(txEffect.l2BlockNumber);
|
|
832
|
+
|
|
833
|
+
// Use existing archiver methods to determine finalization level
|
|
834
|
+
const [provenBlockNumber, checkpointedBlockNumber, finalizedBlockNumber] = await Promise.all([
|
|
835
|
+
this.getProvenBlockNumber(),
|
|
836
|
+
this.getCheckpointedL2BlockNumber(),
|
|
837
|
+
this.getFinalizedL2BlockNumber(),
|
|
838
|
+
]);
|
|
839
|
+
|
|
840
|
+
let status: TxStatus;
|
|
841
|
+
if (blockNumber <= finalizedBlockNumber) {
|
|
842
|
+
status = TxStatus.FINALIZED;
|
|
843
|
+
} else if (blockNumber <= provenBlockNumber) {
|
|
844
|
+
status = TxStatus.PROVEN;
|
|
845
|
+
} else if (blockNumber <= checkpointedBlockNumber) {
|
|
846
|
+
status = TxStatus.CHECKPOINTED;
|
|
847
|
+
} else {
|
|
848
|
+
status = TxStatus.PROPOSED;
|
|
849
|
+
}
|
|
850
|
+
|
|
708
851
|
return new TxReceipt(
|
|
709
852
|
txHash,
|
|
710
|
-
|
|
711
|
-
|
|
853
|
+
status,
|
|
854
|
+
TxReceipt.executionResultFromRevertCode(txEffect.data.revertCode),
|
|
855
|
+
undefined,
|
|
712
856
|
txEffect.data.transactionFee.toBigInt(),
|
|
713
857
|
txEffect.l2BlockHash,
|
|
714
|
-
|
|
858
|
+
blockNumber,
|
|
715
859
|
);
|
|
716
860
|
}
|
|
717
861
|
|
|
@@ -799,21 +943,21 @@ export class BlockStore {
|
|
|
799
943
|
* Gets the pending chain validation status.
|
|
800
944
|
* @returns The validation status or undefined if not set.
|
|
801
945
|
*/
|
|
802
|
-
async getPendingChainValidationStatus(): Promise<
|
|
946
|
+
async getPendingChainValidationStatus(): Promise<ValidateCheckpointResult | undefined> {
|
|
803
947
|
const buffer = await this.#pendingChainValidationStatus.getAsync();
|
|
804
948
|
if (!buffer) {
|
|
805
949
|
return undefined;
|
|
806
950
|
}
|
|
807
|
-
return
|
|
951
|
+
return deserializeValidateCheckpointResult(buffer);
|
|
808
952
|
}
|
|
809
953
|
|
|
810
954
|
/**
|
|
811
955
|
* Sets the pending chain validation status.
|
|
812
956
|
* @param status - The validation status to store.
|
|
813
957
|
*/
|
|
814
|
-
async setPendingChainValidationStatus(status:
|
|
958
|
+
async setPendingChainValidationStatus(status: ValidateCheckpointResult | undefined): Promise<void> {
|
|
815
959
|
if (status) {
|
|
816
|
-
const buffer =
|
|
960
|
+
const buffer = serializeValidateCheckpointResult(status);
|
|
817
961
|
await this.#pendingChainValidationStatus.set(buffer);
|
|
818
962
|
} else {
|
|
819
963
|
await this.#pendingChainValidationStatus.delete();
|
|
@@ -12,7 +12,7 @@ import type {
|
|
|
12
12
|
import { Vector } from '@aztec/stdlib/types';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* LMDB
|
|
15
|
+
* LMDB-based contract class storage for the archiver.
|
|
16
16
|
*/
|
|
17
17
|
export class ContractClassStore {
|
|
18
18
|
#contractClasses: AztecAsyncMap<string, Buffer>;
|
|
@@ -12,7 +12,7 @@ import type { UInt64 } from '@aztec/stdlib/types';
|
|
|
12
12
|
type ContractInstanceUpdateKey = [string, string] | [string, string, number];
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* LMDB
|
|
15
|
+
* LMDB-based contract instance storage for the archiver.
|
|
16
16
|
*/
|
|
17
17
|
export class ContractInstanceStore {
|
|
18
18
|
#contractInstances: AztecAsyncMap<string, Buffer>;
|