@aztec/archiver 0.80.0 → 0.81.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 +5 -9
- package/dest/archiver/archiver.d.ts.map +1 -1
- package/dest/archiver/archiver.js +36 -49
- package/dest/archiver/archiver_store.d.ts +5 -4
- 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 +104 -91
- package/dest/archiver/data_retrieval.d.ts +3 -4
- package/dest/archiver/data_retrieval.d.ts.map +1 -1
- package/dest/archiver/data_retrieval.js +8 -3
- package/dest/archiver/index.d.ts +1 -1
- package/dest/archiver/index.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/block_store.d.ts +6 -6
- package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/block_store.js +24 -21
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +4 -4
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.js +2 -3
- package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/log_store.js +9 -41
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts +4 -4
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +1 -1
- package/dest/archiver/memory_archiver_store/memory_archiver_store.js +25 -54
- package/dest/archiver/structs/published.d.ts +1 -10
- package/dest/archiver/structs/published.d.ts.map +1 -1
- package/dest/archiver/structs/published.js +1 -1
- package/dest/test/mock_l2_block_source.d.ts +9 -0
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +13 -0
- package/package.json +13 -13
- package/src/archiver/archiver.ts +44 -60
- package/src/archiver/archiver_store.ts +5 -4
- package/src/archiver/archiver_store_test_suite.ts +116 -93
- package/src/archiver/data_retrieval.ts +11 -10
- package/src/archiver/index.ts +1 -1
- package/src/archiver/kv_archiver_store/block_store.ts +28 -27
- package/src/archiver/kv_archiver_store/kv_archiver_store.ts +5 -6
- package/src/archiver/kv_archiver_store/log_store.ts +11 -59
- package/src/archiver/memory_archiver_store/memory_archiver_store.ts +35 -66
- package/src/archiver/structs/published.ts +1 -11
- package/src/test/mock_l2_block_source.ts +14 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
2
|
+
import { Signature } from '@aztec/foundation/eth-signature';
|
|
2
3
|
import { toArray } from '@aztec/foundation/iterable';
|
|
3
4
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
5
|
import type { AztecAsyncKVStore, AztecAsyncMap, AztecAsyncSingleton, Range } from '@aztec/kv-store';
|
|
@@ -7,9 +8,9 @@ import { Body, type InBlock, L2Block, L2BlockHash } from '@aztec/stdlib/block';
|
|
|
7
8
|
import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
|
|
8
9
|
import { BlockHeader, TxEffect, TxHash, TxReceipt } from '@aztec/stdlib/tx';
|
|
9
10
|
|
|
10
|
-
import type {
|
|
11
|
+
import type { L1PublishedData, PublishedL2Block } from '../structs/published.js';
|
|
11
12
|
|
|
12
|
-
export { type TxEffect, type TxHash
|
|
13
|
+
export { TxReceipt, type TxEffect, type TxHash } from '@aztec/stdlib/tx';
|
|
13
14
|
|
|
14
15
|
type BlockIndexValue = [blockNumber: number, index: number];
|
|
15
16
|
|
|
@@ -17,6 +18,7 @@ type BlockStorage = {
|
|
|
17
18
|
header: Buffer;
|
|
18
19
|
archive: Buffer;
|
|
19
20
|
l1: L1PublishedData;
|
|
21
|
+
signatures: Buffer[];
|
|
20
22
|
};
|
|
21
23
|
|
|
22
24
|
/**
|
|
@@ -61,25 +63,26 @@ export class BlockStore {
|
|
|
61
63
|
* @param blocks - The L2 blocks to be added to the store.
|
|
62
64
|
* @returns True if the operation is successful.
|
|
63
65
|
*/
|
|
64
|
-
async addBlocks(blocks:
|
|
66
|
+
async addBlocks(blocks: PublishedL2Block[]): Promise<boolean> {
|
|
65
67
|
if (blocks.length === 0) {
|
|
66
68
|
return true;
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
return await this.db.transactionAsync(async () => {
|
|
70
72
|
for (const block of blocks) {
|
|
71
|
-
await this.#blocks.set(block.
|
|
72
|
-
header: block.
|
|
73
|
-
archive: block.
|
|
73
|
+
await this.#blocks.set(block.block.number, {
|
|
74
|
+
header: block.block.header.toBuffer(),
|
|
75
|
+
archive: block.block.archive.toBuffer(),
|
|
74
76
|
l1: block.l1,
|
|
77
|
+
signatures: block.signatures.map(sig => sig.toBuffer()),
|
|
75
78
|
});
|
|
76
79
|
|
|
77
|
-
for (let i = 0; i < block.
|
|
78
|
-
const txEffect = block.
|
|
79
|
-
await this.#txIndex.set(txEffect.txHash.toString(), [block.
|
|
80
|
+
for (let i = 0; i < block.block.body.txEffects.length; i++) {
|
|
81
|
+
const txEffect = block.block.body.txEffects[i];
|
|
82
|
+
await this.#txIndex.set(txEffect.txHash.toString(), [block.block.number, i]);
|
|
80
83
|
}
|
|
81
84
|
|
|
82
|
-
await this.#blockBodies.set((await block.
|
|
85
|
+
await this.#blockBodies.set((await block.block.hash()).toString(), block.block.body.toBuffer());
|
|
83
86
|
}
|
|
84
87
|
|
|
85
88
|
await this.#lastSynchedL1Block.set(blocks[blocks.length - 1].l1.blockNumber);
|
|
@@ -109,9 +112,9 @@ export class BlockStore {
|
|
|
109
112
|
this.#log.warn(`Cannot remove block ${blockNumber} from the store since we don't have it`);
|
|
110
113
|
continue;
|
|
111
114
|
}
|
|
112
|
-
await this.#blocks.delete(block.
|
|
113
|
-
await Promise.all(block.
|
|
114
|
-
const blockHash = (await block.
|
|
115
|
+
await this.#blocks.delete(block.block.number);
|
|
116
|
+
await Promise.all(block.block.body.txEffects.map(tx => this.#txIndex.delete(tx.txHash.toString())));
|
|
117
|
+
const blockHash = (await block.block.hash()).toString();
|
|
115
118
|
await this.#blockBodies.delete(blockHash);
|
|
116
119
|
this.#log.debug(`Unwound block ${blockNumber} ${blockHash}`);
|
|
117
120
|
}
|
|
@@ -126,10 +129,9 @@ export class BlockStore {
|
|
|
126
129
|
* @param limit - The number of blocks to return.
|
|
127
130
|
* @returns The requested L2 blocks
|
|
128
131
|
*/
|
|
129
|
-
async *getBlocks(start: number, limit: number): AsyncIterableIterator<
|
|
132
|
+
async *getBlocks(start: number, limit: number): AsyncIterableIterator<PublishedL2Block> {
|
|
130
133
|
for await (const blockStorage of this.#blocks.valuesAsync(this.#computeBlockRange(start, limit))) {
|
|
131
|
-
|
|
132
|
-
yield block;
|
|
134
|
+
yield await this.getBlockFromBlockStorage(blockStorage);
|
|
133
135
|
}
|
|
134
136
|
}
|
|
135
137
|
|
|
@@ -138,12 +140,11 @@ export class BlockStore {
|
|
|
138
140
|
* @param blockNumber - The number of the block to return.
|
|
139
141
|
* @returns The requested L2 block.
|
|
140
142
|
*/
|
|
141
|
-
async getBlock(blockNumber: number): Promise<
|
|
143
|
+
async getBlock(blockNumber: number): Promise<PublishedL2Block | undefined> {
|
|
142
144
|
const blockStorage = await this.#blocks.getAsync(blockNumber);
|
|
143
145
|
if (!blockStorage || !blockStorage.header) {
|
|
144
146
|
return Promise.resolve(undefined);
|
|
145
147
|
}
|
|
146
|
-
|
|
147
148
|
return this.getBlockFromBlockStorage(blockStorage);
|
|
148
149
|
}
|
|
149
150
|
|
|
@@ -170,9 +171,9 @@ export class BlockStore {
|
|
|
170
171
|
);
|
|
171
172
|
}
|
|
172
173
|
const body = Body.fromBuffer(blockBodyBuffer);
|
|
173
|
-
|
|
174
|
-
const
|
|
175
|
-
return {
|
|
174
|
+
const block = new L2Block(archive, header, body);
|
|
175
|
+
const signatures = blockStorage.signatures.map(Signature.fromBuffer);
|
|
176
|
+
return { block, l1: blockStorage.l1, signatures };
|
|
176
177
|
}
|
|
177
178
|
|
|
178
179
|
/**
|
|
@@ -192,9 +193,9 @@ export class BlockStore {
|
|
|
192
193
|
}
|
|
193
194
|
|
|
194
195
|
return {
|
|
195
|
-
data: block.
|
|
196
|
-
l2BlockNumber: block.
|
|
197
|
-
l2BlockHash: (await block.
|
|
196
|
+
data: block.block.body.txEffects[txIndex],
|
|
197
|
+
l2BlockNumber: block.block.number,
|
|
198
|
+
l2BlockHash: (await block.block.hash()).toString(),
|
|
198
199
|
};
|
|
199
200
|
}
|
|
200
201
|
|
|
@@ -210,15 +211,15 @@ export class BlockStore {
|
|
|
210
211
|
}
|
|
211
212
|
|
|
212
213
|
const block = (await this.getBlock(blockNumber))!;
|
|
213
|
-
const tx = block.
|
|
214
|
+
const tx = block.block.body.txEffects[txIndex];
|
|
214
215
|
|
|
215
216
|
return new TxReceipt(
|
|
216
217
|
txHash,
|
|
217
218
|
TxReceipt.statusFromRevertCode(tx.revertCode),
|
|
218
219
|
'',
|
|
219
220
|
tx.transactionFee.toBigInt(),
|
|
220
|
-
L2BlockHash.fromField(await block.
|
|
221
|
-
block.
|
|
221
|
+
L2BlockHash.fromField(await block.block.hash()),
|
|
222
|
+
block.block.number,
|
|
222
223
|
);
|
|
223
224
|
}
|
|
224
225
|
|
|
@@ -19,7 +19,7 @@ import type { BlockHeader, TxHash, TxReceipt } from '@aztec/stdlib/tx';
|
|
|
19
19
|
|
|
20
20
|
import type { ArchiverDataStore, ArchiverL1SynchPoint } from '../archiver_store.js';
|
|
21
21
|
import type { DataRetrieval } from '../structs/data_retrieval.js';
|
|
22
|
-
import type {
|
|
22
|
+
import type { PublishedL2Block } from '../structs/published.js';
|
|
23
23
|
import { BlockStore } from './block_store.js';
|
|
24
24
|
import { ContractClassStore } from './contract_class_store.js';
|
|
25
25
|
import { ContractInstanceStore } from './contract_instance_store.js';
|
|
@@ -78,9 +78,8 @@ export class KVArchiverDataStore implements ArchiverDataStore {
|
|
|
78
78
|
return this.#contractClassStore.getContractClassIds();
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
return contract;
|
|
81
|
+
getContractInstance(address: AztecAddress, blockNumber: number): Promise<ContractInstanceWithAddress | undefined> {
|
|
82
|
+
return this.#contractInstanceStore.getContractInstance(address, blockNumber);
|
|
84
83
|
}
|
|
85
84
|
|
|
86
85
|
async addContractClasses(
|
|
@@ -148,7 +147,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
|
|
|
148
147
|
* @param blocks - The L2 blocks to be added to the store and the last processed L1 block.
|
|
149
148
|
* @returns True if the operation is successful.
|
|
150
149
|
*/
|
|
151
|
-
addBlocks(blocks:
|
|
150
|
+
addBlocks(blocks: PublishedL2Block[]): Promise<boolean> {
|
|
152
151
|
return this.#blockStore.addBlocks(blocks);
|
|
153
152
|
}
|
|
154
153
|
|
|
@@ -170,7 +169,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
|
|
|
170
169
|
* @param limit - The number of blocks to return.
|
|
171
170
|
* @returns The requested L2 blocks
|
|
172
171
|
*/
|
|
173
|
-
getBlocks(start: number, limit: number): Promise<
|
|
172
|
+
getBlocks(start: number, limit: number): Promise<PublishedL2Block[]> {
|
|
174
173
|
return toArray(this.#blockStore.getBlocks(start, limit));
|
|
175
174
|
}
|
|
176
175
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX
|
|
1
|
+
import { INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX } from '@aztec/constants';
|
|
2
2
|
import type { Fr } from '@aztec/foundation/fields';
|
|
3
3
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
4
|
import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize';
|
|
@@ -40,7 +40,7 @@ export class LogStore {
|
|
|
40
40
|
this.#logsMaxPageSize = logsMaxPageSize;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
#
|
|
43
|
+
#extractTaggedLogs(block: L2Block) {
|
|
44
44
|
const taggedLogs = new Map<string, Buffer[]>();
|
|
45
45
|
const dataStartIndexForBlock =
|
|
46
46
|
block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
|
|
@@ -48,68 +48,22 @@ export class LogStore {
|
|
|
48
48
|
block.body.txEffects.forEach((txEffect, txIndex) => {
|
|
49
49
|
const txHash = txEffect.txHash;
|
|
50
50
|
const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
|
|
51
|
+
|
|
51
52
|
txEffect.privateLogs.forEach(log => {
|
|
52
53
|
const tag = log.fields[0];
|
|
54
|
+
this.#log.debug(`Found private log with tag ${tag.toString()} in block ${block.number}`);
|
|
55
|
+
|
|
53
56
|
const currentLogs = taggedLogs.get(tag.toString()) ?? [];
|
|
54
|
-
currentLogs.push(
|
|
55
|
-
new TxScopedL2Log(
|
|
56
|
-
txHash,
|
|
57
|
-
dataStartIndexForTx,
|
|
58
|
-
block.number,
|
|
59
|
-
/* isFromPublic */ false,
|
|
60
|
-
log.toBuffer(),
|
|
61
|
-
).toBuffer(),
|
|
62
|
-
);
|
|
57
|
+
currentLogs.push(new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, log).toBuffer());
|
|
63
58
|
taggedLogs.set(tag.toString(), currentLogs);
|
|
64
59
|
});
|
|
65
|
-
});
|
|
66
|
-
return taggedLogs;
|
|
67
|
-
}
|
|
68
60
|
|
|
69
|
-
#extractTaggedLogsFromPublic(block: L2Block) {
|
|
70
|
-
const taggedLogs = new Map<string, Buffer[]>();
|
|
71
|
-
const dataStartIndexForBlock =
|
|
72
|
-
block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
|
|
73
|
-
block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX;
|
|
74
|
-
block.body.txEffects.forEach((txEffect, txIndex) => {
|
|
75
|
-
const txHash = txEffect.txHash;
|
|
76
|
-
const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
|
|
77
61
|
txEffect.publicLogs.forEach(log => {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
// See macros/note/mod/ and see how finalization_log[0] is constructed, to understand this monstrosity. (It wasn't me).
|
|
81
|
-
// Search the codebase for "disgusting encoding" to see other hardcoded instances of this encoding, that you might need to change if you ever find yourself here.
|
|
82
|
-
if (!firstFieldBuf.subarray(0, 27).equals(Buffer.alloc(27)) || firstFieldBuf[29] !== 0) {
|
|
83
|
-
// See parseLogFromPublic - the first field of a tagged log is 5 bytes structured:
|
|
84
|
-
// [ publicLen[0], publicLen[1], 0, privateLen[0], privateLen[1]]
|
|
85
|
-
this.#log.warn(`Skipping public log with invalid first field: ${log.log[0]}`);
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
// Check that the length values line up with the log contents
|
|
89
|
-
const publicValuesLength = firstFieldBuf.subarray(-5).readUint16BE();
|
|
90
|
-
const privateValuesLength = firstFieldBuf.subarray(-5).readUint16BE(3);
|
|
91
|
-
// Add 1 for the first field holding lengths
|
|
92
|
-
const totalLogLength = 1 + publicValuesLength + privateValuesLength;
|
|
93
|
-
// Note that zeroes can be valid log values, so we can only assert that we do not go over the given length
|
|
94
|
-
if (totalLogLength > PUBLIC_LOG_DATA_SIZE_IN_FIELDS || log.log.slice(totalLogLength).find(f => !f.isZero())) {
|
|
95
|
-
this.#log.warn(`Skipping invalid tagged public log with first field: ${log.log[0]}`);
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// The first elt stores lengths as above => tag is in fields[1]
|
|
100
|
-
const tag = log.log[1];
|
|
62
|
+
const tag = log.log[0];
|
|
63
|
+
this.#log.debug(`Found public log with tag ${tag.toString()} in block ${block.number}`);
|
|
101
64
|
|
|
102
|
-
this.#log.debug(`Found tagged public log with tag ${tag.toString()} in block ${block.number}`);
|
|
103
65
|
const currentLogs = taggedLogs.get(tag.toString()) ?? [];
|
|
104
|
-
currentLogs.push(
|
|
105
|
-
new TxScopedL2Log(
|
|
106
|
-
txHash,
|
|
107
|
-
dataStartIndexForTx,
|
|
108
|
-
block.number,
|
|
109
|
-
/* isFromPublic */ true,
|
|
110
|
-
log.toBuffer(),
|
|
111
|
-
).toBuffer(),
|
|
112
|
-
);
|
|
66
|
+
currentLogs.push(new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, log).toBuffer());
|
|
113
67
|
taggedLogs.set(tag.toString(), currentLogs);
|
|
114
68
|
});
|
|
115
69
|
});
|
|
@@ -123,7 +77,7 @@ export class LogStore {
|
|
|
123
77
|
*/
|
|
124
78
|
addLogs(blocks: L2Block[]): Promise<boolean> {
|
|
125
79
|
const taggedLogsToAdd = blocks
|
|
126
|
-
.
|
|
80
|
+
.map(block => this.#extractTaggedLogs(block))
|
|
127
81
|
.reduce((acc, val) => {
|
|
128
82
|
for (const [tag, logs] of val.entries()) {
|
|
129
83
|
const currentLogs = acc.get(tag) ?? [];
|
|
@@ -238,9 +192,7 @@ export class LogStore {
|
|
|
238
192
|
*/
|
|
239
193
|
async getLogsByTags(tags: Fr[]): Promise<TxScopedL2Log[][]> {
|
|
240
194
|
const logs = await Promise.all(tags.map(tag => this.#logsByTag.getAsync(tag.toString())));
|
|
241
|
-
return logs.map(
|
|
242
|
-
noteLogBuffers => noteLogBuffers?.map(noteLogBuffer => TxScopedL2Log.fromBuffer(noteLogBuffer)) ?? [],
|
|
243
|
-
);
|
|
195
|
+
return logs.map(logBuffers => logBuffers?.map(logBuffer => TxScopedL2Log.fromBuffer(logBuffer)) ?? []);
|
|
244
196
|
}
|
|
245
197
|
|
|
246
198
|
/**
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
INITIAL_L2_BLOCK_NUM,
|
|
3
|
-
MAX_NOTE_HASHES_PER_TX,
|
|
4
|
-
MAX_NULLIFIERS_PER_TX,
|
|
5
|
-
PUBLIC_LOG_DATA_SIZE_IN_FIELDS,
|
|
6
|
-
} from '@aztec/constants';
|
|
1
|
+
import { INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX } from '@aztec/constants';
|
|
7
2
|
import { Fr } from '@aztec/foundation/fields';
|
|
8
3
|
import { createLogger } from '@aztec/foundation/log';
|
|
9
4
|
import { FunctionSelector } from '@aztec/stdlib/abi';
|
|
@@ -33,7 +28,7 @@ import { type BlockHeader, TxEffect, TxHash, TxReceipt } from '@aztec/stdlib/tx'
|
|
|
33
28
|
|
|
34
29
|
import type { ArchiverDataStore, ArchiverL1SynchPoint } from '../archiver_store.js';
|
|
35
30
|
import type { DataRetrieval } from '../structs/data_retrieval.js';
|
|
36
|
-
import type {
|
|
31
|
+
import type { PublishedL2Block } from '../structs/published.js';
|
|
37
32
|
import { L1ToL2MessageStore } from './l1_to_l2_message_store.js';
|
|
38
33
|
|
|
39
34
|
type StoredContractInstanceUpdate = ContractInstanceUpdateWithAddress & { blockNumber: number; logIndex: number };
|
|
@@ -45,7 +40,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
45
40
|
/**
|
|
46
41
|
* An array containing all the L2 blocks that have been fetched so far.
|
|
47
42
|
*/
|
|
48
|
-
private l2Blocks:
|
|
43
|
+
private l2Blocks: PublishedL2Block[] = [];
|
|
49
44
|
|
|
50
45
|
/**
|
|
51
46
|
* An array containing all the tx effects in the L2 blocks that have been fetched so far.
|
|
@@ -112,7 +107,10 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
112
107
|
return Promise.resolve(Array.from(this.contractClasses.keys()).map(key => Fr.fromHexString(key)));
|
|
113
108
|
}
|
|
114
109
|
|
|
115
|
-
public getContractInstance(
|
|
110
|
+
public getContractInstance(
|
|
111
|
+
address: AztecAddress,
|
|
112
|
+
blockNumber: number,
|
|
113
|
+
): Promise<ContractInstanceWithAddress | undefined> {
|
|
116
114
|
const instance = this.contractInstances.get(address.toString());
|
|
117
115
|
if (!instance) {
|
|
118
116
|
return Promise.resolve(undefined);
|
|
@@ -120,8 +118,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
120
118
|
const updates = this.contractInstanceUpdates.get(address.toString()) || [];
|
|
121
119
|
if (updates.length > 0) {
|
|
122
120
|
const lastUpdate = updates[0];
|
|
123
|
-
|
|
124
|
-
if (currentBlockNumber >= lastUpdate.blockOfChange) {
|
|
121
|
+
if (blockNumber >= lastUpdate.blockOfChange) {
|
|
125
122
|
instance.currentContractClassId = lastUpdate.newContractClassId;
|
|
126
123
|
} else if (!lastUpdate.prevContractClassId.isZero()) {
|
|
127
124
|
instance.currentContractClassId = lastUpdate.prevContractClassId;
|
|
@@ -235,16 +232,16 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
235
232
|
* @param blocks - The L2 blocks to be added to the store and the last processed L1 block.
|
|
236
233
|
* @returns True if the operation is successful.
|
|
237
234
|
*/
|
|
238
|
-
public async addBlocks(blocks:
|
|
235
|
+
public async addBlocks(blocks: PublishedL2Block[]): Promise<boolean> {
|
|
239
236
|
if (blocks.length === 0) {
|
|
240
237
|
return Promise.resolve(true);
|
|
241
238
|
}
|
|
242
239
|
|
|
243
240
|
this.lastL1BlockNewBlocks = blocks[blocks.length - 1].l1.blockNumber;
|
|
244
241
|
this.l2Blocks.push(...blocks);
|
|
245
|
-
const flatTxEffects = blocks.flatMap(b => b.
|
|
242
|
+
const flatTxEffects = blocks.flatMap(b => b.block.body.txEffects.map(txEffect => ({ block: b, txEffect })));
|
|
246
243
|
const wrappedTxEffects = await Promise.all(
|
|
247
|
-
flatTxEffects.map(flatTxEffect => wrapInBlock(flatTxEffect.txEffect, flatTxEffect.block.
|
|
244
|
+
flatTxEffects.map(flatTxEffect => wrapInBlock(flatTxEffect.txEffect, flatTxEffect.block.block)),
|
|
248
245
|
);
|
|
249
246
|
this.txEffects.push(...wrappedTxEffects);
|
|
250
247
|
|
|
@@ -270,68 +267,41 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
270
267
|
if (block == undefined) {
|
|
271
268
|
break;
|
|
272
269
|
}
|
|
273
|
-
block.
|
|
270
|
+
block.block.body.txEffects.forEach(() => this.txEffects.pop());
|
|
274
271
|
}
|
|
275
272
|
|
|
276
273
|
return Promise.resolve(true);
|
|
277
274
|
}
|
|
278
275
|
|
|
279
|
-
#
|
|
276
|
+
#storeTaggedLogs(block: L2Block): void {
|
|
280
277
|
const dataStartIndexForBlock =
|
|
281
278
|
block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
|
|
282
279
|
block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX;
|
|
283
280
|
block.body.txEffects.forEach((txEffect, txIndex) => {
|
|
284
281
|
const txHash = txEffect.txHash;
|
|
285
282
|
const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
|
|
283
|
+
|
|
286
284
|
txEffect.privateLogs.forEach(log => {
|
|
287
285
|
const tag = log.fields[0];
|
|
286
|
+
this.#log.verbose(`Storing private log with tag ${tag.toString()} from block ${block.number}`);
|
|
287
|
+
|
|
288
288
|
const currentLogs = this.taggedLogs.get(tag.toString()) || [];
|
|
289
289
|
this.taggedLogs.set(tag.toString(), [
|
|
290
290
|
...currentLogs,
|
|
291
|
-
new TxScopedL2Log(txHash, dataStartIndexForTx, block.number,
|
|
291
|
+
new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, log),
|
|
292
292
|
]);
|
|
293
293
|
const currentTagsInBlock = this.logTagsPerBlock.get(block.number) || [];
|
|
294
294
|
this.logTagsPerBlock.set(block.number, [...currentTagsInBlock, tag]);
|
|
295
295
|
});
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
296
|
|
|
299
|
-
#storeTaggedLogsFromPublic(block: L2Block): void {
|
|
300
|
-
const dataStartIndexForBlock =
|
|
301
|
-
block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
|
|
302
|
-
block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX;
|
|
303
|
-
block.body.txEffects.forEach((txEffect, txIndex) => {
|
|
304
|
-
const txHash = txEffect.txHash;
|
|
305
|
-
const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
|
|
306
297
|
txEffect.publicLogs.forEach(log => {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
// Search the codebase for "disgusting encoding" to see other hardcoded instances of this encoding, that you might need to change if you ever find yourself here.
|
|
310
|
-
const firstFieldBuf = log.log[0].toBuffer();
|
|
311
|
-
if (!firstFieldBuf.subarray(0, 27).equals(Buffer.alloc(27)) || firstFieldBuf[29] !== 0) {
|
|
312
|
-
// See parseLogFromPublic - the first field of a tagged log is 8 bytes structured:
|
|
313
|
-
// [ publicLen[0], publicLen[1], 0, privateLen[0], privateLen[1]]
|
|
314
|
-
this.#log.warn(`Skipping public log with invalid first field: ${log.log[0]}`);
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
// Check that the length values line up with the log contents
|
|
318
|
-
const publicValuesLength = firstFieldBuf.subarray(-5).readUint16BE();
|
|
319
|
-
const privateValuesLength = firstFieldBuf.subarray(-5).readUint16BE(3);
|
|
320
|
-
// Add 1 for the first field holding lengths
|
|
321
|
-
const totalLogLength = 1 + publicValuesLength + privateValuesLength;
|
|
322
|
-
// Note that zeroes can be valid log values, so we can only assert that we do not go over the given length
|
|
323
|
-
if (totalLogLength > PUBLIC_LOG_DATA_SIZE_IN_FIELDS || log.log.slice(totalLogLength).find(f => !f.isZero())) {
|
|
324
|
-
this.#log.warn(`Skipping invalid tagged public log with first field: ${log.log[0]}`);
|
|
325
|
-
return;
|
|
326
|
-
}
|
|
298
|
+
const tag = log.log[0];
|
|
299
|
+
this.#log.verbose(`Storing public log with tag ${tag.toString()} from block ${block.number}`);
|
|
327
300
|
|
|
328
|
-
// The first elt stores lengths => tag is in fields[1]
|
|
329
|
-
const tag = log.log[1];
|
|
330
|
-
this.#log.verbose(`Storing public tagged log with tag ${tag.toString()} in block ${block.number}`);
|
|
331
301
|
const currentLogs = this.taggedLogs.get(tag.toString()) || [];
|
|
332
302
|
this.taggedLogs.set(tag.toString(), [
|
|
333
303
|
...currentLogs,
|
|
334
|
-
new TxScopedL2Log(txHash, dataStartIndexForTx, block.number,
|
|
304
|
+
new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, log),
|
|
335
305
|
]);
|
|
336
306
|
const currentTagsInBlock = this.logTagsPerBlock.get(block.number) || [];
|
|
337
307
|
this.logTagsPerBlock.set(block.number, [...currentTagsInBlock, tag]);
|
|
@@ -346,8 +316,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
346
316
|
*/
|
|
347
317
|
addLogs(blocks: L2Block[]): Promise<boolean> {
|
|
348
318
|
blocks.forEach(block => {
|
|
349
|
-
this.#
|
|
350
|
-
this.#storeTaggedLogsFromPublic(block);
|
|
319
|
+
this.#storeTaggedLogs(block);
|
|
351
320
|
this.privateLogsPerBlock.set(block.number, block.body.txEffects.map(txEffect => txEffect.privateLogs).flat());
|
|
352
321
|
this.publicLogsPerBlock.set(block.number, block.body.txEffects.map(txEffect => txEffect.publicLogs).flat());
|
|
353
322
|
this.contractClassLogsPerBlock.set(
|
|
@@ -464,7 +433,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
464
433
|
* @returns The requested L2 blocks.
|
|
465
434
|
* @remarks When "from" is smaller than genesis block number, blocks from the beginning are returned.
|
|
466
435
|
*/
|
|
467
|
-
public getBlocks(from: number, limit: number): Promise<
|
|
436
|
+
public getBlocks(from: number, limit: number): Promise<PublishedL2Block[]> {
|
|
468
437
|
if (limit < 1) {
|
|
469
438
|
return Promise.reject(new Error(`Invalid limit: ${limit}`));
|
|
470
439
|
}
|
|
@@ -484,7 +453,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
484
453
|
|
|
485
454
|
public async getBlockHeaders(from: number, limit: number): Promise<BlockHeader[]> {
|
|
486
455
|
const blocks = await this.getBlocks(from, limit);
|
|
487
|
-
return blocks.map(block => block.
|
|
456
|
+
return blocks.map(block => block.block.header);
|
|
488
457
|
}
|
|
489
458
|
|
|
490
459
|
/**
|
|
@@ -504,15 +473,15 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
504
473
|
*/
|
|
505
474
|
public async getSettledTxReceipt(txHash: TxHash): Promise<TxReceipt | undefined> {
|
|
506
475
|
for (const block of this.l2Blocks) {
|
|
507
|
-
for (const txEffect of block.
|
|
476
|
+
for (const txEffect of block.block.body.txEffects) {
|
|
508
477
|
if (txEffect.txHash.equals(txHash)) {
|
|
509
478
|
return new TxReceipt(
|
|
510
479
|
txHash,
|
|
511
480
|
TxReceipt.statusFromRevertCode(txEffect.revertCode),
|
|
512
481
|
'',
|
|
513
482
|
txEffect.transactionFee.toBigInt(),
|
|
514
|
-
L2BlockHash.fromField(await block.
|
|
515
|
-
block.
|
|
483
|
+
L2BlockHash.fromField(await block.block.hash()),
|
|
484
|
+
block.block.number,
|
|
516
485
|
);
|
|
517
486
|
}
|
|
518
487
|
}
|
|
@@ -566,8 +535,8 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
566
535
|
* that tag.
|
|
567
536
|
*/
|
|
568
537
|
getLogsByTags(tags: Fr[]): Promise<TxScopedL2Log[][]> {
|
|
569
|
-
const
|
|
570
|
-
return Promise.resolve(
|
|
538
|
+
const logs = tags.map(tag => this.taggedLogs.get(tag.toString()) || []);
|
|
539
|
+
return Promise.resolve(logs);
|
|
571
540
|
}
|
|
572
541
|
|
|
573
542
|
/**
|
|
@@ -626,8 +595,8 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
626
595
|
if (blockLogs) {
|
|
627
596
|
for (let logIndex = 0; logIndex < blockLogs.length; logIndex++) {
|
|
628
597
|
const log = blockLogs[logIndex];
|
|
629
|
-
const thisTxEffect = block.
|
|
630
|
-
const thisTxIndexInBlock = block.
|
|
598
|
+
const thisTxEffect = block.block.body.txEffects.filter(effect => effect.publicLogs.includes(log))[0];
|
|
599
|
+
const thisTxIndexInBlock = block.block.body.txEffects.indexOf(thisTxEffect);
|
|
631
600
|
const thisLogIndexInTx = thisTxEffect.publicLogs.indexOf(log);
|
|
632
601
|
if (
|
|
633
602
|
(!txHash || thisTxEffect.txHash.equals(txHash)) &&
|
|
@@ -635,7 +604,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
635
604
|
thisTxIndexInBlock >= txIndexInBlock &&
|
|
636
605
|
thisLogIndexInTx >= logIndexInTx
|
|
637
606
|
) {
|
|
638
|
-
logs.push(new ExtendedPublicLog(new LogId(block.
|
|
607
|
+
logs.push(new ExtendedPublicLog(new LogId(block.block.number, thisTxIndexInBlock, thisLogIndexInTx), log));
|
|
639
608
|
if (logs.length === this.maxLogs) {
|
|
640
609
|
return Promise.resolve({
|
|
641
610
|
logs,
|
|
@@ -710,8 +679,8 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
710
679
|
if (blockLogs) {
|
|
711
680
|
for (let logIndex = 0; logIndex < blockLogs.length; logIndex++) {
|
|
712
681
|
const log = blockLogs[logIndex];
|
|
713
|
-
const thisTxEffect = block.
|
|
714
|
-
const thisTxIndexInBlock = block.
|
|
682
|
+
const thisTxEffect = block.block.body.txEffects.filter(effect => effect.contractClassLogs.includes(log))[0];
|
|
683
|
+
const thisTxIndexInBlock = block.block.body.txEffects.indexOf(thisTxEffect);
|
|
715
684
|
const thisLogIndexInTx = thisTxEffect.contractClassLogs.indexOf(log);
|
|
716
685
|
if (
|
|
717
686
|
(!txHash || thisTxEffect.txHash.equals(txHash)) &&
|
|
@@ -720,7 +689,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
720
689
|
thisLogIndexInTx >= logIndexInTx
|
|
721
690
|
) {
|
|
722
691
|
logs.push(
|
|
723
|
-
new ExtendedContractClassLog(new LogId(block.
|
|
692
|
+
new ExtendedContractClassLog(new LogId(block.block.number, thisTxIndexInBlock, thisLogIndexInTx), log),
|
|
724
693
|
);
|
|
725
694
|
if (logs.length === this.maxLogs) {
|
|
726
695
|
return Promise.resolve({
|
|
@@ -743,7 +712,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
743
712
|
if (this.l2Blocks.length === 0) {
|
|
744
713
|
return INITIAL_L2_BLOCK_NUM - 1;
|
|
745
714
|
}
|
|
746
|
-
return this.l2Blocks[this.l2Blocks.length - 1].
|
|
715
|
+
return this.l2Blocks[this.l2Blocks.length - 1].block.number;
|
|
747
716
|
}
|
|
748
717
|
|
|
749
718
|
/**
|
|
@@ -1,11 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export type L1Published<T> = {
|
|
3
|
-
data: T;
|
|
4
|
-
l1: L1PublishedData;
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
export type L1PublishedData = {
|
|
8
|
-
blockNumber: bigint;
|
|
9
|
-
timestamp: bigint;
|
|
10
|
-
blockHash: string;
|
|
11
|
-
};
|
|
1
|
+
export type { PublishedL2Block, L1PublishedData } from '@aztec/stdlib/block';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DefaultL1ContractsConfig } from '@aztec/ethereum';
|
|
2
|
+
import { Buffer32 } from '@aztec/foundation/buffer';
|
|
2
3
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
4
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
5
|
import { L2Block, L2BlockHash, type L2BlockSource, type L2Tips } from '@aztec/stdlib/block';
|
|
@@ -90,6 +91,19 @@ export class MockL2BlockSource implements L2BlockSource {
|
|
|
90
91
|
);
|
|
91
92
|
}
|
|
92
93
|
|
|
94
|
+
public async getPublishedBlocks(from: number, limit: number, proven?: boolean) {
|
|
95
|
+
const blocks = await this.getBlocks(from, limit, proven);
|
|
96
|
+
return blocks.map(block => ({
|
|
97
|
+
block,
|
|
98
|
+
l1: {
|
|
99
|
+
blockNumber: BigInt(block.number),
|
|
100
|
+
blockHash: Buffer32.random().toString(),
|
|
101
|
+
timestamp: BigInt(block.number),
|
|
102
|
+
},
|
|
103
|
+
signatures: [],
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
|
|
93
107
|
getBlockHeader(number: number | 'latest'): Promise<BlockHeader | undefined> {
|
|
94
108
|
return Promise.resolve(this.l2Blocks.at(typeof number === 'number' ? number - 1 : -1)?.header);
|
|
95
109
|
}
|