@aztec/archiver 0.0.1-commit.d431d1c → 0.0.1-commit.d58ff9d0
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 +28 -11
- package/dest/archiver.d.ts +80 -21
- package/dest/archiver.d.ts.map +1 -1
- package/dest/archiver.js +347 -167
- package/dest/config.d.ts +7 -3
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +38 -14
- package/dest/errors.d.ts +60 -9
- package/dest/errors.d.ts.map +1 -1
- package/dest/errors.js +88 -13
- package/dest/factory.d.ts +13 -6
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +59 -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 +35 -32
- package/dest/l1/calldata_retriever.d.ts +81 -50
- package/dest/l1/calldata_retriever.d.ts.map +1 -1
- package/dest/l1/calldata_retriever.js +202 -260
- package/dest/l1/data_retrieval.d.ts +32 -18
- package/dest/l1/data_retrieval.d.ts.map +1 -1
- package/dest/l1/data_retrieval.js +45 -50
- 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/l1/validate_trace.d.ts +6 -3
- package/dest/l1/validate_trace.d.ts.map +1 -1
- package/dest/l1/validate_trace.js +13 -9
- 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 +32 -0
- package/dest/modules/data_source_base.d.ts +75 -48
- package/dest/modules/data_source_base.d.ts.map +1 -1
- package/dest/modules/data_source_base.js +251 -220
- package/dest/modules/data_store_updater.d.ts +65 -29
- package/dest/modules/data_store_updater.d.ts.map +1 -1
- package/dest/modules/data_store_updater.js +242 -153
- package/dest/modules/instrumentation.d.ts +30 -4
- package/dest/modules/instrumentation.d.ts.map +1 -1
- package/dest/modules/instrumentation.js +83 -20
- package/dest/modules/l1_synchronizer.d.ts +16 -14
- package/dest/modules/l1_synchronizer.d.ts.map +1 -1
- package/dest/modules/l1_synchronizer.js +493 -225
- 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 +30 -7
- package/dest/modules/validation.d.ts.map +1 -1
- package/dest/modules/validation.js +35 -17
- package/dest/store/block_store.d.ts +200 -75
- package/dest/store/block_store.d.ts.map +1 -1
- package/dest/store/block_store.js +802 -276
- 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 +51 -73
- 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 +54 -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 +78 -0
- package/dest/store/log_store_codec.d.ts.map +1 -0
- package/dest/store/log_store_codec.js +110 -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 +28 -4
- package/dest/test/fake_l1_state.d.ts.map +1 -1
- package/dest/test/fake_l1_state.js +166 -32
- package/dest/test/index.js +3 -1
- 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_l2_block_source.d.ts +65 -51
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +309 -215
- package/dest/test/mock_structs.d.ts +6 -2
- package/dest/test/mock_structs.d.ts.map +1 -1
- package/dest/test/mock_structs.js +26 -12
- package/dest/test/noop_l1_archiver.d.ts +34 -0
- package/dest/test/noop_l1_archiver.d.ts.map +1 -0
- package/dest/test/noop_l1_archiver.js +88 -0
- package/package.json +15 -14
- package/src/archiver.ts +458 -198
- package/src/config.ts +43 -13
- package/src/errors.ts +134 -21
- package/src/factory.ts +87 -36
- package/src/index.ts +19 -2
- package/src/l1/README.md +25 -68
- package/src/l1/bin/retrieve-calldata.ts +45 -33
- package/src/l1/calldata_retriever.ts +267 -379
- package/src/l1/data_retrieval.ts +70 -74
- package/src/l1/spire_proposer.ts +7 -15
- package/src/l1/validate_historical_logs.ts +140 -0
- package/src/l1/validate_trace.ts +24 -6
- package/src/modules/contract_data_source_adapter.ts +46 -0
- package/src/modules/data_source_base.ts +336 -288
- package/src/modules/data_store_updater.ts +287 -187
- package/src/modules/instrumentation.ts +86 -21
- package/src/modules/l1_synchronizer.ts +667 -278
- package/src/modules/outbox_trees_resolver.ts +199 -0
- package/src/modules/validation.ts +80 -23
- package/src/store/block_store.ts +984 -352
- package/src/store/contract_class_store.ts +57 -107
- package/src/store/contract_instance_store.ts +68 -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 +305 -500
- package/src/store/log_store_codec.ts +143 -0
- package/src/store/message_store.ts +60 -10
- package/src/structs/inbox_message.ts +1 -1
- package/src/test/fake_l1_state.ts +215 -44
- package/src/test/index.ts +3 -0
- package/src/test/mock_archiver.ts +3 -2
- package/src/test/mock_l2_block_source.ts +381 -246
- package/src/test/mock_structs.ts +50 -17
- package/src/test/noop_l1_archiver.ts +158 -0
- package/dest/store/kv_archiver_store.d.ts +0 -336
- package/dest/store/kv_archiver_store.d.ts.map +0 -1
- package/dest/store/kv_archiver_store.js +0 -443
- package/src/store/kv_archiver_store.ts +0 -631
|
@@ -1,38 +1,104 @@
|
|
|
1
1
|
import { GENESIS_ARCHIVE_ROOT } from '@aztec/constants';
|
|
2
2
|
import { DefaultL1ContractsConfig } from '@aztec/ethereum/config';
|
|
3
|
-
import { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import { BlockNumber, CheckpointNumber, IndexWithinCheckpoint, SlotNumber } from '@aztec/foundation/branded-types';
|
|
4
4
|
import { Buffer32 } from '@aztec/foundation/buffer';
|
|
5
5
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
6
6
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
7
7
|
import { createLogger } from '@aztec/foundation/log';
|
|
8
|
-
import {
|
|
8
|
+
import { Body, GENESIS_BLOCK_HEADER_HASH, GENESIS_CHECKPOINT_HEADER_HASH, L2Block } from '@aztec/stdlib/block';
|
|
9
9
|
import { Checkpoint, L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
10
10
|
import { EmptyL1RollupConstants, getSlotRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
|
|
11
|
-
import {
|
|
11
|
+
import { computeCheckpointOutHash } from '@aztec/stdlib/messaging';
|
|
12
|
+
import { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
13
|
+
import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
|
|
14
|
+
import { BlockHeader } from '@aztec/stdlib/tx';
|
|
12
15
|
/**
|
|
13
16
|
* A mocked implementation of L2BlockSource to be used in tests.
|
|
14
17
|
*/ export class MockL2BlockSource {
|
|
15
18
|
l2Blocks = [];
|
|
19
|
+
checkpointList = [];
|
|
16
20
|
provenBlockNumber = 0;
|
|
17
21
|
finalizedBlockNumber = 0;
|
|
18
22
|
checkpointedBlockNumber = 0;
|
|
23
|
+
initialHeader = BlockHeader.empty();
|
|
24
|
+
initialHeaderHash = GENESIS_BLOCK_HEADER_HASH;
|
|
25
|
+
genesisArchiveRoot;
|
|
26
|
+
genesisBlock;
|
|
19
27
|
log = createLogger('archiver:mock_l2_block_source');
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
28
|
+
/** Returns the initial header used to synthesize block 0. */ getInitialHeader() {
|
|
29
|
+
return this.initialHeader;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Sets the initial header used to synthesize block 0. Tests that wire up a real
|
|
33
|
+
* world-state should call this with `worldState.getInitialHeader()` so the L2BlockStream
|
|
34
|
+
* agrees on the genesis hash on both sides. Precomputes and caches the header hash so
|
|
35
|
+
* `getGenesisBlockHash()` can return synchronously.
|
|
36
|
+
*/ async setInitialHeader(header) {
|
|
37
|
+
this.initialHeader = header;
|
|
38
|
+
this.initialHeaderHash = await header.hash();
|
|
39
|
+
this.genesisBlock = undefined;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Returns the precomputed hash of the genesis block header. Defaults to the static
|
|
43
|
+
* {@link GENESIS_BLOCK_HEADER_HASH} unless {@link setInitialHeader} has been called with a
|
|
44
|
+
* custom header.
|
|
45
|
+
*/ getGenesisBlockHash() {
|
|
46
|
+
return this.initialHeaderHash;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Sets the post-genesis archive root used to synthesize block 0. Mirrors the real archiver,
|
|
50
|
+
* whose synthetic block 0 carries `new AppendOnlyTreeSnapshot(genesisArchiveRoot, 1)` rather
|
|
51
|
+
* than `AppendOnlyTreeSnapshot.empty()`. Tests wiring up a real world-state should set this so
|
|
52
|
+
* archive-based block lookups against the mock match production semantics.
|
|
53
|
+
*/ setGenesisArchiveRoot(root) {
|
|
54
|
+
this.genesisArchiveRoot = root;
|
|
55
|
+
this.genesisBlock = undefined;
|
|
56
|
+
}
|
|
57
|
+
getGenesisBlock() {
|
|
58
|
+
if (this.genesisBlock) {
|
|
59
|
+
return this.genesisBlock;
|
|
60
|
+
}
|
|
61
|
+
const archive = this.genesisArchiveRoot ? new AppendOnlyTreeSnapshot(this.genesisArchiveRoot, 1) : AppendOnlyTreeSnapshot.empty();
|
|
62
|
+
return this.genesisBlock = new L2Block(archive, this.initialHeader, Body.empty(), CheckpointNumber.ZERO, IndexWithinCheckpoint(0));
|
|
63
|
+
}
|
|
64
|
+
/** Creates blocks grouped into single-block checkpoints. */ async createBlocks(numBlocks) {
|
|
65
|
+
await this.createCheckpoints(numBlocks, 1);
|
|
66
|
+
}
|
|
67
|
+
getCheckpointNumber() {
|
|
68
|
+
return Promise.resolve(this.checkpointList.length === 0 ? CheckpointNumber.ZERO : CheckpointNumber(this.checkpointList.length));
|
|
69
|
+
}
|
|
70
|
+
/** Creates checkpoints, each containing `blocksPerCheckpoint` blocks. */ async createCheckpoints(numCheckpoints, blocksPerCheckpoint = 1) {
|
|
71
|
+
for(let c = 0; c < numCheckpoints; c++){
|
|
72
|
+
const checkpointNum = CheckpointNumber(this.checkpointList.length + 1);
|
|
73
|
+
const startBlockNum = this.l2Blocks.length + 1;
|
|
74
|
+
const slotNumber = SlotNumber(Number(checkpointNum));
|
|
75
|
+
const checkpoint = await Checkpoint.random(checkpointNum, {
|
|
76
|
+
numBlocks: blocksPerCheckpoint,
|
|
77
|
+
startBlockNumber: startBlockNum,
|
|
78
|
+
slotNumber,
|
|
79
|
+
checkpointNumber: checkpointNum
|
|
25
80
|
});
|
|
26
|
-
this.
|
|
81
|
+
this.checkpointList.push(checkpoint);
|
|
82
|
+
this.l2Blocks.push(...checkpoint.blocks);
|
|
27
83
|
}
|
|
28
|
-
this.log.verbose(`Created ${
|
|
84
|
+
this.log.verbose(`Created ${numCheckpoints} checkpoints with ${blocksPerCheckpoint} blocks each in the mock L2 block source`);
|
|
29
85
|
}
|
|
30
|
-
|
|
86
|
+
addProposedBlocks(blocks) {
|
|
31
87
|
this.l2Blocks.push(...blocks);
|
|
32
|
-
this.log.verbose(`Added ${blocks.length} blocks to the mock L2 block source`);
|
|
88
|
+
this.log.verbose(`Added ${blocks.length} proposed blocks to the mock L2 block source`);
|
|
33
89
|
}
|
|
34
90
|
removeBlocks(numBlocks) {
|
|
35
91
|
this.l2Blocks = this.l2Blocks.slice(0, -numBlocks);
|
|
92
|
+
const maxBlockNum = this.l2Blocks.length;
|
|
93
|
+
// Remove any checkpoint whose last block is beyond the remaining blocks.
|
|
94
|
+
this.checkpointList = this.checkpointList.filter((c)=>{
|
|
95
|
+
const lastBlockNum = c.blocks[0].number + c.blocks.length - 1;
|
|
96
|
+
return lastBlockNum <= maxBlockNum;
|
|
97
|
+
});
|
|
98
|
+
// Keep tip numbers consistent with remaining blocks.
|
|
99
|
+
this.checkpointedBlockNumber = Math.min(this.checkpointedBlockNumber, maxBlockNum);
|
|
100
|
+
this.provenBlockNumber = Math.min(this.provenBlockNumber, maxBlockNum);
|
|
101
|
+
this.finalizedBlockNumber = Math.min(this.finalizedBlockNumber, maxBlockNum);
|
|
36
102
|
this.log.verbose(`Removed ${numBlocks} blocks from the mock L2 block source`);
|
|
37
103
|
}
|
|
38
104
|
setProvenBlockNumber(provenBlockNumber) {
|
|
@@ -45,7 +111,32 @@ import { TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
|
45
111
|
this.finalizedBlockNumber = finalizedBlockNumber;
|
|
46
112
|
}
|
|
47
113
|
setCheckpointedBlockNumber(checkpointedBlockNumber) {
|
|
114
|
+
const prevCheckpointed = this.checkpointedBlockNumber;
|
|
48
115
|
this.checkpointedBlockNumber = checkpointedBlockNumber;
|
|
116
|
+
// Auto-create single-block checkpoints for newly checkpointed blocks that don't have one yet.
|
|
117
|
+
// This handles blocks added via addProposedBlocks that are now being marked as checkpointed.
|
|
118
|
+
const newCheckpoints = [];
|
|
119
|
+
for(let blockNum = prevCheckpointed + 1; blockNum <= checkpointedBlockNumber; blockNum++){
|
|
120
|
+
const block = this.l2Blocks[blockNum - 1];
|
|
121
|
+
if (!block) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (this.checkpointList.some((c)=>c.blocks.some((b)=>b.number === block.number))) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
const checkpointNum = CheckpointNumber(this.checkpointList.length + newCheckpoints.length + 1);
|
|
128
|
+
const checkpoint = new Checkpoint(block.archive, CheckpointHeader.random({
|
|
129
|
+
slotNumber: block.header.globalVariables.slotNumber
|
|
130
|
+
}), [
|
|
131
|
+
block
|
|
132
|
+
], checkpointNum);
|
|
133
|
+
newCheckpoints.push(checkpoint);
|
|
134
|
+
}
|
|
135
|
+
// Insert new checkpoints in order by number.
|
|
136
|
+
if (newCheckpoints.length > 0) {
|
|
137
|
+
this.checkpointList.push(...newCheckpoints);
|
|
138
|
+
this.checkpointList.sort((a, b)=>a.number - b.number);
|
|
139
|
+
}
|
|
49
140
|
}
|
|
50
141
|
/**
|
|
51
142
|
* Method to fetch the rollup contract address at the base-layer.
|
|
@@ -59,201 +150,95 @@ import { TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
|
59
150
|
*/ getRegistryAddress() {
|
|
60
151
|
return Promise.resolve(EthAddress.random());
|
|
61
152
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
*/ getBlockNumber() {
|
|
66
|
-
return Promise.resolve(BlockNumber(this.l2Blocks.length));
|
|
67
|
-
}
|
|
68
|
-
getProvenBlockNumber() {
|
|
69
|
-
return Promise.resolve(BlockNumber(this.provenBlockNumber));
|
|
70
|
-
}
|
|
71
|
-
getCheckpointedBlock(number) {
|
|
72
|
-
if (number > this.checkpointedBlockNumber) {
|
|
73
|
-
return Promise.resolve(undefined);
|
|
153
|
+
async getBlockNumber(query) {
|
|
154
|
+
if (!query) {
|
|
155
|
+
return BlockNumber(this.l2Blocks.length);
|
|
74
156
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return Promise.resolve(undefined);
|
|
157
|
+
if ('number' in query) {
|
|
158
|
+
return query.number;
|
|
78
159
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
async getCheckpointedBlocks(from, limit, _proven) {
|
|
83
|
-
const result = [];
|
|
84
|
-
for(let i = 0; i < limit; i++){
|
|
85
|
-
const blockNum = from + i;
|
|
86
|
-
if (blockNum > this.checkpointedBlockNumber) {
|
|
87
|
-
break;
|
|
88
|
-
}
|
|
89
|
-
const block = await this.getCheckpointedBlock(BlockNumber(blockNum));
|
|
90
|
-
if (block) {
|
|
91
|
-
result.push(block);
|
|
92
|
-
}
|
|
160
|
+
if ('tag' in query) {
|
|
161
|
+
return BlockNumber(this.resolveBlockTag(query.tag));
|
|
93
162
|
}
|
|
94
|
-
|
|
163
|
+
const block = await this.getBlock(query);
|
|
164
|
+
return block ? block.header.globalVariables.blockNumber : undefined;
|
|
95
165
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
return Promise.resolve(block);
|
|
166
|
+
getCheckpoint(query) {
|
|
167
|
+
const checkpoint = this.resolveCheckpointQuery(query);
|
|
168
|
+
if (!checkpoint) {
|
|
169
|
+
return Promise.resolve(undefined);
|
|
170
|
+
}
|
|
171
|
+
return Promise.resolve(new PublishedCheckpoint(checkpoint, this.mockL1DataForCheckpoint(checkpoint), []));
|
|
103
172
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
* @returns The requested L2 block.
|
|
108
|
-
*/ getL2BlockNew(number) {
|
|
109
|
-
const block = this.l2Blocks[number - 1];
|
|
110
|
-
return Promise.resolve(block);
|
|
173
|
+
getCheckpoints(query) {
|
|
174
|
+
const checkpoints = this.resolveCheckpointsQuery(query);
|
|
175
|
+
return Promise.resolve(checkpoints.map((checkpoint)=>new PublishedCheckpoint(checkpoint, this.mockL1DataForCheckpoint(checkpoint), [])));
|
|
111
176
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
* @param limit - The maximum number of blocks to return.
|
|
116
|
-
* @returns The requested mocked L2 blocks.
|
|
117
|
-
*/ getBlocks(from, limit, proven) {
|
|
118
|
-
return Promise.resolve(this.l2Blocks.slice(from - 1, from - 1 + limit).filter((b)=>!proven || this.provenBlockNumber === undefined || b.number <= this.provenBlockNumber));
|
|
119
|
-
}
|
|
120
|
-
getPublishedCheckpoints(from, limit) {
|
|
121
|
-
// TODO(mbps): Implement this properly. This only works when we have one block per checkpoint.
|
|
122
|
-
const blocks = this.l2Blocks.slice(from - 1, from - 1 + limit);
|
|
123
|
-
return Promise.all(blocks.map(async (block)=>{
|
|
124
|
-
// Create a checkpoint from the block - manually construct since L2BlockNew doesn't have toCheckpoint()
|
|
125
|
-
const checkpoint = await Checkpoint.random(block.checkpointNumber, {
|
|
126
|
-
numBlocks: 1
|
|
127
|
-
});
|
|
128
|
-
checkpoint.blocks = [
|
|
129
|
-
block
|
|
130
|
-
];
|
|
131
|
-
return new PublishedCheckpoint(checkpoint, new L1PublishedData(BigInt(block.number), BigInt(block.number), Buffer32.random().toString()), []);
|
|
132
|
-
}));
|
|
177
|
+
getCheckpointByArchive(archive) {
|
|
178
|
+
const checkpoint = this.checkpointList.find((c)=>c.archive.root.equals(archive));
|
|
179
|
+
return Promise.resolve(checkpoint);
|
|
133
180
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
return undefined;
|
|
181
|
+
getCheckpointData(query) {
|
|
182
|
+
const checkpoint = this.resolveCheckpointQuery(query);
|
|
183
|
+
if (!checkpoint) {
|
|
184
|
+
return Promise.resolve(undefined);
|
|
139
185
|
}
|
|
140
|
-
|
|
141
|
-
const checkpoint = await Checkpoint.random(block.checkpointNumber, {
|
|
142
|
-
numBlocks: 1
|
|
143
|
-
});
|
|
144
|
-
checkpoint.blocks = [
|
|
145
|
-
block
|
|
146
|
-
];
|
|
147
|
-
return checkpoint;
|
|
148
|
-
}
|
|
149
|
-
getPublishedBlocks(from, limit, proven) {
|
|
150
|
-
const blocks = this.l2Blocks.slice(from - 1, from - 1 + limit).filter((b)=>!proven || this.provenBlockNumber === undefined || b.number <= this.provenBlockNumber);
|
|
151
|
-
return Promise.resolve(blocks.map((block)=>CheckpointedL2Block.fromFields({
|
|
152
|
-
checkpointNumber: CheckpointNumber(block.number),
|
|
153
|
-
block,
|
|
154
|
-
l1: new L1PublishedData(BigInt(block.number), BigInt(block.number), Buffer32.random().toString()),
|
|
155
|
-
attestations: []
|
|
156
|
-
})));
|
|
186
|
+
return Promise.resolve(this.checkpointToData(checkpoint));
|
|
157
187
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
return this.
|
|
161
|
-
}
|
|
162
|
-
async getPublishedBlockByHash(blockHash) {
|
|
163
|
-
for (const block of this.l2Blocks){
|
|
164
|
-
const hash = await block.hash();
|
|
165
|
-
if (hash.equals(blockHash)) {
|
|
166
|
-
return CheckpointedL2Block.fromFields({
|
|
167
|
-
checkpointNumber: CheckpointNumber(block.number),
|
|
168
|
-
block,
|
|
169
|
-
l1: new L1PublishedData(BigInt(block.number), BigInt(block.number), Buffer32.random().toString()),
|
|
170
|
-
attestations: []
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
return undefined;
|
|
188
|
+
getCheckpointsData(query) {
|
|
189
|
+
const checkpoints = this.resolveCheckpointsQuery(query);
|
|
190
|
+
return Promise.resolve(checkpoints.map((c)=>this.checkpointToData(c)));
|
|
175
191
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
192
|
+
checkpointToData(checkpoint) {
|
|
193
|
+
return {
|
|
194
|
+
checkpointNumber: checkpoint.number,
|
|
195
|
+
header: checkpoint.header,
|
|
196
|
+
archive: checkpoint.archive,
|
|
197
|
+
checkpointOutHash: computeCheckpointOutHash(checkpoint.blocks.map((b)=>b.body.txEffects.map((tx)=>tx.l2ToL1Msgs))),
|
|
198
|
+
startBlock: checkpoint.blocks[0].number,
|
|
199
|
+
blockCount: checkpoint.blocks.length,
|
|
200
|
+
feeAssetPriceModifier: checkpoint.feeAssetPriceModifier,
|
|
201
|
+
attestations: [],
|
|
202
|
+
l1: this.mockL1DataForCheckpoint(checkpoint)
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
resolveCheckpointQuery(query) {
|
|
206
|
+
if ('number' in query) {
|
|
207
|
+
return this.checkpointList[query.number - 1];
|
|
180
208
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
block,
|
|
184
|
-
l1: new L1PublishedData(BigInt(block.number), BigInt(block.number), Buffer32.random().toString()),
|
|
185
|
-
attestations: []
|
|
186
|
-
}));
|
|
187
|
-
}
|
|
188
|
-
async getL2BlockNewByHash(blockHash) {
|
|
189
|
-
for (const block of this.l2Blocks){
|
|
190
|
-
const hash = await block.hash();
|
|
191
|
-
if (hash.equals(blockHash)) {
|
|
192
|
-
return block;
|
|
193
|
-
}
|
|
209
|
+
if ('slot' in query) {
|
|
210
|
+
return this.checkpointList.find((c)=>c.header.slotNumber === query.slot);
|
|
194
211
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
212
|
+
switch(query.tag){
|
|
213
|
+
case 'checkpointed':
|
|
214
|
+
return this.checkpointList[this.checkpointList.length - 1];
|
|
215
|
+
case 'proven':
|
|
216
|
+
{
|
|
217
|
+
const provenCheckpoint = this.checkpointList.filter((c)=>c.blocks.some((b)=>b.number <= this.provenBlockNumber));
|
|
218
|
+
return provenCheckpoint.at(-1);
|
|
219
|
+
}
|
|
220
|
+
case 'finalized':
|
|
221
|
+
{
|
|
222
|
+
const finalizedCheckpoint = this.checkpointList.filter((c)=>c.blocks.some((b)=>b.number <= this.finalizedBlockNumber));
|
|
223
|
+
return finalizedCheckpoint.at(-1);
|
|
224
|
+
}
|
|
207
225
|
}
|
|
208
|
-
return undefined;
|
|
209
|
-
}
|
|
210
|
-
getBlockHeaderByArchive(archive) {
|
|
211
|
-
const block = this.l2Blocks.find((b)=>b.archive.root.equals(archive));
|
|
212
|
-
return Promise.resolve(block?.header);
|
|
213
|
-
}
|
|
214
|
-
getBlockHeader(number) {
|
|
215
|
-
return Promise.resolve(this.l2Blocks.at(typeof number === 'number' ? number - 1 : -1)?.header);
|
|
216
|
-
}
|
|
217
|
-
getCheckpointsForEpoch(epochNumber) {
|
|
218
|
-
// TODO(mbps): Implement this properly. This only works when we have one block per checkpoint.
|
|
219
|
-
const epochDuration = DefaultL1ContractsConfig.aztecEpochDuration;
|
|
220
|
-
const [start, end] = getSlotRangeForEpoch(epochNumber, {
|
|
221
|
-
epochDuration
|
|
222
|
-
});
|
|
223
|
-
const blocks = this.l2Blocks.filter((b)=>{
|
|
224
|
-
const slot = b.header.globalVariables.slotNumber;
|
|
225
|
-
return slot >= start && slot <= end;
|
|
226
|
-
});
|
|
227
|
-
// Create checkpoints from blocks - manually construct since L2BlockNew doesn't have toCheckpoint()
|
|
228
|
-
return Promise.all(blocks.map(async (block)=>{
|
|
229
|
-
const checkpoint = await Checkpoint.random(block.checkpointNumber, {
|
|
230
|
-
numBlocks: 1
|
|
231
|
-
});
|
|
232
|
-
checkpoint.blocks = [
|
|
233
|
-
block
|
|
234
|
-
];
|
|
235
|
-
return checkpoint;
|
|
236
|
-
}));
|
|
237
226
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
const
|
|
245
|
-
return
|
|
246
|
-
}
|
|
247
|
-
return
|
|
227
|
+
resolveCheckpointsQuery(query) {
|
|
228
|
+
if ('from' in query) {
|
|
229
|
+
return this.checkpointList.slice(query.from - 1, query.from - 1 + query.limit);
|
|
230
|
+
}
|
|
231
|
+
if ('fromSlot' in query) {
|
|
232
|
+
const matching = this.checkpointList.filter((c)=>query.reverse ? c.header.slotNumber <= query.fromSlot : c.header.slotNumber >= query.fromSlot);
|
|
233
|
+
const nearestFirst = query.reverse ? matching.reverse() : matching;
|
|
234
|
+
return nearestFirst.slice(0, query.limit);
|
|
235
|
+
}
|
|
236
|
+
return this.getCheckpointsInEpoch(query.epoch);
|
|
248
237
|
}
|
|
249
238
|
getBlocksForSlot(slotNumber) {
|
|
250
239
|
const blocks = this.l2Blocks.filter((b)=>b.header.globalVariables.slotNumber === slotNumber);
|
|
251
240
|
return Promise.resolve(blocks);
|
|
252
241
|
}
|
|
253
|
-
async getBlockHeadersForEpoch(epochNumber) {
|
|
254
|
-
const blocks = await this.getBlocksForEpoch(epochNumber);
|
|
255
|
-
return blocks.map((b)=>b.header);
|
|
256
|
-
}
|
|
257
242
|
/**
|
|
258
243
|
* Gets a tx effect.
|
|
259
244
|
* @param txHash - The hash of the tx corresponding to the tx effect.
|
|
@@ -270,28 +255,19 @@ import { TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
|
270
255
|
return {
|
|
271
256
|
data: txEffect,
|
|
272
257
|
l2BlockNumber: block.number,
|
|
273
|
-
l2BlockHash:
|
|
274
|
-
txIndexInBlock: block.body.txEffects.
|
|
258
|
+
l2BlockHash: await block.hash(),
|
|
259
|
+
txIndexInBlock: block.body.txEffects.findIndex((t)=>t.txHash.equals(txHash)),
|
|
260
|
+
slotNumber: block.header.globalVariables.slotNumber
|
|
275
261
|
};
|
|
276
262
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
* @returns The requested tx receipt (or undefined if not found).
|
|
281
|
-
*/ async getSettledTxReceipt(txHash) {
|
|
282
|
-
for (const block of this.l2Blocks){
|
|
283
|
-
for (const txEffect of block.body.txEffects){
|
|
284
|
-
if (txEffect.txHash.equals(txHash)) {
|
|
285
|
-
return new TxReceipt(txHash, TxStatus.SUCCESS, '', txEffect.transactionFee.toBigInt(), L2BlockHash.fromField(await block.hash()), block.number);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
return undefined;
|
|
263
|
+
getL2ToL1MembershipWitness() {
|
|
264
|
+
// Mock does not back the L2-to-L1 message witness flow.
|
|
265
|
+
return Promise.resolve(undefined);
|
|
290
266
|
}
|
|
291
267
|
async getL2Tips() {
|
|
292
268
|
const [latest, proven, finalized, checkpointed] = [
|
|
293
269
|
await this.getBlockNumber(),
|
|
294
|
-
|
|
270
|
+
this.provenBlockNumber,
|
|
295
271
|
this.finalizedBlockNumber,
|
|
296
272
|
this.checkpointedBlockNumber
|
|
297
273
|
];
|
|
@@ -299,29 +275,45 @@ import { TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
|
299
275
|
const provenBlock = this.l2Blocks[proven - 1];
|
|
300
276
|
const finalizedBlock = this.l2Blocks[finalized - 1];
|
|
301
277
|
const checkpointedBlock = this.l2Blocks[checkpointed - 1];
|
|
278
|
+
// For genesis tips (block number 0) report the dynamic initial header hash so consumers
|
|
279
|
+
// running L2BlockStream against this mock agree at block 0 with their local tip store.
|
|
280
|
+
const genesisHash = (await this.initialHeader.hash()).toString();
|
|
281
|
+
const tipHash = async (block, number)=>{
|
|
282
|
+
if (block) {
|
|
283
|
+
return (await block.hash()).toString();
|
|
284
|
+
}
|
|
285
|
+
return number === 0 ? genesisHash : '';
|
|
286
|
+
};
|
|
302
287
|
const latestBlockId = {
|
|
303
288
|
number: BlockNumber(latest),
|
|
304
|
-
hash:
|
|
289
|
+
hash: await tipHash(latestBlock, latest)
|
|
305
290
|
};
|
|
306
291
|
const provenBlockId = {
|
|
307
292
|
number: BlockNumber(proven),
|
|
308
|
-
hash:
|
|
293
|
+
hash: await tipHash(provenBlock, proven)
|
|
309
294
|
};
|
|
310
295
|
const finalizedBlockId = {
|
|
311
296
|
number: BlockNumber(finalized),
|
|
312
|
-
hash:
|
|
297
|
+
hash: await tipHash(finalizedBlock, finalized)
|
|
313
298
|
};
|
|
314
299
|
const checkpointedBlockId = {
|
|
315
300
|
number: BlockNumber(checkpointed),
|
|
316
|
-
hash:
|
|
301
|
+
hash: await tipHash(checkpointedBlock, checkpointed)
|
|
317
302
|
};
|
|
318
|
-
const makeTipId = (blockId)=>
|
|
303
|
+
const makeTipId = (blockId)=>{
|
|
304
|
+
const checkpointNumber = this.findCheckpointNumberForBlock(blockId.number) ?? CheckpointNumber(0);
|
|
305
|
+
// Match production semantics: checkpoint 0 is fully synthetic (no real checkpoint header
|
|
306
|
+
// exists at 0), so its hash stays at the protocol constant `GENESIS_CHECKPOINT_HEADER_HASH`
|
|
307
|
+
// even though the block-0 hash is dynamic. See L2TipsCache for the production path.
|
|
308
|
+
const hash = checkpointNumber === 0 ? GENESIS_CHECKPOINT_HEADER_HASH.toString() : blockId.hash;
|
|
309
|
+
return {
|
|
319
310
|
block: blockId,
|
|
320
311
|
checkpoint: {
|
|
321
|
-
number:
|
|
322
|
-
hash
|
|
312
|
+
number: checkpointNumber,
|
|
313
|
+
hash
|
|
323
314
|
}
|
|
324
|
-
}
|
|
315
|
+
};
|
|
316
|
+
};
|
|
325
317
|
return {
|
|
326
318
|
proposed: latestBlockId,
|
|
327
319
|
checkpointed: makeTipId(checkpointedBlockId),
|
|
@@ -329,10 +321,10 @@ import { TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
|
329
321
|
finalized: makeTipId(finalizedBlockId)
|
|
330
322
|
};
|
|
331
323
|
}
|
|
332
|
-
|
|
324
|
+
getSyncedL2EpochNumber() {
|
|
333
325
|
throw new Error('Method not implemented.');
|
|
334
326
|
}
|
|
335
|
-
|
|
327
|
+
getSyncedL2SlotNumber() {
|
|
336
328
|
throw new Error('Method not implemented.');
|
|
337
329
|
}
|
|
338
330
|
isEpochComplete(_epochNumber) {
|
|
@@ -341,9 +333,12 @@ import { TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
|
341
333
|
getL1Constants() {
|
|
342
334
|
return Promise.resolve(EmptyL1RollupConstants);
|
|
343
335
|
}
|
|
336
|
+
isPruneDueAtSlot(_slot) {
|
|
337
|
+
return Promise.resolve(false);
|
|
338
|
+
}
|
|
344
339
|
getGenesisValues() {
|
|
345
340
|
return Promise.resolve({
|
|
346
|
-
genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT)
|
|
341
|
+
genesisArchiveRoot: this.genesisArchiveRoot ?? new Fr(GENESIS_ARCHIVE_ROOT)
|
|
347
342
|
});
|
|
348
343
|
}
|
|
349
344
|
getL1Timestamp() {
|
|
@@ -384,6 +379,88 @@ import { TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
|
384
379
|
syncImmediate() {
|
|
385
380
|
return Promise.resolve();
|
|
386
381
|
}
|
|
382
|
+
async getBlock(query) {
|
|
383
|
+
if ('number' in query) {
|
|
384
|
+
if (query.number === 0) {
|
|
385
|
+
return this.getGenesisBlock();
|
|
386
|
+
}
|
|
387
|
+
return this.l2Blocks[query.number - 1];
|
|
388
|
+
}
|
|
389
|
+
if ('hash' in query) {
|
|
390
|
+
const genesis = this.getGenesisBlock();
|
|
391
|
+
if ((await genesis.hash()).equals(query.hash)) {
|
|
392
|
+
return genesis;
|
|
393
|
+
}
|
|
394
|
+
for (const b of this.l2Blocks){
|
|
395
|
+
const hash = await b.hash();
|
|
396
|
+
if (hash.equals(query.hash)) {
|
|
397
|
+
return b;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return undefined;
|
|
401
|
+
}
|
|
402
|
+
if ('archive' in query) {
|
|
403
|
+
const genesis = this.getGenesisBlock();
|
|
404
|
+
if (genesis.archive.root.equals(query.archive)) {
|
|
405
|
+
return genesis;
|
|
406
|
+
}
|
|
407
|
+
return this.l2Blocks.find((b)=>b.archive.root.equals(query.archive));
|
|
408
|
+
}
|
|
409
|
+
const number = this.resolveBlockTag(query.tag);
|
|
410
|
+
if (number === 0) {
|
|
411
|
+
return this.getGenesisBlock();
|
|
412
|
+
}
|
|
413
|
+
return this.l2Blocks[number - 1];
|
|
414
|
+
}
|
|
415
|
+
resolveBlockTag(tag) {
|
|
416
|
+
switch(tag){
|
|
417
|
+
case 'latest':
|
|
418
|
+
case 'proposed':
|
|
419
|
+
return this.l2Blocks.length;
|
|
420
|
+
case 'checkpointed':
|
|
421
|
+
return this.checkpointedBlockNumber;
|
|
422
|
+
case 'proven':
|
|
423
|
+
return this.provenBlockNumber;
|
|
424
|
+
case 'finalized':
|
|
425
|
+
return this.finalizedBlockNumber;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
getBlocks(query) {
|
|
429
|
+
let blocks;
|
|
430
|
+
if ('from' in query) {
|
|
431
|
+
blocks = this.l2Blocks.slice(query.from - 1, query.from - 1 + query.limit);
|
|
432
|
+
} else {
|
|
433
|
+
const epochCheckpoints = this.getCheckpointsInEpoch(query.epoch);
|
|
434
|
+
blocks = epochCheckpoints.flatMap((c)=>c.blocks);
|
|
435
|
+
}
|
|
436
|
+
if (query.onlyCheckpointed) {
|
|
437
|
+
blocks = blocks.filter((b)=>b.header.globalVariables.blockNumber <= this.checkpointedBlockNumber);
|
|
438
|
+
}
|
|
439
|
+
return Promise.resolve(blocks);
|
|
440
|
+
}
|
|
441
|
+
async getBlockData(query) {
|
|
442
|
+
const block = await this.getBlock(query);
|
|
443
|
+
if (!block) {
|
|
444
|
+
return undefined;
|
|
445
|
+
}
|
|
446
|
+
return {
|
|
447
|
+
header: block.header,
|
|
448
|
+
archive: block.archive,
|
|
449
|
+
blockHash: await block.hash(),
|
|
450
|
+
checkpointNumber: block.checkpointNumber,
|
|
451
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
async getBlocksData(query) {
|
|
455
|
+
const blocks = await this.getBlocks(query);
|
|
456
|
+
return Promise.all(blocks.map(async (block)=>({
|
|
457
|
+
header: block.header,
|
|
458
|
+
archive: block.archive,
|
|
459
|
+
blockHash: await block.hash(),
|
|
460
|
+
checkpointNumber: block.checkpointNumber,
|
|
461
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint
|
|
462
|
+
})));
|
|
463
|
+
}
|
|
387
464
|
isPendingChainInvalid() {
|
|
388
465
|
return Promise.resolve(false);
|
|
389
466
|
}
|
|
@@ -392,4 +469,21 @@ import { TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
|
392
469
|
valid: true
|
|
393
470
|
});
|
|
394
471
|
}
|
|
472
|
+
getProposedCheckpointData(_query) {
|
|
473
|
+
return Promise.resolve(undefined);
|
|
474
|
+
}
|
|
475
|
+
/** Returns checkpoints whose slot falls within the given epoch. */ getCheckpointsInEpoch(epochNumber) {
|
|
476
|
+
const epochDuration = DefaultL1ContractsConfig.aztecEpochDuration;
|
|
477
|
+
const [start, end] = getSlotRangeForEpoch(epochNumber, {
|
|
478
|
+
epochDuration
|
|
479
|
+
});
|
|
480
|
+
return this.checkpointList.filter((c)=>c.header.slotNumber >= start && c.header.slotNumber <= end);
|
|
481
|
+
}
|
|
482
|
+
/** Creates a mock L1PublishedData for a checkpoint. */ mockL1DataForCheckpoint(checkpoint) {
|
|
483
|
+
return new L1PublishedData(BigInt(checkpoint.number), BigInt(checkpoint.number), Buffer32.random().toString());
|
|
484
|
+
}
|
|
485
|
+
/** Finds the checkpoint number for a block, or undefined if the block is not in any checkpoint. */ findCheckpointNumberForBlock(blockNumber) {
|
|
486
|
+
const checkpoint = this.checkpointList.find((c)=>c.blocks.some((b)=>b.number === blockNumber));
|
|
487
|
+
return checkpoint?.number;
|
|
488
|
+
}
|
|
395
489
|
}
|