@aztec/archiver 0.23.0 → 0.26.1
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 +625 -0
- package/src/archiver/archiver_store.ts +226 -0
- package/src/archiver/archiver_store_test_suite.ts +676 -0
- package/src/archiver/config.ts +89 -0
- package/src/archiver/data_retrieval.ts +232 -0
- package/src/archiver/eth_log_handlers.ts +342 -0
- package/src/archiver/index.ts +5 -0
- package/src/archiver/kv_archiver_store/block_body_store.ts +54 -0
- package/src/archiver/kv_archiver_store/block_store.ts +199 -0
- package/src/archiver/kv_archiver_store/contract_class_store.ts +68 -0
- package/src/archiver/kv_archiver_store/contract_instance_store.ts +26 -0
- package/src/archiver/kv_archiver_store/contract_store.ts +98 -0
- package/src/archiver/kv_archiver_store/kv_archiver_store.ts +300 -0
- package/src/archiver/kv_archiver_store/log_store.ts +174 -0
- package/src/archiver/kv_archiver_store/message_store.ts +174 -0
- package/src/archiver/memory_archiver_store/l1_to_l2_message_store.ts +91 -0
- package/src/archiver/memory_archiver_store/memory_archiver_store.ts +506 -0
- package/src/index.ts +55 -0
- package/src/rpc/archiver_client.ts +35 -0
- package/src/rpc/archiver_server.ts +41 -0
- package/src/rpc/index.ts +2 -0
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
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
|
+
import { createDebugLogger } from '@aztec/foundation/log';
|
|
4
|
+
import { AztecKVStore, AztecMap, Range } from '@aztec/kv-store';
|
|
5
|
+
|
|
6
|
+
import { BlockBodyStore } from './block_body_store.js';
|
|
7
|
+
|
|
8
|
+
type BlockIndexValue = [blockNumber: number, index: number];
|
|
9
|
+
|
|
10
|
+
type BlockStorage = {
|
|
11
|
+
l1BlockNumber: bigint;
|
|
12
|
+
header: Buffer;
|
|
13
|
+
archive: Buffer;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* LMDB implementation of the ArchiverDataStore interface.
|
|
18
|
+
*/
|
|
19
|
+
export class BlockStore {
|
|
20
|
+
/** Map block number to block data */
|
|
21
|
+
#blocks: AztecMap<number, BlockStorage>;
|
|
22
|
+
|
|
23
|
+
/** Index mapping transaction hash (as a string) to its location in a block */
|
|
24
|
+
#txIndex: AztecMap<string, BlockIndexValue>;
|
|
25
|
+
|
|
26
|
+
/** Index mapping a contract's address (as a string) to its location in a block */
|
|
27
|
+
#contractIndex: AztecMap<string, BlockIndexValue>;
|
|
28
|
+
|
|
29
|
+
#log = createDebugLogger('aztec:archiver:block_store');
|
|
30
|
+
|
|
31
|
+
#blockBodyStore: BlockBodyStore;
|
|
32
|
+
|
|
33
|
+
constructor(private db: AztecKVStore, blockBodyStore: BlockBodyStore) {
|
|
34
|
+
this.#blockBodyStore = blockBodyStore;
|
|
35
|
+
|
|
36
|
+
this.#blocks = db.openMap('archiver_blocks');
|
|
37
|
+
this.#txIndex = db.openMap('archiver_tx_index');
|
|
38
|
+
this.#contractIndex = db.openMap('archiver_contract_index');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Append new blocks to the store's list.
|
|
43
|
+
* @param blocks - The L2 blocks to be added to the store.
|
|
44
|
+
* @returns True if the operation is successful.
|
|
45
|
+
*/
|
|
46
|
+
addBlocks(blocks: L2Block[]): Promise<boolean> {
|
|
47
|
+
return this.db.transaction(() => {
|
|
48
|
+
for (const block of blocks) {
|
|
49
|
+
void this.#blocks.set(block.number, {
|
|
50
|
+
header: block.header.toBuffer(),
|
|
51
|
+
archive: block.archive.toBuffer(),
|
|
52
|
+
l1BlockNumber: block.getL1BlockNumber(),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
block.getTxs().forEach((tx, i) => {
|
|
56
|
+
void this.#txIndex.set(tx.txHash.toString(), [block.number, i]);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
block.body.txEffects
|
|
60
|
+
.flatMap(txEffect => txEffect.contractData)
|
|
61
|
+
.forEach((contractData, i) => {
|
|
62
|
+
if (contractData.contractAddress.isZero()) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
void this.#contractIndex.set(contractData.contractAddress.toString(), [block.number, i]);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return true;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Gets up to `limit` amount of L2 blocks starting from `from`.
|
|
76
|
+
* @param start - Number of the first block to return (inclusive).
|
|
77
|
+
* @param limit - The number of blocks to return.
|
|
78
|
+
* @returns The requested L2 blocks
|
|
79
|
+
*/
|
|
80
|
+
*getBlocks(start: number, limit: number): IterableIterator<L2Block> {
|
|
81
|
+
for (const blockStorage of this.#blocks.values(this.#computeBlockRange(start, limit))) {
|
|
82
|
+
yield this.getBlockFromBlockStorage(blockStorage);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Gets an L2 block.
|
|
88
|
+
* @param blockNumber - The number of the block to return.
|
|
89
|
+
* @returns The requested L2 block.
|
|
90
|
+
*/
|
|
91
|
+
getBlock(blockNumber: number): L2Block | undefined {
|
|
92
|
+
const blockStorage = this.#blocks.get(blockNumber);
|
|
93
|
+
if (!blockStorage || !blockStorage.header) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
|
|
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
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
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).
|
|
120
|
+
*/
|
|
121
|
+
getTxEffect(txHash: TxHash): TxEffect | undefined {
|
|
122
|
+
const [blockNumber, txIndex] = this.getTxLocation(txHash) ?? [];
|
|
123
|
+
if (typeof blockNumber !== 'number' || typeof txIndex !== 'number') {
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const block = this.getBlock(blockNumber);
|
|
128
|
+
return block?.getTx(txIndex);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
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.
|
|
149
|
+
* @returns The block number and index of the tx.
|
|
150
|
+
*/
|
|
151
|
+
getTxLocation(txHash: TxHash): [blockNumber: number, txIndex: number] | undefined {
|
|
152
|
+
return this.#txIndex.get(txHash.toString());
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Looks up which block deployed a particular contract.
|
|
157
|
+
* @param contractAddress - The address of the contract to look up.
|
|
158
|
+
* @returns The block number and index of the contract.
|
|
159
|
+
*/
|
|
160
|
+
getContractLocation(contractAddress: AztecAddress): [blockNumber: number, index: number] | undefined {
|
|
161
|
+
return this.#contractIndex.get(contractAddress.toString());
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Gets the number of the latest L2 block processed.
|
|
166
|
+
* @returns The number of the latest L2 block processed.
|
|
167
|
+
*/
|
|
168
|
+
getBlockNumber(): number {
|
|
169
|
+
const [lastBlockNumber] = this.#blocks.keys({ reverse: true, limit: 1 });
|
|
170
|
+
return typeof lastBlockNumber === 'number' ? lastBlockNumber : INITIAL_L2_BLOCK_NUM - 1;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Gets the most recent L1 block processed.
|
|
175
|
+
* @returns The L1 block that published the latest L2 block
|
|
176
|
+
*/
|
|
177
|
+
getL1BlockNumber(): bigint {
|
|
178
|
+
const [lastBlock] = this.#blocks.values({ reverse: true, limit: 1 });
|
|
179
|
+
if (!lastBlock) {
|
|
180
|
+
return 0n;
|
|
181
|
+
} else {
|
|
182
|
+
return lastBlock.l1BlockNumber;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
#computeBlockRange(start: number, limit: number): Required<Pick<Range<number>, 'start' | 'end'>> {
|
|
187
|
+
if (limit < 1) {
|
|
188
|
+
throw new Error(`Invalid limit: ${limit}`);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (start < INITIAL_L2_BLOCK_NUM) {
|
|
192
|
+
this.#log(`Clamping start block ${start} to ${INITIAL_L2_BLOCK_NUM}`);
|
|
193
|
+
start = INITIAL_L2_BLOCK_NUM;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const end = start + limit;
|
|
197
|
+
return { start, end };
|
|
198
|
+
}
|
|
199
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Fr, FunctionSelector } from '@aztec/circuits.js';
|
|
2
|
+
import { BufferReader, numToUInt8, serializeToBuffer } from '@aztec/foundation/serialize';
|
|
3
|
+
import { AztecKVStore, AztecMap } from '@aztec/kv-store';
|
|
4
|
+
import { ContractClassPublic } from '@aztec/types/contracts';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* LMDB implementation of the ArchiverDataStore interface.
|
|
8
|
+
*/
|
|
9
|
+
export class ContractClassStore {
|
|
10
|
+
#contractClasses: AztecMap<string, Buffer>;
|
|
11
|
+
|
|
12
|
+
constructor(db: AztecKVStore) {
|
|
13
|
+
this.#contractClasses = db.openMap('archiver_contract_classes');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
addContractClass(contractClass: ContractClassPublic): Promise<boolean> {
|
|
17
|
+
return this.#contractClasses.set(contractClass.id.toString(), serializeContractClassPublic(contractClass));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
getContractClass(id: Fr): ContractClassPublic | undefined {
|
|
21
|
+
const contractClass = this.#contractClasses.get(id.toString());
|
|
22
|
+
return contractClass && { ...deserializeContractClassPublic(contractClass), id };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
getContractClassIds(): Fr[] {
|
|
26
|
+
return Array.from(this.#contractClasses.keys()).map(key => Fr.fromString(key));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function serializeContractClassPublic(contractClass: ContractClassPublic): Buffer {
|
|
31
|
+
return serializeToBuffer(
|
|
32
|
+
numToUInt8(contractClass.version),
|
|
33
|
+
contractClass.artifactHash,
|
|
34
|
+
contractClass.privateFunctions?.length ?? 0,
|
|
35
|
+
contractClass.privateFunctions?.map(f => serializeToBuffer(f.selector, f.vkHash, f.isInternal)) ?? [],
|
|
36
|
+
contractClass.publicFunctions.length,
|
|
37
|
+
contractClass.publicFunctions?.map(f =>
|
|
38
|
+
serializeToBuffer(f.selector, f.bytecode.length, f.bytecode, f.isInternal),
|
|
39
|
+
) ?? [],
|
|
40
|
+
contractClass.packedBytecode.length,
|
|
41
|
+
contractClass.packedBytecode,
|
|
42
|
+
contractClass.privateFunctionsRoot,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function deserializeContractClassPublic(buffer: Buffer): Omit<ContractClassPublic, 'id'> {
|
|
47
|
+
const reader = BufferReader.asReader(buffer);
|
|
48
|
+
return {
|
|
49
|
+
version: reader.readUInt8() as 1,
|
|
50
|
+
artifactHash: reader.readObject(Fr),
|
|
51
|
+
privateFunctions: reader.readVector({
|
|
52
|
+
fromBuffer: reader => ({
|
|
53
|
+
selector: reader.readObject(FunctionSelector),
|
|
54
|
+
vkHash: reader.readObject(Fr),
|
|
55
|
+
isInternal: reader.readBoolean(),
|
|
56
|
+
}),
|
|
57
|
+
}),
|
|
58
|
+
publicFunctions: reader.readVector({
|
|
59
|
+
fromBuffer: reader => ({
|
|
60
|
+
selector: reader.readObject(FunctionSelector),
|
|
61
|
+
bytecode: reader.readBuffer(),
|
|
62
|
+
isInternal: reader.readBoolean(),
|
|
63
|
+
}),
|
|
64
|
+
}),
|
|
65
|
+
packedBytecode: reader.readBuffer(),
|
|
66
|
+
privateFunctionsRoot: reader.readObject(Fr),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { AztecAddress } from '@aztec/circuits.js';
|
|
2
|
+
import { AztecKVStore, AztecMap } from '@aztec/kv-store';
|
|
3
|
+
import { ContractInstanceWithAddress, SerializableContractInstance } from '@aztec/types/contracts';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* LMDB implementation of the ArchiverDataStore interface.
|
|
7
|
+
*/
|
|
8
|
+
export class ContractInstanceStore {
|
|
9
|
+
#contractInstances: AztecMap<string, Buffer>;
|
|
10
|
+
|
|
11
|
+
constructor(db: AztecKVStore) {
|
|
12
|
+
this.#contractInstances = db.openMap('archiver_contract_instances');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
addContractInstance(contractInstance: ContractInstanceWithAddress): Promise<boolean> {
|
|
16
|
+
return this.#contractInstances.set(
|
|
17
|
+
contractInstance.address.toString(),
|
|
18
|
+
new SerializableContractInstance(contractInstance).toBuffer(),
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getContractInstance(address: AztecAddress): ContractInstanceWithAddress | undefined {
|
|
23
|
+
const contractInstance = this.#contractInstances.get(address.toString());
|
|
24
|
+
return contractInstance && SerializableContractInstance.fromBuffer(contractInstance).withAddress(address);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { ContractData, ExtendedContractData } from '@aztec/circuit-types';
|
|
2
|
+
import { AztecAddress } from '@aztec/foundation/aztec-address';
|
|
3
|
+
import { createDebugLogger } from '@aztec/foundation/log';
|
|
4
|
+
import { AztecKVStore, AztecMap } from '@aztec/kv-store';
|
|
5
|
+
|
|
6
|
+
import { BlockStore } from './block_store.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* LMDB implementation of the ArchiverDataStore interface.
|
|
10
|
+
*/
|
|
11
|
+
export class ContractStore {
|
|
12
|
+
#blockStore: BlockStore;
|
|
13
|
+
#extendedContractData: AztecMap<number, Buffer[]>;
|
|
14
|
+
#log = createDebugLogger('aztec:archiver:contract_store');
|
|
15
|
+
|
|
16
|
+
constructor(private db: AztecKVStore, blockStore: BlockStore) {
|
|
17
|
+
this.#extendedContractData = db.openMap('archiver_extended_contract_data');
|
|
18
|
+
this.#blockStore = blockStore;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Add new extended contract data from an L2 block to the store's list.
|
|
23
|
+
* @param data - List of contracts' data to be added.
|
|
24
|
+
* @param blockNum - Number of the L2 block the contract data was deployed in.
|
|
25
|
+
* @returns True if the operation is successful.
|
|
26
|
+
*/
|
|
27
|
+
addExtendedContractData(data: ExtendedContractData[], blockNum: number): Promise<boolean> {
|
|
28
|
+
return this.#extendedContractData.swap(blockNum, (existingData = []) => {
|
|
29
|
+
existingData.push(...data.map(d => d.toBuffer()));
|
|
30
|
+
return existingData;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Get the extended contract data for this contract.
|
|
36
|
+
* @param contractAddress - The contract data address.
|
|
37
|
+
* @returns The extended contract data or undefined if not found.
|
|
38
|
+
*/
|
|
39
|
+
getExtendedContractData(contractAddress: AztecAddress): ExtendedContractData | undefined {
|
|
40
|
+
const [blockNumber, _] = this.#blockStore.getContractLocation(contractAddress) ?? [];
|
|
41
|
+
|
|
42
|
+
if (typeof blockNumber !== 'number') {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
for (const contract of this.#extendedContractData.get(blockNumber) ?? []) {
|
|
47
|
+
const extendedContractData = ExtendedContractData.fromBuffer(contract);
|
|
48
|
+
if (extendedContractData.contractData.contractAddress.equals(contractAddress)) {
|
|
49
|
+
return extendedContractData;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Lookup all extended contract data in an L2 block.
|
|
58
|
+
* @param blockNumber - The block number to get all contract data from.
|
|
59
|
+
* @returns All extended contract data in the block (if found).
|
|
60
|
+
*/
|
|
61
|
+
getExtendedContractDataInBlock(blockNumber: number): Array<ExtendedContractData> {
|
|
62
|
+
return (this.#extendedContractData.get(blockNumber) ?? []).map(contract =>
|
|
63
|
+
ExtendedContractData.fromBuffer(contract),
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Get basic info for an L2 contract.
|
|
69
|
+
* Contains contract address & the ethereum portal address.
|
|
70
|
+
* @param contractAddress - The contract data address.
|
|
71
|
+
* @returns ContractData with the portal address (if we didn't throw an error).
|
|
72
|
+
*/
|
|
73
|
+
getContractData(contractAddress: AztecAddress): ContractData | undefined {
|
|
74
|
+
const [blockNumber, index] = this.#blockStore.getContractLocation(contractAddress) ?? [];
|
|
75
|
+
if (typeof blockNumber !== 'number' || typeof index !== 'number') {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const block = this.#blockStore.getBlock(blockNumber);
|
|
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];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Get basic info for an all L2 contracts deployed in a block.
|
|
90
|
+
* Contains contract address & the ethereum portal address.
|
|
91
|
+
* @param blockNumber - Number of the L2 block where contracts were deployed.
|
|
92
|
+
* @returns ContractData with the portal address (if we didn't throw an error).
|
|
93
|
+
*/
|
|
94
|
+
getContractDataInBlock(blockNumber: number): ContractData[] {
|
|
95
|
+
const block = this.#blockStore.getBlock(blockNumber);
|
|
96
|
+
return block?.body.txEffects.flatMap(txEffect => txEffect.contractData) ?? [];
|
|
97
|
+
}
|
|
98
|
+
}
|