@aztec/archiver 0.24.0 → 0.26.2
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 +15 -11
- package/dest/archiver/archiver.d.ts.map +1 -1
- package/dest/archiver/archiver.js +67 -72
- package/dest/archiver/archiver_store.d.ts +37 -15
- package/dest/archiver/archiver_store.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.js +70 -54
- package/dest/archiver/data_retrieval.d.ts +18 -8
- package/dest/archiver/data_retrieval.d.ts.map +1 -1
- package/dest/archiver/data_retrieval.js +39 -14
- package/dest/archiver/eth_log_handlers.d.ts +25 -23
- package/dest/archiver/eth_log_handlers.d.ts.map +1 -1
- package/dest/archiver/eth_log_handlers.js +98 -57
- package/dest/archiver/kv_archiver_store/block_body_store.d.ts +27 -0
- package/dest/archiver/kv_archiver_store/block_body_store.d.ts.map +1 -0
- package/dest/archiver/kv_archiver_store/block_body_store.js +47 -0
- package/dest/archiver/kv_archiver_store/block_store.d.ts +19 -11
- package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/block_store.js +58 -30
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +1 -0
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/contract_class_store.js +4 -1
- package/dest/archiver/kv_archiver_store/contract_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/contract_store.js +6 -3
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +36 -16
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.js +52 -22
- package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/log_store.js +4 -3
- package/dest/archiver/kv_archiver_store/message_store.d.ts +9 -9
- package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/message_store.js +34 -31
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts +6 -6
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts.map +1 -1
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.js +18 -18
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts +41 -16
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +1 -1
- package/dest/archiver/memory_archiver_store/memory_archiver_store.js +78 -29
- package/dest/index.js +2 -2
- package/dest/rpc/archiver_client.d.ts.map +1 -1
- package/dest/rpc/archiver_client.js +3 -3
- package/dest/rpc/archiver_server.d.ts.map +1 -1
- package/dest/rpc/archiver_server.js +4 -3
- package/package.json +10 -10
- package/src/archiver/archiver.ts +95 -92
- package/src/archiver/archiver_store.ts +42 -15
- package/src/archiver/archiver_store_test_suite.ts +73 -58
- package/src/archiver/data_retrieval.ts +61 -16
- package/src/archiver/eth_log_handlers.ts +142 -68
- package/src/archiver/kv_archiver_store/block_body_store.ts +54 -0
- package/src/archiver/kv_archiver_store/block_store.ts +71 -36
- package/src/archiver/kv_archiver_store/contract_class_store.ts +4 -0
- package/src/archiver/kv_archiver_store/contract_store.ts +7 -2
- package/src/archiver/kv_archiver_store/kv_archiver_store.ts +56 -20
- package/src/archiver/kv_archiver_store/log_store.ts +2 -2
- package/src/archiver/kv_archiver_store/message_store.ts +34 -30
- package/src/archiver/memory_archiver_store/l1_to_l2_message_store.ts +17 -17
- package/src/archiver/memory_archiver_store/memory_archiver_store.ts +91 -29
- package/src/index.ts +1 -0
- package/src/rpc/archiver_client.ts +3 -1
- package/src/rpc/archiver_server.ts +5 -1
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
|
+
Body,
|
|
2
3
|
ContractData,
|
|
3
4
|
EncodedContractFunction,
|
|
4
5
|
ExtendedContractData,
|
|
5
6
|
L1Actor,
|
|
6
7
|
L1ToL2Message,
|
|
7
8
|
L2Actor,
|
|
8
|
-
L2Block,
|
|
9
9
|
} from '@aztec/circuit-types';
|
|
10
|
+
import { AppendOnlyTreeSnapshot, Header } from '@aztec/circuits.js';
|
|
10
11
|
import { AztecAddress } from '@aztec/foundation/aztec-address';
|
|
11
12
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
12
13
|
import { Fr } from '@aztec/foundation/fields';
|
|
13
14
|
import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize';
|
|
14
|
-
import { ContractDeploymentEmitterAbi, InboxAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
15
|
+
import { AvailabilityOracleAbi, ContractDeploymentEmitterAbi, InboxAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
15
16
|
|
|
16
17
|
import { Hex, Log, PublicClient, decodeFunctionData, getAbiItem, getAddress, hexToBytes } from 'viem';
|
|
17
18
|
|
|
@@ -21,7 +22,7 @@ import { Hex, Log, PublicClient, decodeFunctionData, getAbiItem, getAddress, hex
|
|
|
21
22
|
* @returns Array of all Pending L1 to L2 messages that were processed
|
|
22
23
|
*/
|
|
23
24
|
export function processPendingL1ToL2MessageAddedLogs(
|
|
24
|
-
logs: Log<bigint, number, undefined, true, typeof InboxAbi, 'MessageAdded'>[],
|
|
25
|
+
logs: Log<bigint, number, false, undefined, true, typeof InboxAbi, 'MessageAdded'>[],
|
|
25
26
|
): [L1ToL2Message, bigint][] {
|
|
26
27
|
const l1ToL2Messages: [L1ToL2Message, bigint][] = [];
|
|
27
28
|
for (const log of logs) {
|
|
@@ -46,10 +47,10 @@ export function processPendingL1ToL2MessageAddedLogs(
|
|
|
46
47
|
/**
|
|
47
48
|
* Process newly received L1ToL2MessageCancelled logs.
|
|
48
49
|
* @param logs - L1ToL2MessageCancelled logs.
|
|
49
|
-
* @returns Array of
|
|
50
|
+
* @returns Array of entry keys of the L1 to L2 messages that were cancelled
|
|
50
51
|
*/
|
|
51
52
|
export function processCancelledL1ToL2MessagesLogs(
|
|
52
|
-
logs: Log<bigint, number, undefined, true, typeof InboxAbi, 'L1ToL2MessageCancelled'>[],
|
|
53
|
+
logs: Log<bigint, number, false, undefined, true, typeof InboxAbi, 'L1ToL2MessageCancelled'>[],
|
|
53
54
|
): [Fr, bigint][] {
|
|
54
55
|
const cancelledL1ToL2Messages: [Fr, bigint][] = [];
|
|
55
56
|
for (const log of logs) {
|
|
@@ -63,62 +64,116 @@ export function processCancelledL1ToL2MessagesLogs(
|
|
|
63
64
|
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
64
65
|
* @param expectedL2BlockNumber - The next expected L2 block number.
|
|
65
66
|
* @param logs - L2BlockProcessed logs.
|
|
67
|
+
* @returns - An array of tuples representing block metadata including the header, archive tree snapshot, and associated l1 block number.
|
|
66
68
|
*/
|
|
67
|
-
export async function
|
|
69
|
+
export async function processL2BlockProcessedLogs(
|
|
68
70
|
publicClient: PublicClient,
|
|
69
71
|
expectedL2BlockNumber: bigint,
|
|
70
|
-
logs: Log<bigint, number, undefined, true, typeof RollupAbi, 'L2BlockProcessed'>[],
|
|
71
|
-
): Promise<
|
|
72
|
-
const
|
|
72
|
+
logs: Log<bigint, number, false, undefined, true, typeof RollupAbi, 'L2BlockProcessed'>[],
|
|
73
|
+
): Promise<[Header, AppendOnlyTreeSnapshot, bigint][]> {
|
|
74
|
+
const retrievedBlockMetadata: [Header, AppendOnlyTreeSnapshot, bigint][] = [];
|
|
73
75
|
for (const log of logs) {
|
|
74
76
|
const blockNum = log.args.blockNumber;
|
|
75
77
|
if (blockNum !== expectedL2BlockNumber) {
|
|
76
78
|
throw new Error('Block number mismatch. Expected: ' + expectedL2BlockNumber + ' but got: ' + blockNum + '.');
|
|
77
79
|
}
|
|
78
80
|
// TODO: Fetch blocks from calldata in parallel
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
const [header, archive] = await getBlockMetadataFromRollupTx(
|
|
82
|
+
publicClient,
|
|
83
|
+
log.transactionHash!,
|
|
84
|
+
log.args.blockNumber,
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
retrievedBlockMetadata.push([header, archive, log.blockNumber!]);
|
|
82
88
|
expectedL2BlockNumber++;
|
|
83
89
|
}
|
|
84
|
-
|
|
90
|
+
|
|
91
|
+
return retrievedBlockMetadata;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export async function processTxsPublishedLogs(
|
|
95
|
+
publicClient: PublicClient,
|
|
96
|
+
logs: Log<bigint, number, false, undefined, true, typeof AvailabilityOracleAbi, 'TxsPublished'>[],
|
|
97
|
+
): Promise<[Body, Buffer][]> {
|
|
98
|
+
const retrievedBlockBodies: [Body, Buffer][] = [];
|
|
99
|
+
for (const log of logs) {
|
|
100
|
+
const newBlockBody = await getBlockBodiesFromAvailabilityOracleTx(publicClient, log.transactionHash!);
|
|
101
|
+
retrievedBlockBodies.push([newBlockBody, Buffer.from(hexToBytes(log.args.txsHash))]);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return retrievedBlockBodies;
|
|
85
105
|
}
|
|
86
106
|
|
|
87
107
|
/**
|
|
88
|
-
*
|
|
108
|
+
* Gets block metadata (header and archive snapshot) from the calldata of an L1 transaction.
|
|
89
109
|
* Assumes that the block was published from an EOA.
|
|
90
110
|
* TODO: Add retries and error management.
|
|
91
111
|
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
92
112
|
* @param txHash - Hash of the tx that published it.
|
|
93
113
|
* @param l2BlockNum - L2 block number.
|
|
94
|
-
* @returns
|
|
114
|
+
* @returns L2 block metadata (header and archive) from the calldata, deserialized
|
|
95
115
|
*/
|
|
96
|
-
async function
|
|
116
|
+
async function getBlockMetadataFromRollupTx(
|
|
97
117
|
publicClient: PublicClient,
|
|
98
118
|
txHash: `0x${string}`,
|
|
99
119
|
l2BlockNum: bigint,
|
|
100
|
-
): Promise<
|
|
120
|
+
): Promise<[Header, AppendOnlyTreeSnapshot]> {
|
|
101
121
|
const { input: data } = await publicClient.getTransaction({ hash: txHash });
|
|
102
|
-
// TODO: File a bug in viem who complains if we dont remove the ctor from the abi here
|
|
103
122
|
const { functionName, args } = decodeFunctionData({
|
|
104
|
-
abi: RollupAbi
|
|
123
|
+
abi: RollupAbi,
|
|
105
124
|
data,
|
|
106
125
|
});
|
|
126
|
+
|
|
107
127
|
if (functionName !== 'process') {
|
|
108
128
|
throw new Error(`Unexpected method called ${functionName}`);
|
|
109
129
|
}
|
|
110
|
-
const [headerHex, archiveRootHex
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
130
|
+
const [headerHex, archiveRootHex] = args! as readonly [Hex, Hex, Hex, Hex];
|
|
131
|
+
|
|
132
|
+
const header = Header.fromBuffer(Buffer.from(hexToBytes(headerHex)));
|
|
133
|
+
|
|
134
|
+
const blockNumberFromHeader = header.globalVariables.blockNumber.toBigInt();
|
|
135
|
+
|
|
136
|
+
if (blockNumberFromHeader !== l2BlockNum) {
|
|
137
|
+
throw new Error(`Block number mismatch: expected ${l2BlockNum} but got ${blockNumberFromHeader}`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const archive = AppendOnlyTreeSnapshot.fromBuffer(
|
|
141
|
+
Buffer.concat([
|
|
142
|
+
Buffer.from(hexToBytes(archiveRootHex)), // L2Block.archive.root
|
|
143
|
+
numToUInt32BE(Number(l2BlockNum)), // L2Block.archive.nextAvailableLeafIndex
|
|
144
|
+
]),
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
return [header, archive];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Gets block bodies from calldata of an L1 transaction, and deserializes them into Body objects.
|
|
152
|
+
* Assumes that the block was published from an EOA.
|
|
153
|
+
* TODO: Add retries and error management.
|
|
154
|
+
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
155
|
+
* @param txHash - Hash of the tx that published it.
|
|
156
|
+
* @returns An L2 block body from the calldata, deserialized
|
|
157
|
+
*/
|
|
158
|
+
async function getBlockBodiesFromAvailabilityOracleTx(
|
|
159
|
+
publicClient: PublicClient,
|
|
160
|
+
txHash: `0x${string}`,
|
|
161
|
+
): Promise<Body> {
|
|
162
|
+
const { input: data } = await publicClient.getTransaction({ hash: txHash });
|
|
163
|
+
const { functionName, args } = decodeFunctionData({
|
|
164
|
+
abi: AvailabilityOracleAbi,
|
|
165
|
+
data,
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
if (functionName !== 'publish') {
|
|
169
|
+
throw new Error(`Unexpected method called ${functionName}`);
|
|
120
170
|
}
|
|
121
|
-
|
|
171
|
+
|
|
172
|
+
const [bodyHex] = args! as [Hex];
|
|
173
|
+
|
|
174
|
+
const blockBody = Body.fromBuffer(Buffer.from(hexToBytes(bodyHex)));
|
|
175
|
+
|
|
176
|
+
return blockBody;
|
|
122
177
|
}
|
|
123
178
|
|
|
124
179
|
/**
|
|
@@ -129,21 +184,43 @@ async function getBlockFromCallData(
|
|
|
129
184
|
* @param toBlock - Last block to get logs from (inclusive).
|
|
130
185
|
* @returns An array of `L2BlockProcessed` logs.
|
|
131
186
|
*/
|
|
132
|
-
export
|
|
187
|
+
export function getL2BlockProcessedLogs(
|
|
133
188
|
publicClient: PublicClient,
|
|
134
189
|
rollupAddress: EthAddress,
|
|
135
190
|
fromBlock: bigint,
|
|
136
191
|
toBlock: bigint,
|
|
137
|
-
) {
|
|
138
|
-
|
|
139
|
-
// as a standalone constant.
|
|
140
|
-
const abiItem = getAbiItem({
|
|
141
|
-
abi: RollupAbi,
|
|
142
|
-
name: 'L2BlockProcessed',
|
|
143
|
-
});
|
|
144
|
-
return await publicClient.getLogs<typeof abiItem, true>({
|
|
192
|
+
): Promise<Log<bigint, number, false, undefined, true, typeof RollupAbi, 'L2BlockProcessed'>[]> {
|
|
193
|
+
return publicClient.getLogs({
|
|
145
194
|
address: getAddress(rollupAddress.toString()),
|
|
146
|
-
event:
|
|
195
|
+
event: getAbiItem({
|
|
196
|
+
abi: RollupAbi,
|
|
197
|
+
name: 'L2BlockProcessed',
|
|
198
|
+
}),
|
|
199
|
+
fromBlock,
|
|
200
|
+
toBlock: toBlock + 1n, // the toBlock argument in getLogs is exclusive
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Gets relevant `TxsPublished` logs from chain.
|
|
206
|
+
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
207
|
+
* @param dataAvailabilityOracleAddress - The address of the availability oracle contract.
|
|
208
|
+
* @param fromBlock - First block to get logs from (inclusive).
|
|
209
|
+
* @param toBlock - Last block to get logs from (inclusive).
|
|
210
|
+
* @returns An array of `TxsPublished` logs.
|
|
211
|
+
*/
|
|
212
|
+
export function getTxsPublishedLogs(
|
|
213
|
+
publicClient: PublicClient,
|
|
214
|
+
dataAvailabilityOracleAddress: EthAddress,
|
|
215
|
+
fromBlock: bigint,
|
|
216
|
+
toBlock: bigint,
|
|
217
|
+
): Promise<Log<bigint, number, false, undefined, true, typeof AvailabilityOracleAbi, 'TxsPublished'>[]> {
|
|
218
|
+
return publicClient.getLogs({
|
|
219
|
+
address: getAddress(dataAvailabilityOracleAddress.toString()),
|
|
220
|
+
event: getAbiItem({
|
|
221
|
+
abi: AvailabilityOracleAbi,
|
|
222
|
+
name: 'TxsPublished',
|
|
223
|
+
}),
|
|
147
224
|
fromBlock,
|
|
148
225
|
toBlock: toBlock + 1n, // the toBlock argument in getLogs is exclusive
|
|
149
226
|
});
|
|
@@ -157,19 +234,18 @@ export async function getL2BlockProcessedLogs(
|
|
|
157
234
|
* @param toBlock - Last block to get logs from (inclusive).
|
|
158
235
|
* @returns An array of `ContractDeployment` logs.
|
|
159
236
|
*/
|
|
160
|
-
export
|
|
237
|
+
export function getContractDeploymentLogs(
|
|
161
238
|
publicClient: PublicClient,
|
|
162
239
|
contractDeploymentEmitterAddress: EthAddress,
|
|
163
240
|
fromBlock: bigint,
|
|
164
241
|
toBlock: bigint,
|
|
165
|
-
): Promise<Log<bigint, number, undefined, true, typeof ContractDeploymentEmitterAbi, 'ContractDeployment'>[]> {
|
|
166
|
-
|
|
167
|
-
abi: ContractDeploymentEmitterAbi,
|
|
168
|
-
name: 'ContractDeployment',
|
|
169
|
-
});
|
|
170
|
-
return await publicClient.getLogs({
|
|
242
|
+
): Promise<Log<bigint, number, false, undefined, true, typeof ContractDeploymentEmitterAbi, 'ContractDeployment'>[]> {
|
|
243
|
+
return publicClient.getLogs({
|
|
171
244
|
address: getAddress(contractDeploymentEmitterAddress.toString()),
|
|
172
|
-
event:
|
|
245
|
+
event: getAbiItem({
|
|
246
|
+
abi: ContractDeploymentEmitterAbi,
|
|
247
|
+
name: 'ContractDeployment',
|
|
248
|
+
}),
|
|
173
249
|
fromBlock,
|
|
174
250
|
toBlock: toBlock + 1n, // the toBlock argument in getLogs is exclusive
|
|
175
251
|
});
|
|
@@ -177,20 +253,20 @@ export async function getContractDeploymentLogs(
|
|
|
177
253
|
|
|
178
254
|
/**
|
|
179
255
|
* Processes newly received ContractDeployment logs.
|
|
180
|
-
* @param
|
|
256
|
+
* @param blockNumberToBodyHash - A mapping from block number to relevant body hash.
|
|
181
257
|
* @param logs - ContractDeployment logs.
|
|
182
258
|
* @returns The set of retrieved extended contract data items.
|
|
183
259
|
*/
|
|
184
260
|
export function processContractDeploymentLogs(
|
|
185
|
-
|
|
186
|
-
logs: Log<bigint, number, undefined, true, typeof ContractDeploymentEmitterAbi, 'ContractDeployment'>[],
|
|
261
|
+
blockNumberToBodyHash: { [key: number]: Buffer | undefined },
|
|
262
|
+
logs: Log<bigint, number, false, undefined, true, typeof ContractDeploymentEmitterAbi, 'ContractDeployment'>[],
|
|
187
263
|
): [ExtendedContractData[], number][] {
|
|
188
264
|
const extendedContractData: [ExtendedContractData[], number][] = [];
|
|
189
265
|
for (let i = 0; i < logs.length; i++) {
|
|
190
266
|
const log = logs[i];
|
|
191
267
|
const l2BlockNum = Number(log.args.l2BlockNum);
|
|
192
268
|
const blockHash = Buffer.from(hexToBytes(log.args.l2BlockHash));
|
|
193
|
-
const expectedBlockHash =
|
|
269
|
+
const expectedBlockHash = blockNumberToBodyHash[l2BlockNum];
|
|
194
270
|
if (expectedBlockHash === undefined || !blockHash.equals(expectedBlockHash)) {
|
|
195
271
|
continue;
|
|
196
272
|
}
|
|
@@ -223,19 +299,18 @@ export function processContractDeploymentLogs(
|
|
|
223
299
|
* @param toBlock - Last block to get logs from (inclusive).
|
|
224
300
|
* @returns An array of `MessageAdded` logs.
|
|
225
301
|
*/
|
|
226
|
-
export
|
|
302
|
+
export function getPendingL1ToL2MessageLogs(
|
|
227
303
|
publicClient: PublicClient,
|
|
228
304
|
inboxAddress: EthAddress,
|
|
229
305
|
fromBlock: bigint,
|
|
230
306
|
toBlock: bigint,
|
|
231
|
-
): Promise<Log<bigint, number, undefined, true, typeof InboxAbi, 'MessageAdded'>[]> {
|
|
232
|
-
|
|
233
|
-
abi: InboxAbi,
|
|
234
|
-
name: 'MessageAdded',
|
|
235
|
-
});
|
|
236
|
-
return await publicClient.getLogs({
|
|
307
|
+
): Promise<Log<bigint, number, false, undefined, true, typeof InboxAbi, 'MessageAdded'>[]> {
|
|
308
|
+
return publicClient.getLogs({
|
|
237
309
|
address: getAddress(inboxAddress.toString()),
|
|
238
|
-
event:
|
|
310
|
+
event: getAbiItem({
|
|
311
|
+
abi: InboxAbi,
|
|
312
|
+
name: 'MessageAdded',
|
|
313
|
+
}),
|
|
239
314
|
fromBlock,
|
|
240
315
|
toBlock: toBlock + 1n, // the toBlock argument in getLogs is exclusive
|
|
241
316
|
});
|
|
@@ -249,19 +324,18 @@ export async function getPendingL1ToL2MessageLogs(
|
|
|
249
324
|
* @param toBlock - Last block to get logs from (inclusive).
|
|
250
325
|
* @returns An array of `L1ToL2MessageCancelled` logs.
|
|
251
326
|
*/
|
|
252
|
-
export
|
|
327
|
+
export function getL1ToL2MessageCancelledLogs(
|
|
253
328
|
publicClient: PublicClient,
|
|
254
329
|
inboxAddress: EthAddress,
|
|
255
330
|
fromBlock: bigint,
|
|
256
331
|
toBlock: bigint,
|
|
257
|
-
): Promise<Log<bigint, number, undefined, true, typeof InboxAbi, 'L1ToL2MessageCancelled'>[]> {
|
|
258
|
-
|
|
259
|
-
abi: InboxAbi,
|
|
260
|
-
name: 'L1ToL2MessageCancelled',
|
|
261
|
-
});
|
|
262
|
-
return await publicClient.getLogs({
|
|
332
|
+
): Promise<Log<bigint, number, false, undefined, true, typeof InboxAbi, 'L1ToL2MessageCancelled'>[]> {
|
|
333
|
+
return publicClient.getLogs({
|
|
263
334
|
address: getAddress(inboxAddress.toString()),
|
|
264
|
-
event:
|
|
335
|
+
event: getAbiItem({
|
|
336
|
+
abi: InboxAbi,
|
|
337
|
+
name: 'L1ToL2MessageCancelled',
|
|
338
|
+
}),
|
|
265
339
|
fromBlock,
|
|
266
340
|
toBlock: toBlock + 1n, // the toBlock argument in getLogs is exclusive
|
|
267
341
|
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Body } from '@aztec/circuit-types';
|
|
2
|
+
import { AztecKVStore, AztecMap } from '@aztec/kv-store';
|
|
3
|
+
|
|
4
|
+
export class BlockBodyStore {
|
|
5
|
+
/** Map block body hash to block body */
|
|
6
|
+
#blockBodies: AztecMap<string, Buffer>;
|
|
7
|
+
|
|
8
|
+
constructor(private db: AztecKVStore) {
|
|
9
|
+
this.#blockBodies = db.openMap('archiver_block_bodies');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Append new block bodies to the store's map.
|
|
14
|
+
* @param blockBodies - The L2 block bodies to be added to the store.
|
|
15
|
+
* @returns True if the operation is successful.
|
|
16
|
+
*/
|
|
17
|
+
addBlockBodies(blockBodies: Body[]): Promise<boolean> {
|
|
18
|
+
return this.db.transaction(() => {
|
|
19
|
+
for (const body of blockBodies) {
|
|
20
|
+
void this.#blockBodies.set(body.getCalldataHash().toString('hex'), body.toBuffer());
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return true;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Gets a list of L2 block bodies with its associated txsHashes
|
|
29
|
+
* @param txsHashes - The txsHashes list that corresponds to the blockBodies we want to retrieve
|
|
30
|
+
* @returns The requested L2 block bodies
|
|
31
|
+
*/
|
|
32
|
+
async getBlockBodies(txsHashes: Buffer[]): Promise<Body[]> {
|
|
33
|
+
const blockBodiesBuffer = await this.db.transaction(() =>
|
|
34
|
+
txsHashes.map(txsHash => this.#blockBodies.get(txsHash.toString('hex'))),
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
if (blockBodiesBuffer.some(bodyBuffer => bodyBuffer === undefined)) {
|
|
38
|
+
throw new Error('Block body buffer is undefined');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return blockBodiesBuffer.map(blockBodyBuffer => Body.fromBuffer(blockBodyBuffer!));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Gets an L2 block body.
|
|
46
|
+
* @param txsHash - The txHash of the the block body to return
|
|
47
|
+
* @returns The requested L2 block body
|
|
48
|
+
*/
|
|
49
|
+
getBlockBody(txsHash: Buffer): Body | undefined {
|
|
50
|
+
const blockBody = this.#blockBodies.get(txsHash.toString('hex'));
|
|
51
|
+
|
|
52
|
+
return blockBody && Body.fromBuffer(blockBody);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { AztecAddress } from '@aztec/circuits.js';
|
|
1
|
+
import { L2Block, TxEffect, TxHash, TxReceipt, TxStatus } from '@aztec/circuit-types';
|
|
2
|
+
import { AppendOnlyTreeSnapshot, AztecAddress, Header, INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js';
|
|
3
3
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
4
4
|
import { AztecKVStore, AztecMap, Range } from '@aztec/kv-store';
|
|
5
5
|
|
|
6
|
+
import { BlockBodyStore } from './block_body_store.js';
|
|
7
|
+
|
|
6
8
|
type BlockIndexValue = [blockNumber: number, index: number];
|
|
7
9
|
|
|
8
|
-
type
|
|
9
|
-
blockNumber: number;
|
|
10
|
+
type BlockStorage = {
|
|
10
11
|
l1BlockNumber: bigint;
|
|
11
|
-
|
|
12
|
+
header: Buffer;
|
|
13
|
+
archive: Buffer;
|
|
12
14
|
};
|
|
13
15
|
|
|
14
16
|
/**
|
|
@@ -16,7 +18,7 @@ type BlockContext = {
|
|
|
16
18
|
*/
|
|
17
19
|
export class BlockStore {
|
|
18
20
|
/** Map block number to block data */
|
|
19
|
-
#blocks: AztecMap<number,
|
|
21
|
+
#blocks: AztecMap<number, BlockStorage>;
|
|
20
22
|
|
|
21
23
|
/** Index mapping transaction hash (as a string) to its location in a block */
|
|
22
24
|
#txIndex: AztecMap<string, BlockIndexValue>;
|
|
@@ -26,9 +28,12 @@ export class BlockStore {
|
|
|
26
28
|
|
|
27
29
|
#log = createDebugLogger('aztec:archiver:block_store');
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
#blockBodyStore: BlockBodyStore;
|
|
32
|
+
|
|
33
|
+
constructor(private db: AztecKVStore, blockBodyStore: BlockBodyStore) {
|
|
34
|
+
this.#blockBodyStore = blockBodyStore;
|
|
31
35
|
|
|
36
|
+
this.#blocks = db.openMap('archiver_blocks');
|
|
32
37
|
this.#txIndex = db.openMap('archiver_tx_index');
|
|
33
38
|
this.#contractIndex = db.openMap('archiver_contract_index');
|
|
34
39
|
}
|
|
@@ -42,25 +47,24 @@ export class BlockStore {
|
|
|
42
47
|
return this.db.transaction(() => {
|
|
43
48
|
for (const block of blocks) {
|
|
44
49
|
void this.#blocks.set(block.number, {
|
|
45
|
-
|
|
46
|
-
|
|
50
|
+
header: block.header.toBuffer(),
|
|
51
|
+
archive: block.archive.toBuffer(),
|
|
47
52
|
l1BlockNumber: block.getL1BlockNumber(),
|
|
48
53
|
});
|
|
49
54
|
|
|
50
|
-
|
|
51
|
-
if (tx.txHash.isZero()) {
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
55
|
+
block.getTxs().forEach((tx, i) => {
|
|
54
56
|
void this.#txIndex.set(tx.txHash.toString(), [block.number, i]);
|
|
55
|
-
}
|
|
57
|
+
});
|
|
56
58
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
block.body.txEffects
|
|
60
|
+
.flatMap(txEffect => txEffect.contractData)
|
|
61
|
+
.forEach((contractData, i) => {
|
|
62
|
+
if (contractData.contractAddress.isZero()) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
61
65
|
|
|
62
|
-
|
|
63
|
-
|
|
66
|
+
void this.#contractIndex.set(contractData.contractAddress.toString(), [block.number, i]);
|
|
67
|
+
});
|
|
64
68
|
}
|
|
65
69
|
|
|
66
70
|
return true;
|
|
@@ -71,35 +75,51 @@ export class BlockStore {
|
|
|
71
75
|
* Gets up to `limit` amount of L2 blocks starting from `from`.
|
|
72
76
|
* @param start - Number of the first block to return (inclusive).
|
|
73
77
|
* @param limit - The number of blocks to return.
|
|
74
|
-
* @returns The requested L2 blocks
|
|
78
|
+
* @returns The requested L2 blocks
|
|
75
79
|
*/
|
|
76
80
|
*getBlocks(start: number, limit: number): IterableIterator<L2Block> {
|
|
77
|
-
for (const
|
|
78
|
-
yield
|
|
81
|
+
for (const blockStorage of this.#blocks.values(this.#computeBlockRange(start, limit))) {
|
|
82
|
+
yield this.getBlockFromBlockStorage(blockStorage);
|
|
79
83
|
}
|
|
80
84
|
}
|
|
81
85
|
|
|
82
86
|
/**
|
|
83
87
|
* Gets an L2 block.
|
|
84
88
|
* @param blockNumber - The number of the block to return.
|
|
85
|
-
* @returns The requested L2 block
|
|
89
|
+
* @returns The requested L2 block.
|
|
86
90
|
*/
|
|
87
91
|
getBlock(blockNumber: number): L2Block | undefined {
|
|
88
|
-
const
|
|
89
|
-
if (!
|
|
92
|
+
const blockStorage = this.#blocks.get(blockNumber);
|
|
93
|
+
if (!blockStorage || !blockStorage.header) {
|
|
90
94
|
return undefined;
|
|
91
95
|
}
|
|
92
96
|
|
|
93
|
-
return
|
|
97
|
+
return this.getBlockFromBlockStorage(blockStorage);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private getBlockFromBlockStorage(blockStorage: BlockStorage) {
|
|
101
|
+
const header = Header.fromBuffer(blockStorage.header);
|
|
102
|
+
const archive = AppendOnlyTreeSnapshot.fromBuffer(blockStorage.archive);
|
|
103
|
+
const body = this.#blockBodyStore.getBlockBody(header.contentCommitment.txsHash);
|
|
104
|
+
|
|
105
|
+
if (body === undefined) {
|
|
106
|
+
throw new Error('Body is not able to be retrieved from BodyStore');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return L2Block.fromFields({
|
|
110
|
+
header,
|
|
111
|
+
archive,
|
|
112
|
+
body,
|
|
113
|
+
});
|
|
94
114
|
}
|
|
95
115
|
|
|
96
116
|
/**
|
|
97
|
-
* Gets
|
|
98
|
-
* @param txHash - The txHash of the
|
|
99
|
-
* @returns The requested
|
|
117
|
+
* Gets a tx effect.
|
|
118
|
+
* @param txHash - The txHash of the tx corresponding to the tx effect.
|
|
119
|
+
* @returns The requested tx effect (or undefined if not found).
|
|
100
120
|
*/
|
|
101
|
-
|
|
102
|
-
const [blockNumber, txIndex] = this.
|
|
121
|
+
getTxEffect(txHash: TxHash): TxEffect | undefined {
|
|
122
|
+
const [blockNumber, txIndex] = this.getTxLocation(txHash) ?? [];
|
|
103
123
|
if (typeof blockNumber !== 'number' || typeof txIndex !== 'number') {
|
|
104
124
|
return undefined;
|
|
105
125
|
}
|
|
@@ -109,11 +129,26 @@ export class BlockStore {
|
|
|
109
129
|
}
|
|
110
130
|
|
|
111
131
|
/**
|
|
112
|
-
*
|
|
113
|
-
* @param txHash - The
|
|
132
|
+
* Gets a receipt of a settled tx.
|
|
133
|
+
* @param txHash - The hash of a tx we try to get the receipt for.
|
|
134
|
+
* @returns The requested tx receipt (or undefined if not found).
|
|
135
|
+
*/
|
|
136
|
+
getSettledTxReceipt(txHash: TxHash): TxReceipt | undefined {
|
|
137
|
+
const [blockNumber, txIndex] = this.getTxLocation(txHash) ?? [];
|
|
138
|
+
if (typeof blockNumber !== 'number' || typeof txIndex !== 'number') {
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const block = this.getBlock(blockNumber)!;
|
|
143
|
+
return new TxReceipt(txHash, TxStatus.MINED, '', block.hash().toBuffer(), block.number);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Looks up which block included the requested tx effect.
|
|
148
|
+
* @param txHash - The txHash of the tx.
|
|
114
149
|
* @returns The block number and index of the tx.
|
|
115
150
|
*/
|
|
116
|
-
|
|
151
|
+
getTxLocation(txHash: TxHash): [blockNumber: number, txIndex: number] | undefined {
|
|
117
152
|
return this.#txIndex.get(txHash.toString());
|
|
118
153
|
}
|
|
119
154
|
|
|
@@ -21,6 +21,10 @@ export class ContractClassStore {
|
|
|
21
21
|
const contractClass = this.#contractClasses.get(id.toString());
|
|
22
22
|
return contractClass && { ...deserializeContractClassPublic(contractClass), id };
|
|
23
23
|
}
|
|
24
|
+
|
|
25
|
+
getContractClassIds(): Fr[] {
|
|
26
|
+
return Array.from(this.#contractClasses.keys()).map(key => Fr.fromString(key));
|
|
27
|
+
}
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
export function serializeContractClassPublic(contractClass: ContractClassPublic): Buffer {
|
|
@@ -77,7 +77,12 @@ export class ContractStore {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
const block = this.#blockStore.getBlock(blockNumber);
|
|
80
|
-
|
|
80
|
+
|
|
81
|
+
if (block?.body.txEffects[index].contractData.length !== 1) {
|
|
82
|
+
throw new Error(`Contract data at block: ${blockNumber}, tx: ${index} does not have length of 1`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return block?.body.txEffects[index].contractData[0];
|
|
81
86
|
}
|
|
82
87
|
|
|
83
88
|
/**
|
|
@@ -88,6 +93,6 @@ export class ContractStore {
|
|
|
88
93
|
*/
|
|
89
94
|
getContractDataInBlock(blockNumber: number): ContractData[] {
|
|
90
95
|
const block = this.#blockStore.getBlock(blockNumber);
|
|
91
|
-
return block?.
|
|
96
|
+
return block?.body.txEffects.flatMap(txEffect => txEffect.contractData) ?? [];
|
|
92
97
|
}
|
|
93
98
|
}
|