@aztec/archiver 0.0.1-commit.96dac018d → 0.0.1-commit.993d240
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/README.md +19 -11
- package/dest/archiver.d.ts +36 -17
- package/dest/archiver.d.ts.map +1 -1
- package/dest/archiver.js +257 -75
- package/dest/config.d.ts +6 -3
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +23 -15
- package/dest/errors.d.ts +55 -9
- package/dest/errors.d.ts.map +1 -1
- package/dest/errors.js +81 -14
- package/dest/factory.d.ts +13 -9
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +47 -35
- package/dest/index.d.ts +11 -3
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +10 -2
- package/dest/l1/calldata_retriever.d.ts +2 -1
- package/dest/l1/calldata_retriever.d.ts.map +1 -1
- package/dest/l1/calldata_retriever.js +15 -5
- package/dest/l1/data_retrieval.d.ts +24 -12
- package/dest/l1/data_retrieval.d.ts.map +1 -1
- package/dest/l1/data_retrieval.js +36 -37
- package/dest/l1/trace_tx.d.ts +12 -66
- package/dest/l1/trace_tx.d.ts.map +1 -1
- package/dest/l1/validate_historical_logs.d.ts +23 -0
- package/dest/l1/validate_historical_logs.d.ts.map +1 -0
- package/dest/l1/validate_historical_logs.js +108 -0
- package/dest/modules/contract_data_source_adapter.d.ts +25 -0
- package/dest/modules/contract_data_source_adapter.d.ts.map +1 -0
- package/dest/modules/contract_data_source_adapter.js +40 -0
- package/dest/modules/data_source_base.d.ts +70 -46
- package/dest/modules/data_source_base.d.ts.map +1 -1
- package/dest/modules/data_source_base.js +270 -135
- package/dest/modules/data_store_updater.d.ts +42 -17
- package/dest/modules/data_store_updater.d.ts.map +1 -1
- package/dest/modules/data_store_updater.js +191 -122
- package/dest/modules/instrumentation.d.ts +7 -2
- package/dest/modules/instrumentation.d.ts.map +1 -1
- package/dest/modules/instrumentation.js +25 -7
- package/dest/modules/l1_synchronizer.d.ts +12 -6
- package/dest/modules/l1_synchronizer.d.ts.map +1 -1
- package/dest/modules/l1_synchronizer.js +432 -205
- package/dest/modules/validation.d.ts +4 -3
- package/dest/modules/validation.d.ts.map +1 -1
- package/dest/modules/validation.js +6 -6
- package/dest/store/block_store.d.ts +174 -70
- package/dest/store/block_store.d.ts.map +1 -1
- package/dest/store/block_store.js +696 -250
- package/dest/store/contract_class_store.d.ts +17 -4
- package/dest/store/contract_class_store.d.ts.map +1 -1
- package/dest/store/contract_class_store.js +24 -68
- package/dest/store/contract_instance_store.d.ts +28 -1
- package/dest/store/contract_instance_store.d.ts.map +1 -1
- package/dest/store/contract_instance_store.js +37 -2
- package/dest/store/data_stores.d.ts +68 -0
- package/dest/store/data_stores.d.ts.map +1 -0
- package/dest/store/data_stores.js +54 -0
- package/dest/store/function_names_cache.d.ts +17 -0
- package/dest/store/function_names_cache.d.ts.map +1 -0
- package/dest/store/function_names_cache.js +30 -0
- package/dest/store/l2_tips_cache.d.ts +13 -7
- package/dest/store/l2_tips_cache.d.ts.map +1 -1
- package/dest/store/l2_tips_cache.js +13 -76
- package/dest/store/log_store.d.ts +42 -37
- package/dest/store/log_store.d.ts.map +1 -1
- package/dest/store/log_store.js +262 -408
- package/dest/store/log_store_codec.d.ts +70 -0
- package/dest/store/log_store_codec.d.ts.map +1 -0
- package/dest/store/log_store_codec.js +101 -0
- package/dest/store/message_store.d.ts +11 -1
- package/dest/store/message_store.d.ts.map +1 -1
- package/dest/store/message_store.js +51 -9
- package/dest/test/fake_l1_state.d.ts +20 -1
- package/dest/test/fake_l1_state.d.ts.map +1 -1
- package/dest/test/fake_l1_state.js +114 -18
- package/dest/test/mock_l1_to_l2_message_source.d.ts +1 -1
- package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
- package/dest/test/mock_l1_to_l2_message_source.js +2 -1
- package/dest/test/mock_l2_block_source.d.ts +52 -46
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +246 -170
- package/dest/test/mock_structs.d.ts +4 -1
- package/dest/test/mock_structs.d.ts.map +1 -1
- package/dest/test/mock_structs.js +13 -1
- package/dest/test/noop_l1_archiver.d.ts +12 -6
- package/dest/test/noop_l1_archiver.d.ts.map +1 -1
- package/dest/test/noop_l1_archiver.js +26 -9
- package/package.json +14 -14
- package/src/archiver.ts +313 -75
- package/src/config.ts +32 -12
- package/src/errors.ts +122 -21
- package/src/factory.ts +54 -29
- package/src/index.ts +18 -2
- package/src/l1/calldata_retriever.ts +16 -5
- package/src/l1/data_retrieval.ts +52 -53
- package/src/l1/validate_historical_logs.ts +140 -0
- package/src/modules/contract_data_source_adapter.ts +55 -0
- package/src/modules/data_source_base.ts +336 -171
- package/src/modules/data_store_updater.ts +224 -154
- package/src/modules/instrumentation.ts +28 -8
- package/src/modules/l1_synchronizer.ts +572 -248
- package/src/modules/validation.ts +10 -9
- package/src/store/block_store.ts +865 -290
- package/src/store/contract_class_store.ts +31 -103
- package/src/store/contract_instance_store.ts +51 -5
- package/src/store/data_stores.ts +104 -0
- package/src/store/function_names_cache.ts +37 -0
- package/src/store/l2_tips_cache.ts +16 -70
- package/src/store/log_store.ts +301 -559
- package/src/store/log_store_codec.ts +132 -0
- package/src/store/message_store.ts +60 -10
- package/src/structs/inbox_message.ts +1 -1
- package/src/test/fake_l1_state.ts +142 -29
- package/src/test/mock_l1_to_l2_message_source.ts +1 -0
- package/src/test/mock_l2_block_source.ts +309 -205
- package/src/test/mock_structs.ts +20 -6
- package/src/test/noop_l1_archiver.ts +39 -9
- package/dest/store/kv_archiver_store.d.ts +0 -354
- package/dest/store/kv_archiver_store.d.ts.map +0 -1
- package/dest/store/kv_archiver_store.js +0 -464
- package/src/store/kv_archiver_store.ts +0 -671
|
@@ -1,38 +1,133 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
2
|
+
import {
|
|
3
|
+
BlockNumber,
|
|
4
|
+
CheckpointNumber,
|
|
5
|
+
type EpochNumber,
|
|
6
|
+
IndexWithinCheckpoint,
|
|
7
|
+
type SlotNumber,
|
|
8
|
+
} from '@aztec/foundation/branded-types';
|
|
3
9
|
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
10
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
5
|
-
import { isDefined } from '@aztec/foundation/types';
|
|
6
11
|
import type { FunctionSelector } from '@aztec/stdlib/abi';
|
|
7
12
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
8
|
-
import {
|
|
9
|
-
|
|
13
|
+
import {
|
|
14
|
+
type BlockData,
|
|
15
|
+
type BlockHash,
|
|
16
|
+
type BlockQuery,
|
|
17
|
+
type BlockTag,
|
|
18
|
+
type BlocksQuery,
|
|
19
|
+
Body,
|
|
20
|
+
type CheckpointQuery,
|
|
21
|
+
type CheckpointsQuery,
|
|
22
|
+
L2Block,
|
|
23
|
+
type L2Tips,
|
|
24
|
+
type ProposedCheckpointQuery,
|
|
25
|
+
} from '@aztec/stdlib/block';
|
|
26
|
+
import {
|
|
27
|
+
Checkpoint,
|
|
28
|
+
type CheckpointData,
|
|
29
|
+
type ProposedCheckpointData,
|
|
30
|
+
PublishedCheckpoint,
|
|
31
|
+
} from '@aztec/stdlib/checkpoint';
|
|
10
32
|
import type { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
|
|
11
|
-
import {
|
|
12
|
-
|
|
33
|
+
import {
|
|
34
|
+
type L1RollupConstants,
|
|
35
|
+
getEpochAtSlot,
|
|
36
|
+
getEpochNumberAtTimestamp,
|
|
37
|
+
getLastL1SlotTimestampForL2Slot,
|
|
38
|
+
getProofSubmissionDeadlineEpoch,
|
|
39
|
+
getSlotRangeForEpoch,
|
|
40
|
+
} from '@aztec/stdlib/epoch-helpers';
|
|
13
41
|
import type { L2LogsSource } from '@aztec/stdlib/interfaces/server';
|
|
14
|
-
import type {
|
|
42
|
+
import type { LogResult, PrivateLogsQuery, PublicLogsQuery } from '@aztec/stdlib/logs';
|
|
15
43
|
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
16
|
-
import
|
|
44
|
+
import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
|
|
17
45
|
import type { BlockHeader, IndexedTxEffect, TxHash, TxReceipt } from '@aztec/stdlib/tx';
|
|
18
46
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
19
47
|
|
|
20
48
|
import type { ArchiverDataSource } from '../interfaces.js';
|
|
21
|
-
import type {
|
|
49
|
+
import type { ResolvedBlockQuery, ResolvedBlocksQuery } from '../store/block_store.js';
|
|
50
|
+
import type { ArchiverDataStores } from '../store/data_stores.js';
|
|
22
51
|
import type { ValidateCheckpointResult } from './validation.js';
|
|
23
52
|
|
|
24
53
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
54
|
+
* Sentinel returned by {@link ArchiverDataSourceBase#resolveBlockQuery} when a query resolves
|
|
55
|
+
* to the genesis block. Forces single-block lookup methods to take the genesis branch
|
|
56
|
+
* explicitly rather than silently falling through to the BlockStore (which never has a block 0).
|
|
57
|
+
*/
|
|
58
|
+
type GenesisBlockQuery = { genesis: true };
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Abstract base class implementing ArchiverDataSource using a bundle of archiver substores.
|
|
62
|
+
* Provides implementations for all read-side methods and declares abstract methods for
|
|
63
|
+
* L1-dependent functionality that subclasses must implement.
|
|
28
64
|
*/
|
|
29
65
|
export abstract class ArchiverDataSourceBase
|
|
30
66
|
implements ArchiverDataSource, L2LogsSource, ContractDataSource, L1ToL2MessageSource
|
|
31
67
|
{
|
|
68
|
+
/** The injected genesis block header. */
|
|
69
|
+
protected readonly initialHeader: BlockHeader;
|
|
70
|
+
/** Precomputed hash of the initial header, exposed via {@link getGenesisBlockHash}. */
|
|
71
|
+
protected readonly initialBlockHash: BlockHash;
|
|
72
|
+
/** Archive root after block 0 was appended — read from L1 (`Rollup.getGenesisArchiveTreeRoot`). */
|
|
73
|
+
protected readonly genesisArchiveRoot: Fr;
|
|
74
|
+
|
|
75
|
+
/** Memoized synthetic genesis block — callers rely on referential identity for caching. */
|
|
76
|
+
private readonly genesisBlock: L2Block;
|
|
77
|
+
/** Memoized synthetic genesis block data — kept consistent with {@link genesisBlock}. */
|
|
78
|
+
private readonly genesisBlockData: BlockData;
|
|
79
|
+
|
|
32
80
|
constructor(
|
|
33
|
-
protected readonly
|
|
34
|
-
protected readonly l1Constants
|
|
35
|
-
|
|
81
|
+
protected readonly stores: ArchiverDataStores,
|
|
82
|
+
protected readonly l1Constants: L1RollupConstants | undefined,
|
|
83
|
+
initialHeader: BlockHeader,
|
|
84
|
+
initialBlockHash: BlockHash,
|
|
85
|
+
genesisArchiveRoot: Fr,
|
|
86
|
+
) {
|
|
87
|
+
this.initialHeader = initialHeader;
|
|
88
|
+
this.initialBlockHash = initialBlockHash;
|
|
89
|
+
this.genesisArchiveRoot = genesisArchiveRoot;
|
|
90
|
+
|
|
91
|
+
const genesisArchive = new AppendOnlyTreeSnapshot(genesisArchiveRoot, 1);
|
|
92
|
+
this.genesisBlock = new L2Block(
|
|
93
|
+
genesisArchive,
|
|
94
|
+
initialHeader,
|
|
95
|
+
Body.empty(),
|
|
96
|
+
CheckpointNumber.ZERO,
|
|
97
|
+
IndexWithinCheckpoint(0),
|
|
98
|
+
);
|
|
99
|
+
this.genesisBlockData = {
|
|
100
|
+
header: initialHeader,
|
|
101
|
+
archive: genesisArchive,
|
|
102
|
+
blockHash: initialBlockHash,
|
|
103
|
+
checkpointNumber: CheckpointNumber.ZERO,
|
|
104
|
+
indexWithinCheckpoint: IndexWithinCheckpoint(0),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Returns the precomputed hash of the genesis block header. */
|
|
109
|
+
public getGenesisBlockHash(): BlockHash {
|
|
110
|
+
return this.initialBlockHash;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Returns the synthetic genesis L2Block (memoized — same instance across calls). */
|
|
114
|
+
private getGenesisBlock(): L2Block {
|
|
115
|
+
return this.genesisBlock;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Returns genesis block data (memoized — same instance across calls). */
|
|
119
|
+
private getGenesisBlockData(): BlockData {
|
|
120
|
+
return this.genesisBlockData;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Type guard distinguishing the genesis sentinel from a {@link ResolvedBlockQuery}.
|
|
125
|
+
* `resolveBlockQuery` already rewrites every genesis-matching shape to the sentinel,
|
|
126
|
+
* so callers only need this single sync check.
|
|
127
|
+
*/
|
|
128
|
+
private isGenesisBlockQuery(query: ResolvedBlockQuery | GenesisBlockQuery): query is GenesisBlockQuery {
|
|
129
|
+
return 'genesis' in query;
|
|
130
|
+
}
|
|
36
131
|
|
|
37
132
|
abstract getRollupAddress(): Promise<EthAddress>;
|
|
38
133
|
|
|
@@ -46,115 +141,153 @@ export abstract class ArchiverDataSourceBase
|
|
|
46
141
|
|
|
47
142
|
abstract getL2Tips(): Promise<L2Tips>;
|
|
48
143
|
|
|
49
|
-
abstract
|
|
144
|
+
abstract getSyncedL2SlotNumber(): Promise<SlotNumber | undefined>;
|
|
50
145
|
|
|
51
|
-
abstract
|
|
146
|
+
abstract getSyncedL2EpochNumber(): Promise<EpochNumber | undefined>;
|
|
52
147
|
|
|
53
148
|
abstract isEpochComplete(epochNumber: EpochNumber): Promise<boolean>;
|
|
54
149
|
|
|
55
150
|
abstract syncImmediate(): Promise<void>;
|
|
56
151
|
|
|
57
|
-
public
|
|
58
|
-
|
|
59
|
-
|
|
152
|
+
public async isPruneDueAtSlot(slot: SlotNumber): Promise<boolean> {
|
|
153
|
+
if (!this.l1Constants) {
|
|
154
|
+
throw new Error('isPruneDueAtSlot requires l1Constants');
|
|
155
|
+
}
|
|
156
|
+
const tips = await this.getL2Tips();
|
|
157
|
+
const proven = tips.proven.checkpoint.number;
|
|
158
|
+
const pending = tips.checkpointed.checkpoint.number;
|
|
159
|
+
if (pending === proven) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
60
162
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
163
|
+
const oldestUnproven = await this.getCheckpointData({ number: CheckpointNumber(Number(proven) + 1) });
|
|
164
|
+
if (!oldestUnproven) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
64
167
|
|
|
65
|
-
|
|
66
|
-
|
|
168
|
+
const slotTs = getLastL1SlotTimestampForL2Slot(slot, this.l1Constants);
|
|
169
|
+
const slotEpoch = getEpochNumberAtTimestamp(slotTs, this.l1Constants);
|
|
170
|
+
const oldestUnprovenEpoch = getEpochAtSlot(oldestUnproven.header.slotNumber, this.l1Constants);
|
|
171
|
+
const deadlineEpoch = getProofSubmissionDeadlineEpoch(oldestUnprovenEpoch, this.l1Constants);
|
|
172
|
+
return slotEpoch >= deadlineEpoch;
|
|
67
173
|
}
|
|
68
174
|
|
|
69
|
-
public
|
|
70
|
-
return this.
|
|
175
|
+
public getCheckpointNumber(): Promise<CheckpointNumber> {
|
|
176
|
+
return this.stores.blocks.getLatestCheckpointNumber();
|
|
71
177
|
}
|
|
72
178
|
|
|
73
|
-
public
|
|
74
|
-
return this.
|
|
179
|
+
public getProvenCheckpointNumber(): Promise<CheckpointNumber> {
|
|
180
|
+
return this.stores.blocks.getProvenCheckpointNumber();
|
|
75
181
|
}
|
|
76
182
|
|
|
77
|
-
public
|
|
78
|
-
|
|
79
|
-
|
|
183
|
+
public getBlockNumber(): Promise<BlockNumber>;
|
|
184
|
+
public getBlockNumber(query: BlockQuery): Promise<BlockNumber | undefined>;
|
|
185
|
+
public async getBlockNumber(query?: BlockQuery): Promise<BlockNumber | undefined> {
|
|
186
|
+
if (!query) {
|
|
187
|
+
return this.stores.blocks.getLatestL2BlockNumber();
|
|
188
|
+
}
|
|
189
|
+
const resolved = await this.resolveBlockQuery(query);
|
|
190
|
+
if (resolved === undefined) {
|
|
80
191
|
return undefined;
|
|
81
192
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
public getCheckpointedBlock(number: BlockNumber): Promise<CheckpointedL2Block | undefined> {
|
|
87
|
-
return this.store.getCheckpointedBlock(number);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
public getCheckpointedL2BlockNumber(): Promise<BlockNumber> {
|
|
91
|
-
return this.store.getCheckpointedL2BlockNumber();
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
public getFinalizedL2BlockNumber(): Promise<BlockNumber> {
|
|
95
|
-
return this.store.getFinalizedL2BlockNumber();
|
|
193
|
+
if (this.isGenesisBlockQuery(resolved)) {
|
|
194
|
+
return BlockNumber.ZERO;
|
|
195
|
+
}
|
|
196
|
+
return this.stores.blocks.getBlockNumber(resolved);
|
|
96
197
|
}
|
|
97
198
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
199
|
+
/**
|
|
200
|
+
* Resolves a {@link CheckpointQuery} to a concrete `CheckpointNumber`, or undefined when the
|
|
201
|
+
* query refers to a position that has no checkpoint yet (e.g. `{ slot }` not found).
|
|
202
|
+
*/
|
|
203
|
+
private resolveCheckpointQuery(query: CheckpointQuery): Promise<CheckpointNumber | undefined> {
|
|
204
|
+
if ('number' in query) {
|
|
205
|
+
return Promise.resolve(query.number);
|
|
101
206
|
}
|
|
102
|
-
if (
|
|
103
|
-
return
|
|
207
|
+
if ('slot' in query) {
|
|
208
|
+
return this.stores.blocks.getCheckpointNumberBySlot(query.slot);
|
|
104
209
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
210
|
+
// tag variant
|
|
211
|
+
switch (query.tag) {
|
|
212
|
+
case 'checkpointed':
|
|
213
|
+
return this.stores.blocks.getLatestCheckpointNumber();
|
|
214
|
+
case 'proven':
|
|
215
|
+
return this.stores.blocks.getProvenCheckpointNumber();
|
|
216
|
+
case 'finalized':
|
|
217
|
+
return this.stores.blocks.getFinalizedCheckpointNumber();
|
|
108
218
|
}
|
|
109
|
-
return checkpoint.header;
|
|
110
219
|
}
|
|
111
220
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
221
|
+
/**
|
|
222
|
+
* Resolves a {@link CheckpointsQuery} to a concrete `{from, limit}` pair used by BlockStore,
|
|
223
|
+
* or undefined when the epoch has no checkpoints.
|
|
224
|
+
*/
|
|
225
|
+
private async resolveCheckpointsQuery(
|
|
226
|
+
query: CheckpointsQuery,
|
|
227
|
+
): Promise<{ from: CheckpointNumber; limit: number } | undefined> {
|
|
228
|
+
if ('from' in query) {
|
|
229
|
+
return query;
|
|
230
|
+
}
|
|
231
|
+
const numbers = await this.getCheckpointNumbersForEpoch(query.epoch);
|
|
232
|
+
if (numbers.length === 0) {
|
|
115
233
|
return undefined;
|
|
116
234
|
}
|
|
117
|
-
return
|
|
235
|
+
return { from: numbers[0], limit: numbers.length };
|
|
118
236
|
}
|
|
119
237
|
|
|
120
|
-
public
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
238
|
+
public async getCheckpoint(query: CheckpointQuery): Promise<PublishedCheckpoint | undefined> {
|
|
239
|
+
const number = await this.resolveCheckpointQuery(query);
|
|
240
|
+
if (number === undefined || number === 0) {
|
|
241
|
+
return undefined;
|
|
242
|
+
}
|
|
243
|
+
const data = await this.stores.blocks.getCheckpointData(number);
|
|
244
|
+
if (!data) {
|
|
245
|
+
return undefined;
|
|
246
|
+
}
|
|
247
|
+
return this.getPublishedCheckpointFromCheckpointData(data);
|
|
126
248
|
}
|
|
127
249
|
|
|
128
|
-
public
|
|
129
|
-
|
|
250
|
+
public async getCheckpoints(query: CheckpointsQuery): Promise<PublishedCheckpoint[]> {
|
|
251
|
+
const resolved = await this.resolveCheckpointsQuery(query);
|
|
252
|
+
if (!resolved) {
|
|
253
|
+
return [];
|
|
254
|
+
}
|
|
255
|
+
const checkpoints = await this.stores.blocks.getRangeOfCheckpoints(resolved.from, resolved.limit);
|
|
256
|
+
return Promise.all(checkpoints.map(ch => this.getPublishedCheckpointFromCheckpointData(ch)));
|
|
130
257
|
}
|
|
131
258
|
|
|
132
|
-
public
|
|
133
|
-
|
|
259
|
+
public async getCheckpointData(query: CheckpointQuery): Promise<CheckpointData | undefined> {
|
|
260
|
+
const number = await this.resolveCheckpointQuery(query);
|
|
261
|
+
if (number === undefined || number === 0) {
|
|
262
|
+
return undefined;
|
|
263
|
+
}
|
|
264
|
+
return this.stores.blocks.getCheckpointData(number);
|
|
134
265
|
}
|
|
135
266
|
|
|
136
|
-
public
|
|
137
|
-
|
|
267
|
+
public async getCheckpointsData(query: CheckpointsQuery): Promise<CheckpointData[]> {
|
|
268
|
+
const resolved = await this.resolveCheckpointsQuery(query);
|
|
269
|
+
if (!resolved) {
|
|
270
|
+
return [];
|
|
271
|
+
}
|
|
272
|
+
return this.stores.blocks.getRangeOfCheckpoints(resolved.from, resolved.limit);
|
|
138
273
|
}
|
|
139
274
|
|
|
140
|
-
public
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
number = await this.store.getLatestBlockNumber();
|
|
275
|
+
public getProposedCheckpointData(query?: ProposedCheckpointQuery): Promise<ProposedCheckpointData | undefined> {
|
|
276
|
+
if (!query || 'tag' in query) {
|
|
277
|
+
return this.stores.blocks.getLastProposedCheckpoint();
|
|
144
278
|
}
|
|
145
|
-
if (number
|
|
146
|
-
return
|
|
279
|
+
if ('number' in query) {
|
|
280
|
+
return this.stores.blocks.getProposedCheckpointByNumber(query.number);
|
|
147
281
|
}
|
|
148
|
-
|
|
149
|
-
return publishedBlock;
|
|
282
|
+
return this.stores.blocks.getProposedCheckpointBySlot(query.slot);
|
|
150
283
|
}
|
|
151
284
|
|
|
152
285
|
public getTxEffect(txHash: TxHash): Promise<IndexedTxEffect | undefined> {
|
|
153
|
-
return this.
|
|
286
|
+
return this.stores.blocks.getTxEffect(txHash);
|
|
154
287
|
}
|
|
155
288
|
|
|
156
289
|
public getSettledTxReceipt(txHash: TxHash): Promise<TxReceipt | undefined> {
|
|
157
|
-
return this.
|
|
290
|
+
return this.stores.blocks.getSettledTxReceipt(txHash, this.l1Constants);
|
|
158
291
|
}
|
|
159
292
|
|
|
160
293
|
public isPendingChainInvalid(): Promise<boolean> {
|
|
@@ -162,35 +295,23 @@ export abstract class ArchiverDataSourceBase
|
|
|
162
295
|
}
|
|
163
296
|
|
|
164
297
|
public async getPendingChainValidationStatus(): Promise<ValidateCheckpointResult> {
|
|
165
|
-
return (await this.
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
public getPrivateLogsByTags(tags: SiloedTag[], page?: number): Promise<TxScopedL2Log[][]> {
|
|
169
|
-
return this.store.getPrivateLogsByTags(tags, page);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
public getPublicLogsByTagsFromContract(
|
|
173
|
-
contractAddress: AztecAddress,
|
|
174
|
-
tags: Tag[],
|
|
175
|
-
page?: number,
|
|
176
|
-
): Promise<TxScopedL2Log[][]> {
|
|
177
|
-
return this.store.getPublicLogsByTagsFromContract(contractAddress, tags, page);
|
|
298
|
+
return (await this.stores.blocks.getPendingChainValidationStatus()) ?? { valid: true };
|
|
178
299
|
}
|
|
179
300
|
|
|
180
|
-
public
|
|
181
|
-
return this.
|
|
301
|
+
public getPrivateLogsByTags(query: PrivateLogsQuery): Promise<LogResult[][]> {
|
|
302
|
+
return this.stores.logs.getPrivateLogsByTags(query);
|
|
182
303
|
}
|
|
183
304
|
|
|
184
|
-
public
|
|
185
|
-
return this.
|
|
305
|
+
public getPublicLogsByTags(query: PublicLogsQuery): Promise<LogResult[][]> {
|
|
306
|
+
return this.stores.logs.getPublicLogsByTags(query);
|
|
186
307
|
}
|
|
187
308
|
|
|
188
309
|
public getContractClass(id: Fr): Promise<ContractClassPublic | undefined> {
|
|
189
|
-
return this.
|
|
310
|
+
return this.stores.contractClasses.getContractClass(id);
|
|
190
311
|
}
|
|
191
312
|
|
|
192
313
|
public getBytecodeCommitment(id: Fr): Promise<Fr | undefined> {
|
|
193
|
-
return this.
|
|
314
|
+
return this.stores.contractClasses.getBytecodeCommitment(id);
|
|
194
315
|
}
|
|
195
316
|
|
|
196
317
|
public async getContract(
|
|
@@ -199,43 +320,39 @@ export abstract class ArchiverDataSourceBase
|
|
|
199
320
|
): Promise<ContractInstanceWithAddress | undefined> {
|
|
200
321
|
let timestamp;
|
|
201
322
|
if (maybeTimestamp === undefined) {
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
timestamp = latestBlockHeader ? latestBlockHeader.globalVariables.timestamp : 0n;
|
|
323
|
+
const latestBlockData = await this.getBlockData({ tag: 'proposed' });
|
|
324
|
+
timestamp = latestBlockData ? latestBlockData.header.globalVariables.timestamp : 0n;
|
|
205
325
|
} else {
|
|
206
326
|
timestamp = maybeTimestamp;
|
|
207
327
|
}
|
|
208
328
|
|
|
209
|
-
return this.
|
|
329
|
+
return this.stores.contractInstances.getContractInstance(address, timestamp);
|
|
210
330
|
}
|
|
211
331
|
|
|
212
332
|
public getContractClassIds(): Promise<Fr[]> {
|
|
213
|
-
return this.
|
|
333
|
+
return this.stores.contractClasses.getContractClassIds();
|
|
214
334
|
}
|
|
215
335
|
|
|
216
|
-
|
|
217
|
-
|
|
336
|
+
/** Looks up a public function name given a selector. */
|
|
337
|
+
public getDebugFunctionName(_address: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
|
|
338
|
+
return Promise.resolve(this.stores.functionNames.get(selector));
|
|
218
339
|
}
|
|
219
340
|
|
|
341
|
+
/** Register public function signatures so they can be looked up by selector. */
|
|
220
342
|
public registerContractFunctionSignatures(signatures: string[]): Promise<void> {
|
|
221
|
-
return this.
|
|
343
|
+
return this.stores.functionNames.register(signatures);
|
|
222
344
|
}
|
|
223
345
|
|
|
224
346
|
public getL1ToL2Messages(checkpointNumber: CheckpointNumber): Promise<Fr[]> {
|
|
225
|
-
return this.
|
|
347
|
+
return this.stores.messages.getL1ToL2Messages(checkpointNumber);
|
|
226
348
|
}
|
|
227
349
|
|
|
228
350
|
public getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise<bigint | undefined> {
|
|
229
|
-
return this.
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
public async getCheckpoints(checkpointNumber: CheckpointNumber, limit: number): Promise<PublishedCheckpoint[]> {
|
|
233
|
-
const checkpoints = await this.store.getRangeOfCheckpoints(checkpointNumber, limit);
|
|
234
|
-
return Promise.all(checkpoints.map(ch => this.getPublishedCheckpointFromCheckpointData(ch)));
|
|
351
|
+
return this.stores.messages.getL1ToL2MessageIndex(l1ToL2Message);
|
|
235
352
|
}
|
|
236
353
|
|
|
237
354
|
private async getPublishedCheckpointFromCheckpointData(checkpoint: CheckpointData): Promise<PublishedCheckpoint> {
|
|
238
|
-
const blocksForCheckpoint = await this.
|
|
355
|
+
const blocksForCheckpoint = await this.stores.blocks.getBlocksForCheckpoint(checkpoint.checkpointNumber);
|
|
239
356
|
if (!blocksForCheckpoint) {
|
|
240
357
|
throw new Error(`Blocks for checkpoint ${checkpoint.checkpointNumber} not found`);
|
|
241
358
|
}
|
|
@@ -244,85 +361,133 @@ export abstract class ArchiverDataSourceBase
|
|
|
244
361
|
checkpoint.header,
|
|
245
362
|
blocksForCheckpoint,
|
|
246
363
|
checkpoint.checkpointNumber,
|
|
364
|
+
checkpoint.feeAssetPriceModifier,
|
|
247
365
|
);
|
|
248
366
|
return new PublishedCheckpoint(fullCheckpoint, checkpoint.l1, checkpoint.attestations);
|
|
249
367
|
}
|
|
250
368
|
|
|
251
369
|
public getBlocksForSlot(slotNumber: SlotNumber): Promise<L2Block[]> {
|
|
252
|
-
return this.
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
public async getCheckpointedBlocksForEpoch(epochNumber: EpochNumber): Promise<CheckpointedL2Block[]> {
|
|
256
|
-
const checkpointsData = await this.getCheckpointsDataForEpoch(epochNumber);
|
|
257
|
-
const blocks = await Promise.all(
|
|
258
|
-
checkpointsData.flatMap(checkpoint =>
|
|
259
|
-
range(checkpoint.blockCount, checkpoint.startBlock).map(blockNumber =>
|
|
260
|
-
this.getCheckpointedBlock(BlockNumber(blockNumber)),
|
|
261
|
-
),
|
|
262
|
-
),
|
|
263
|
-
);
|
|
264
|
-
return blocks.filter(isDefined);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
public async getCheckpointedBlockHeadersForEpoch(epochNumber: EpochNumber): Promise<BlockHeader[]> {
|
|
268
|
-
const checkpointsData = await this.getCheckpointsDataForEpoch(epochNumber);
|
|
269
|
-
const blocks = await Promise.all(
|
|
270
|
-
checkpointsData.flatMap(checkpoint =>
|
|
271
|
-
range(checkpoint.blockCount, checkpoint.startBlock).map(blockNumber =>
|
|
272
|
-
this.getBlockHeader(BlockNumber(blockNumber)),
|
|
273
|
-
),
|
|
274
|
-
),
|
|
275
|
-
);
|
|
276
|
-
return blocks.filter(isDefined);
|
|
370
|
+
return this.stores.blocks.getBlocksForSlot(slotNumber);
|
|
277
371
|
}
|
|
278
372
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
return Promise.all(
|
|
282
|
-
checkpointsData.map(data => this.getPublishedCheckpointFromCheckpointData(data).then(p => p.checkpoint)),
|
|
283
|
-
);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/** Returns checkpoint data for all checkpoints whose slot falls within the given epoch. */
|
|
287
|
-
public getCheckpointsDataForEpoch(epochNumber: EpochNumber): Promise<CheckpointData[]> {
|
|
373
|
+
/** Returns just the checkpoint numbers for all checkpoints whose slot falls within the given epoch. */
|
|
374
|
+
private getCheckpointNumbersForEpoch(epochNumber: EpochNumber): Promise<CheckpointNumber[]> {
|
|
288
375
|
if (!this.l1Constants) {
|
|
289
376
|
throw new Error('L1 constants not set');
|
|
290
377
|
}
|
|
291
378
|
|
|
292
379
|
const [start, end] = getSlotRangeForEpoch(epochNumber, this.l1Constants);
|
|
293
|
-
return this.
|
|
380
|
+
return this.stores.blocks.getCheckpointNumbersForSlotRange(start, end);
|
|
294
381
|
}
|
|
295
382
|
|
|
296
|
-
public async getBlock(
|
|
297
|
-
|
|
298
|
-
if (
|
|
299
|
-
number = await this.store.getLatestBlockNumber();
|
|
300
|
-
}
|
|
301
|
-
if (number === 0) {
|
|
383
|
+
public async getBlock(query: BlockQuery): Promise<L2Block | undefined> {
|
|
384
|
+
const resolved = await this.resolveBlockQuery(query);
|
|
385
|
+
if (resolved === undefined) {
|
|
302
386
|
return undefined;
|
|
303
387
|
}
|
|
304
|
-
|
|
388
|
+
if (this.isGenesisBlockQuery(resolved)) {
|
|
389
|
+
return this.getGenesisBlock();
|
|
390
|
+
}
|
|
391
|
+
return this.stores.blocks.getBlock(resolved);
|
|
305
392
|
}
|
|
306
393
|
|
|
307
|
-
|
|
308
|
-
|
|
394
|
+
/**
|
|
395
|
+
* Range queries iterate physical blocks only; the genesis block is NOT prepended.
|
|
396
|
+
* `L2BlockStream` consumers (`world-state.handleL2Blocks`, etc.) emit `blocks-added` events for
|
|
397
|
+
* real blocks and would be surprised by a synthetic block 0. Use {@link getBlock} or
|
|
398
|
+
* {@link getBlockData} for genesis-aware single-block lookups.
|
|
399
|
+
*/
|
|
400
|
+
public async getBlocks(query: BlocksQuery): Promise<L2Block[]> {
|
|
401
|
+
const resolved = await this.resolveBlocksQuery(query);
|
|
402
|
+
return resolved ? this.stores.blocks.getBlocks(resolved) : [];
|
|
309
403
|
}
|
|
310
404
|
|
|
311
|
-
public
|
|
312
|
-
|
|
405
|
+
public async getBlockData(query: BlockQuery): Promise<BlockData | undefined> {
|
|
406
|
+
const resolved = await this.resolveBlockQuery(query);
|
|
407
|
+
if (resolved === undefined) {
|
|
408
|
+
return undefined;
|
|
409
|
+
}
|
|
410
|
+
if (this.isGenesisBlockQuery(resolved)) {
|
|
411
|
+
return this.getGenesisBlockData();
|
|
412
|
+
}
|
|
413
|
+
return this.stores.blocks.getBlockData(resolved);
|
|
313
414
|
}
|
|
314
415
|
|
|
315
|
-
|
|
316
|
-
|
|
416
|
+
/** See {@link getBlocks} — range queries do not prepend the genesis block. */
|
|
417
|
+
public async getBlocksData(query: BlocksQuery): Promise<BlockData[]> {
|
|
418
|
+
const resolved = await this.resolveBlocksQuery(query);
|
|
419
|
+
return resolved ? this.stores.blocks.getBlocksData(resolved) : [];
|
|
317
420
|
}
|
|
318
421
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
422
|
+
/**
|
|
423
|
+
* Resolves a {@link BlockQuery} to either the genesis sentinel or a {@link ResolvedBlockQuery}
|
|
424
|
+
* understood by BlockStore. Detects every shape that points at block 0 — `{number:0}`,
|
|
425
|
+
* `{hash}` matching the initial header, `{archive}` matching the post-genesis archive root,
|
|
426
|
+
* and `{tag}` resolving to 0 — and rewrites them to the sentinel so callers branch once.
|
|
427
|
+
*/
|
|
428
|
+
private async resolveBlockQuery(query: BlockQuery): Promise<ResolvedBlockQuery | GenesisBlockQuery | undefined> {
|
|
429
|
+
if ('number' in query) {
|
|
430
|
+
return query.number === BlockNumber.ZERO ? { genesis: true } : query;
|
|
431
|
+
}
|
|
432
|
+
if ('hash' in query) {
|
|
433
|
+
return query.hash.equals(this.initialBlockHash) ? { genesis: true } : query;
|
|
434
|
+
}
|
|
435
|
+
if ('archive' in query) {
|
|
436
|
+
return query.archive.equals(this.genesisArchiveRoot) ? { genesis: true } : query;
|
|
437
|
+
}
|
|
438
|
+
const number = await this.resolveBlockTag(query.tag);
|
|
439
|
+
if (number === BlockNumber.ZERO) {
|
|
440
|
+
return { genesis: true };
|
|
441
|
+
}
|
|
442
|
+
return { number };
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/** Maps a {@link BlockTag} to the matching block number for the current chain state. */
|
|
446
|
+
private resolveBlockTag(tag: BlockTag): Promise<BlockNumber> {
|
|
447
|
+
switch (tag) {
|
|
448
|
+
case 'latest':
|
|
449
|
+
case 'proposed':
|
|
450
|
+
return this.stores.blocks.getLatestL2BlockNumber();
|
|
451
|
+
case 'checkpointed':
|
|
452
|
+
return this.stores.blocks.getCheckpointedL2BlockNumber();
|
|
453
|
+
case 'proven':
|
|
454
|
+
return this.stores.blocks.getProvenBlockNumber();
|
|
455
|
+
case 'finalized':
|
|
456
|
+
return this.stores.blocks.getFinalizedL2BlockNumber();
|
|
457
|
+
}
|
|
322
458
|
}
|
|
323
459
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
460
|
+
/**
|
|
461
|
+
* Converts an epoch-based BlocksQuery to a from/limit query using l1Constants.
|
|
462
|
+
* Returns undefined when the epoch has no checkpoints, so callers can return [] without
|
|
463
|
+
* entering BlockStore. Reads only the two endpoint checkpoints rather than the whole epoch.
|
|
464
|
+
*/
|
|
465
|
+
private async resolveBlocksQuery(query: BlocksQuery): Promise<ResolvedBlocksQuery | undefined> {
|
|
466
|
+
if (!('epoch' in query)) {
|
|
467
|
+
if (query.from < INITIAL_L2_BLOCK_NUM) {
|
|
468
|
+
throw new Error(
|
|
469
|
+
`getBlocks/getBlocksData: 'from' must be >= ${INITIAL_L2_BLOCK_NUM}, got ${query.from}. ` +
|
|
470
|
+
`Use getBlock({number:0})/getBlockData({number:0}) for genesis-aware single-block lookups.`,
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
return query;
|
|
474
|
+
}
|
|
475
|
+
const checkpointNumbers = await this.getCheckpointNumbersForEpoch(query.epoch);
|
|
476
|
+
if (checkpointNumbers.length === 0) {
|
|
477
|
+
return undefined;
|
|
478
|
+
}
|
|
479
|
+
const firstNumber = checkpointNumbers[0];
|
|
480
|
+
const lastNumber = checkpointNumbers[checkpointNumbers.length - 1];
|
|
481
|
+
const first = await this.stores.blocks.getCheckpointData(firstNumber);
|
|
482
|
+
if (!first) {
|
|
483
|
+
return undefined;
|
|
484
|
+
}
|
|
485
|
+
const last = firstNumber === lastNumber ? first : await this.stores.blocks.getCheckpointData(lastNumber);
|
|
486
|
+
if (!last) {
|
|
487
|
+
return undefined;
|
|
488
|
+
}
|
|
489
|
+
const from = BlockNumber(first.startBlock);
|
|
490
|
+
const limit = last.startBlock + last.blockCount - first.startBlock;
|
|
491
|
+
return { from, limit, onlyCheckpointed: true };
|
|
327
492
|
}
|
|
328
493
|
}
|