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