@aztec/archiver 0.52.0 → 0.54.0
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 +2 -1
- package/dest/archiver/archiver.d.ts.map +1 -1
- package/dest/archiver/archiver.js +5 -4
- package/dest/archiver/archiver_store.d.ts +4 -4
- package/dest/archiver/archiver_store.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.js +18 -18
- package/dest/archiver/config.d.ts +4 -0
- package/dest/archiver/config.d.ts.map +1 -1
- package/dest/archiver/config.js +6 -1
- package/dest/archiver/data_retrieval.d.ts +10 -2
- package/dest/archiver/data_retrieval.d.ts.map +1 -1
- package/dest/archiver/data_retrieval.js +17 -2
- package/dest/archiver/eth_log_handlers.d.ts +19 -1
- package/dest/archiver/eth_log_handlers.d.ts.map +1 -1
- package/dest/archiver/eth_log_handlers.js +38 -2
- package/dest/archiver/kv_archiver_store/block_body_store.d.ts +1 -1
- package/dest/archiver/kv_archiver_store/block_body_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/block_body_store.js +2 -2
- 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/block_store.js +2 -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/kv_archiver_store/message_store.js +2 -2
- package/dest/archiver/kv_archiver_store/proven_store.d.ts +1 -1
- package/dest/archiver/kv_archiver_store/proven_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/proven_store.js +2 -2
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +1 -1
- package/dest/archiver/memory_archiver_store/memory_archiver_store.js +7 -6
- package/dest/factory.d.ts +2 -4
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +5 -3
- package/dest/index.d.ts +2 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +3 -3
- package/package.json +14 -11
- package/src/archiver/archiver.ts +8 -2
- package/src/archiver/archiver_store.ts +4 -4
- package/src/archiver/archiver_store_test_suite.ts +17 -17
- package/src/archiver/config.ts +10 -0
- package/src/archiver/data_retrieval.ts +26 -3
- package/src/archiver/eth_log_handlers.ts +55 -1
- package/src/archiver/kv_archiver_store/block_body_store.ts +2 -2
- package/src/archiver/kv_archiver_store/block_store.ts +2 -2
- package/src/archiver/kv_archiver_store/message_store.ts +2 -2
- package/src/archiver/kv_archiver_store/proven_store.ts +2 -2
- package/src/archiver/memory_archiver_store/memory_archiver_store.ts +8 -5
- package/src/factory.ts +4 -4
- package/src/index.ts +3 -2
|
@@ -97,12 +97,12 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch
|
|
|
97
97
|
});
|
|
98
98
|
|
|
99
99
|
describe('getSynchPoint', () => {
|
|
100
|
-
it('returns
|
|
100
|
+
it('returns undefined if no blocks have been added', async () => {
|
|
101
101
|
await expect(store.getSynchPoint()).resolves.toEqual({
|
|
102
|
-
blocksSynchedTo:
|
|
103
|
-
messagesSynchedTo:
|
|
104
|
-
blockBodiesSynchedTo:
|
|
105
|
-
provenLogsSynchedTo:
|
|
102
|
+
blocksSynchedTo: undefined,
|
|
103
|
+
messagesSynchedTo: undefined,
|
|
104
|
+
blockBodiesSynchedTo: undefined,
|
|
105
|
+
provenLogsSynchedTo: undefined,
|
|
106
106
|
} satisfies ArchiverL1SynchPoint);
|
|
107
107
|
});
|
|
108
108
|
|
|
@@ -110,19 +110,19 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch
|
|
|
110
110
|
await store.addBlocks(blocks);
|
|
111
111
|
await expect(store.getSynchPoint()).resolves.toEqual({
|
|
112
112
|
blocksSynchedTo: 19n,
|
|
113
|
-
messagesSynchedTo:
|
|
114
|
-
blockBodiesSynchedTo:
|
|
115
|
-
provenLogsSynchedTo:
|
|
113
|
+
messagesSynchedTo: undefined,
|
|
114
|
+
blockBodiesSynchedTo: undefined,
|
|
115
|
+
provenLogsSynchedTo: undefined,
|
|
116
116
|
} satisfies ArchiverL1SynchPoint);
|
|
117
117
|
});
|
|
118
118
|
|
|
119
119
|
it('returns the L1 block number in which the most recent L2 block body was published', async () => {
|
|
120
120
|
await store.addBlockBodies(blockBodies);
|
|
121
121
|
await expect(store.getSynchPoint()).resolves.toEqual({
|
|
122
|
-
blocksSynchedTo:
|
|
123
|
-
messagesSynchedTo:
|
|
122
|
+
blocksSynchedTo: undefined,
|
|
123
|
+
messagesSynchedTo: undefined,
|
|
124
124
|
blockBodiesSynchedTo: blockBodies.lastProcessedL1BlockNumber,
|
|
125
|
-
provenLogsSynchedTo:
|
|
125
|
+
provenLogsSynchedTo: undefined,
|
|
126
126
|
} satisfies ArchiverL1SynchPoint);
|
|
127
127
|
});
|
|
128
128
|
|
|
@@ -132,19 +132,19 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch
|
|
|
132
132
|
retrievedData: [new InboxLeaf(0n, 0n, Fr.ZERO)],
|
|
133
133
|
});
|
|
134
134
|
await expect(store.getSynchPoint()).resolves.toEqual({
|
|
135
|
-
blocksSynchedTo:
|
|
135
|
+
blocksSynchedTo: undefined,
|
|
136
136
|
messagesSynchedTo: 1n,
|
|
137
|
-
blockBodiesSynchedTo:
|
|
138
|
-
provenLogsSynchedTo:
|
|
137
|
+
blockBodiesSynchedTo: undefined,
|
|
138
|
+
provenLogsSynchedTo: undefined,
|
|
139
139
|
} satisfies ArchiverL1SynchPoint);
|
|
140
140
|
});
|
|
141
141
|
|
|
142
142
|
it('returns the L1 block number that most recently logged a proven block', async () => {
|
|
143
143
|
await store.setProvenL2BlockNumber({ lastProcessedL1BlockNumber: 3n, retrievedData: 5 });
|
|
144
144
|
await expect(store.getSynchPoint()).resolves.toEqual({
|
|
145
|
-
blocksSynchedTo:
|
|
146
|
-
messagesSynchedTo:
|
|
147
|
-
blockBodiesSynchedTo:
|
|
145
|
+
blocksSynchedTo: undefined,
|
|
146
|
+
messagesSynchedTo: undefined,
|
|
147
|
+
blockBodiesSynchedTo: undefined,
|
|
148
148
|
provenLogsSynchedTo: 3n,
|
|
149
149
|
} satisfies ArchiverL1SynchPoint);
|
|
150
150
|
});
|
package/src/archiver/config.ts
CHANGED
|
@@ -22,6 +22,11 @@ export type ArchiverConfig = {
|
|
|
22
22
|
*/
|
|
23
23
|
archiverPollingIntervalMS?: number;
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* The L1 block to start reading from
|
|
27
|
+
*/
|
|
28
|
+
archiverL1StartBlock: number;
|
|
29
|
+
|
|
25
30
|
/**
|
|
26
31
|
* The polling interval viem uses in ms
|
|
27
32
|
*/
|
|
@@ -52,6 +57,11 @@ export const archiverConfigMappings: ConfigMappingsType<ArchiverConfig> = {
|
|
|
52
57
|
description: 'The polling interval in ms for retrieving new L2 blocks and encrypted logs.',
|
|
53
58
|
...numberConfigHelper(1000),
|
|
54
59
|
},
|
|
60
|
+
archiverL1StartBlock: {
|
|
61
|
+
env: 'ARCHIVER_L1_START_BLOCK',
|
|
62
|
+
description: 'The L1 block the archiver should start reading logs from',
|
|
63
|
+
...numberConfigHelper(0),
|
|
64
|
+
},
|
|
55
65
|
viemPollingIntervalMS: {
|
|
56
66
|
env: 'ARCHIVER_VIEM_POLLING_INTERVAL_MS',
|
|
57
67
|
description: 'The polling interval viem uses in ms',
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { type Body, type InboxLeaf } from '@aztec/circuit-types';
|
|
2
|
-
import { type AppendOnlyTreeSnapshot, Fr, type Header } from '@aztec/circuits.js';
|
|
2
|
+
import { type AppendOnlyTreeSnapshot, Fr, type Header, type Proof } from '@aztec/circuits.js';
|
|
3
3
|
import { type EthAddress } from '@aztec/foundation/eth-address';
|
|
4
4
|
import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log';
|
|
5
5
|
import { RollupAbi } from '@aztec/l1-artifacts';
|
|
6
6
|
|
|
7
|
-
import { type PublicClient, getAbiItem } from 'viem';
|
|
7
|
+
import { type Hex, type PublicClient, getAbiItem } from 'viem';
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
|
+
getBlockProofFromSubmitProofTx,
|
|
10
11
|
getL2BlockProposedLogs,
|
|
11
12
|
getMessageSentLogs,
|
|
12
13
|
getTxsPublishedLogs,
|
|
@@ -147,7 +148,7 @@ export async function retrieveL2ProofVerifiedEvents(
|
|
|
147
148
|
rollupAddress: EthAddress,
|
|
148
149
|
searchStartBlock: bigint,
|
|
149
150
|
searchEndBlock?: bigint,
|
|
150
|
-
): Promise<{ l1BlockNumber: bigint; l2BlockNumber: bigint; proverId: Fr }[]> {
|
|
151
|
+
): Promise<{ l1BlockNumber: bigint; l2BlockNumber: bigint; proverId: Fr; txHash: Hex }[]> {
|
|
151
152
|
const logs = await publicClient.getLogs({
|
|
152
153
|
address: rollupAddress.toString(),
|
|
153
154
|
fromBlock: searchStartBlock,
|
|
@@ -160,5 +161,27 @@ export async function retrieveL2ProofVerifiedEvents(
|
|
|
160
161
|
l1BlockNumber: log.blockNumber,
|
|
161
162
|
l2BlockNumber: log.args.blockNumber,
|
|
162
163
|
proverId: Fr.fromString(log.args.proverId),
|
|
164
|
+
txHash: log.transactionHash,
|
|
163
165
|
}));
|
|
164
166
|
}
|
|
167
|
+
|
|
168
|
+
/** Retrieve submitted proofs from the rollup contract */
|
|
169
|
+
export async function retrieveL2ProofsFromRollup(
|
|
170
|
+
publicClient: PublicClient,
|
|
171
|
+
rollupAddress: EthAddress,
|
|
172
|
+
searchStartBlock: bigint,
|
|
173
|
+
searchEndBlock?: bigint,
|
|
174
|
+
): Promise<DataRetrieval<{ proof: Proof; proverId: Fr; l2BlockNumber: bigint; txHash: `0x${string}` }>> {
|
|
175
|
+
const logs = await retrieveL2ProofVerifiedEvents(publicClient, rollupAddress, searchStartBlock, searchEndBlock);
|
|
176
|
+
const retrievedData: { proof: Proof; proverId: Fr; l2BlockNumber: bigint; txHash: `0x${string}` }[] = [];
|
|
177
|
+
const lastProcessedL1BlockNumber = logs.length > 0 ? logs.at(-1)!.l1BlockNumber : searchStartBlock - 1n;
|
|
178
|
+
|
|
179
|
+
for (const { txHash, proverId, l2BlockNumber } of logs) {
|
|
180
|
+
const proofData = await getBlockProofFromSubmitProofTx(publicClient, txHash, l2BlockNumber, proverId);
|
|
181
|
+
retrievedData.push({ proof: proofData.proof, proverId: proofData.proverId, l2BlockNumber, txHash });
|
|
182
|
+
}
|
|
183
|
+
return {
|
|
184
|
+
retrievedData,
|
|
185
|
+
lastProcessedL1BlockNumber,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Body, InboxLeaf } from '@aztec/circuit-types';
|
|
2
|
-
import { AppendOnlyTreeSnapshot, Header } from '@aztec/circuits.js';
|
|
2
|
+
import { AppendOnlyTreeSnapshot, Header, Proof } from '@aztec/circuits.js';
|
|
3
3
|
import { type EthAddress } from '@aztec/foundation/eth-address';
|
|
4
4
|
import { Fr } from '@aztec/foundation/fields';
|
|
5
5
|
import { numToUInt32BE } from '@aztec/foundation/serialize';
|
|
@@ -257,3 +257,57 @@ export function getMessageSentLogs(
|
|
|
257
257
|
toBlock: toBlock + 1n, // the toBlock argument in getLogs is exclusive
|
|
258
258
|
});
|
|
259
259
|
}
|
|
260
|
+
|
|
261
|
+
export type SubmitBlockProof = {
|
|
262
|
+
header: Header;
|
|
263
|
+
archiveRoot: Fr;
|
|
264
|
+
proverId: Fr;
|
|
265
|
+
aggregationObject: Buffer;
|
|
266
|
+
proof: Proof;
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Gets block metadata (header and archive snapshot) from the calldata of an L1 transaction.
|
|
271
|
+
* Assumes that the block was published from an EOA.
|
|
272
|
+
* TODO: Add retries and error management.
|
|
273
|
+
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
274
|
+
* @param txHash - Hash of the tx that published it.
|
|
275
|
+
* @param l2BlockNum - L2 block number.
|
|
276
|
+
* @returns L2 block metadata (header and archive) from the calldata, deserialized
|
|
277
|
+
*/
|
|
278
|
+
export async function getBlockProofFromSubmitProofTx(
|
|
279
|
+
publicClient: PublicClient,
|
|
280
|
+
txHash: `0x${string}`,
|
|
281
|
+
l2BlockNum: bigint,
|
|
282
|
+
expectedProverId: Fr,
|
|
283
|
+
): Promise<SubmitBlockProof> {
|
|
284
|
+
const { input: data } = await publicClient.getTransaction({ hash: txHash });
|
|
285
|
+
const { functionName, args } = decodeFunctionData({
|
|
286
|
+
abi: RollupAbi,
|
|
287
|
+
data,
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
if (!(functionName === 'submitBlockRootProof')) {
|
|
291
|
+
throw new Error(`Unexpected method called ${functionName}`);
|
|
292
|
+
}
|
|
293
|
+
const [headerHex, archiveHex, proverIdHex, aggregationObjectHex, proofHex] = args!;
|
|
294
|
+
|
|
295
|
+
const header = Header.fromBuffer(Buffer.from(hexToBytes(headerHex)));
|
|
296
|
+
const proverId = Fr.fromString(proverIdHex);
|
|
297
|
+
|
|
298
|
+
const blockNumberFromHeader = header.globalVariables.blockNumber.toBigInt();
|
|
299
|
+
if (blockNumberFromHeader !== l2BlockNum) {
|
|
300
|
+
throw new Error(`Block number mismatch: expected ${l2BlockNum} but got ${blockNumberFromHeader}`);
|
|
301
|
+
}
|
|
302
|
+
if (!proverId.equals(expectedProverId)) {
|
|
303
|
+
throw new Error(`Prover ID mismatch: expected ${expectedProverId} but got ${proverId}`);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return {
|
|
307
|
+
header,
|
|
308
|
+
proverId,
|
|
309
|
+
aggregationObject: Buffer.from(hexToBytes(aggregationObjectHex)),
|
|
310
|
+
archiveRoot: Fr.fromString(archiveHex),
|
|
311
|
+
proof: Proof.fromBuffer(Buffer.from(hexToBytes(proofHex))),
|
|
312
|
+
};
|
|
313
|
+
}
|
|
@@ -68,7 +68,7 @@ export class BlockBodyStore {
|
|
|
68
68
|
* Gets the last L1 block number in which a L2 block body was included
|
|
69
69
|
* @returns The L1 block number
|
|
70
70
|
*/
|
|
71
|
-
getSynchedL1BlockNumber(): bigint {
|
|
72
|
-
return this.#lastSynchedL1Block.get()
|
|
71
|
+
getSynchedL1BlockNumber(): bigint | undefined {
|
|
72
|
+
return this.#lastSynchedL1Block.get();
|
|
73
73
|
}
|
|
74
74
|
}
|
|
@@ -180,8 +180,8 @@ export class BlockStore {
|
|
|
180
180
|
* Gets the most recent L1 block processed.
|
|
181
181
|
* @returns The L1 block that published the latest L2 block
|
|
182
182
|
*/
|
|
183
|
-
getSynchedL1BlockNumber(): bigint {
|
|
184
|
-
return this.#lastSynchedL1Block.get()
|
|
183
|
+
getSynchedL1BlockNumber(): bigint | undefined {
|
|
184
|
+
return this.#lastSynchedL1Block.get();
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
#computeBlockRange(start: number, limit: number): Required<Pick<Range<number>, 'start' | 'end'>> {
|
|
@@ -32,8 +32,8 @@ export class MessageStore {
|
|
|
32
32
|
* Gets the last L1 block number that emitted new messages.
|
|
33
33
|
* @returns The last L1 block number processed
|
|
34
34
|
*/
|
|
35
|
-
getSynchedL1BlockNumber(): bigint {
|
|
36
|
-
return this.#lastL1BlockMessages.get()
|
|
35
|
+
getSynchedL1BlockNumber(): bigint | undefined {
|
|
36
|
+
return this.#lastL1BlockMessages.get();
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/**
|
|
@@ -17,8 +17,8 @@ export class ProvenStore {
|
|
|
17
17
|
/**
|
|
18
18
|
* Gets the most recent L1 block processed.
|
|
19
19
|
*/
|
|
20
|
-
getSynchedL1BlockNumber(): bigint {
|
|
21
|
-
return this.#lastSynchedL1Block.get()
|
|
20
|
+
getSynchedL1BlockNumber(): bigint | undefined {
|
|
21
|
+
return this.#lastSynchedL1Block.get();
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
getProvenL2BlockNumber(): number {
|
|
@@ -83,10 +83,10 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
83
83
|
|
|
84
84
|
private contractInstances: Map<string, ContractInstanceWithAddress> = new Map();
|
|
85
85
|
|
|
86
|
-
private lastL1BlockNewBlocks: bigint =
|
|
87
|
-
private lastL1BlockNewBlockBodies: bigint =
|
|
88
|
-
private lastL1BlockNewMessages: bigint =
|
|
89
|
-
private lastL1BlockNewProvenLogs: bigint =
|
|
86
|
+
private lastL1BlockNewBlocks: bigint | undefined = undefined;
|
|
87
|
+
private lastL1BlockNewBlockBodies: bigint | undefined = undefined;
|
|
88
|
+
private lastL1BlockNewMessages: bigint | undefined = undefined;
|
|
89
|
+
private lastL1BlockNewProvenLogs: bigint | undefined = undefined;
|
|
90
90
|
|
|
91
91
|
private lastProvenL2BlockNumber: number = 0;
|
|
92
92
|
|
|
@@ -225,7 +225,10 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
225
225
|
* @returns True if the operation is successful.
|
|
226
226
|
*/
|
|
227
227
|
public addL1ToL2Messages(messages: DataRetrieval<InboxLeaf>): Promise<boolean> {
|
|
228
|
-
if (
|
|
228
|
+
if (
|
|
229
|
+
typeof this.lastL1BlockNewMessages === 'bigint' &&
|
|
230
|
+
messages.lastProcessedL1BlockNumber <= this.lastL1BlockNewMessages
|
|
231
|
+
) {
|
|
229
232
|
return Promise.resolve(false);
|
|
230
233
|
}
|
|
231
234
|
|
package/src/factory.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createDebugLogger } from '@aztec/foundation/log';
|
|
2
|
+
import { createStore } from '@aztec/kv-store/utils';
|
|
2
3
|
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
3
4
|
import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
|
|
4
5
|
|
|
@@ -7,14 +8,13 @@ import { type ArchiverConfig } from './archiver/config.js';
|
|
|
7
8
|
import { KVArchiverDataStore } from './archiver/index.js';
|
|
8
9
|
import { createArchiverClient } from './rpc/archiver_client.js';
|
|
9
10
|
|
|
10
|
-
export function createArchiver(
|
|
11
|
+
export async function createArchiver(
|
|
11
12
|
config: ArchiverConfig,
|
|
12
|
-
store: AztecKVStore,
|
|
13
13
|
telemetry: TelemetryClient = new NoopTelemetryClient(),
|
|
14
14
|
opts: { blockUntilSync: boolean } = { blockUntilSync: true },
|
|
15
15
|
) {
|
|
16
16
|
if (!config.archiverUrl) {
|
|
17
|
-
|
|
17
|
+
const store = await createStore('archiver', config, createDebugLogger('aztec:archiver:lmdb'));
|
|
18
18
|
const archiverStore = new KVArchiverDataStore(store, config.maxLogs);
|
|
19
19
|
return Archiver.createAndSync(config, archiverStore, telemetry, opts.blockUntilSync);
|
|
20
20
|
} else {
|
package/src/index.ts
CHANGED
|
@@ -13,8 +13,9 @@ export * from './archiver/index.js';
|
|
|
13
13
|
export * from './rpc/index.js';
|
|
14
14
|
export * from './factory.js';
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
export { retrieveL2ProofVerifiedEvents, retrieveBlockMetadataFromRollup } from './archiver/data_retrieval.js';
|
|
17
|
+
|
|
18
|
+
export { getL2BlockProposedLogs } from './archiver/eth_log_handlers.js';
|
|
18
19
|
|
|
19
20
|
const log = createDebugLogger('aztec:archiver');
|
|
20
21
|
|