@aztec/archiver 0.0.1-commit.b655e406 → 0.0.1-commit.d3ec352c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/archiver/archiver.d.ts +53 -40
- package/dest/archiver/archiver.d.ts.map +1 -1
- package/dest/archiver/archiver.js +333 -221
- package/dest/archiver/archiver_store.d.ts +16 -15
- 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 +85 -84
- package/dest/archiver/config.d.ts +1 -1
- package/dest/archiver/config.d.ts.map +1 -1
- package/dest/archiver/config.js +5 -0
- package/dest/archiver/data_retrieval.d.ts +18 -17
- package/dest/archiver/data_retrieval.d.ts.map +1 -1
- package/dest/archiver/data_retrieval.js +111 -86
- package/dest/archiver/errors.d.ts +1 -1
- package/dest/archiver/errors.d.ts.map +1 -1
- package/dest/archiver/index.d.ts +1 -1
- package/dest/archiver/instrumentation.d.ts +3 -3
- package/dest/archiver/instrumentation.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/block_store.d.ts +9 -8
- package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/block_store.js +8 -7
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +1 -1
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +1 -1
- 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 +18 -17
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/log_store.d.ts +1 -1
- package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/log_store.js +3 -2
- package/dest/archiver/kv_archiver_store/message_store.d.ts +1 -1
- package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
- package/dest/archiver/structs/data_retrieval.d.ts +1 -1
- package/dest/archiver/structs/inbox_message.d.ts +3 -3
- package/dest/archiver/structs/inbox_message.d.ts.map +1 -1
- package/dest/archiver/structs/inbox_message.js +2 -1
- package/dest/archiver/structs/published.d.ts +3 -2
- package/dest/archiver/structs/published.d.ts.map +1 -1
- package/dest/archiver/validation.d.ts +10 -4
- package/dest/archiver/validation.d.ts.map +1 -1
- package/dest/archiver/validation.js +29 -21
- package/dest/factory.d.ts +1 -1
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +3 -2
- package/dest/index.d.ts +2 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -1
- package/dest/rpc/index.d.ts +2 -2
- package/dest/test/index.d.ts +1 -1
- package/dest/test/mock_archiver.d.ts +14 -5
- package/dest/test/mock_archiver.d.ts.map +1 -1
- package/dest/test/mock_archiver.js +19 -10
- package/dest/test/mock_l1_to_l2_message_source.d.ts +4 -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 +7 -2
- package/dest/test/mock_l2_block_source.d.ts +14 -9
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +20 -7
- package/dest/test/mock_structs.d.ts +1 -1
- package/dest/test/mock_structs.d.ts.map +1 -1
- package/dest/test/mock_structs.js +3 -2
- package/package.json +17 -17
- package/src/archiver/archiver.ts +448 -290
- package/src/archiver/archiver_store.ts +19 -14
- package/src/archiver/archiver_store_test_suite.ts +111 -79
- package/src/archiver/config.ts +5 -0
- package/src/archiver/data_retrieval.ts +157 -125
- package/src/archiver/instrumentation.ts +2 -2
- package/src/archiver/kv_archiver_store/block_store.ts +17 -16
- package/src/archiver/kv_archiver_store/kv_archiver_store.ts +16 -15
- package/src/archiver/kv_archiver_store/log_store.ts +3 -2
- package/src/archiver/structs/inbox_message.ts +5 -4
- package/src/archiver/structs/published.ts +2 -1
- package/src/archiver/validation.ts +52 -27
- package/src/factory.ts +3 -2
- package/src/index.ts +1 -1
- package/src/test/mock_archiver.ts +22 -11
- package/src/test/mock_l1_to_l2_message_source.ts +9 -3
- package/src/test/mock_l2_block_source.ts +30 -13
- package/src/test/mock_structs.ts +3 -2
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
BlobDeserializationError,
|
|
3
|
+
type CheckpointBlobData,
|
|
4
|
+
SpongeBlob,
|
|
5
|
+
decodeCheckpointBlobDataFromBlobs,
|
|
6
|
+
encodeBlockBlobData,
|
|
7
|
+
} from '@aztec/blob-lib';
|
|
2
8
|
import type { BlobSinkClientInterface } from '@aztec/blob-sink/client';
|
|
3
9
|
import type {
|
|
4
10
|
EpochProofPublicInputArgs,
|
|
@@ -6,20 +12,21 @@ import type {
|
|
|
6
12
|
ViemCommitteeAttestations,
|
|
7
13
|
ViemHeader,
|
|
8
14
|
ViemPublicClient,
|
|
9
|
-
ViemStateReference,
|
|
10
15
|
} from '@aztec/ethereum';
|
|
11
16
|
import { asyncPool } from '@aztec/foundation/async-pool';
|
|
17
|
+
import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
12
18
|
import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
|
|
13
19
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
14
20
|
import type { ViemSignature } from '@aztec/foundation/eth-signature';
|
|
15
21
|
import { Fr } from '@aztec/foundation/fields';
|
|
16
22
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
17
23
|
import { type InboxAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
18
|
-
import { Body, CommitteeAttestation,
|
|
24
|
+
import { Body, CommitteeAttestation, L2BlockNew } from '@aztec/stdlib/block';
|
|
25
|
+
import { Checkpoint, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
19
26
|
import { Proof } from '@aztec/stdlib/proofs';
|
|
20
27
|
import { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
21
28
|
import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
|
|
22
|
-
import { GlobalVariables, StateReference } from '@aztec/stdlib/tx';
|
|
29
|
+
import { BlockHeader, GlobalVariables, PartialStateReference, StateReference } from '@aztec/stdlib/tx';
|
|
23
30
|
|
|
24
31
|
import {
|
|
25
32
|
type GetContractEventsReturnType,
|
|
@@ -36,75 +43,106 @@ import type { DataRetrieval } from './structs/data_retrieval.js';
|
|
|
36
43
|
import type { InboxMessage } from './structs/inbox_message.js';
|
|
37
44
|
import type { L1PublishedData } from './structs/published.js';
|
|
38
45
|
|
|
39
|
-
export type
|
|
40
|
-
|
|
46
|
+
export type RetrievedCheckpoint = {
|
|
47
|
+
checkpointNumber: CheckpointNumber;
|
|
41
48
|
archiveRoot: Fr;
|
|
42
|
-
stateReference: StateReference;
|
|
43
49
|
header: CheckpointHeader;
|
|
44
|
-
|
|
50
|
+
checkpointBlobData: CheckpointBlobData;
|
|
45
51
|
l1: L1PublishedData;
|
|
46
52
|
chainId: Fr;
|
|
47
53
|
version: Fr;
|
|
48
54
|
attestations: CommitteeAttestation[];
|
|
49
55
|
};
|
|
50
56
|
|
|
51
|
-
export async function
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
57
|
+
export async function retrievedToPublishedCheckpoint({
|
|
58
|
+
checkpointNumber,
|
|
59
|
+
archiveRoot,
|
|
60
|
+
header: checkpointHeader,
|
|
61
|
+
checkpointBlobData,
|
|
62
|
+
l1,
|
|
63
|
+
chainId,
|
|
64
|
+
version,
|
|
65
|
+
attestations,
|
|
66
|
+
}: RetrievedCheckpoint): Promise<PublishedCheckpoint> {
|
|
67
|
+
const { blocks: blocksBlobData } = checkpointBlobData;
|
|
68
|
+
|
|
69
|
+
// The lastArchiveRoot of a block is the new archive for the previous block.
|
|
70
|
+
const newArchiveRoots = blocksBlobData
|
|
71
|
+
.map(b => b.lastArchiveRoot)
|
|
72
|
+
.slice(1)
|
|
73
|
+
.concat([archiveRoot]);
|
|
74
|
+
|
|
75
|
+
// `blocksBlobData` is created from `decodeCheckpointBlobDataFromBlobs`. An error will be thrown if it can't read a
|
|
76
|
+
// field for the `l1ToL2MessageRoot` of the first block. So below we can safely assume it exists:
|
|
77
|
+
const l1toL2MessageTreeRoot = blocksBlobData[0].l1ToL2MessageRoot!;
|
|
78
|
+
|
|
79
|
+
const spongeBlob = SpongeBlob.init();
|
|
80
|
+
const l2Blocks: L2BlockNew[] = [];
|
|
81
|
+
for (let i = 0; i < blocksBlobData.length; i++) {
|
|
82
|
+
const blockBlobData = blocksBlobData[i];
|
|
83
|
+
const { blockEndMarker, blockEndStateField, lastArchiveRoot, noteHashRoot, nullifierRoot, publicDataRoot } =
|
|
84
|
+
blockBlobData;
|
|
85
|
+
|
|
86
|
+
const l2BlockNumber = blockEndMarker.blockNumber;
|
|
87
|
+
|
|
88
|
+
const globalVariables = GlobalVariables.from({
|
|
89
|
+
chainId,
|
|
90
|
+
version,
|
|
91
|
+
blockNumber: l2BlockNumber,
|
|
92
|
+
slotNumber: checkpointHeader.slotNumber,
|
|
93
|
+
timestamp: blockEndMarker.timestamp,
|
|
94
|
+
coinbase: checkpointHeader.coinbase,
|
|
95
|
+
feeRecipient: checkpointHeader.feeRecipient,
|
|
96
|
+
gasFees: checkpointHeader.gasFees,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const state = StateReference.from({
|
|
100
|
+
l1ToL2MessageTree: new AppendOnlyTreeSnapshot(
|
|
101
|
+
l1toL2MessageTreeRoot,
|
|
102
|
+
blockEndStateField.l1ToL2MessageNextAvailableLeafIndex,
|
|
103
|
+
),
|
|
104
|
+
partial: PartialStateReference.from({
|
|
105
|
+
noteHashTree: new AppendOnlyTreeSnapshot(noteHashRoot, blockEndStateField.noteHashNextAvailableLeafIndex),
|
|
106
|
+
nullifierTree: new AppendOnlyTreeSnapshot(nullifierRoot, blockEndStateField.nullifierNextAvailableLeafIndex),
|
|
107
|
+
publicDataTree: new AppendOnlyTreeSnapshot(publicDataRoot, blockEndStateField.publicDataNextAvailableLeafIndex),
|
|
108
|
+
}),
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const body = Body.fromTxBlobData(checkpointBlobData.blocks[0].txs);
|
|
112
|
+
|
|
113
|
+
const blobFields = encodeBlockBlobData(blockBlobData);
|
|
114
|
+
await spongeBlob.absorb(blobFields);
|
|
115
|
+
|
|
116
|
+
const clonedSpongeBlob = spongeBlob.clone();
|
|
117
|
+
const spongeBlobHash = await clonedSpongeBlob.squeeze();
|
|
118
|
+
|
|
119
|
+
const header = BlockHeader.from({
|
|
120
|
+
lastArchive: new AppendOnlyTreeSnapshot(lastArchiveRoot, l2BlockNumber),
|
|
121
|
+
state,
|
|
122
|
+
spongeBlobHash,
|
|
123
|
+
globalVariables,
|
|
124
|
+
totalFees: body.txEffects.reduce((accum, txEffect) => accum.add(txEffect.transactionFee), Fr.ZERO),
|
|
125
|
+
totalManaUsed: new Fr(blockEndStateField.totalManaUsed),
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const newArchive = new AppendOnlyTreeSnapshot(newArchiveRoots[i], l2BlockNumber + 1);
|
|
129
|
+
|
|
130
|
+
l2Blocks.push(new L2BlockNew(newArchive, header, body));
|
|
131
|
+
}
|
|
79
132
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
await spongeBlob.absorb(blockBlobFields);
|
|
87
|
-
const spongeBlobHash = await spongeBlob.squeeze();
|
|
88
|
-
|
|
89
|
-
const body = Body.fromBlobFields(blockBlobFields);
|
|
90
|
-
|
|
91
|
-
const header = L2BlockHeader.from({
|
|
92
|
-
lastArchive: new AppendOnlyTreeSnapshot(checkpointHeader.lastArchiveRoot, l2BlockNumber),
|
|
93
|
-
contentCommitment: checkpointHeader.contentCommitment,
|
|
94
|
-
state: stateReference,
|
|
95
|
-
globalVariables,
|
|
96
|
-
totalFees: body.txEffects.reduce((accum, txEffect) => accum.add(txEffect.transactionFee), Fr.ZERO),
|
|
97
|
-
totalManaUsed: checkpointHeader.totalManaUsed,
|
|
98
|
-
spongeBlobHash,
|
|
133
|
+
const lastBlock = l2Blocks.at(-1)!;
|
|
134
|
+
const checkpoint = Checkpoint.from({
|
|
135
|
+
archive: new AppendOnlyTreeSnapshot(archiveRoot, lastBlock.number + 1),
|
|
136
|
+
header: checkpointHeader,
|
|
137
|
+
blocks: l2Blocks,
|
|
138
|
+
number: checkpointNumber,
|
|
99
139
|
});
|
|
100
140
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
return PublishedL2Block.fromFields({ block, l1, attestations });
|
|
141
|
+
return PublishedCheckpoint.from({ checkpoint, l1, attestations });
|
|
104
142
|
}
|
|
105
143
|
|
|
106
144
|
/**
|
|
107
|
-
* Fetches new
|
|
145
|
+
* Fetches new checkpoints.
|
|
108
146
|
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
109
147
|
* @param rollupAddress - The address of the rollup contract.
|
|
110
148
|
* @param searchStartBlock - The block number to use for starting the search.
|
|
@@ -112,15 +150,15 @@ export async function retrievedBlockToPublishedL2Block(retrievedBlock: Retrieved
|
|
|
112
150
|
* @param expectedNextL2BlockNum - The next L2 block number that we expect to find.
|
|
113
151
|
* @returns An array of block; as well as the next eth block to search from.
|
|
114
152
|
*/
|
|
115
|
-
export async function
|
|
153
|
+
export async function retrieveCheckpointsFromRollup(
|
|
116
154
|
rollup: GetContractReturnType<typeof RollupAbi, ViemPublicClient>,
|
|
117
155
|
publicClient: ViemPublicClient,
|
|
118
156
|
blobSinkClient: BlobSinkClientInterface,
|
|
119
157
|
searchStartBlock: bigint,
|
|
120
158
|
searchEndBlock: bigint,
|
|
121
159
|
logger: Logger = createLogger('archiver'),
|
|
122
|
-
): Promise<
|
|
123
|
-
const
|
|
160
|
+
): Promise<RetrievedCheckpoint[]> {
|
|
161
|
+
const retrievedCheckpoints: RetrievedCheckpoint[] = [];
|
|
124
162
|
|
|
125
163
|
let rollupConstants: { chainId: Fr; version: Fr; targetCommitteeSize: number } | undefined;
|
|
126
164
|
|
|
@@ -128,8 +166,8 @@ export async function retrieveBlocksFromRollup(
|
|
|
128
166
|
if (searchStartBlock > searchEndBlock) {
|
|
129
167
|
break;
|
|
130
168
|
}
|
|
131
|
-
const
|
|
132
|
-
await rollup.getEvents.
|
|
169
|
+
const checkpointProposedLogs = (
|
|
170
|
+
await rollup.getEvents.CheckpointProposed(
|
|
133
171
|
{},
|
|
134
172
|
{
|
|
135
173
|
fromBlock: searchStartBlock,
|
|
@@ -138,13 +176,13 @@ export async function retrieveBlocksFromRollup(
|
|
|
138
176
|
)
|
|
139
177
|
).filter(log => log.blockNumber! >= searchStartBlock && log.blockNumber! <= searchEndBlock);
|
|
140
178
|
|
|
141
|
-
if (
|
|
179
|
+
if (checkpointProposedLogs.length === 0) {
|
|
142
180
|
break;
|
|
143
181
|
}
|
|
144
182
|
|
|
145
|
-
const lastLog =
|
|
183
|
+
const lastLog = checkpointProposedLogs.at(-1)!;
|
|
146
184
|
logger.debug(
|
|
147
|
-
`Got ${
|
|
185
|
+
`Got ${checkpointProposedLogs.length} processed logs for checkpoints ${checkpointProposedLogs[0].args.checkpointNumber}-${lastLog.args.checkpointNumber} between L1 blocks ${searchStartBlock}-${searchEndBlock}`,
|
|
148
186
|
);
|
|
149
187
|
|
|
150
188
|
if (rollupConstants === undefined) {
|
|
@@ -160,52 +198,52 @@ export async function retrieveBlocksFromRollup(
|
|
|
160
198
|
};
|
|
161
199
|
}
|
|
162
200
|
|
|
163
|
-
const
|
|
201
|
+
const newCheckpoints = await processCheckpointProposedLogs(
|
|
164
202
|
rollup,
|
|
165
203
|
publicClient,
|
|
166
204
|
blobSinkClient,
|
|
167
|
-
|
|
205
|
+
checkpointProposedLogs,
|
|
168
206
|
rollupConstants,
|
|
169
207
|
logger,
|
|
170
208
|
);
|
|
171
|
-
|
|
209
|
+
retrievedCheckpoints.push(...newCheckpoints);
|
|
172
210
|
searchStartBlock = lastLog.blockNumber! + 1n;
|
|
173
211
|
} while (searchStartBlock <= searchEndBlock);
|
|
174
212
|
|
|
175
|
-
// The
|
|
176
|
-
return
|
|
213
|
+
// The asyncPool from processCheckpointProposedLogs will not necessarily return the checkpoints in order, so we sort them before returning.
|
|
214
|
+
return retrievedCheckpoints.sort((a, b) => Number(a.l1.blockNumber - b.l1.blockNumber));
|
|
177
215
|
}
|
|
178
216
|
|
|
179
217
|
/**
|
|
180
|
-
* Processes newly received
|
|
218
|
+
* Processes newly received CheckpointProposed logs.
|
|
181
219
|
* @param rollup - The rollup contract
|
|
182
220
|
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
183
|
-
* @param logs -
|
|
184
|
-
* @returns - An array
|
|
221
|
+
* @param logs - CheckpointProposed logs.
|
|
222
|
+
* @returns - An array of checkpoints.
|
|
185
223
|
*/
|
|
186
|
-
async function
|
|
224
|
+
async function processCheckpointProposedLogs(
|
|
187
225
|
rollup: GetContractReturnType<typeof RollupAbi, ViemPublicClient>,
|
|
188
226
|
publicClient: ViemPublicClient,
|
|
189
227
|
blobSinkClient: BlobSinkClientInterface,
|
|
190
|
-
logs: GetContractEventsReturnType<typeof RollupAbi, '
|
|
228
|
+
logs: GetContractEventsReturnType<typeof RollupAbi, 'CheckpointProposed'>,
|
|
191
229
|
{ chainId, version, targetCommitteeSize }: { chainId: Fr; version: Fr; targetCommitteeSize: number },
|
|
192
230
|
logger: Logger,
|
|
193
|
-
): Promise<
|
|
194
|
-
const
|
|
231
|
+
): Promise<RetrievedCheckpoint[]> {
|
|
232
|
+
const retrievedCheckpoints: RetrievedCheckpoint[] = [];
|
|
195
233
|
await asyncPool(10, logs, async log => {
|
|
196
|
-
const
|
|
234
|
+
const checkpointNumber = CheckpointNumber.fromBigInt(log.args.checkpointNumber!);
|
|
197
235
|
const archive = log.args.archive!;
|
|
198
|
-
const archiveFromChain = await rollup.read.archiveAt([BigInt(
|
|
236
|
+
const archiveFromChain = await rollup.read.archiveAt([BigInt(checkpointNumber)]);
|
|
199
237
|
const blobHashes = log.args.versionedBlobHashes!.map(blobHash => Buffer.from(blobHash.slice(2), 'hex'));
|
|
200
238
|
|
|
201
|
-
// The value from the event and contract will match only if the
|
|
239
|
+
// The value from the event and contract will match only if the checkpoint is in the chain.
|
|
202
240
|
if (archive === archiveFromChain) {
|
|
203
|
-
const
|
|
241
|
+
const checkpoint = await getCheckpointFromRollupTx(
|
|
204
242
|
publicClient,
|
|
205
243
|
blobSinkClient,
|
|
206
244
|
log.transactionHash!,
|
|
207
245
|
blobHashes,
|
|
208
|
-
|
|
246
|
+
checkpointNumber,
|
|
209
247
|
rollup.address,
|
|
210
248
|
targetCommitteeSize,
|
|
211
249
|
logger,
|
|
@@ -217,22 +255,22 @@ async function processL2BlockProposedLogs(
|
|
|
217
255
|
timestamp: await getL1BlockTime(publicClient, log.blockNumber),
|
|
218
256
|
};
|
|
219
257
|
|
|
220
|
-
|
|
221
|
-
logger.trace(`Retrieved
|
|
258
|
+
retrievedCheckpoints.push({ ...checkpoint, l1, chainId, version });
|
|
259
|
+
logger.trace(`Retrieved checkpoint ${checkpointNumber} from L1 tx ${log.transactionHash}`, {
|
|
222
260
|
l1BlockNumber: log.blockNumber,
|
|
223
|
-
|
|
261
|
+
checkpointNumber,
|
|
224
262
|
archive: archive.toString(),
|
|
225
|
-
attestations:
|
|
263
|
+
attestations: checkpoint.attestations,
|
|
226
264
|
});
|
|
227
265
|
} else {
|
|
228
|
-
logger.warn(`Ignoring
|
|
266
|
+
logger.warn(`Ignoring checkpoint ${checkpointNumber} due to archive root mismatch`, {
|
|
229
267
|
actual: archive,
|
|
230
268
|
expected: archiveFromChain,
|
|
231
269
|
});
|
|
232
270
|
}
|
|
233
271
|
});
|
|
234
272
|
|
|
235
|
-
return
|
|
273
|
+
return retrievedCheckpoints;
|
|
236
274
|
}
|
|
237
275
|
|
|
238
276
|
export async function getL1BlockTime(publicClient: ViemPublicClient, blockNumber: bigint): Promise<bigint> {
|
|
@@ -291,24 +329,25 @@ function extractRollupProposeCalldata(multicall3Data: Hex, rollupAddress: Hex):
|
|
|
291
329
|
}
|
|
292
330
|
|
|
293
331
|
/**
|
|
294
|
-
* Gets
|
|
295
|
-
* Assumes that the
|
|
332
|
+
* Gets checkpoint from the calldata of an L1 transaction.
|
|
333
|
+
* Assumes that the checkpoint was published from an EOA.
|
|
296
334
|
* TODO: Add retries and error management.
|
|
297
335
|
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
298
336
|
* @param txHash - Hash of the tx that published it.
|
|
299
|
-
* @param
|
|
300
|
-
* @returns
|
|
337
|
+
* @param checkpointNumber - Checkpoint number.
|
|
338
|
+
* @returns Checkpoint from the calldata, deserialized
|
|
301
339
|
*/
|
|
302
|
-
async function
|
|
340
|
+
async function getCheckpointFromRollupTx(
|
|
303
341
|
publicClient: ViemPublicClient,
|
|
304
342
|
blobSinkClient: BlobSinkClientInterface,
|
|
305
343
|
txHash: `0x${string}`,
|
|
306
344
|
blobHashes: Buffer[], // TODO(md): buffer32?
|
|
307
|
-
|
|
345
|
+
checkpointNumber: CheckpointNumber,
|
|
308
346
|
rollupAddress: Hex,
|
|
309
347
|
targetCommitteeSize: number,
|
|
310
348
|
logger: Logger,
|
|
311
|
-
): Promise<Omit<
|
|
349
|
+
): Promise<Omit<RetrievedCheckpoint, 'l1' | 'chainId' | 'version'>> {
|
|
350
|
+
logger.trace(`Fetching checkpoint ${checkpointNumber} from rollup tx ${txHash}`);
|
|
312
351
|
const { input: forwarderData, blockHash } = await publicClient.getTransaction({ hash: txHash });
|
|
313
352
|
|
|
314
353
|
const rollupData = extractRollupProposeCalldata(forwarderData, rollupAddress);
|
|
@@ -324,7 +363,6 @@ async function getBlockFromRollupTx(
|
|
|
324
363
|
const [decodedArgs, packedAttestations, _signers, _blobInput] = rollupArgs! as readonly [
|
|
325
364
|
{
|
|
326
365
|
archive: Hex;
|
|
327
|
-
stateReference: ViemStateReference;
|
|
328
366
|
oracleInput: {
|
|
329
367
|
feeAssetPriceModifier: bigint;
|
|
330
368
|
};
|
|
@@ -340,10 +378,10 @@ async function getBlockFromRollupTx(
|
|
|
340
378
|
const attestations = CommitteeAttestation.fromPacked(packedAttestations, targetCommitteeSize);
|
|
341
379
|
|
|
342
380
|
logger.trace(`Recovered propose calldata from tx ${txHash}`, {
|
|
343
|
-
|
|
381
|
+
checkpointNumber,
|
|
344
382
|
archive: decodedArgs.archive,
|
|
345
|
-
stateReference: decodedArgs.stateReference,
|
|
346
383
|
header: decodedArgs.header,
|
|
384
|
+
l1BlockHash: blockHash,
|
|
347
385
|
blobHashes,
|
|
348
386
|
attestations,
|
|
349
387
|
packedAttestations,
|
|
@@ -353,16 +391,13 @@ async function getBlockFromRollupTx(
|
|
|
353
391
|
const header = CheckpointHeader.fromViem(decodedArgs.header);
|
|
354
392
|
const blobBodies = await blobSinkClient.getBlobSidecar(blockHash, blobHashes);
|
|
355
393
|
if (blobBodies.length === 0) {
|
|
356
|
-
throw new NoBlobBodiesFoundError(
|
|
394
|
+
throw new NoBlobBodiesFoundError(checkpointNumber);
|
|
357
395
|
}
|
|
358
396
|
|
|
359
|
-
let
|
|
397
|
+
let checkpointBlobData: CheckpointBlobData;
|
|
360
398
|
try {
|
|
361
|
-
//
|
|
362
|
-
|
|
363
|
-
blobBodies.map(b => b.blob),
|
|
364
|
-
true /* checkEncoding */,
|
|
365
|
-
);
|
|
399
|
+
// Attempt to decode the checkpoint blob data.
|
|
400
|
+
checkpointBlobData = decodeCheckpointBlobDataFromBlobs(blobBodies.map(b => b.blob));
|
|
366
401
|
} catch (err: any) {
|
|
367
402
|
if (err instanceof BlobDeserializationError) {
|
|
368
403
|
logger.fatal(err.message);
|
|
@@ -374,14 +409,11 @@ async function getBlockFromRollupTx(
|
|
|
374
409
|
|
|
375
410
|
const archiveRoot = new Fr(Buffer.from(hexToBytes(decodedArgs.archive)));
|
|
376
411
|
|
|
377
|
-
const stateReference = StateReference.fromViem(decodedArgs.stateReference);
|
|
378
|
-
|
|
379
412
|
return {
|
|
380
|
-
|
|
413
|
+
checkpointNumber,
|
|
381
414
|
archiveRoot,
|
|
382
|
-
stateReference,
|
|
383
415
|
header,
|
|
384
|
-
|
|
416
|
+
checkpointBlobData,
|
|
385
417
|
attestations,
|
|
386
418
|
};
|
|
387
419
|
}
|
|
@@ -432,13 +464,13 @@ export async function retrieveL1ToL2Messages(
|
|
|
432
464
|
|
|
433
465
|
function mapLogsInboxMessage(logs: GetContractEventsReturnType<typeof InboxAbi, 'MessageSent'>): InboxMessage[] {
|
|
434
466
|
return logs.map(log => {
|
|
435
|
-
const { index, hash,
|
|
467
|
+
const { index, hash, checkpointNumber, rollingHash } = log.args;
|
|
436
468
|
return {
|
|
437
469
|
index: index!,
|
|
438
470
|
leaf: Fr.fromHexString(hash!),
|
|
439
471
|
l1BlockNumber: log.blockNumber,
|
|
440
472
|
l1BlockHash: Buffer32.fromString(log.blockHash),
|
|
441
|
-
l2BlockNumber: Number(
|
|
473
|
+
l2BlockNumber: BlockNumber(Number(checkpointNumber!)),
|
|
442
474
|
rollingHash: Buffer16.fromString(rollingHash!),
|
|
443
475
|
};
|
|
444
476
|
});
|
|
@@ -450,7 +482,7 @@ export async function retrieveL2ProofVerifiedEvents(
|
|
|
450
482
|
rollupAddress: EthAddress,
|
|
451
483
|
searchStartBlock: bigint,
|
|
452
484
|
searchEndBlock?: bigint,
|
|
453
|
-
): Promise<{ l1BlockNumber: bigint;
|
|
485
|
+
): Promise<{ l1BlockNumber: bigint; checkpointNumber: CheckpointNumber; proverId: Fr; txHash: Hex }[]> {
|
|
454
486
|
const logs = await publicClient.getLogs({
|
|
455
487
|
address: rollupAddress.toString(),
|
|
456
488
|
fromBlock: searchStartBlock,
|
|
@@ -461,7 +493,7 @@ export async function retrieveL2ProofVerifiedEvents(
|
|
|
461
493
|
|
|
462
494
|
return logs.map(log => ({
|
|
463
495
|
l1BlockNumber: log.blockNumber,
|
|
464
|
-
|
|
496
|
+
checkpointNumber: CheckpointNumber.fromBigInt(log.args.checkpointNumber),
|
|
465
497
|
proverId: Fr.fromHexString(log.args.proverId),
|
|
466
498
|
txHash: log.transactionHash,
|
|
467
499
|
}));
|
|
@@ -473,14 +505,14 @@ export async function retrieveL2ProofsFromRollup(
|
|
|
473
505
|
rollupAddress: EthAddress,
|
|
474
506
|
searchStartBlock: bigint,
|
|
475
507
|
searchEndBlock?: bigint,
|
|
476
|
-
): Promise<DataRetrieval<{ proof: Proof; proverId: Fr;
|
|
508
|
+
): Promise<DataRetrieval<{ proof: Proof; proverId: Fr; checkpointNumber: number; txHash: `0x${string}` }>> {
|
|
477
509
|
const logs = await retrieveL2ProofVerifiedEvents(publicClient, rollupAddress, searchStartBlock, searchEndBlock);
|
|
478
|
-
const retrievedData: { proof: Proof; proverId: Fr;
|
|
510
|
+
const retrievedData: { proof: Proof; proverId: Fr; checkpointNumber: number; txHash: `0x${string}` }[] = [];
|
|
479
511
|
const lastProcessedL1BlockNumber = logs.length > 0 ? logs.at(-1)!.l1BlockNumber : searchStartBlock - 1n;
|
|
480
512
|
|
|
481
|
-
for (const { txHash, proverId,
|
|
513
|
+
for (const { txHash, proverId, checkpointNumber } of logs) {
|
|
482
514
|
const proofData = await getProofFromSubmitProofTx(publicClient, txHash, proverId);
|
|
483
|
-
retrievedData.push({ proof: proofData.proof, proverId: proofData.proverId,
|
|
515
|
+
retrievedData.push({ proof: proofData.proof, proverId: proofData.proverId, checkpointNumber, txHash });
|
|
484
516
|
}
|
|
485
517
|
return {
|
|
486
518
|
retrievedData,
|
|
@@ -488,26 +520,26 @@ export async function retrieveL2ProofsFromRollup(
|
|
|
488
520
|
};
|
|
489
521
|
}
|
|
490
522
|
|
|
491
|
-
export type
|
|
523
|
+
export type SubmitEpochProof = {
|
|
492
524
|
archiveRoot: Fr;
|
|
493
525
|
proverId: Fr;
|
|
494
526
|
proof: Proof;
|
|
495
527
|
};
|
|
496
528
|
|
|
497
529
|
/**
|
|
498
|
-
* Gets
|
|
530
|
+
* Gets epoch proof metadata (archive root and proof) from the calldata of an L1 transaction.
|
|
499
531
|
* Assumes that the block was published from an EOA.
|
|
500
532
|
* TODO: Add retries and error management.
|
|
501
533
|
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
502
534
|
* @param txHash - Hash of the tx that published it.
|
|
503
|
-
* @param
|
|
504
|
-
* @returns
|
|
535
|
+
* @param expectedProverId - Expected prover ID.
|
|
536
|
+
* @returns Epoch proof metadata from the calldata, deserialized.
|
|
505
537
|
*/
|
|
506
538
|
export async function getProofFromSubmitProofTx(
|
|
507
539
|
publicClient: ViemPublicClient,
|
|
508
540
|
txHash: `0x${string}`,
|
|
509
541
|
expectedProverId: Fr,
|
|
510
|
-
): Promise<
|
|
542
|
+
): Promise<SubmitEpochProof> {
|
|
511
543
|
const { input: data } = await publicClient.getTransaction({ hash: txHash });
|
|
512
544
|
const { functionName, args } = decodeFunctionData({ abi: RollupAbi, data });
|
|
513
545
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
|
-
import type {
|
|
2
|
+
import type { L2BlockNew } from '@aztec/stdlib/block';
|
|
3
3
|
import {
|
|
4
4
|
Attributes,
|
|
5
5
|
type Gauge,
|
|
@@ -139,7 +139,7 @@ export class ArchiverInstrumentation {
|
|
|
139
139
|
return this.telemetry.isEnabled();
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
public processNewBlocks(syncTimePerBlock: number, blocks:
|
|
142
|
+
public processNewBlocks(syncTimePerBlock: number, blocks: L2BlockNew[]) {
|
|
143
143
|
this.syncDurationPerBlock.record(Math.ceil(syncTimePerBlock));
|
|
144
144
|
this.blockHeight.record(Math.max(...blocks.map(b => b.number)));
|
|
145
145
|
this.syncBlockCount.add(blocks.length);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
2
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
3
|
import { Fr } from '@aztec/foundation/fields';
|
|
3
4
|
import { toArray } from '@aztec/foundation/iterable';
|
|
4
5
|
import { createLogger } from '@aztec/foundation/log';
|
|
@@ -158,7 +159,7 @@ export class BlockStore {
|
|
|
158
159
|
* @param blocksToUnwind - The number of blocks we are to unwind
|
|
159
160
|
* @returns True if the operation is successful
|
|
160
161
|
*/
|
|
161
|
-
async unwindBlocks(from:
|
|
162
|
+
async unwindBlocks(from: BlockNumber, blocksToUnwind: number) {
|
|
162
163
|
return await this.db.transactionAsync(async () => {
|
|
163
164
|
const last = await this.getSynchedL2BlockNumber();
|
|
164
165
|
if (from !== last) {
|
|
@@ -167,12 +168,12 @@ export class BlockStore {
|
|
|
167
168
|
|
|
168
169
|
const proven = await this.getProvenL2BlockNumber();
|
|
169
170
|
if (from - blocksToUnwind < proven) {
|
|
170
|
-
await this.setProvenL2BlockNumber(from - blocksToUnwind);
|
|
171
|
+
await this.setProvenL2BlockNumber(BlockNumber(from - blocksToUnwind));
|
|
171
172
|
}
|
|
172
173
|
|
|
173
174
|
for (let i = 0; i < blocksToUnwind; i++) {
|
|
174
175
|
const blockNumber = from - i;
|
|
175
|
-
const block = await this.getBlock(blockNumber);
|
|
176
|
+
const block = await this.getBlock(BlockNumber(blockNumber));
|
|
176
177
|
|
|
177
178
|
if (block === undefined) {
|
|
178
179
|
this.#log.warn(`Cannot remove block ${blockNumber} from the store since we don't have it`);
|
|
@@ -200,7 +201,7 @@ export class BlockStore {
|
|
|
200
201
|
* @param limit - The number of blocks to return.
|
|
201
202
|
* @returns The requested L2 blocks
|
|
202
203
|
*/
|
|
203
|
-
async *getBlocks(start:
|
|
204
|
+
async *getBlocks(start: BlockNumber, limit: number): AsyncIterableIterator<PublishedL2Block> {
|
|
204
205
|
for await (const [blockNumber, blockStorage] of this.getBlockStorages(start, limit)) {
|
|
205
206
|
const block = await this.getBlockFromBlockStorage(blockNumber, blockStorage);
|
|
206
207
|
if (block) {
|
|
@@ -214,7 +215,7 @@ export class BlockStore {
|
|
|
214
215
|
* @param blockNumber - The number of the block to return.
|
|
215
216
|
* @returns The requested L2 block.
|
|
216
217
|
*/
|
|
217
|
-
async getBlock(blockNumber:
|
|
218
|
+
async getBlock(blockNumber: BlockNumber): Promise<PublishedL2Block | undefined> {
|
|
218
219
|
const blockStorage = await this.#blocks.getAsync(blockNumber);
|
|
219
220
|
if (!blockStorage || !blockStorage.header) {
|
|
220
221
|
return Promise.resolve(undefined);
|
|
@@ -232,7 +233,7 @@ export class BlockStore {
|
|
|
232
233
|
if (blockNumber === undefined) {
|
|
233
234
|
return undefined;
|
|
234
235
|
}
|
|
235
|
-
return this.getBlock(blockNumber);
|
|
236
|
+
return this.getBlock(BlockNumber(blockNumber));
|
|
236
237
|
}
|
|
237
238
|
|
|
238
239
|
/**
|
|
@@ -245,7 +246,7 @@ export class BlockStore {
|
|
|
245
246
|
if (blockNumber === undefined) {
|
|
246
247
|
return undefined;
|
|
247
248
|
}
|
|
248
|
-
return this.getBlock(blockNumber);
|
|
249
|
+
return this.getBlock(BlockNumber(blockNumber));
|
|
249
250
|
}
|
|
250
251
|
|
|
251
252
|
/**
|
|
@@ -288,7 +289,7 @@ export class BlockStore {
|
|
|
288
289
|
* @param limit - The number of blocks to return.
|
|
289
290
|
* @returns The requested L2 block headers
|
|
290
291
|
*/
|
|
291
|
-
async *getBlockHeaders(start:
|
|
292
|
+
async *getBlockHeaders(start: BlockNumber, limit: number): AsyncIterableIterator<BlockHeader> {
|
|
292
293
|
for await (const [blockNumber, blockStorage] of this.getBlockStorages(start, limit)) {
|
|
293
294
|
const header = L2BlockHeader.fromBuffer(blockStorage.header).toBlockHeader();
|
|
294
295
|
if (header.getBlockNumber() !== blockNumber) {
|
|
@@ -300,7 +301,7 @@ export class BlockStore {
|
|
|
300
301
|
}
|
|
301
302
|
}
|
|
302
303
|
|
|
303
|
-
private async *getBlockStorages(start:
|
|
304
|
+
private async *getBlockStorages(start: BlockNumber, limit: number) {
|
|
304
305
|
let expectedBlockNumber = start;
|
|
305
306
|
for await (const [blockNumber, blockStorage] of this.#blocks.entriesAsync(this.#computeBlockRange(start, limit))) {
|
|
306
307
|
if (blockNumber !== expectedBlockNumber) {
|
|
@@ -382,7 +383,7 @@ export class BlockStore {
|
|
|
382
383
|
'',
|
|
383
384
|
txEffect.data.transactionFee.toBigInt(),
|
|
384
385
|
txEffect.l2BlockHash,
|
|
385
|
-
txEffect.l2BlockNumber,
|
|
386
|
+
BlockNumber(txEffect.l2BlockNumber),
|
|
386
387
|
);
|
|
387
388
|
}
|
|
388
389
|
|
|
@@ -413,9 +414,9 @@ export class BlockStore {
|
|
|
413
414
|
* Gets the number of the latest L2 block processed.
|
|
414
415
|
* @returns The number of the latest L2 block processed.
|
|
415
416
|
*/
|
|
416
|
-
async getSynchedL2BlockNumber(): Promise<
|
|
417
|
+
async getSynchedL2BlockNumber(): Promise<BlockNumber> {
|
|
417
418
|
const [lastBlockNumber] = await toArray(this.#blocks.keysAsync({ reverse: true, limit: 1 }));
|
|
418
|
-
return typeof lastBlockNumber === 'number' ? lastBlockNumber : INITIAL_L2_BLOCK_NUM - 1;
|
|
419
|
+
return typeof lastBlockNumber === 'number' ? BlockNumber(lastBlockNumber) : BlockNumber(INITIAL_L2_BLOCK_NUM - 1);
|
|
419
420
|
}
|
|
420
421
|
|
|
421
422
|
/**
|
|
@@ -430,19 +431,19 @@ export class BlockStore {
|
|
|
430
431
|
return this.#lastSynchedL1Block.set(l1BlockNumber);
|
|
431
432
|
}
|
|
432
433
|
|
|
433
|
-
async getProvenL2BlockNumber(): Promise<
|
|
434
|
+
async getProvenL2BlockNumber(): Promise<BlockNumber> {
|
|
434
435
|
const [latestBlockNumber, provenBlockNumber] = await Promise.all([
|
|
435
436
|
this.getSynchedL2BlockNumber(),
|
|
436
437
|
this.#lastProvenL2Block.getAsync(),
|
|
437
438
|
]);
|
|
438
|
-
return (provenBlockNumber ?? 0) > latestBlockNumber ? latestBlockNumber : (provenBlockNumber ?? 0);
|
|
439
|
+
return (provenBlockNumber ?? 0) > latestBlockNumber ? latestBlockNumber : BlockNumber(provenBlockNumber ?? 0);
|
|
439
440
|
}
|
|
440
441
|
|
|
441
|
-
setProvenL2BlockNumber(blockNumber:
|
|
442
|
+
setProvenL2BlockNumber(blockNumber: BlockNumber) {
|
|
442
443
|
return this.#lastProvenL2Block.set(blockNumber);
|
|
443
444
|
}
|
|
444
445
|
|
|
445
|
-
#computeBlockRange(start:
|
|
446
|
+
#computeBlockRange(start: BlockNumber, limit: number): Required<Pick<Range<number>, 'start' | 'limit'>> {
|
|
446
447
|
if (limit < 1) {
|
|
447
448
|
throw new Error(`Invalid limit: ${limit}`);
|
|
448
449
|
}
|