@aztec/archiver 0.0.1-commit.b655e406 → 0.0.1-commit.fce3e4f
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 +30 -20
- package/dest/archiver/archiver.d.ts.map +1 -1
- package/dest/archiver/archiver.js +294 -208
- package/dest/archiver/archiver_store.d.ts +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 +5 -4
- 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 +17 -17
- package/dest/archiver/data_retrieval.d.ts.map +1 -1
- package/dest/archiver/data_retrieval.js +110 -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 +1 -1
- package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
- 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 +2 -2
- 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/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 +1 -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/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 +1 -1
- package/dest/test/mock_archiver.d.ts.map +1 -1
- package/dest/test/mock_l1_to_l2_message_source.d.ts +1 -1
- package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.d.ts +7 -6
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +1 -1
- package/dest/test/mock_structs.d.ts +1 -1
- package/package.json +17 -17
- package/src/archiver/archiver.ts +380 -244
- package/src/archiver/archiver_store_test_suite.ts +5 -4
- package/src/archiver/config.ts +5 -0
- package/src/archiver/data_retrieval.ts +156 -125
- package/src/archiver/instrumentation.ts +2 -2
- package/src/archiver/structs/published.ts +2 -1
- package/src/archiver/validation.ts +52 -27
- package/src/index.ts +1 -1
- package/src/test/mock_l2_block_source.ts +7 -6
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
PRIVATE_LOG_SIZE_IN_FIELDS,
|
|
5
5
|
} from '@aztec/constants';
|
|
6
6
|
import { makeTuple } from '@aztec/foundation/array';
|
|
7
|
+
import { EpochNumber } from '@aztec/foundation/branded-types';
|
|
7
8
|
import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
|
|
8
9
|
import { times, timesParallel } from '@aztec/foundation/collection';
|
|
9
10
|
import { randomInt } from '@aztec/foundation/crypto';
|
|
@@ -1189,7 +1190,7 @@ export function describeArchiverDataStore(
|
|
|
1189
1190
|
valid: false,
|
|
1190
1191
|
block: randomBlockInfo(1),
|
|
1191
1192
|
committee: [EthAddress.random(), EthAddress.random()],
|
|
1192
|
-
epoch:
|
|
1193
|
+
epoch: EpochNumber(123),
|
|
1193
1194
|
seed: 456n,
|
|
1194
1195
|
attestors: [EthAddress.random()],
|
|
1195
1196
|
attestations: [CommitteeAttestation.random()],
|
|
@@ -1208,7 +1209,7 @@ export function describeArchiverDataStore(
|
|
|
1208
1209
|
block: randomBlockInfo(2),
|
|
1209
1210
|
committee: [EthAddress.random()],
|
|
1210
1211
|
attestors: [EthAddress.random()],
|
|
1211
|
-
epoch:
|
|
1212
|
+
epoch: EpochNumber(789),
|
|
1212
1213
|
seed: 101n,
|
|
1213
1214
|
attestations: [CommitteeAttestation.random()],
|
|
1214
1215
|
reason: 'invalid-attestation',
|
|
@@ -1227,7 +1228,7 @@ export function describeArchiverDataStore(
|
|
|
1227
1228
|
valid: false,
|
|
1228
1229
|
block: randomBlockInfo(3),
|
|
1229
1230
|
committee: [EthAddress.random()],
|
|
1230
|
-
epoch:
|
|
1231
|
+
epoch: EpochNumber(999),
|
|
1231
1232
|
seed: 888n,
|
|
1232
1233
|
attestors: [EthAddress.random()],
|
|
1233
1234
|
attestations: [CommitteeAttestation.random()],
|
|
@@ -1246,7 +1247,7 @@ export function describeArchiverDataStore(
|
|
|
1246
1247
|
valid: false,
|
|
1247
1248
|
block: randomBlockInfo(4),
|
|
1248
1249
|
committee: [],
|
|
1249
|
-
epoch:
|
|
1250
|
+
epoch: EpochNumber(0),
|
|
1250
1251
|
seed: 0n,
|
|
1251
1252
|
attestors: [],
|
|
1252
1253
|
attestations: [],
|
package/src/archiver/config.ts
CHANGED
|
@@ -50,6 +50,11 @@ export const archiverConfigMappings: ConfigMappingsType<ArchiverConfig> = {
|
|
|
50
50
|
description: 'Whether to skip validating block attestations (use only for testing).',
|
|
51
51
|
...booleanConfigHelper(false),
|
|
52
52
|
},
|
|
53
|
+
maxAllowedEthClientDriftSeconds: {
|
|
54
|
+
env: 'MAX_ALLOWED_ETH_CLIENT_DRIFT_SECONDS',
|
|
55
|
+
description: 'Maximum allowed drift in seconds between the Ethereum client and current time.',
|
|
56
|
+
...numberConfigHelper(300),
|
|
57
|
+
},
|
|
53
58
|
...chainConfigMappings,
|
|
54
59
|
...l1ReaderConfigMappings,
|
|
55
60
|
viemPollingIntervalMS: {
|
|
@@ -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,7 +12,6 @@ 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';
|
|
12
17
|
import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
|
|
@@ -15,11 +20,12 @@ import type { ViemSignature } from '@aztec/foundation/eth-signature';
|
|
|
15
20
|
import { Fr } from '@aztec/foundation/fields';
|
|
16
21
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
17
22
|
import { type InboxAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
18
|
-
import { Body, CommitteeAttestation,
|
|
23
|
+
import { Body, CommitteeAttestation, L2BlockNew } from '@aztec/stdlib/block';
|
|
24
|
+
import { Checkpoint, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
19
25
|
import { Proof } from '@aztec/stdlib/proofs';
|
|
20
26
|
import { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
21
27
|
import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
|
|
22
|
-
import { GlobalVariables, StateReference } from '@aztec/stdlib/tx';
|
|
28
|
+
import { BlockHeader, GlobalVariables, PartialStateReference, StateReference } from '@aztec/stdlib/tx';
|
|
23
29
|
|
|
24
30
|
import {
|
|
25
31
|
type GetContractEventsReturnType,
|
|
@@ -36,75 +42,106 @@ import type { DataRetrieval } from './structs/data_retrieval.js';
|
|
|
36
42
|
import type { InboxMessage } from './structs/inbox_message.js';
|
|
37
43
|
import type { L1PublishedData } from './structs/published.js';
|
|
38
44
|
|
|
39
|
-
export type
|
|
40
|
-
|
|
45
|
+
export type RetrievedCheckpoint = {
|
|
46
|
+
checkpointNumber: number;
|
|
41
47
|
archiveRoot: Fr;
|
|
42
|
-
stateReference: StateReference;
|
|
43
48
|
header: CheckpointHeader;
|
|
44
|
-
|
|
49
|
+
checkpointBlobData: CheckpointBlobData;
|
|
45
50
|
l1: L1PublishedData;
|
|
46
51
|
chainId: Fr;
|
|
47
52
|
version: Fr;
|
|
48
53
|
attestations: CommitteeAttestation[];
|
|
49
54
|
};
|
|
50
55
|
|
|
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
|
-
|
|
56
|
+
export async function retrievedToPublishedCheckpoint({
|
|
57
|
+
checkpointNumber,
|
|
58
|
+
archiveRoot,
|
|
59
|
+
header: checkpointHeader,
|
|
60
|
+
checkpointBlobData,
|
|
61
|
+
l1,
|
|
62
|
+
chainId,
|
|
63
|
+
version,
|
|
64
|
+
attestations,
|
|
65
|
+
}: RetrievedCheckpoint): Promise<PublishedCheckpoint> {
|
|
66
|
+
const { blocks: blocksBlobData } = checkpointBlobData;
|
|
67
|
+
|
|
68
|
+
// The lastArchiveRoot of a block is the new archive for the previous block.
|
|
69
|
+
const newArchiveRoots = blocksBlobData
|
|
70
|
+
.map(b => b.lastArchiveRoot)
|
|
71
|
+
.slice(1)
|
|
72
|
+
.concat([archiveRoot]);
|
|
73
|
+
|
|
74
|
+
// `blocksBlobData` is created from `decodeCheckpointBlobDataFromBlobs`. An error will be thrown if it can't read a
|
|
75
|
+
// field for the `l1ToL2MessageRoot` of the first block. So below we can safely assume it exists:
|
|
76
|
+
const l1toL2MessageTreeRoot = blocksBlobData[0].l1ToL2MessageRoot!;
|
|
77
|
+
|
|
78
|
+
const spongeBlob = SpongeBlob.init();
|
|
79
|
+
const l2Blocks: L2BlockNew[] = [];
|
|
80
|
+
for (let i = 0; i < blocksBlobData.length; i++) {
|
|
81
|
+
const blockBlobData = blocksBlobData[i];
|
|
82
|
+
const { blockEndMarker, blockEndStateField, lastArchiveRoot, noteHashRoot, nullifierRoot, publicDataRoot } =
|
|
83
|
+
blockBlobData;
|
|
84
|
+
|
|
85
|
+
const l2BlockNumber = blockEndMarker.blockNumber;
|
|
86
|
+
|
|
87
|
+
const globalVariables = GlobalVariables.from({
|
|
88
|
+
chainId,
|
|
89
|
+
version,
|
|
90
|
+
blockNumber: l2BlockNumber,
|
|
91
|
+
slotNumber: checkpointHeader.slotNumber,
|
|
92
|
+
timestamp: blockEndMarker.timestamp,
|
|
93
|
+
coinbase: checkpointHeader.coinbase,
|
|
94
|
+
feeRecipient: checkpointHeader.feeRecipient,
|
|
95
|
+
gasFees: checkpointHeader.gasFees,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const state = StateReference.from({
|
|
99
|
+
l1ToL2MessageTree: new AppendOnlyTreeSnapshot(
|
|
100
|
+
l1toL2MessageTreeRoot,
|
|
101
|
+
blockEndStateField.l1ToL2MessageNextAvailableLeafIndex,
|
|
102
|
+
),
|
|
103
|
+
partial: PartialStateReference.from({
|
|
104
|
+
noteHashTree: new AppendOnlyTreeSnapshot(noteHashRoot, blockEndStateField.noteHashNextAvailableLeafIndex),
|
|
105
|
+
nullifierTree: new AppendOnlyTreeSnapshot(nullifierRoot, blockEndStateField.nullifierNextAvailableLeafIndex),
|
|
106
|
+
publicDataTree: new AppendOnlyTreeSnapshot(publicDataRoot, blockEndStateField.publicDataNextAvailableLeafIndex),
|
|
107
|
+
}),
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const body = Body.fromTxBlobData(checkpointBlobData.blocks[0].txs);
|
|
111
|
+
|
|
112
|
+
const blobFields = encodeBlockBlobData(blockBlobData);
|
|
113
|
+
await spongeBlob.absorb(blobFields);
|
|
114
|
+
|
|
115
|
+
const clonedSpongeBlob = spongeBlob.clone();
|
|
116
|
+
const spongeBlobHash = await clonedSpongeBlob.squeeze();
|
|
117
|
+
|
|
118
|
+
const header = BlockHeader.from({
|
|
119
|
+
lastArchive: new AppendOnlyTreeSnapshot(lastArchiveRoot, l2BlockNumber),
|
|
120
|
+
state,
|
|
121
|
+
spongeBlobHash,
|
|
122
|
+
globalVariables,
|
|
123
|
+
totalFees: body.txEffects.reduce((accum, txEffect) => accum.add(txEffect.transactionFee), Fr.ZERO),
|
|
124
|
+
totalManaUsed: new Fr(blockEndStateField.totalManaUsed),
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const newArchive = new AppendOnlyTreeSnapshot(newArchiveRoots[i], l2BlockNumber + 1);
|
|
128
|
+
|
|
129
|
+
l2Blocks.push(new L2BlockNew(newArchive, header, body));
|
|
130
|
+
}
|
|
79
131
|
|
|
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,
|
|
132
|
+
const lastBlock = l2Blocks.at(-1)!;
|
|
133
|
+
const checkpoint = Checkpoint.from({
|
|
134
|
+
archive: new AppendOnlyTreeSnapshot(archiveRoot, lastBlock.number + 1),
|
|
135
|
+
header: checkpointHeader,
|
|
136
|
+
blocks: l2Blocks,
|
|
137
|
+
number: checkpointNumber,
|
|
99
138
|
});
|
|
100
139
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
return PublishedL2Block.fromFields({ block, l1, attestations });
|
|
140
|
+
return PublishedCheckpoint.from({ checkpoint, l1, attestations });
|
|
104
141
|
}
|
|
105
142
|
|
|
106
143
|
/**
|
|
107
|
-
* Fetches new
|
|
144
|
+
* Fetches new checkpoints.
|
|
108
145
|
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
109
146
|
* @param rollupAddress - The address of the rollup contract.
|
|
110
147
|
* @param searchStartBlock - The block number to use for starting the search.
|
|
@@ -112,15 +149,15 @@ export async function retrievedBlockToPublishedL2Block(retrievedBlock: Retrieved
|
|
|
112
149
|
* @param expectedNextL2BlockNum - The next L2 block number that we expect to find.
|
|
113
150
|
* @returns An array of block; as well as the next eth block to search from.
|
|
114
151
|
*/
|
|
115
|
-
export async function
|
|
152
|
+
export async function retrieveCheckpointsFromRollup(
|
|
116
153
|
rollup: GetContractReturnType<typeof RollupAbi, ViemPublicClient>,
|
|
117
154
|
publicClient: ViemPublicClient,
|
|
118
155
|
blobSinkClient: BlobSinkClientInterface,
|
|
119
156
|
searchStartBlock: bigint,
|
|
120
157
|
searchEndBlock: bigint,
|
|
121
158
|
logger: Logger = createLogger('archiver'),
|
|
122
|
-
): Promise<
|
|
123
|
-
const
|
|
159
|
+
): Promise<RetrievedCheckpoint[]> {
|
|
160
|
+
const retrievedCheckpoints: RetrievedCheckpoint[] = [];
|
|
124
161
|
|
|
125
162
|
let rollupConstants: { chainId: Fr; version: Fr; targetCommitteeSize: number } | undefined;
|
|
126
163
|
|
|
@@ -128,8 +165,8 @@ export async function retrieveBlocksFromRollup(
|
|
|
128
165
|
if (searchStartBlock > searchEndBlock) {
|
|
129
166
|
break;
|
|
130
167
|
}
|
|
131
|
-
const
|
|
132
|
-
await rollup.getEvents.
|
|
168
|
+
const checkpointProposedLogs = (
|
|
169
|
+
await rollup.getEvents.CheckpointProposed(
|
|
133
170
|
{},
|
|
134
171
|
{
|
|
135
172
|
fromBlock: searchStartBlock,
|
|
@@ -138,13 +175,13 @@ export async function retrieveBlocksFromRollup(
|
|
|
138
175
|
)
|
|
139
176
|
).filter(log => log.blockNumber! >= searchStartBlock && log.blockNumber! <= searchEndBlock);
|
|
140
177
|
|
|
141
|
-
if (
|
|
178
|
+
if (checkpointProposedLogs.length === 0) {
|
|
142
179
|
break;
|
|
143
180
|
}
|
|
144
181
|
|
|
145
|
-
const lastLog =
|
|
182
|
+
const lastLog = checkpointProposedLogs.at(-1)!;
|
|
146
183
|
logger.debug(
|
|
147
|
-
`Got ${
|
|
184
|
+
`Got ${checkpointProposedLogs.length} processed logs for checkpoints ${checkpointProposedLogs[0].args.checkpointNumber}-${lastLog.args.checkpointNumber} between L1 blocks ${searchStartBlock}-${searchEndBlock}`,
|
|
148
185
|
);
|
|
149
186
|
|
|
150
187
|
if (rollupConstants === undefined) {
|
|
@@ -160,52 +197,52 @@ export async function retrieveBlocksFromRollup(
|
|
|
160
197
|
};
|
|
161
198
|
}
|
|
162
199
|
|
|
163
|
-
const
|
|
200
|
+
const newCheckpoints = await processCheckpointProposedLogs(
|
|
164
201
|
rollup,
|
|
165
202
|
publicClient,
|
|
166
203
|
blobSinkClient,
|
|
167
|
-
|
|
204
|
+
checkpointProposedLogs,
|
|
168
205
|
rollupConstants,
|
|
169
206
|
logger,
|
|
170
207
|
);
|
|
171
|
-
|
|
208
|
+
retrievedCheckpoints.push(...newCheckpoints);
|
|
172
209
|
searchStartBlock = lastLog.blockNumber! + 1n;
|
|
173
210
|
} while (searchStartBlock <= searchEndBlock);
|
|
174
211
|
|
|
175
|
-
// The
|
|
176
|
-
return
|
|
212
|
+
// The asyncPool from processCheckpointProposedLogs will not necessarily return the checkpoints in order, so we sort them before returning.
|
|
213
|
+
return retrievedCheckpoints.sort((a, b) => Number(a.l1.blockNumber - b.l1.blockNumber));
|
|
177
214
|
}
|
|
178
215
|
|
|
179
216
|
/**
|
|
180
|
-
* Processes newly received
|
|
217
|
+
* Processes newly received CheckpointProposed logs.
|
|
181
218
|
* @param rollup - The rollup contract
|
|
182
219
|
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
183
|
-
* @param logs -
|
|
184
|
-
* @returns - An array
|
|
220
|
+
* @param logs - CheckpointProposed logs.
|
|
221
|
+
* @returns - An array of checkpoints.
|
|
185
222
|
*/
|
|
186
|
-
async function
|
|
223
|
+
async function processCheckpointProposedLogs(
|
|
187
224
|
rollup: GetContractReturnType<typeof RollupAbi, ViemPublicClient>,
|
|
188
225
|
publicClient: ViemPublicClient,
|
|
189
226
|
blobSinkClient: BlobSinkClientInterface,
|
|
190
|
-
logs: GetContractEventsReturnType<typeof RollupAbi, '
|
|
227
|
+
logs: GetContractEventsReturnType<typeof RollupAbi, 'CheckpointProposed'>,
|
|
191
228
|
{ chainId, version, targetCommitteeSize }: { chainId: Fr; version: Fr; targetCommitteeSize: number },
|
|
192
229
|
logger: Logger,
|
|
193
|
-
): Promise<
|
|
194
|
-
const
|
|
230
|
+
): Promise<RetrievedCheckpoint[]> {
|
|
231
|
+
const retrievedCheckpoints: RetrievedCheckpoint[] = [];
|
|
195
232
|
await asyncPool(10, logs, async log => {
|
|
196
|
-
const
|
|
233
|
+
const checkpointNumber = Number(log.args.checkpointNumber!);
|
|
197
234
|
const archive = log.args.archive!;
|
|
198
|
-
const archiveFromChain = await rollup.read.archiveAt([BigInt(
|
|
235
|
+
const archiveFromChain = await rollup.read.archiveAt([BigInt(checkpointNumber)]);
|
|
199
236
|
const blobHashes = log.args.versionedBlobHashes!.map(blobHash => Buffer.from(blobHash.slice(2), 'hex'));
|
|
200
237
|
|
|
201
|
-
// The value from the event and contract will match only if the
|
|
238
|
+
// The value from the event and contract will match only if the checkpoint is in the chain.
|
|
202
239
|
if (archive === archiveFromChain) {
|
|
203
|
-
const
|
|
240
|
+
const checkpoint = await getCheckpointFromRollupTx(
|
|
204
241
|
publicClient,
|
|
205
242
|
blobSinkClient,
|
|
206
243
|
log.transactionHash!,
|
|
207
244
|
blobHashes,
|
|
208
|
-
|
|
245
|
+
checkpointNumber,
|
|
209
246
|
rollup.address,
|
|
210
247
|
targetCommitteeSize,
|
|
211
248
|
logger,
|
|
@@ -217,22 +254,22 @@ async function processL2BlockProposedLogs(
|
|
|
217
254
|
timestamp: await getL1BlockTime(publicClient, log.blockNumber),
|
|
218
255
|
};
|
|
219
256
|
|
|
220
|
-
|
|
221
|
-
logger.trace(`Retrieved
|
|
257
|
+
retrievedCheckpoints.push({ ...checkpoint, l1, chainId, version });
|
|
258
|
+
logger.trace(`Retrieved checkpoint ${checkpointNumber} from L1 tx ${log.transactionHash}`, {
|
|
222
259
|
l1BlockNumber: log.blockNumber,
|
|
223
|
-
|
|
260
|
+
checkpointNumber,
|
|
224
261
|
archive: archive.toString(),
|
|
225
|
-
attestations:
|
|
262
|
+
attestations: checkpoint.attestations,
|
|
226
263
|
});
|
|
227
264
|
} else {
|
|
228
|
-
logger.warn(`Ignoring
|
|
265
|
+
logger.warn(`Ignoring checkpoint ${checkpointNumber} due to archive root mismatch`, {
|
|
229
266
|
actual: archive,
|
|
230
267
|
expected: archiveFromChain,
|
|
231
268
|
});
|
|
232
269
|
}
|
|
233
270
|
});
|
|
234
271
|
|
|
235
|
-
return
|
|
272
|
+
return retrievedCheckpoints;
|
|
236
273
|
}
|
|
237
274
|
|
|
238
275
|
export async function getL1BlockTime(publicClient: ViemPublicClient, blockNumber: bigint): Promise<bigint> {
|
|
@@ -291,24 +328,25 @@ function extractRollupProposeCalldata(multicall3Data: Hex, rollupAddress: Hex):
|
|
|
291
328
|
}
|
|
292
329
|
|
|
293
330
|
/**
|
|
294
|
-
* Gets
|
|
295
|
-
* Assumes that the
|
|
331
|
+
* Gets checkpoint from the calldata of an L1 transaction.
|
|
332
|
+
* Assumes that the checkpoint was published from an EOA.
|
|
296
333
|
* TODO: Add retries and error management.
|
|
297
334
|
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
298
335
|
* @param txHash - Hash of the tx that published it.
|
|
299
|
-
* @param
|
|
300
|
-
* @returns
|
|
336
|
+
* @param checkpointNumber - Checkpoint number.
|
|
337
|
+
* @returns Checkpoint from the calldata, deserialized
|
|
301
338
|
*/
|
|
302
|
-
async function
|
|
339
|
+
async function getCheckpointFromRollupTx(
|
|
303
340
|
publicClient: ViemPublicClient,
|
|
304
341
|
blobSinkClient: BlobSinkClientInterface,
|
|
305
342
|
txHash: `0x${string}`,
|
|
306
343
|
blobHashes: Buffer[], // TODO(md): buffer32?
|
|
307
|
-
|
|
344
|
+
checkpointNumber: number,
|
|
308
345
|
rollupAddress: Hex,
|
|
309
346
|
targetCommitteeSize: number,
|
|
310
347
|
logger: Logger,
|
|
311
|
-
): Promise<Omit<
|
|
348
|
+
): Promise<Omit<RetrievedCheckpoint, 'l1' | 'chainId' | 'version'>> {
|
|
349
|
+
logger.trace(`Fetching checkpoint ${checkpointNumber} from rollup tx ${txHash}`);
|
|
312
350
|
const { input: forwarderData, blockHash } = await publicClient.getTransaction({ hash: txHash });
|
|
313
351
|
|
|
314
352
|
const rollupData = extractRollupProposeCalldata(forwarderData, rollupAddress);
|
|
@@ -324,7 +362,6 @@ async function getBlockFromRollupTx(
|
|
|
324
362
|
const [decodedArgs, packedAttestations, _signers, _blobInput] = rollupArgs! as readonly [
|
|
325
363
|
{
|
|
326
364
|
archive: Hex;
|
|
327
|
-
stateReference: ViemStateReference;
|
|
328
365
|
oracleInput: {
|
|
329
366
|
feeAssetPriceModifier: bigint;
|
|
330
367
|
};
|
|
@@ -340,10 +377,10 @@ async function getBlockFromRollupTx(
|
|
|
340
377
|
const attestations = CommitteeAttestation.fromPacked(packedAttestations, targetCommitteeSize);
|
|
341
378
|
|
|
342
379
|
logger.trace(`Recovered propose calldata from tx ${txHash}`, {
|
|
343
|
-
|
|
380
|
+
checkpointNumber,
|
|
344
381
|
archive: decodedArgs.archive,
|
|
345
|
-
stateReference: decodedArgs.stateReference,
|
|
346
382
|
header: decodedArgs.header,
|
|
383
|
+
l1BlockHash: blockHash,
|
|
347
384
|
blobHashes,
|
|
348
385
|
attestations,
|
|
349
386
|
packedAttestations,
|
|
@@ -353,16 +390,13 @@ async function getBlockFromRollupTx(
|
|
|
353
390
|
const header = CheckpointHeader.fromViem(decodedArgs.header);
|
|
354
391
|
const blobBodies = await blobSinkClient.getBlobSidecar(blockHash, blobHashes);
|
|
355
392
|
if (blobBodies.length === 0) {
|
|
356
|
-
throw new NoBlobBodiesFoundError(
|
|
393
|
+
throw new NoBlobBodiesFoundError(checkpointNumber);
|
|
357
394
|
}
|
|
358
395
|
|
|
359
|
-
let
|
|
396
|
+
let checkpointBlobData: CheckpointBlobData;
|
|
360
397
|
try {
|
|
361
|
-
//
|
|
362
|
-
|
|
363
|
-
blobBodies.map(b => b.blob),
|
|
364
|
-
true /* checkEncoding */,
|
|
365
|
-
);
|
|
398
|
+
// Attempt to decode the checkpoint blob data.
|
|
399
|
+
checkpointBlobData = decodeCheckpointBlobDataFromBlobs(blobBodies.map(b => b.blob));
|
|
366
400
|
} catch (err: any) {
|
|
367
401
|
if (err instanceof BlobDeserializationError) {
|
|
368
402
|
logger.fatal(err.message);
|
|
@@ -374,14 +408,11 @@ async function getBlockFromRollupTx(
|
|
|
374
408
|
|
|
375
409
|
const archiveRoot = new Fr(Buffer.from(hexToBytes(decodedArgs.archive)));
|
|
376
410
|
|
|
377
|
-
const stateReference = StateReference.fromViem(decodedArgs.stateReference);
|
|
378
|
-
|
|
379
411
|
return {
|
|
380
|
-
|
|
412
|
+
checkpointNumber,
|
|
381
413
|
archiveRoot,
|
|
382
|
-
stateReference,
|
|
383
414
|
header,
|
|
384
|
-
|
|
415
|
+
checkpointBlobData,
|
|
385
416
|
attestations,
|
|
386
417
|
};
|
|
387
418
|
}
|
|
@@ -432,13 +463,13 @@ export async function retrieveL1ToL2Messages(
|
|
|
432
463
|
|
|
433
464
|
function mapLogsInboxMessage(logs: GetContractEventsReturnType<typeof InboxAbi, 'MessageSent'>): InboxMessage[] {
|
|
434
465
|
return logs.map(log => {
|
|
435
|
-
const { index, hash,
|
|
466
|
+
const { index, hash, checkpointNumber, rollingHash } = log.args;
|
|
436
467
|
return {
|
|
437
468
|
index: index!,
|
|
438
469
|
leaf: Fr.fromHexString(hash!),
|
|
439
470
|
l1BlockNumber: log.blockNumber,
|
|
440
471
|
l1BlockHash: Buffer32.fromString(log.blockHash),
|
|
441
|
-
l2BlockNumber: Number(
|
|
472
|
+
l2BlockNumber: Number(checkpointNumber!),
|
|
442
473
|
rollingHash: Buffer16.fromString(rollingHash!),
|
|
443
474
|
};
|
|
444
475
|
});
|
|
@@ -450,7 +481,7 @@ export async function retrieveL2ProofVerifiedEvents(
|
|
|
450
481
|
rollupAddress: EthAddress,
|
|
451
482
|
searchStartBlock: bigint,
|
|
452
483
|
searchEndBlock?: bigint,
|
|
453
|
-
): Promise<{ l1BlockNumber: bigint;
|
|
484
|
+
): Promise<{ l1BlockNumber: bigint; checkpointNumber: number; proverId: Fr; txHash: Hex }[]> {
|
|
454
485
|
const logs = await publicClient.getLogs({
|
|
455
486
|
address: rollupAddress.toString(),
|
|
456
487
|
fromBlock: searchStartBlock,
|
|
@@ -461,7 +492,7 @@ export async function retrieveL2ProofVerifiedEvents(
|
|
|
461
492
|
|
|
462
493
|
return logs.map(log => ({
|
|
463
494
|
l1BlockNumber: log.blockNumber,
|
|
464
|
-
|
|
495
|
+
checkpointNumber: Number(log.args.checkpointNumber),
|
|
465
496
|
proverId: Fr.fromHexString(log.args.proverId),
|
|
466
497
|
txHash: log.transactionHash,
|
|
467
498
|
}));
|
|
@@ -473,14 +504,14 @@ export async function retrieveL2ProofsFromRollup(
|
|
|
473
504
|
rollupAddress: EthAddress,
|
|
474
505
|
searchStartBlock: bigint,
|
|
475
506
|
searchEndBlock?: bigint,
|
|
476
|
-
): Promise<DataRetrieval<{ proof: Proof; proverId: Fr;
|
|
507
|
+
): Promise<DataRetrieval<{ proof: Proof; proverId: Fr; checkpointNumber: number; txHash: `0x${string}` }>> {
|
|
477
508
|
const logs = await retrieveL2ProofVerifiedEvents(publicClient, rollupAddress, searchStartBlock, searchEndBlock);
|
|
478
|
-
const retrievedData: { proof: Proof; proverId: Fr;
|
|
509
|
+
const retrievedData: { proof: Proof; proverId: Fr; checkpointNumber: number; txHash: `0x${string}` }[] = [];
|
|
479
510
|
const lastProcessedL1BlockNumber = logs.length > 0 ? logs.at(-1)!.l1BlockNumber : searchStartBlock - 1n;
|
|
480
511
|
|
|
481
|
-
for (const { txHash, proverId,
|
|
512
|
+
for (const { txHash, proverId, checkpointNumber } of logs) {
|
|
482
513
|
const proofData = await getProofFromSubmitProofTx(publicClient, txHash, proverId);
|
|
483
|
-
retrievedData.push({ proof: proofData.proof, proverId: proofData.proverId,
|
|
514
|
+
retrievedData.push({ proof: proofData.proof, proverId: proofData.proverId, checkpointNumber, txHash });
|
|
484
515
|
}
|
|
485
516
|
return {
|
|
486
517
|
retrievedData,
|
|
@@ -488,26 +519,26 @@ export async function retrieveL2ProofsFromRollup(
|
|
|
488
519
|
};
|
|
489
520
|
}
|
|
490
521
|
|
|
491
|
-
export type
|
|
522
|
+
export type SubmitEpochProof = {
|
|
492
523
|
archiveRoot: Fr;
|
|
493
524
|
proverId: Fr;
|
|
494
525
|
proof: Proof;
|
|
495
526
|
};
|
|
496
527
|
|
|
497
528
|
/**
|
|
498
|
-
* Gets
|
|
529
|
+
* Gets epoch proof metadata (archive root and proof) from the calldata of an L1 transaction.
|
|
499
530
|
* Assumes that the block was published from an EOA.
|
|
500
531
|
* TODO: Add retries and error management.
|
|
501
532
|
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
502
533
|
* @param txHash - Hash of the tx that published it.
|
|
503
|
-
* @param
|
|
504
|
-
* @returns
|
|
534
|
+
* @param expectedProverId - Expected prover ID.
|
|
535
|
+
* @returns Epoch proof metadata from the calldata, deserialized.
|
|
505
536
|
*/
|
|
506
537
|
export async function getProofFromSubmitProofTx(
|
|
507
538
|
publicClient: ViemPublicClient,
|
|
508
539
|
txHash: `0x${string}`,
|
|
509
540
|
expectedProverId: Fr,
|
|
510
|
-
): Promise<
|
|
541
|
+
): Promise<SubmitEpochProof> {
|
|
511
542
|
const { input: data } = await publicClient.getTransaction({ hash: txHash });
|
|
512
543
|
const { functionName, args } = decodeFunctionData({ abi: RollupAbi, data });
|
|
513
544
|
|
|
@@ -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 +1,2 @@
|
|
|
1
|
-
export type { PublishedL2Block
|
|
1
|
+
export type { PublishedL2Block } from '@aztec/stdlib/block';
|
|
2
|
+
export type { L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|