@aztec/world-state 3.0.0-nightly.20251205 → 3.0.0-nightly.20251206
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/native/native_world_state.d.ts +3 -3
- package/dest/native/native_world_state.d.ts.map +1 -1
- package/dest/native/native_world_state.js +7 -5
- package/dest/synchronizer/server_world_state_synchronizer.d.ts +1 -9
- package/dest/synchronizer/server_world_state_synchronizer.d.ts.map +1 -1
- package/dest/synchronizer/server_world_state_synchronizer.js +11 -29
- package/dest/synchronizer/utils.d.ts +11 -0
- package/dest/synchronizer/utils.d.ts.map +1 -0
- package/dest/synchronizer/utils.js +59 -0
- package/dest/test/utils.d.ts +19 -7
- package/dest/test/utils.d.ts.map +1 -1
- package/dest/test/utils.js +49 -9
- package/dest/world-state-db/merkle_tree_db.d.ts +5 -5
- package/dest/world-state-db/merkle_tree_db.d.ts.map +1 -1
- package/package.json +10 -10
- package/src/native/native_world_state.ts +15 -9
- package/src/synchronizer/server_world_state_synchronizer.ts +18 -41
- package/src/synchronizer/utils.ts +83 -0
- package/src/test/utils.ts +55 -16
- package/src/world-state-db/merkle_tree_db.ts +5 -5
|
@@ -2,7 +2,7 @@ import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
|
2
2
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
3
|
import { Fr } from '@aztec/foundation/fields';
|
|
4
4
|
import { type Logger } from '@aztec/foundation/log';
|
|
5
|
-
import type {
|
|
5
|
+
import type { L2BlockNew } from '@aztec/stdlib/block';
|
|
6
6
|
import type { IndexedTreeId, MerkleTreeReadOperations, MerkleTreeWriteOperations } from '@aztec/stdlib/interfaces/server';
|
|
7
7
|
import type { SnapshotDataKeys } from '@aztec/stdlib/snapshots';
|
|
8
8
|
import { type NullifierLeafPreimage, PublicDataTreeLeaf } from '@aztec/stdlib/trees';
|
|
@@ -30,7 +30,7 @@ export declare class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
30
30
|
getSnapshot(blockNumber: BlockNumber): MerkleTreeReadOperations;
|
|
31
31
|
fork(blockNumber?: BlockNumber): Promise<MerkleTreeWriteOperations>;
|
|
32
32
|
getInitialHeader(): BlockHeader;
|
|
33
|
-
handleL2BlockAndMessages(l2Block:
|
|
33
|
+
handleL2BlockAndMessages(l2Block: L2BlockNew, l1ToL2Messages: Fr[], isFirstBlock: boolean): Promise<WorldStateStatusFull>;
|
|
34
34
|
close(): Promise<void>;
|
|
35
35
|
private buildInitialHeader;
|
|
36
36
|
private sanitizeAndCacheSummaryFromFull;
|
|
@@ -60,4 +60,4 @@ export declare class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
60
60
|
backupTo(dstPath: string, compact?: boolean): Promise<Record<Exclude<SnapshotDataKeys, 'archiver'>, string>>;
|
|
61
61
|
}
|
|
62
62
|
export declare const NATIVE_WORLD_STATE_DBS: readonly [readonly ["l1-to-l2-message-tree", "L1ToL2MessageTree"], readonly ["archive-tree", "ArchiveTree"], readonly ["public-data-tree", "PublicDataTree"], readonly ["note-hash-tree", "NoteHashTree"], readonly ["nullifier-tree", "NullifierTree"]];
|
|
63
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
63
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmF0aXZlX3dvcmxkX3N0YXRlLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbmF0aXZlL25hdGl2ZV93b3JsZF9zdGF0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFFOUQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQzNELE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUU5QyxPQUFPLEVBQUUsS0FBSyxNQUFNLEVBQWdCLE1BQU0sdUJBQXVCLENBQUM7QUFDbEUsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFdEQsT0FBTyxLQUFLLEVBQ1YsYUFBYSxFQUNiLHdCQUF3QixFQUN4Qix5QkFBeUIsRUFDMUIsTUFBTSxpQ0FBaUMsQ0FBQztBQUN6QyxPQUFPLEtBQUssRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ2hFLE9BQU8sRUFBK0IsS0FBSyxxQkFBcUIsRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ2xILE9BQU8sRUFBRSxXQUFXLEVBQXlDLE1BQU0sa0JBQWtCLENBQUM7QUFTdEYsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sdUNBQXVDLENBQUM7QUFDbEYsT0FBTyxLQUFLLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUN6RSxPQUFPLEtBQUssRUFBRSx1QkFBdUIsSUFBSSxrQkFBa0IsRUFBRSxNQUFNLHFDQUFxQyxDQUFDO0FBRXpHLE9BQU8sRUFFTCxLQUFLLG9CQUFvQixFQUN6QixLQUFLLHVCQUF1QixFQUs3QixNQUFNLGNBQWMsQ0FBQztBQUN0QixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQztBQUlwRSxlQUFPLE1BQU0sc0JBQXNCLElBQUksQ0FBQztBQUV4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
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native_world_state.d.ts","sourceRoot":"","sources":["../../src/native/native_world_state.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAE9D,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAE9C,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAClE,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"native_world_state.d.ts","sourceRoot":"","sources":["../../src/native/native_world_state.ts"],"names":[],"mappings":"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"}
|
|
@@ -127,12 +127,14 @@ export class NativeWorldStateService {
|
|
|
127
127
|
getInitialHeader() {
|
|
128
128
|
return this.initialHeader;
|
|
129
129
|
}
|
|
130
|
-
async handleL2BlockAndMessages(l2Block, l1ToL2Messages,
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
130
|
+
async handleL2BlockAndMessages(l2Block, l1ToL2Messages, isFirstBlock) {
|
|
131
|
+
if (!isFirstBlock && l1ToL2Messages.length > 0) {
|
|
132
|
+
throw new Error(`L1 to L2 messages must be empty for non-first blocks, but got ${l1ToL2Messages.length} messages for block ${l2Block.number}.`);
|
|
133
|
+
}
|
|
134
|
+
// We have to pad the given l1 to l2 messages, and the note hashes and nullifiers within tx effects, because that's
|
|
135
|
+
// how the trees are built by circuits.
|
|
135
136
|
const paddedL1ToL2Messages = isFirstBlock ? padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP) : [];
|
|
137
|
+
const paddedNoteHashes = l2Block.body.txEffects.flatMap((txEffect)=>padArrayEnd(txEffect.noteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX));
|
|
136
138
|
const paddedNullifiers = l2Block.body.txEffects.flatMap((txEffect)=>padArrayEnd(txEffect.nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX)).map((nullifier)=>new NullifierLeaf(nullifier));
|
|
137
139
|
const publicDataWrites = l2Block.body.txEffects.flatMap((txEffect)=>{
|
|
138
140
|
return txEffect.publicDataWrites.map((write)=>{
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
|
-
import type { Fr } from '@aztec/foundation/fields';
|
|
3
2
|
import { type Logger } from '@aztec/foundation/log';
|
|
4
3
|
import type { L2BlockSource, L2BlockStream, L2BlockStreamEvent, L2BlockStreamEventHandler, L2BlockStreamLocalDataProvider, L2Tips } from '@aztec/stdlib/block';
|
|
5
4
|
import { type WorldStateSynchronizer, type WorldStateSynchronizerStatus } from '@aztec/stdlib/interfaces/server';
|
|
@@ -65,12 +64,5 @@ export declare class ServerWorldStateSynchronizer implements WorldStateSynchroni
|
|
|
65
64
|
* @param newState - New state value.
|
|
66
65
|
*/
|
|
67
66
|
private setCurrentState;
|
|
68
|
-
/**
|
|
69
|
-
* Verifies that the L1 to L2 messages hash to the block inHash.
|
|
70
|
-
* @param l1ToL2Messages - The L1 to L2 messages for the block.
|
|
71
|
-
* @param inHash - The inHash of the block.
|
|
72
|
-
* @throws If the L1 to L2 messages do not hash to the block inHash.
|
|
73
|
-
*/
|
|
74
|
-
protected verifyMessagesHashToInHash(l1ToL2Messages: Fr[], inHash: Fr): Promise<void>;
|
|
75
67
|
}
|
|
76
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
68
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyX3dvcmxkX3N0YXRlX3N5bmNocm9uaXplci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3N5bmNocm9uaXplci9zZXJ2ZXJfd29ybGRfc3RhdGVfc3luY2hyb25pemVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUU5RCxPQUFPLEVBQUUsS0FBSyxNQUFNLEVBQWdCLE1BQU0sdUJBQXVCLENBQUM7QUFHbEUsT0FBTyxLQUFLLEVBR1YsYUFBYSxFQUNiLGFBQWEsRUFDYixrQkFBa0IsRUFDbEIseUJBQXlCLEVBQ3pCLDhCQUE4QixFQUM5QixNQUFNLEVBQ1AsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QixPQUFPLEVBR0wsS0FBSyxzQkFBc0IsRUFDM0IsS0FBSyw0QkFBNEIsRUFDbEMsTUFBTSxpQ0FBaUMsQ0FBQztBQUN6QyxPQUFPLEtBQUssRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ25FLE9BQU8sS0FBSyxFQUFFLGdCQUFnQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFFaEUsT0FBTyxFQUFnQixLQUFLLHdCQUF3QixFQUFFLEtBQUsseUJBQXlCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUdsSCxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSx1Q0FBdUMsQ0FBQztBQUVsRixPQUFPLEtBQUssRUFBRSx1QkFBdUIsRUFBRSxNQUFNLHFDQUFxQyxDQUFDO0FBQ25GLE9BQU8sS0FBSyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sYUFBYSxDQUFDO0FBSXBELFlBQVksRUFBRSxnQkFBZ0IsRUFBRSxDQUFDO0FBRWpDOzs7O0dBSUc7QUFDSCxxQkFBYSw0QkFDWCxZQUFXLHNCQUFzQixFQUFFLDhCQUE4QixFQUFFLHlCQUF5QjtJQWlCMUYsT0FBTyxDQUFDLFFBQVEsQ0FBQyxZQUFZO0lBQzdCLE9BQU8sQ0FBQyxRQUFRLENBQUMsYUFBYTtJQUM5QixPQUFPLENBQUMsUUFBUSxDQUFDLE1BQU07SUFDdkIsT0FBTyxDQUFDLGVBQWU7SUFDdkIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxHQUFHO0lBbkJ0QixPQUFPLENBQUMsUUFBUSxDQUFDLG1CQUFtQixDQUEyQjtJQUUvRCxPQUFPLENBQUMsd0JBQXdCLENBQW9CO0lBQ3BELE9BQU8sQ0FBQyxhQUFhLENBQXFCO0lBQzFDLE9BQU8sQ0FBQyxZQUFZLENBQXVEO0lBQzNFLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBaUY7SUFFN0csT0FBTyxDQUFDLFdBQVcsQ0FBZ0M7SUFDbkQsU0FBUyxDQUFDLFdBQVcsRUFBRSxhQUFhLEdBQUcsU0FBUyxDQUFDO0lBSWpELE9BQU8sQ0FBQyxpQkFBaUIsQ0FBMEI7SUFFbkQsWUFDbUIsWUFBWSxFQUFFLHVCQUF1QixFQUNyQyxhQUFhLEVBQUUsYUFBYSxHQUFHLG1CQUFtQixFQUNsRCxNQUFNLEVBQUUsZ0JBQWdCLEVBQ2pDLGVBQWUsNEJBQXNELEVBQzVELEdBQUcsR0FBRSxNQUFvQyxFQVMzRDtJQUVNLFlBQVksSUFBSSx3QkFBd0IsQ0FFOUM7SUFFTSxXQUFXLENBQUMsV0FBVyxFQUFFLFdBQVcsR0FBRyx3QkFBd0IsQ0FFckU7SUFFTSxJQUFJLENBQUMsV0FBVyxDQUFDLEVBQUUsV0FBVyxHQUFHLE9BQU8sQ0FBQyx5QkFBeUIsQ0FBQyxDQUV6RTtJQUVNLFFBQVEsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLE9BQU8sQ0FBQyxFQUFFLE9BQU8sR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsRUFBRSxVQUFVLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUVsSDtJQUVNLEtBQUssSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLENBRTVCO0lBRVksS0FBSyxtRkFnQ2pCO0lBRUQsU0FBUyxDQUFDLGlCQUFpQixJQUFJLGFBQWEsQ0FRM0M7SUFFWSxJQUFJLGtCQU9oQjtJQUVZLE1BQU0sSUFBSSxPQUFPLENBQUMsNEJBQTRCLENBQUMsQ0FhM0Q7SUFFWSxvQkFBb0IseUJBRWhDO0lBRVksUUFBUSxrQkFJcEI7SUFFTSxVQUFVLFNBT2hCO0lBRUQ7Ozs7O09BS0c7SUFDVSxhQUFhLENBQ3hCLGlCQUFpQixDQUFDLEVBQUUsV0FBVyxFQUMvQiwyQkFBMkIsQ0FBQyxFQUFFLE9BQU8sR0FDcEMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxDQTZDdEI7SUFFRCxvR0FBb0c7SUFDdkYsY0FBYyxDQUFDLE1BQU0sRUFBRSxXQUFXLEdBQUcsT0FBTyxDQUFDLE1BQU0sR0FBRyxTQUFTLENBQUMsQ0FhNUU7SUFFRCxnR0FBZ0c7SUFDbkYsU0FBUyxJQUFJLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FVeEM7SUFFRCxvREFBb0Q7SUFDdkMsc0JBQXNCLENBQUMsS0FBSyxFQUFFLGtCQUFrQixHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FlNUU7WUFPYSxjQUFjO1lBZ0NkLGFBQWE7WUFxQmIsb0JBQW9CO0lBZWxDLE9BQU8sQ0FBQyxpQkFBaUI7WUFNWCxpQkFBaUI7SUFRL0I7OztPQUdHO0lBQ0gsT0FBTyxDQUFDLGVBQWU7Q0FJeEIifQ==
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server_world_state_synchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/server_world_state_synchronizer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server_world_state_synchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/server_world_state_synchronizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import { L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/constants';
|
|
2
1
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
3
|
-
import { SHA256Trunc } from '@aztec/foundation/crypto';
|
|
4
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
5
3
|
import { promiseWithResolvers } from '@aztec/foundation/promise';
|
|
6
4
|
import { elapsed } from '@aztec/foundation/timer';
|
|
7
|
-
import { MerkleTreeCalculator } from '@aztec/foundation/trees';
|
|
8
5
|
import { WorldStateRunningState } from '@aztec/stdlib/interfaces/server';
|
|
9
6
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
10
7
|
import { TraceableL2BlockStream, getTelemetryClient } from '@aztec/telemetry-client';
|
|
11
8
|
import { WorldStateInstrumentation } from '../instrumentation/instrumentation.js';
|
|
12
9
|
import { WorldStateSynchronizerError } from './errors.js';
|
|
10
|
+
import { findFirstBlocksInCheckpoints } from './utils.js';
|
|
13
11
|
/**
|
|
14
12
|
* Synchronizes the world state with the L2 blocks from a L2BlockSource via a block stream.
|
|
15
13
|
* The synchronizer will download the L2 blocks from the L2BlockSource and update the merkle trees.
|
|
@@ -207,7 +205,7 @@ import { WorldStateSynchronizerError } from './errors.js';
|
|
|
207
205
|
/** Handles an event emitted by the block stream. */ async handleBlockStreamEvent(event) {
|
|
208
206
|
switch(event.type){
|
|
209
207
|
case 'blocks-added':
|
|
210
|
-
await this.handleL2Blocks(event.blocks.map((b)=>b.block));
|
|
208
|
+
await this.handleL2Blocks(event.blocks.map((b)=>b.block.toL2Block()));
|
|
211
209
|
break;
|
|
212
210
|
case 'chain-pruned':
|
|
213
211
|
await this.handleChainPruned(BlockNumber(event.block.number));
|
|
@@ -226,18 +224,19 @@ import { WorldStateSynchronizerError } from './errors.js';
|
|
|
226
224
|
* @returns Whether the block handled was produced by this same node.
|
|
227
225
|
*/ async handleL2Blocks(l2Blocks) {
|
|
228
226
|
this.log.trace(`Handling L2 blocks ${l2Blocks[0].number} to ${l2Blocks.at(-1).number}`);
|
|
229
|
-
const
|
|
230
|
-
const l1ToL2Messages = await Promise.all(messagePromises);
|
|
227
|
+
const firstBlocksInCheckpoints = await findFirstBlocksInCheckpoints(l2Blocks, this.l2BlockSource);
|
|
231
228
|
let updateStatus = undefined;
|
|
232
|
-
for(
|
|
233
|
-
const
|
|
234
|
-
|
|
229
|
+
for (const block of l2Blocks){
|
|
230
|
+
const l1ToL2Messages = firstBlocksInCheckpoints.get(block.number) ?? [];
|
|
231
|
+
const isFirstBlock = firstBlocksInCheckpoints.has(block.number);
|
|
232
|
+
const [duration, result] = await elapsed(()=>this.handleL2Block(block, l1ToL2Messages, isFirstBlock));
|
|
233
|
+
this.log.info(`World state updated with L2 block ${block.number}`, {
|
|
235
234
|
eventName: 'l2-block-handled',
|
|
236
235
|
duration,
|
|
237
236
|
unfinalizedBlockNumber: BigInt(result.summary.unfinalizedBlockNumber),
|
|
238
237
|
finalizedBlockNumber: BigInt(result.summary.finalizedBlockNumber),
|
|
239
238
|
oldestHistoricBlock: BigInt(result.summary.oldestHistoricalBlock),
|
|
240
|
-
...
|
|
239
|
+
...block.getStats()
|
|
241
240
|
});
|
|
242
241
|
updateStatus = result;
|
|
243
242
|
}
|
|
@@ -251,19 +250,14 @@ import { WorldStateSynchronizerError } from './errors.js';
|
|
|
251
250
|
* @param l2Block - The L2 block to handle.
|
|
252
251
|
* @param l1ToL2Messages - The L1 to L2 messages for the block.
|
|
253
252
|
* @returns Whether the block handled was produced by this same node.
|
|
254
|
-
*/ async handleL2Block(l2Block, l1ToL2Messages) {
|
|
255
|
-
// First we check that the L1 to L2 messages hash to the block inHash.
|
|
256
|
-
// Note that we cannot optimize this check by checking the root of the subtree after inserting the messages
|
|
257
|
-
// to the real L1_TO_L2_MESSAGE_TREE (like we do in merkleTreeDb.handleL2BlockAndMessages(...)) because that
|
|
258
|
-
// tree uses pedersen and we don't have access to the converted root.
|
|
259
|
-
await this.verifyMessagesHashToInHash(l1ToL2Messages, l2Block.header.contentCommitment.inHash);
|
|
253
|
+
*/ async handleL2Block(l2Block, l1ToL2Messages, isFirstBlock) {
|
|
260
254
|
// If the above check succeeds, we can proceed to handle the block.
|
|
261
255
|
this.log.trace(`Pushing L2 block ${l2Block.number} to merkle tree db `, {
|
|
262
256
|
blockNumber: l2Block.number,
|
|
263
257
|
blockHash: await l2Block.hash().then((h)=>h.toString()),
|
|
264
258
|
l1ToL2Messages: l1ToL2Messages.map((msg)=>msg.toString())
|
|
265
259
|
});
|
|
266
|
-
const result = await this.merkleTreeDb.handleL2BlockAndMessages(l2Block, l1ToL2Messages);
|
|
260
|
+
const result = await this.merkleTreeDb.handleL2BlockAndMessages(l2Block, l1ToL2Messages, isFirstBlock);
|
|
267
261
|
if (this.currentState === WorldStateRunningState.SYNCHING && l2Block.number >= this.latestBlockNumberAtStart) {
|
|
268
262
|
this.setCurrentState(WorldStateRunningState.RUNNING);
|
|
269
263
|
this.syncPromise.resolve();
|
|
@@ -303,16 +297,4 @@ import { WorldStateSynchronizerError } from './errors.js';
|
|
|
303
297
|
this.currentState = newState;
|
|
304
298
|
this.log.debug(`Moved to state ${WorldStateRunningState[this.currentState]}`);
|
|
305
299
|
}
|
|
306
|
-
/**
|
|
307
|
-
* Verifies that the L1 to L2 messages hash to the block inHash.
|
|
308
|
-
* @param l1ToL2Messages - The L1 to L2 messages for the block.
|
|
309
|
-
* @param inHash - The inHash of the block.
|
|
310
|
-
* @throws If the L1 to L2 messages do not hash to the block inHash.
|
|
311
|
-
*/ async verifyMessagesHashToInHash(l1ToL2Messages, inHash) {
|
|
312
|
-
const treeCalculator = await MerkleTreeCalculator.create(L1_TO_L2_MSG_SUBTREE_HEIGHT, Buffer.alloc(32), (lhs, rhs)=>Promise.resolve(new SHA256Trunc().hash(lhs, rhs)));
|
|
313
|
-
const root = await treeCalculator.computeTreeRoot(l1ToL2Messages.map((msg)=>msg.toBuffer()));
|
|
314
|
-
if (!root.equals(inHash.toBuffer())) {
|
|
315
|
-
throw new Error('Obtained L1 to L2 messages failed to be hashed to the block inHash');
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
300
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Fr } from '@aztec/foundation/fields';
|
|
2
|
+
import type { L2BlockNew, L2BlockSource } from '@aztec/stdlib/block';
|
|
3
|
+
import { type L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
4
|
+
/**
|
|
5
|
+
* Determine which blocks in the given array are the first block in a checkpoint.
|
|
6
|
+
* @param blocks - The candidate blocks, sorted by block number in ascending order.
|
|
7
|
+
* @param l2BlockSource - The L2 block source to use to fetch the checkpoints, block headers and L1->L2 messages.
|
|
8
|
+
* @returns A map of block numbers that begin a checkpoint to the L1->L2 messages for that checkpoint.
|
|
9
|
+
*/
|
|
10
|
+
export declare function findFirstBlocksInCheckpoints(blocks: L2BlockNew[], l2BlockSource: L2BlockSource & L1ToL2MessageSource): Promise<Map<number, Fr[]>>;
|
|
11
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zeW5jaHJvbml6ZXIvdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxLQUFLLEVBQUUsRUFBRSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDbkQsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLGFBQWEsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRXJFLE9BQU8sRUFBRSxLQUFLLG1CQUFtQixFQUFtQyxNQUFNLHlCQUF5QixDQUFDO0FBRXBHOzs7OztHQUtHO0FBQ0gsd0JBQXNCLDRCQUE0QixDQUNoRCxNQUFNLEVBQUUsVUFBVSxFQUFFLEVBQ3BCLGFBQWEsRUFBRSxhQUFhLEdBQUcsbUJBQW1CLEdBQ2pELE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FtRTVCIn0=
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/synchronizer/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAErE,OAAO,EAAE,KAAK,mBAAmB,EAAmC,MAAM,yBAAyB,CAAC;AAEpG;;;;;GAKG;AACH,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,UAAU,EAAE,EACpB,aAAa,EAAE,aAAa,GAAG,mBAAmB,GACjD,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,CAmE5B"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
|
+
import { computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
|
|
3
|
+
/**
|
|
4
|
+
* Determine which blocks in the given array are the first block in a checkpoint.
|
|
5
|
+
* @param blocks - The candidate blocks, sorted by block number in ascending order.
|
|
6
|
+
* @param l2BlockSource - The L2 block source to use to fetch the checkpoints, block headers and L1->L2 messages.
|
|
7
|
+
* @returns A map of block numbers that begin a checkpoint to the L1->L2 messages for that checkpoint.
|
|
8
|
+
*/ export async function findFirstBlocksInCheckpoints(blocks, l2BlockSource) {
|
|
9
|
+
// Select the blocks that are the final block within each group of identical slot numbers.
|
|
10
|
+
let seenSlot;
|
|
11
|
+
const maybeLastBlocks = [
|
|
12
|
+
...blocks
|
|
13
|
+
].reverse().filter((b)=>{
|
|
14
|
+
if (b.header.globalVariables.slotNumber !== seenSlot) {
|
|
15
|
+
seenSlot = b.header.globalVariables.slotNumber;
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
return false;
|
|
19
|
+
}).reverse();
|
|
20
|
+
// Try to fetch the checkpoints for those blocks. If undefined (which should only occur for blocks.at(-1)),
|
|
21
|
+
// then the block is not the last one in a checkpoint.
|
|
22
|
+
// If we are not checking the inHashes below, only blocks.at(-1) would need its checkpoint header fetched.
|
|
23
|
+
const checkpointedBlocks = (await Promise.all(maybeLastBlocks.map(async (b)=>({
|
|
24
|
+
blockNumber: b.number,
|
|
25
|
+
// A checkpoint's archive root is the archive root of its last block.
|
|
26
|
+
checkpoint: await l2BlockSource.getCheckpointByArchive(b.archive.root)
|
|
27
|
+
})))).filter((b)=>b.checkpoint !== undefined);
|
|
28
|
+
// Verify that the L1->L2 messages hash to the checkpoint's inHash.
|
|
29
|
+
const checkpointedL1ToL2Messages = await Promise.all(checkpointedBlocks.map((b)=>l2BlockSource.getL1ToL2MessagesForCheckpoint(b.checkpoint.number)));
|
|
30
|
+
checkpointedBlocks.forEach((b, i)=>{
|
|
31
|
+
const computedInHash = computeInHashFromL1ToL2Messages(checkpointedL1ToL2Messages[i]);
|
|
32
|
+
const inHash = b.checkpoint.header.contentCommitment.inHash;
|
|
33
|
+
if (!computedInHash.equals(inHash)) {
|
|
34
|
+
throw new Error('Obtained L1 to L2 messages failed to be hashed to the checkpoint inHash');
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
// Compute the first block numbers, which should be right after each checkpointed block. Exclude blocks that haven't
|
|
38
|
+
// been added yet.
|
|
39
|
+
const firstBlockNumbers = checkpointedBlocks.map((b)=>BlockNumber(b.blockNumber + 1)).filter((n)=>n <= blocks.at(-1).number);
|
|
40
|
+
// Check if blocks[0] is the first block in a checkpoint.
|
|
41
|
+
if (blocks[0].number === 1) {
|
|
42
|
+
firstBlockNumbers.push(blocks[0].number);
|
|
43
|
+
} else {
|
|
44
|
+
const lastBlockHeader = await l2BlockSource.getBlockHeader(BlockNumber(blocks[0].number - 1));
|
|
45
|
+
if (!lastBlockHeader) {
|
|
46
|
+
throw new Error(`Failed to get block ${blocks[0].number - 1}`);
|
|
47
|
+
}
|
|
48
|
+
if (lastBlockHeader.globalVariables.slotNumber !== blocks[0].header.globalVariables.slotNumber) {
|
|
49
|
+
firstBlockNumbers.push(blocks[0].number);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Fetch the L1->L2 messages for the first blocks and assign them to the map.
|
|
53
|
+
const messagesByBlockNumber = new Map();
|
|
54
|
+
await Promise.all(firstBlockNumbers.map(async (blockNumber)=>{
|
|
55
|
+
const l1ToL2Messages = await l2BlockSource.getL1ToL2Messages(blockNumber);
|
|
56
|
+
messagesByBlockNumber.set(blockNumber, l1ToL2Messages);
|
|
57
|
+
}));
|
|
58
|
+
return messagesByBlockNumber;
|
|
59
|
+
}
|
package/dest/test/utils.d.ts
CHANGED
|
@@ -1,20 +1,32 @@
|
|
|
1
|
-
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
1
|
+
import { BlockNumber, type CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
2
2
|
import { Fr } from '@aztec/foundation/fields';
|
|
3
|
-
import {
|
|
3
|
+
import { L2BlockNew } from '@aztec/stdlib/block';
|
|
4
|
+
import { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
4
5
|
import type { MerkleTreeReadOperations, MerkleTreeWriteOperations } from '@aztec/stdlib/interfaces/server';
|
|
5
6
|
import type { NativeWorldStateService } from '../native/native_world_state.js';
|
|
6
|
-
export declare function mockBlock(blockNum: BlockNumber, size: number, fork: MerkleTreeWriteOperations, maxEffects?: number | undefined): Promise<{
|
|
7
|
-
block:
|
|
7
|
+
export declare function mockBlock(blockNum: BlockNumber, size: number, fork: MerkleTreeWriteOperations, maxEffects?: number | undefined, numL1ToL2Messages?: number, isFirstBlock?: boolean): Promise<{
|
|
8
|
+
block: L2BlockNew;
|
|
8
9
|
messages: Fr[];
|
|
9
10
|
}>;
|
|
10
11
|
export declare function mockEmptyBlock(blockNum: BlockNumber, fork: MerkleTreeWriteOperations): Promise<{
|
|
11
|
-
block:
|
|
12
|
+
block: L2BlockNew;
|
|
12
13
|
messages: Fr[];
|
|
13
14
|
}>;
|
|
14
15
|
export declare function mockBlocks(from: BlockNumber, count: number, numTxs: number, worldState: NativeWorldStateService): Promise<{
|
|
15
|
-
blocks:
|
|
16
|
+
blocks: L2BlockNew[];
|
|
16
17
|
messages: Fr[][];
|
|
17
18
|
}>;
|
|
19
|
+
export declare function mockL1ToL2Messages(numL1ToL2Messages: number): Fr[];
|
|
20
|
+
export declare function mockCheckpoint(checkpointNumber: CheckpointNumber, { startBlockNumber, numBlocks, numTxsPerBlock, numL1ToL2Messages, fork }?: {
|
|
21
|
+
startBlockNumber?: BlockNumber;
|
|
22
|
+
numBlocks?: number;
|
|
23
|
+
numTxsPerBlock?: number;
|
|
24
|
+
numL1ToL2Messages?: number;
|
|
25
|
+
fork?: MerkleTreeWriteOperations;
|
|
26
|
+
}): Promise<{
|
|
27
|
+
checkpoint: Checkpoint;
|
|
28
|
+
messages: Fr[];
|
|
29
|
+
}>;
|
|
18
30
|
export declare function assertSameState(forkA: MerkleTreeReadOperations, forkB: MerkleTreeReadOperations): Promise<void>;
|
|
19
31
|
export declare function compareChains(left: MerkleTreeReadOperations, right: MerkleTreeReadOperations): Promise<void>;
|
|
20
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
32
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90ZXN0L3V0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQU1BLE9BQU8sRUFBRSxXQUFXLEVBQUUsS0FBSyxnQkFBZ0IsRUFBYyxNQUFNLGlDQUFpQyxDQUFDO0FBRWpHLE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUM5QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDakQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3RELE9BQU8sS0FBSyxFQUVWLHdCQUF3QixFQUN4Qix5QkFBeUIsRUFDMUIsTUFBTSxpQ0FBaUMsQ0FBQztBQUl6QyxPQUFPLEtBQUssRUFBRSx1QkFBdUIsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRS9FLHdCQUFzQixTQUFTLENBQzdCLFFBQVEsRUFBRSxXQUFXLEVBQ3JCLElBQUksRUFBRSxNQUFNLEVBQ1osSUFBSSxFQUFFLHlCQUF5QixFQUMvQixVQUFVLEdBQUUsTUFBTSxHQUFHLFNBQWdCLEVBQ3JDLGlCQUFpQixHQUFFLE1BQTRDLEVBQy9ELFlBQVksR0FBRSxPQUFjOzs7R0F3RDdCO0FBRUQsd0JBQXNCLGNBQWMsQ0FBQyxRQUFRLEVBQUUsV0FBVyxFQUFFLElBQUksRUFBRSx5QkFBeUI7OztHQWlEMUY7QUFFRCx3QkFBc0IsVUFBVSxDQUM5QixJQUFJLEVBQUUsV0FBVyxFQUNqQixLQUFLLEVBQUUsTUFBTSxFQUNiLE1BQU0sRUFBRSxNQUFNLEVBQ2QsVUFBVSxFQUFFLHVCQUF1Qjs7O0dBZXBDO0FBRUQsd0JBQWdCLGtCQUFrQixDQUFDLGlCQUFpQixFQUFFLE1BQU0sUUFFM0Q7QUFFRCx3QkFBc0IsY0FBYyxDQUNsQyxnQkFBZ0IsRUFBRSxnQkFBZ0IsRUFDbEMsRUFDRSxnQkFBaUMsRUFDakMsU0FBYSxFQUNiLGNBQWtCLEVBQ2xCLGlCQUFxQixFQUNyQixJQUFJLEVBQ0wsR0FBRTtJQUNELGdCQUFnQixDQUFDLEVBQUUsV0FBVyxDQUFDO0lBQy9CLFNBQVMsQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUNuQixjQUFjLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDeEIsaUJBQWlCLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDM0IsSUFBSSxDQUFDLEVBQUUseUJBQXlCLENBQUM7Q0FDN0I7OztHQXFCUDtBQUVELHdCQUFzQixlQUFlLENBQUMsS0FBSyxFQUFFLHdCQUF3QixFQUFFLEtBQUssRUFBRSx3QkFBd0IsaUJBUXJHO0FBRUQsd0JBQXNCLGFBQWEsQ0FBQyxJQUFJLEVBQUUsd0JBQXdCLEVBQUUsS0FBSyxFQUFFLHdCQUF3QixpQkFZbEcifQ==
|
package/dest/test/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/test/utils.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/test/utils.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAc,MAAM,iCAAiC,CAAC;AAEjG,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,KAAK,EAEV,wBAAwB,EACxB,yBAAyB,EAC1B,MAAM,iCAAiC,CAAC;AAIzC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAE/E,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,WAAW,EACrB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,yBAAyB,EAC/B,UAAU,GAAE,MAAM,GAAG,SAAgB,EACrC,iBAAiB,GAAE,MAA4C,EAC/D,YAAY,GAAE,OAAc;;;GAwD7B;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,yBAAyB;;;GAiD1F;AAED,wBAAsB,UAAU,CAC9B,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,uBAAuB;;;GAepC;AAED,wBAAgB,kBAAkB,CAAC,iBAAiB,EAAE,MAAM,QAE3D;AAED,wBAAsB,cAAc,CAClC,gBAAgB,EAAE,gBAAgB,EAClC,EACE,gBAAiC,EACjC,SAAa,EACb,cAAkB,EAClB,iBAAqB,EACrB,IAAI,EACL,GAAE;IACD,gBAAgB,CAAC,EAAE,WAAW,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,IAAI,CAAC,EAAE,yBAAyB,CAAC;CAC7B;;;GAqBP;AAED,wBAAsB,eAAe,CAAC,KAAK,EAAE,wBAAwB,EAAE,KAAK,EAAE,wBAAwB,iBAQrG;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,wBAAwB,EAAE,KAAK,EAAE,wBAAwB,iBAYlG"}
|
package/dest/test/utils.js
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
import { MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, NULLIFIER_SUBTREE_HEIGHT, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
|
|
2
|
-
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
|
+
import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
3
|
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
4
4
|
import { Fr } from '@aztec/foundation/fields';
|
|
5
|
-
import {
|
|
5
|
+
import { L2BlockNew } from '@aztec/stdlib/block';
|
|
6
|
+
import { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
7
|
+
import { computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
|
|
6
8
|
import { AppendOnlyTreeSnapshot, MerkleTreeId } from '@aztec/stdlib/trees';
|
|
7
|
-
export async function mockBlock(blockNum, size, fork, maxEffects = 1000) {
|
|
8
|
-
const l2Block = await
|
|
9
|
-
|
|
9
|
+
export async function mockBlock(blockNum, size, fork, maxEffects = 1000, numL1ToL2Messages = NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, isFirstBlock = true) {
|
|
10
|
+
const l2Block = await L2BlockNew.random(blockNum, {
|
|
11
|
+
txsPerBlock: size,
|
|
12
|
+
txOptions: {
|
|
13
|
+
maxEffects
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
const l1ToL2Messages = mockL1ToL2Messages(numL1ToL2Messages);
|
|
10
17
|
{
|
|
11
18
|
const insertData = async (treeId, data, subTreeHeight, fork)=>{
|
|
12
19
|
for (const dataBatch of data){
|
|
@@ -16,7 +23,7 @@ export async function mockBlock(blockNum, size, fork, maxEffects = 1000) {
|
|
|
16
23
|
const publicDataInsert = insertData(MerkleTreeId.PUBLIC_DATA_TREE, l2Block.body.txEffects.map((txEffect)=>txEffect.publicDataWrites.map((write)=>write.toBuffer())), 0, fork);
|
|
17
24
|
const nullifierInsert = insertData(MerkleTreeId.NULLIFIER_TREE, l2Block.body.txEffects.map((txEffect)=>padArrayEnd(txEffect.nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX).map((nullifier)=>nullifier.toBuffer())), NULLIFIER_SUBTREE_HEIGHT, fork);
|
|
18
25
|
const noteHashesPadded = l2Block.body.txEffects.flatMap((txEffect)=>padArrayEnd(txEffect.noteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX));
|
|
19
|
-
const l1ToL2MessagesPadded = padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
26
|
+
const l1ToL2MessagesPadded = isFirstBlock ? padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP) : l1ToL2Messages;
|
|
20
27
|
const noteHashInsert = fork.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, noteHashesPadded);
|
|
21
28
|
const messageInsert = fork.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2MessagesPadded);
|
|
22
29
|
await Promise.all([
|
|
@@ -28,7 +35,7 @@ export async function mockBlock(blockNum, size, fork, maxEffects = 1000) {
|
|
|
28
35
|
}
|
|
29
36
|
const state = await fork.getStateReference();
|
|
30
37
|
l2Block.header.state = state;
|
|
31
|
-
await fork.updateArchive(l2Block.
|
|
38
|
+
await fork.updateArchive(l2Block.header);
|
|
32
39
|
const archiveState = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
|
|
33
40
|
l2Block.archive = new AppendOnlyTreeSnapshot(Fr.fromBuffer(archiveState.root), Number(archiveState.size));
|
|
34
41
|
return {
|
|
@@ -37,7 +44,7 @@ export async function mockBlock(blockNum, size, fork, maxEffects = 1000) {
|
|
|
37
44
|
};
|
|
38
45
|
}
|
|
39
46
|
export async function mockEmptyBlock(blockNum, fork) {
|
|
40
|
-
const l2Block =
|
|
47
|
+
const l2Block = L2BlockNew.empty();
|
|
41
48
|
const l1ToL2Messages = Array(16).fill(0).map(Fr.zero);
|
|
42
49
|
l2Block.header.globalVariables.blockNumber = blockNum;
|
|
43
50
|
// Sync the append only trees
|
|
@@ -58,7 +65,7 @@ export async function mockEmptyBlock(blockNum, fork) {
|
|
|
58
65
|
}
|
|
59
66
|
const state = await fork.getStateReference();
|
|
60
67
|
l2Block.header.state = state;
|
|
61
|
-
await fork.updateArchive(l2Block.
|
|
68
|
+
await fork.updateArchive(l2Block.header);
|
|
62
69
|
const archiveState = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
|
|
63
70
|
l2Block.archive = new AppendOnlyTreeSnapshot(Fr.fromBuffer(archiveState.root), Number(archiveState.size));
|
|
64
71
|
return {
|
|
@@ -81,6 +88,39 @@ export async function mockBlocks(from, count, numTxs, worldState) {
|
|
|
81
88
|
messages: messagesArray
|
|
82
89
|
};
|
|
83
90
|
}
|
|
91
|
+
export function mockL1ToL2Messages(numL1ToL2Messages) {
|
|
92
|
+
return Array(numL1ToL2Messages).fill(0).map(Fr.random);
|
|
93
|
+
}
|
|
94
|
+
export async function mockCheckpoint(checkpointNumber, { startBlockNumber = BlockNumber(1), numBlocks = 1, numTxsPerBlock = 1, numL1ToL2Messages = 1, fork } = {}) {
|
|
95
|
+
const slotNumber = SlotNumber(checkpointNumber * 10);
|
|
96
|
+
const blocksAndMessages = [];
|
|
97
|
+
for(let i = 0; i < numBlocks; i++){
|
|
98
|
+
const blockNumber = BlockNumber(startBlockNumber + i);
|
|
99
|
+
const { block, messages } = fork ? await mockBlock(blockNumber, numTxsPerBlock, fork, blockNumber === startBlockNumber ? numL1ToL2Messages : 0) : {
|
|
100
|
+
block: await L2BlockNew.random(blockNumber, {
|
|
101
|
+
txsPerBlock: numTxsPerBlock,
|
|
102
|
+
slotNumber
|
|
103
|
+
}),
|
|
104
|
+
messages: mockL1ToL2Messages(numL1ToL2Messages)
|
|
105
|
+
};
|
|
106
|
+
blocksAndMessages.push({
|
|
107
|
+
block,
|
|
108
|
+
messages
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
const messages = blocksAndMessages[0].messages;
|
|
112
|
+
const inHash = computeInHashFromL1ToL2Messages(messages);
|
|
113
|
+
const checkpoint = await Checkpoint.random(checkpointNumber, {
|
|
114
|
+
numBlocks: 0,
|
|
115
|
+
slotNumber,
|
|
116
|
+
inHash
|
|
117
|
+
});
|
|
118
|
+
checkpoint.blocks = blocksAndMessages.map(({ block })=>block);
|
|
119
|
+
return {
|
|
120
|
+
checkpoint,
|
|
121
|
+
messages
|
|
122
|
+
};
|
|
123
|
+
}
|
|
84
124
|
export async function assertSameState(forkA, forkB) {
|
|
85
125
|
const nativeStateRef = await forkA.getStateReference();
|
|
86
126
|
const nativeArchive = await forkA.getTreeInfo(MerkleTreeId.ARCHIVE);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
2
|
import type { Fr } from '@aztec/foundation/fields';
|
|
3
3
|
import type { IndexedTreeSnapshot, TreeSnapshot } from '@aztec/merkle-tree';
|
|
4
|
-
import type {
|
|
4
|
+
import type { L2BlockNew } from '@aztec/stdlib/block';
|
|
5
5
|
import type { ForkMerkleTreeOperations, MerkleTreeReadOperations } from '@aztec/stdlib/interfaces/server';
|
|
6
6
|
import type { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
7
7
|
import type { WorldStateStatusFull, WorldStateStatusSummary } from '../native/message.js';
|
|
@@ -34,10 +34,10 @@ export interface MerkleTreeAdminDatabase extends ForkMerkleTreeOperations {
|
|
|
34
34
|
* Handles a single L2 block (i.e. Inserts the new note hashes into the merkle tree).
|
|
35
35
|
* @param block - The L2 block to handle.
|
|
36
36
|
* @param l1ToL2Messages - The L1 to L2 messages for the block.
|
|
37
|
-
* @param isFirstBlock - Whether the block is the first block in a checkpoint.
|
|
38
|
-
*
|
|
37
|
+
* @param isFirstBlock - Whether the block is the first block in a checkpoint. The messages are padded and inserted
|
|
38
|
+
* to the tree for the first block in a checkpoint.
|
|
39
39
|
*/
|
|
40
|
-
handleL2BlockAndMessages(block:
|
|
40
|
+
handleL2BlockAndMessages(block: L2BlockNew, l1ToL2Messages: Fr[], isFirstBlock: boolean): Promise<WorldStateStatusFull>;
|
|
41
41
|
/**
|
|
42
42
|
* Gets a handle that allows reading the latest committed state
|
|
43
43
|
*/
|
|
@@ -70,4 +70,4 @@ export interface MerkleTreeAdminDatabase extends ForkMerkleTreeOperations {
|
|
|
70
70
|
/** Deletes the db. */
|
|
71
71
|
clear(): Promise<void>;
|
|
72
72
|
}
|
|
73
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
73
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVya2xlX3RyZWVfZGIuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy93b3JsZC1zdGF0ZS1kYi9tZXJrbGVfdHJlZV9kYi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDOUQsT0FBTyxLQUFLLEVBQUUsRUFBRSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDbkQsT0FBTyxLQUFLLEVBQUUsbUJBQW1CLEVBQUUsWUFBWSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDNUUsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdEQsT0FBTyxLQUFLLEVBQUUsd0JBQXdCLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUMxRyxPQUFPLEtBQUssRUFBRSxZQUFZLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUV4RCxPQUFPLEtBQUssRUFBRSxvQkFBb0IsRUFBRSx1QkFBdUIsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBRTFGOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBQ0gsZUFBTyxNQUFNLDJCQUEyQixRQUE0QixDQUFDO0FBRXJFLGVBQU8sTUFBTSw2QkFBNkIsUUFBbUQsQ0FBQztBQUU5RixNQUFNLE1BQU0sYUFBYSxHQUFHO0lBQzFCLENBQUMsWUFBWSxDQUFDLGNBQWMsQ0FBQyxFQUFFLG1CQUFtQixDQUFDO0lBQ25ELENBQUMsWUFBWSxDQUFDLGNBQWMsQ0FBQyxFQUFFLFlBQVksQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNoRCxDQUFDLFlBQVksQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFLG1CQUFtQixDQUFDO0lBQ3JELENBQUMsWUFBWSxDQUFDLHFCQUFxQixDQUFDLEVBQUUsWUFBWSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZELENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxFQUFFLFlBQVksQ0FBQyxFQUFFLENBQUMsQ0FBQztDQUMxQyxDQUFDO0FBRUYsTUFBTSxXQUFXLHVCQUF3QixTQUFRLHdCQUF3QjtJQUN2RTs7Ozs7O09BTUc7SUFDSCx3QkFBd0IsQ0FDdEIsS0FBSyxFQUFFLFVBQVUsRUFDakIsY0FBYyxFQUFFLEVBQUUsRUFBRSxFQUNwQixZQUFZLEVBQUUsT0FBTyxHQUNwQixPQUFPLENBQUMsb0JBQW9CLENBQUMsQ0FBQztJQUVqQzs7T0FFRztJQUNILFlBQVksSUFBSSx3QkFBd0IsQ0FBQztJQUV6Qzs7OztPQUlHO0lBQ0gsc0JBQXNCLENBQUMsYUFBYSxFQUFFLFdBQVcsR0FBRyxPQUFPLENBQUMsb0JBQW9CLENBQUMsQ0FBQztJQUVsRjs7OztPQUlHO0lBQ0gsWUFBWSxDQUFDLGFBQWEsRUFBRSxXQUFXLEdBQUcsT0FBTyxDQUFDLG9CQUFvQixDQUFDLENBQUM7SUFFeEU7Ozs7T0FJRztJQUNILFlBQVksQ0FBQyxhQUFhLEVBQUUsV0FBVyxHQUFHLE9BQU8sQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO0lBRTNFOzs7T0FHRztJQUNILGdCQUFnQixJQUFJLE9BQU8sQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO0lBRXJELHlCQUF5QjtJQUN6QixLQUFLLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBRXZCLHNCQUFzQjtJQUN0QixLQUFLLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO0NBQ3hCIn0=
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merkle_tree_db.d.ts","sourceRoot":"","sources":["../../src/world-state-db/merkle_tree_db.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,KAAK,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"merkle_tree_db.d.ts","sourceRoot":"","sources":["../../src/world-state-db/merkle_tree_db.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,KAAK,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,wBAAwB,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAC1G,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,KAAK,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAE1F;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,2BAA2B,QAA4B,CAAC;AAErE,eAAO,MAAM,6BAA6B,QAAmD,CAAC;AAE9F,MAAM,MAAM,aAAa,GAAG;IAC1B,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,mBAAmB,CAAC;IACnD,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC,CAAC;IAChD,CAAC,YAAY,CAAC,gBAAgB,CAAC,EAAE,mBAAmB,CAAC;IACrD,CAAC,YAAY,CAAC,qBAAqB,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC,CAAC;IACvD,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC,CAAC;CAC1C,CAAC;AAEF,MAAM,WAAW,uBAAwB,SAAQ,wBAAwB;IACvE;;;;;;OAMG;IACH,wBAAwB,CACtB,KAAK,EAAE,UAAU,EACjB,cAAc,EAAE,EAAE,EAAE,EACpB,YAAY,EAAE,OAAO,GACpB,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAEjC;;OAEG;IACH,YAAY,IAAI,wBAAwB,CAAC;IAEzC;;;;OAIG;IACH,sBAAsB,CAAC,aAAa,EAAE,WAAW,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAElF;;;;OAIG;IACH,YAAY,CAAC,aAAa,EAAE,WAAW,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAExE;;;;OAIG;IACH,YAAY,CAAC,aAAa,EAAE,WAAW,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAE3E;;;OAGG;IACH,gBAAgB,IAAI,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAErD,yBAAyB;IACzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB,sBAAsB;IACtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/world-state",
|
|
3
|
-
"version": "3.0.0-nightly.
|
|
3
|
+
"version": "3.0.0-nightly.20251206",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dest/index.js",
|
|
@@ -64,19 +64,19 @@
|
|
|
64
64
|
]
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@aztec/constants": "3.0.0-nightly.
|
|
68
|
-
"@aztec/foundation": "3.0.0-nightly.
|
|
69
|
-
"@aztec/kv-store": "3.0.0-nightly.
|
|
70
|
-
"@aztec/merkle-tree": "3.0.0-nightly.
|
|
71
|
-
"@aztec/native": "3.0.0-nightly.
|
|
72
|
-
"@aztec/protocol-contracts": "3.0.0-nightly.
|
|
73
|
-
"@aztec/stdlib": "3.0.0-nightly.
|
|
74
|
-
"@aztec/telemetry-client": "3.0.0-nightly.
|
|
67
|
+
"@aztec/constants": "3.0.0-nightly.20251206",
|
|
68
|
+
"@aztec/foundation": "3.0.0-nightly.20251206",
|
|
69
|
+
"@aztec/kv-store": "3.0.0-nightly.20251206",
|
|
70
|
+
"@aztec/merkle-tree": "3.0.0-nightly.20251206",
|
|
71
|
+
"@aztec/native": "3.0.0-nightly.20251206",
|
|
72
|
+
"@aztec/protocol-contracts": "3.0.0-nightly.20251206",
|
|
73
|
+
"@aztec/stdlib": "3.0.0-nightly.20251206",
|
|
74
|
+
"@aztec/telemetry-client": "3.0.0-nightly.20251206",
|
|
75
75
|
"tslib": "^2.4.0",
|
|
76
76
|
"zod": "^3.23.8"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
|
-
"@aztec/archiver": "3.0.0-nightly.
|
|
79
|
+
"@aztec/archiver": "3.0.0-nightly.20251206",
|
|
80
80
|
"@jest/globals": "^30.0.0",
|
|
81
81
|
"@types/jest": "^30.0.0",
|
|
82
82
|
"@types/node": "^22.15.17",
|
|
@@ -5,7 +5,7 @@ import { EthAddress } from '@aztec/foundation/eth-address';
|
|
|
5
5
|
import { Fr } from '@aztec/foundation/fields';
|
|
6
6
|
import { tryRmDir } from '@aztec/foundation/fs';
|
|
7
7
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
8
|
-
import type {
|
|
8
|
+
import type { L2BlockNew } from '@aztec/stdlib/block';
|
|
9
9
|
import { DatabaseVersionManager } from '@aztec/stdlib/database-version';
|
|
10
10
|
import type {
|
|
11
11
|
IndexedTreeId,
|
|
@@ -181,20 +181,26 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
public async handleL2BlockAndMessages(
|
|
184
|
-
l2Block:
|
|
184
|
+
l2Block: L2BlockNew,
|
|
185
185
|
l1ToL2Messages: Fr[],
|
|
186
|
-
|
|
187
|
-
// Temporary hack to only insert l1 to l2 messages for the first block in a checkpoint.
|
|
188
|
-
isFirstBlock = true,
|
|
186
|
+
isFirstBlock: boolean,
|
|
189
187
|
): Promise<WorldStateStatusFull> {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
188
|
+
if (!isFirstBlock && l1ToL2Messages.length > 0) {
|
|
189
|
+
throw new Error(
|
|
190
|
+
`L1 to L2 messages must be empty for non-first blocks, but got ${l1ToL2Messages.length} messages for block ${l2Block.number}.`,
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// We have to pad the given l1 to l2 messages, and the note hashes and nullifiers within tx effects, because that's
|
|
195
|
+
// how the trees are built by circuits.
|
|
194
196
|
const paddedL1ToL2Messages = isFirstBlock
|
|
195
197
|
? padArrayEnd<Fr, number>(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP)
|
|
196
198
|
: [];
|
|
197
199
|
|
|
200
|
+
const paddedNoteHashes = l2Block.body.txEffects.flatMap(txEffect =>
|
|
201
|
+
padArrayEnd(txEffect.noteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX),
|
|
202
|
+
);
|
|
203
|
+
|
|
198
204
|
const paddedNullifiers = l2Block.body.txEffects
|
|
199
205
|
.flatMap(txEffect => padArrayEnd(txEffect.nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX))
|
|
200
206
|
.map(nullifier => new NullifierLeaf(nullifier));
|
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import { L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/constants';
|
|
2
1
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
3
|
-
import { SHA256Trunc } from '@aztec/foundation/crypto';
|
|
4
2
|
import type { Fr } from '@aztec/foundation/fields';
|
|
5
3
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
6
4
|
import { promiseWithResolvers } from '@aztec/foundation/promise';
|
|
7
5
|
import { elapsed } from '@aztec/foundation/timer';
|
|
8
|
-
import { MerkleTreeCalculator } from '@aztec/foundation/trees';
|
|
9
6
|
import type {
|
|
10
|
-
L2Block,
|
|
11
7
|
L2BlockId,
|
|
8
|
+
L2BlockNew,
|
|
12
9
|
L2BlockSource,
|
|
13
10
|
L2BlockStream,
|
|
14
11
|
L2BlockStreamEvent,
|
|
@@ -33,6 +30,7 @@ import type { WorldStateStatusFull } from '../native/message.js';
|
|
|
33
30
|
import type { MerkleTreeAdminDatabase } from '../world-state-db/merkle_tree_db.js';
|
|
34
31
|
import type { WorldStateConfig } from './config.js';
|
|
35
32
|
import { WorldStateSynchronizerError } from './errors.js';
|
|
33
|
+
import { findFirstBlocksInCheckpoints } from './utils.js';
|
|
36
34
|
|
|
37
35
|
export type { SnapshotDataKeys };
|
|
38
36
|
|
|
@@ -270,7 +268,7 @@ export class ServerWorldStateSynchronizer
|
|
|
270
268
|
public async handleBlockStreamEvent(event: L2BlockStreamEvent): Promise<void> {
|
|
271
269
|
switch (event.type) {
|
|
272
270
|
case 'blocks-added':
|
|
273
|
-
await this.handleL2Blocks(event.blocks.map(b => b.block));
|
|
271
|
+
await this.handleL2Blocks(event.blocks.map(b => b.block.toL2Block()));
|
|
274
272
|
break;
|
|
275
273
|
case 'chain-pruned':
|
|
276
274
|
await this.handleChainPruned(BlockNumber(event.block.number));
|
|
@@ -289,22 +287,23 @@ export class ServerWorldStateSynchronizer
|
|
|
289
287
|
* @param l2Blocks - The L2 blocks to handle.
|
|
290
288
|
* @returns Whether the block handled was produced by this same node.
|
|
291
289
|
*/
|
|
292
|
-
private async handleL2Blocks(l2Blocks:
|
|
290
|
+
private async handleL2Blocks(l2Blocks: L2BlockNew[]) {
|
|
293
291
|
this.log.trace(`Handling L2 blocks ${l2Blocks[0].number} to ${l2Blocks.at(-1)!.number}`);
|
|
294
292
|
|
|
295
|
-
const
|
|
296
|
-
const l1ToL2Messages: Fr[][] = await Promise.all(messagePromises);
|
|
297
|
-
let updateStatus: WorldStateStatusFull | undefined = undefined;
|
|
293
|
+
const firstBlocksInCheckpoints = await findFirstBlocksInCheckpoints(l2Blocks, this.l2BlockSource);
|
|
298
294
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
295
|
+
let updateStatus: WorldStateStatusFull | undefined = undefined;
|
|
296
|
+
for (const block of l2Blocks) {
|
|
297
|
+
const l1ToL2Messages = firstBlocksInCheckpoints.get(block.number) ?? [];
|
|
298
|
+
const isFirstBlock = firstBlocksInCheckpoints.has(block.number);
|
|
299
|
+
const [duration, result] = await elapsed(() => this.handleL2Block(block, l1ToL2Messages, isFirstBlock));
|
|
300
|
+
this.log.info(`World state updated with L2 block ${block.number}`, {
|
|
302
301
|
eventName: 'l2-block-handled',
|
|
303
302
|
duration,
|
|
304
303
|
unfinalizedBlockNumber: BigInt(result.summary.unfinalizedBlockNumber),
|
|
305
304
|
finalizedBlockNumber: BigInt(result.summary.finalizedBlockNumber),
|
|
306
305
|
oldestHistoricBlock: BigInt(result.summary.oldestHistoricalBlock),
|
|
307
|
-
...
|
|
306
|
+
...block.getStats(),
|
|
308
307
|
} satisfies L2BlockHandledStats);
|
|
309
308
|
updateStatus = result;
|
|
310
309
|
}
|
|
@@ -320,20 +319,18 @@ export class ServerWorldStateSynchronizer
|
|
|
320
319
|
* @param l1ToL2Messages - The L1 to L2 messages for the block.
|
|
321
320
|
* @returns Whether the block handled was produced by this same node.
|
|
322
321
|
*/
|
|
323
|
-
private async handleL2Block(
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
await this.verifyMessagesHashToInHash(l1ToL2Messages, l2Block.header.contentCommitment.inHash);
|
|
329
|
-
|
|
322
|
+
private async handleL2Block(
|
|
323
|
+
l2Block: L2BlockNew,
|
|
324
|
+
l1ToL2Messages: Fr[],
|
|
325
|
+
isFirstBlock: boolean,
|
|
326
|
+
): Promise<WorldStateStatusFull> {
|
|
330
327
|
// If the above check succeeds, we can proceed to handle the block.
|
|
331
328
|
this.log.trace(`Pushing L2 block ${l2Block.number} to merkle tree db `, {
|
|
332
329
|
blockNumber: l2Block.number,
|
|
333
330
|
blockHash: await l2Block.hash().then(h => h.toString()),
|
|
334
331
|
l1ToL2Messages: l1ToL2Messages.map(msg => msg.toString()),
|
|
335
332
|
});
|
|
336
|
-
const result = await this.merkleTreeDb.handleL2BlockAndMessages(l2Block, l1ToL2Messages);
|
|
333
|
+
const result = await this.merkleTreeDb.handleL2BlockAndMessages(l2Block, l1ToL2Messages, isFirstBlock);
|
|
337
334
|
|
|
338
335
|
if (this.currentState === WorldStateRunningState.SYNCHING && l2Block.number >= this.latestBlockNumberAtStart) {
|
|
339
336
|
this.setCurrentState(WorldStateRunningState.RUNNING);
|
|
@@ -380,24 +377,4 @@ export class ServerWorldStateSynchronizer
|
|
|
380
377
|
this.currentState = newState;
|
|
381
378
|
this.log.debug(`Moved to state ${WorldStateRunningState[this.currentState]}`);
|
|
382
379
|
}
|
|
383
|
-
|
|
384
|
-
/**
|
|
385
|
-
* Verifies that the L1 to L2 messages hash to the block inHash.
|
|
386
|
-
* @param l1ToL2Messages - The L1 to L2 messages for the block.
|
|
387
|
-
* @param inHash - The inHash of the block.
|
|
388
|
-
* @throws If the L1 to L2 messages do not hash to the block inHash.
|
|
389
|
-
*/
|
|
390
|
-
protected async verifyMessagesHashToInHash(l1ToL2Messages: Fr[], inHash: Fr) {
|
|
391
|
-
const treeCalculator = await MerkleTreeCalculator.create(
|
|
392
|
-
L1_TO_L2_MSG_SUBTREE_HEIGHT,
|
|
393
|
-
Buffer.alloc(32),
|
|
394
|
-
(lhs, rhs) => Promise.resolve(new SHA256Trunc().hash(lhs, rhs)),
|
|
395
|
-
);
|
|
396
|
-
|
|
397
|
-
const root = await treeCalculator.computeTreeRoot(l1ToL2Messages.map(msg => msg.toBuffer()));
|
|
398
|
-
|
|
399
|
-
if (!root.equals(inHash.toBuffer())) {
|
|
400
|
-
throw new Error('Obtained L1 to L2 messages failed to be hashed to the block inHash');
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
380
|
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { BlockNumber, type SlotNumber } from '@aztec/foundation/branded-types';
|
|
2
|
+
import type { Fr } from '@aztec/foundation/fields';
|
|
3
|
+
import type { L2BlockNew, L2BlockSource } from '@aztec/stdlib/block';
|
|
4
|
+
import type { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
5
|
+
import { type L1ToL2MessageSource, computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Determine which blocks in the given array are the first block in a checkpoint.
|
|
9
|
+
* @param blocks - The candidate blocks, sorted by block number in ascending order.
|
|
10
|
+
* @param l2BlockSource - The L2 block source to use to fetch the checkpoints, block headers and L1->L2 messages.
|
|
11
|
+
* @returns A map of block numbers that begin a checkpoint to the L1->L2 messages for that checkpoint.
|
|
12
|
+
*/
|
|
13
|
+
export async function findFirstBlocksInCheckpoints(
|
|
14
|
+
blocks: L2BlockNew[],
|
|
15
|
+
l2BlockSource: L2BlockSource & L1ToL2MessageSource,
|
|
16
|
+
): Promise<Map<number, Fr[]>> {
|
|
17
|
+
// Select the blocks that are the final block within each group of identical slot numbers.
|
|
18
|
+
let seenSlot: SlotNumber | undefined;
|
|
19
|
+
const maybeLastBlocks = [...blocks]
|
|
20
|
+
.reverse()
|
|
21
|
+
.filter(b => {
|
|
22
|
+
if (b.header.globalVariables.slotNumber !== seenSlot) {
|
|
23
|
+
seenSlot = b.header.globalVariables.slotNumber;
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
return false;
|
|
27
|
+
})
|
|
28
|
+
.reverse();
|
|
29
|
+
|
|
30
|
+
// Try to fetch the checkpoints for those blocks. If undefined (which should only occur for blocks.at(-1)),
|
|
31
|
+
// then the block is not the last one in a checkpoint.
|
|
32
|
+
// If we are not checking the inHashes below, only blocks.at(-1) would need its checkpoint header fetched.
|
|
33
|
+
const checkpointedBlocks = (
|
|
34
|
+
await Promise.all(
|
|
35
|
+
maybeLastBlocks.map(async b => ({
|
|
36
|
+
blockNumber: b.number,
|
|
37
|
+
// A checkpoint's archive root is the archive root of its last block.
|
|
38
|
+
checkpoint: await l2BlockSource.getCheckpointByArchive(b.archive.root),
|
|
39
|
+
})),
|
|
40
|
+
)
|
|
41
|
+
).filter(b => b.checkpoint !== undefined) as { blockNumber: BlockNumber; checkpoint: Checkpoint }[];
|
|
42
|
+
|
|
43
|
+
// Verify that the L1->L2 messages hash to the checkpoint's inHash.
|
|
44
|
+
const checkpointedL1ToL2Messages: Fr[][] = await Promise.all(
|
|
45
|
+
checkpointedBlocks.map(b => l2BlockSource.getL1ToL2MessagesForCheckpoint(b.checkpoint!.number)),
|
|
46
|
+
);
|
|
47
|
+
checkpointedBlocks.forEach((b, i) => {
|
|
48
|
+
const computedInHash = computeInHashFromL1ToL2Messages(checkpointedL1ToL2Messages[i]);
|
|
49
|
+
const inHash = b.checkpoint.header.contentCommitment.inHash;
|
|
50
|
+
if (!computedInHash.equals(inHash)) {
|
|
51
|
+
throw new Error('Obtained L1 to L2 messages failed to be hashed to the checkpoint inHash');
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Compute the first block numbers, which should be right after each checkpointed block. Exclude blocks that haven't
|
|
56
|
+
// been added yet.
|
|
57
|
+
const firstBlockNumbers = checkpointedBlocks
|
|
58
|
+
.map(b => BlockNumber(b.blockNumber + 1))
|
|
59
|
+
.filter(n => n <= blocks.at(-1)!.number);
|
|
60
|
+
// Check if blocks[0] is the first block in a checkpoint.
|
|
61
|
+
if (blocks[0].number === 1) {
|
|
62
|
+
firstBlockNumbers.push(blocks[0].number);
|
|
63
|
+
} else {
|
|
64
|
+
const lastBlockHeader = await l2BlockSource.getBlockHeader(BlockNumber(blocks[0].number - 1));
|
|
65
|
+
if (!lastBlockHeader) {
|
|
66
|
+
throw new Error(`Failed to get block ${blocks[0].number - 1}`);
|
|
67
|
+
}
|
|
68
|
+
if (lastBlockHeader.globalVariables.slotNumber !== blocks[0].header.globalVariables.slotNumber) {
|
|
69
|
+
firstBlockNumbers.push(blocks[0].number);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Fetch the L1->L2 messages for the first blocks and assign them to the map.
|
|
74
|
+
const messagesByBlockNumber = new Map<BlockNumber, Fr[]>();
|
|
75
|
+
await Promise.all(
|
|
76
|
+
firstBlockNumbers.map(async blockNumber => {
|
|
77
|
+
const l1ToL2Messages = await l2BlockSource.getL1ToL2Messages(blockNumber);
|
|
78
|
+
messagesByBlockNumber.set(blockNumber, l1ToL2Messages);
|
|
79
|
+
}),
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
return messagesByBlockNumber;
|
|
83
|
+
}
|
package/src/test/utils.ts
CHANGED
|
@@ -4,15 +4,17 @@ import {
|
|
|
4
4
|
NULLIFIER_SUBTREE_HEIGHT,
|
|
5
5
|
NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
6
6
|
} from '@aztec/constants';
|
|
7
|
-
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
7
|
+
import { BlockNumber, type CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
8
8
|
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
9
9
|
import { Fr } from '@aztec/foundation/fields';
|
|
10
|
-
import {
|
|
10
|
+
import { L2BlockNew } from '@aztec/stdlib/block';
|
|
11
|
+
import { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
11
12
|
import type {
|
|
12
13
|
IndexedTreeId,
|
|
13
14
|
MerkleTreeReadOperations,
|
|
14
15
|
MerkleTreeWriteOperations,
|
|
15
16
|
} from '@aztec/stdlib/interfaces/server';
|
|
17
|
+
import { computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
|
|
16
18
|
import { AppendOnlyTreeSnapshot, MerkleTreeId } from '@aztec/stdlib/trees';
|
|
17
19
|
|
|
18
20
|
import type { NativeWorldStateService } from '../native/native_world_state.js';
|
|
@@ -22,17 +24,11 @@ export async function mockBlock(
|
|
|
22
24
|
size: number,
|
|
23
25
|
fork: MerkleTreeWriteOperations,
|
|
24
26
|
maxEffects: number | undefined = 1000, // Defaults to the maximum tx effects.
|
|
27
|
+
numL1ToL2Messages: number = NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
28
|
+
isFirstBlock: boolean = true,
|
|
25
29
|
) {
|
|
26
|
-
const l2Block = await
|
|
27
|
-
|
|
28
|
-
size,
|
|
29
|
-
undefined,
|
|
30
|
-
undefined,
|
|
31
|
-
undefined,
|
|
32
|
-
undefined,
|
|
33
|
-
maxEffects,
|
|
34
|
-
);
|
|
35
|
-
const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.random);
|
|
30
|
+
const l2Block = await L2BlockNew.random(blockNum, { txsPerBlock: size, txOptions: { maxEffects } });
|
|
31
|
+
const l1ToL2Messages = mockL1ToL2Messages(numL1ToL2Messages);
|
|
36
32
|
|
|
37
33
|
{
|
|
38
34
|
const insertData = async (
|
|
@@ -64,7 +60,9 @@ export async function mockBlock(
|
|
|
64
60
|
padArrayEnd(txEffect.noteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX),
|
|
65
61
|
);
|
|
66
62
|
|
|
67
|
-
const l1ToL2MessagesPadded =
|
|
63
|
+
const l1ToL2MessagesPadded = isFirstBlock
|
|
64
|
+
? padArrayEnd<Fr, number>(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP)
|
|
65
|
+
: l1ToL2Messages;
|
|
68
66
|
|
|
69
67
|
const noteHashInsert = fork.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, noteHashesPadded);
|
|
70
68
|
const messageInsert = fork.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2MessagesPadded);
|
|
@@ -73,7 +71,7 @@ export async function mockBlock(
|
|
|
73
71
|
|
|
74
72
|
const state = await fork.getStateReference();
|
|
75
73
|
l2Block.header.state = state;
|
|
76
|
-
await fork.updateArchive(l2Block.
|
|
74
|
+
await fork.updateArchive(l2Block.header);
|
|
77
75
|
|
|
78
76
|
const archiveState = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
|
|
79
77
|
|
|
@@ -86,7 +84,7 @@ export async function mockBlock(
|
|
|
86
84
|
}
|
|
87
85
|
|
|
88
86
|
export async function mockEmptyBlock(blockNum: BlockNumber, fork: MerkleTreeWriteOperations) {
|
|
89
|
-
const l2Block =
|
|
87
|
+
const l2Block = L2BlockNew.empty();
|
|
90
88
|
const l1ToL2Messages = Array(16).fill(0).map(Fr.zero);
|
|
91
89
|
|
|
92
90
|
l2Block.header.globalVariables.blockNumber = blockNum;
|
|
@@ -124,7 +122,7 @@ export async function mockEmptyBlock(blockNum: BlockNumber, fork: MerkleTreeWrit
|
|
|
124
122
|
|
|
125
123
|
const state = await fork.getStateReference();
|
|
126
124
|
l2Block.header.state = state;
|
|
127
|
-
await fork.updateArchive(l2Block.
|
|
125
|
+
await fork.updateArchive(l2Block.header);
|
|
128
126
|
|
|
129
127
|
const archiveState = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
|
|
130
128
|
|
|
@@ -157,6 +155,47 @@ export async function mockBlocks(
|
|
|
157
155
|
return { blocks, messages: messagesArray };
|
|
158
156
|
}
|
|
159
157
|
|
|
158
|
+
export function mockL1ToL2Messages(numL1ToL2Messages: number) {
|
|
159
|
+
return Array(numL1ToL2Messages).fill(0).map(Fr.random);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export async function mockCheckpoint(
|
|
163
|
+
checkpointNumber: CheckpointNumber,
|
|
164
|
+
{
|
|
165
|
+
startBlockNumber = BlockNumber(1),
|
|
166
|
+
numBlocks = 1,
|
|
167
|
+
numTxsPerBlock = 1,
|
|
168
|
+
numL1ToL2Messages = 1,
|
|
169
|
+
fork,
|
|
170
|
+
}: {
|
|
171
|
+
startBlockNumber?: BlockNumber;
|
|
172
|
+
numBlocks?: number;
|
|
173
|
+
numTxsPerBlock?: number;
|
|
174
|
+
numL1ToL2Messages?: number;
|
|
175
|
+
fork?: MerkleTreeWriteOperations;
|
|
176
|
+
} = {},
|
|
177
|
+
) {
|
|
178
|
+
const slotNumber = SlotNumber(checkpointNumber * 10);
|
|
179
|
+
const blocksAndMessages = [];
|
|
180
|
+
for (let i = 0; i < numBlocks; i++) {
|
|
181
|
+
const blockNumber = BlockNumber(startBlockNumber + i);
|
|
182
|
+
const { block, messages } = fork
|
|
183
|
+
? await mockBlock(blockNumber, numTxsPerBlock, fork, blockNumber === startBlockNumber ? numL1ToL2Messages : 0)
|
|
184
|
+
: {
|
|
185
|
+
block: await L2BlockNew.random(blockNumber, { txsPerBlock: numTxsPerBlock, slotNumber }),
|
|
186
|
+
messages: mockL1ToL2Messages(numL1ToL2Messages),
|
|
187
|
+
};
|
|
188
|
+
blocksAndMessages.push({ block, messages });
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const messages = blocksAndMessages[0].messages;
|
|
192
|
+
const inHash = computeInHashFromL1ToL2Messages(messages);
|
|
193
|
+
const checkpoint = await Checkpoint.random(checkpointNumber, { numBlocks: 0, slotNumber, inHash });
|
|
194
|
+
checkpoint.blocks = blocksAndMessages.map(({ block }) => block);
|
|
195
|
+
|
|
196
|
+
return { checkpoint, messages };
|
|
197
|
+
}
|
|
198
|
+
|
|
160
199
|
export async function assertSameState(forkA: MerkleTreeReadOperations, forkB: MerkleTreeReadOperations) {
|
|
161
200
|
const nativeStateRef = await forkA.getStateReference();
|
|
162
201
|
const nativeArchive = await forkA.getTreeInfo(MerkleTreeId.ARCHIVE);
|
|
@@ -2,7 +2,7 @@ import { MAX_NULLIFIERS_PER_TX, MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX } f
|
|
|
2
2
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
3
3
|
import type { Fr } from '@aztec/foundation/fields';
|
|
4
4
|
import type { IndexedTreeSnapshot, TreeSnapshot } from '@aztec/merkle-tree';
|
|
5
|
-
import type {
|
|
5
|
+
import type { L2BlockNew } from '@aztec/stdlib/block';
|
|
6
6
|
import type { ForkMerkleTreeOperations, MerkleTreeReadOperations } from '@aztec/stdlib/interfaces/server';
|
|
7
7
|
import type { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
8
8
|
|
|
@@ -40,13 +40,13 @@ export interface MerkleTreeAdminDatabase extends ForkMerkleTreeOperations {
|
|
|
40
40
|
* Handles a single L2 block (i.e. Inserts the new note hashes into the merkle tree).
|
|
41
41
|
* @param block - The L2 block to handle.
|
|
42
42
|
* @param l1ToL2Messages - The L1 to L2 messages for the block.
|
|
43
|
-
* @param isFirstBlock - Whether the block is the first block in a checkpoint.
|
|
44
|
-
*
|
|
43
|
+
* @param isFirstBlock - Whether the block is the first block in a checkpoint. The messages are padded and inserted
|
|
44
|
+
* to the tree for the first block in a checkpoint.
|
|
45
45
|
*/
|
|
46
46
|
handleL2BlockAndMessages(
|
|
47
|
-
block:
|
|
47
|
+
block: L2BlockNew,
|
|
48
48
|
l1ToL2Messages: Fr[],
|
|
49
|
-
isFirstBlock
|
|
49
|
+
isFirstBlock: boolean,
|
|
50
50
|
): Promise<WorldStateStatusFull>;
|
|
51
51
|
|
|
52
52
|
/**
|