@aztec/world-state 5.0.0-rc.2 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/native/native_world_state_instance.d.ts +1 -1
- package/dest/native/native_world_state_instance.d.ts.map +1 -1
- package/dest/native/native_world_state_instance.js +10 -1
- package/dest/synchronizer/errors.d.ts +8 -1
- package/dest/synchronizer/errors.d.ts.map +1 -1
- package/dest/synchronizer/errors.js +8 -1
- package/dest/synchronizer/index.d.ts +2 -1
- package/dest/synchronizer/index.d.ts.map +1 -1
- package/dest/synchronizer/index.js +1 -0
- package/dest/synchronizer/server_world_state_synchronizer.d.ts +5 -4
- package/dest/synchronizer/server_world_state_synchronizer.d.ts.map +1 -1
- package/dest/synchronizer/server_world_state_synchronizer.js +35 -2
- package/dest/testing.d.ts +2 -2
- package/dest/testing.d.ts.map +1 -1
- package/dest/testing.js +15 -4
- package/package.json +10 -10
- package/src/native/native_world_state_instance.ts +13 -0
- package/src/synchronizer/errors.ts +8 -0
- package/src/synchronizer/index.ts +1 -0
- package/src/synchronizer/server_world_state_synchronizer.ts +44 -4
- package/src/testing.ts +14 -4
|
@@ -47,4 +47,4 @@ export declare class NativeWorldState implements NativeWorldStateInstance {
|
|
|
47
47
|
close(): Promise<void>;
|
|
48
48
|
private _sendMessage;
|
|
49
49
|
}
|
|
50
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
50
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmF0aXZlX3dvcmxkX3N0YXRlX2luc3RhbmNlLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbmF0aXZlL25hdGl2ZV93b3JsZF9zdGF0ZV9pbnN0YW5jZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFVQSxPQUFPLEVBQUUsS0FBSyxNQUFNLEVBQUUsS0FBSyxjQUFjLEVBQWdCLE1BQU0sdUJBQXVCLENBQUM7QUFHdkYsT0FBTyxFQUFzQixLQUFLLFdBQVcsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBS2pGLE9BQU8sS0FBSyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sdUNBQXVDLENBQUM7QUFDdkYsT0FBTyxLQUFLLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUN6RSxPQUFPLEVBQ0wscUJBQXFCLEVBQ3JCLEtBQUssaUJBQWlCLEVBQ3RCLEtBQUssMkJBQTJCLEVBQ2hDLEtBQUssa0JBQWtCLEVBSXhCLE1BQU0sY0FBYyxDQUFDO0FBS3RCLE1BQU0sV0FBVyx3QkFBd0I7SUFDdkMsSUFBSSxDQUFDLENBQUMsU0FBUyxxQkFBcUIsRUFDbEMsV0FBVyxFQUFFLENBQUMsRUFDZCxJQUFJLEVBQUUsaUJBQWlCLENBQUMsQ0FBQyxDQUFDLEdBQUcsMkJBQTJCLEdBQ3ZELE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBRWxDLFNBQVMsSUFBSSxHQUFHLENBQUM7Q0FDbEI7QUFFRDs7R0FFRztBQUNILHFCQUFhLGdCQUFpQixZQUFXLHdCQUF3QjtJQVU3RCxPQUFPLENBQUMsUUFBUSxDQUFDLE9BQU87SUFDeEIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxjQUFjO0lBQy9CLE9BQU8sQ0FBQyxRQUFRLENBQUMsT0FBTztJQUN4QixPQUFPLENBQUMsUUFBUSxDQUFDLGVBQWU7SUFFaEMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxHQUFHO0lBQ3BCLE9BQU8sQ0FBQyxRQUFRLENBQUMsU0FBUztJQWY1QixPQUFPLENBQUMsSUFBSSxDQUFRO0lBR3BCLE9BQU8sQ0FBQyxNQUFNLENBQXlDO0lBRXZELE9BQU8sQ0FBQyxRQUFRLENBQStFO0lBRS9GLCtDQUErQztJQUMvQyxZQUNtQixPQUFPLEVBQUUsTUFBTSxFQUNmLGNBQWMsRUFBRSxzQkFBc0IsRUFDdEMsT0FBTyx5QkFBa0MsRUFDekMsZUFBZSxFQUFFLHlCQUF5QixFQUMzRCxRQUFRLENBQUMsRUFBRSxjQUFjLEVBQ1IsR0FBRyxHQUFFLE1BQXVELEVBQzVELFNBQVMsR0FBRSxPQUFlLEVBc0Q1QztJQUVNLFVBQVUsV0FFaEI7SUFFTSxLQUFLLHFCQVVYO0lBRUQ7Ozs7OztPQU1HO0lBQ0ksU0FBUyxJQUFJLEdBQUcsQ0FpQnRCO0lBRUQ7Ozs7Ozs7T0FPRztJQUNVLElBQUksQ0FBQyxDQUFDLFNBQVMscUJBQXFCLEVBQy9DLFdBQVcsRUFBRSxDQUFDLEVBQ2QsSUFBSSxFQUFFLGlCQUFpQixDQUFDLENBQUMsQ0FBQyxHQUFHLDJCQUEyQixFQUV4RCxlQUFlLDZEQUF1RSxFQUN0RixZQUFZLHNCQUFvQixHQUMvQixPQUFPLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0E0RGhDO0lBRUQ7O09BRUc7SUFDVSxLQUFLLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQWVsQztZQUVhLFlBQVk7Q0E4RDNCIn0=
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native_world_state_instance.d.ts","sourceRoot":"","sources":["../../src/native/native_world_state_instance.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,cAAc,EAAgB,MAAM,uBAAuB,CAAC;AAGvF,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAKjF,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,uCAAuC,CAAC;AACvF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,EACL,qBAAqB,EACrB,KAAK,iBAAiB,EACtB,KAAK,2BAA2B,EAChC,KAAK,kBAAkB,EAIxB,MAAM,cAAc,CAAC;AAKtB,MAAM,WAAW,wBAAwB;IACvC,IAAI,CAAC,CAAC,SAAS,qBAAqB,EAClC,WAAW,EAAE,CAAC,EACd,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,2BAA2B,GACvD,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;IAElC,SAAS,IAAI,GAAG,CAAC;CAClB;AAED;;GAEG;AACH,qBAAa,gBAAiB,YAAW,wBAAwB;IAU7D,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAEhC,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAf5B,OAAO,CAAC,IAAI,CAAQ;IAGpB,OAAO,CAAC,MAAM,CAAyC;IAEvD,OAAO,CAAC,QAAQ,CAA+E;IAE/F,+CAA+C;IAC/C,YACmB,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,sBAAsB,EACtC,OAAO,yBAAkC,EACzC,eAAe,EAAE,yBAAyB,EAC3D,QAAQ,CAAC,EAAE,cAAc,EACR,GAAG,GAAE,MAAuD,EAC5D,SAAS,GAAE,OAAe,
|
|
1
|
+
{"version":3,"file":"native_world_state_instance.d.ts","sourceRoot":"","sources":["../../src/native/native_world_state_instance.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,cAAc,EAAgB,MAAM,uBAAuB,CAAC;AAGvF,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAKjF,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,uCAAuC,CAAC;AACvF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,EACL,qBAAqB,EACrB,KAAK,iBAAiB,EACtB,KAAK,2BAA2B,EAChC,KAAK,kBAAkB,EAIxB,MAAM,cAAc,CAAC;AAKtB,MAAM,WAAW,wBAAwB;IACvC,IAAI,CAAC,CAAC,SAAS,qBAAqB,EAClC,WAAW,EAAE,CAAC,EACd,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,2BAA2B,GACvD,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;IAElC,SAAS,IAAI,GAAG,CAAC;CAClB;AAED;;GAEG;AACH,qBAAa,gBAAiB,YAAW,wBAAwB;IAU7D,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAEhC,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAf5B,OAAO,CAAC,IAAI,CAAQ;IAGpB,OAAO,CAAC,MAAM,CAAyC;IAEvD,OAAO,CAAC,QAAQ,CAA+E;IAE/F,+CAA+C;IAC/C,YACmB,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,sBAAsB,EACtC,OAAO,yBAAkC,EACzC,eAAe,EAAE,yBAAyB,EAC3D,QAAQ,CAAC,EAAE,cAAc,EACR,GAAG,GAAE,MAAuD,EAC5D,SAAS,GAAE,OAAe,EAsD5C;IAEM,UAAU,WAEhB;IAEM,KAAK,qBAUX;IAED;;;;;;OAMG;IACI,SAAS,IAAI,GAAG,CAiBtB;IAED;;;;;;;OAOG;IACU,IAAI,CAAC,CAAC,SAAS,qBAAqB,EAC/C,WAAW,EAAE,CAAC,EACd,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,2BAA2B,EAExD,eAAe,6DAAuE,EACtF,YAAY,sBAAoB,GAC/B,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CA4DhC;IAED;;OAEG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAelC;YAEa,YAAY;CA8D3B"}
|
|
@@ -36,6 +36,15 @@ const MAX_WORLD_STATE_THREADS = +(process.env.HARDWARE_CONCURRENCY || '16');
|
|
|
36
36
|
d.slot.toBuffer(),
|
|
37
37
|
d.value.toBuffer()
|
|
38
38
|
]);
|
|
39
|
+
// Nullifiers to pre-insert into the genesis nullifier tree (empty by default, so production genesis roots are
|
|
40
|
+
// unchanged). The native indexed nullifier tree requires its prefilled leaves to be unique and strictly
|
|
41
|
+
// increasing, so we enforce that here before handing them over rather than failing deep inside the C++ tree
|
|
42
|
+
// construction.
|
|
43
|
+
const prefilledNullifiers = genesis.prefilledNullifiers ?? [];
|
|
44
|
+
for(let i = 1; i < prefilledNullifiers.length; i++){
|
|
45
|
+
assert(prefilledNullifiers[i].toBigInt() > prefilledNullifiers[i - 1].toBigInt(), 'Prefilled genesis nullifiers must be unique and strictly increasing');
|
|
46
|
+
}
|
|
47
|
+
const prefilledNullifiersBufferArray = prefilledNullifiers.map((n)=>n.toBuffer());
|
|
39
48
|
const ws = new BaseNativeWorldState(dataDir, {
|
|
40
49
|
[MerkleTreeId.NULLIFIER_TREE]: NULLIFIER_TREE_HEIGHT,
|
|
41
50
|
[MerkleTreeId.NOTE_HASH_TREE]: NOTE_HASH_TREE_HEIGHT,
|
|
@@ -45,7 +54,7 @@ const MAX_WORLD_STATE_THREADS = +(process.env.HARDWARE_CONCURRENCY || '16');
|
|
|
45
54
|
}, {
|
|
46
55
|
[MerkleTreeId.NULLIFIER_TREE]: 2 * MAX_NULLIFIERS_PER_TX,
|
|
47
56
|
[MerkleTreeId.PUBLIC_DATA_TREE]: 2 * MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX
|
|
48
|
-
}, prefilledPublicDataBufferArray, DomainSeparator.BLOCK_HEADER_HASH, Number(genesis.genesisTimestamp), {
|
|
57
|
+
}, prefilledPublicDataBufferArray, prefilledNullifiersBufferArray, DomainSeparator.BLOCK_HEADER_HASH, Number(genesis.genesisTimestamp), {
|
|
49
58
|
[MerkleTreeId.NULLIFIER_TREE]: wsTreeMapSizes.nullifierTreeMapSizeKb,
|
|
50
59
|
[MerkleTreeId.NOTE_HASH_TREE]: wsTreeMapSizes.noteHashTreeMapSizeKb,
|
|
51
60
|
[MerkleTreeId.PUBLIC_DATA_TREE]: wsTreeMapSizes.publicDataTreeMapSizeKb,
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown by {@link ServerWorldStateSynchronizer.syncImmediate} when world state cannot be synced to the requested
|
|
3
|
+
* target: either the block is not available from the block source (`block_not_available`, e.g. it was pruned away)
|
|
4
|
+
* or the synced block does not match the requested hash (`block_hash_mismatch`, i.e. a reorg). Both causes are
|
|
5
|
+
* transient from the caller's perspective: re-resolving the query against the current chain and retrying may succeed
|
|
6
|
+
* or produce a more precise error.
|
|
7
|
+
*/
|
|
1
8
|
export declare class WorldStateSynchronizerError extends Error {
|
|
2
9
|
constructor(message: string, options?: ErrorOptions);
|
|
3
10
|
}
|
|
4
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
11
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3JzLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc3luY2hyb25pemVyL2Vycm9ycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFDSCxxQkFBYSwyQkFBNEIsU0FBUSxLQUFLO0lBQ3BELFlBQVksT0FBTyxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsRUFBRSxZQUFZLEVBR2xEO0NBQ0YifQ==
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/synchronizer/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,2BAA4B,SAAQ,KAAK;IACpD,YAAY,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/synchronizer/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,qBAAa,2BAA4B,SAAQ,KAAK;IACpD,YAAY,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,EAGlD;CACF"}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Thrown by {@link ServerWorldStateSynchronizer.syncImmediate} when world state cannot be synced to the requested
|
|
3
|
+
* target: either the block is not available from the block source (`block_not_available`, e.g. it was pruned away)
|
|
4
|
+
* or the synced block does not match the requested hash (`block_hash_mismatch`, i.e. a reorg). Both causes are
|
|
5
|
+
* transient from the caller's perspective: re-resolving the query against the current chain and retrying may succeed
|
|
6
|
+
* or produce a more precise error.
|
|
7
|
+
*/ export class WorldStateSynchronizerError extends Error {
|
|
2
8
|
constructor(message, options){
|
|
3
9
|
super(message, options);
|
|
10
|
+
this.name = 'WorldStateSynchronizerError';
|
|
4
11
|
}
|
|
5
12
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export * from './server_world_state_synchronizer.js';
|
|
2
2
|
export * from './factory.js';
|
|
3
|
-
|
|
3
|
+
export * from './errors.js';
|
|
4
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zeW5jaHJvbml6ZXIvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxzQ0FBc0MsQ0FBQztBQUNyRCxjQUFjLGNBQWMsQ0FBQztBQUM3QixjQUFjLGFBQWEsQ0FBQyJ9
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/synchronizer/index.ts"],"names":[],"mappings":"AAAA,cAAc,sCAAsC,CAAC;AACrD,cAAc,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/synchronizer/index.ts"],"names":[],"mappings":"AAAA,cAAc,sCAAsC,CAAC;AACrD,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
2
|
import { type Logger } from '@aztec/foundation/log';
|
|
3
|
-
import { type BlockHash, type L2BlockSource,
|
|
3
|
+
import { type BlockHash, EventDrivenL2BlockStream, type L2BlockSource, type L2BlockStreamEvent, type L2BlockStreamEventHandler, type L2BlockStreamLocalDataProvider, type LocalChainTips } from '@aztec/stdlib/block';
|
|
4
4
|
import { type WorldStateSynchronizer, type WorldStateSynchronizerStatus } from '@aztec/stdlib/interfaces/server';
|
|
5
5
|
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
6
6
|
import type { SnapshotDataKeys } from '@aztec/stdlib/snapshots';
|
|
@@ -25,18 +25,19 @@ export declare class ServerWorldStateSynchronizer implements WorldStateSynchroni
|
|
|
25
25
|
private historyToKeep;
|
|
26
26
|
private currentState;
|
|
27
27
|
private syncPromise;
|
|
28
|
-
protected blockStream:
|
|
28
|
+
protected blockStream: EventDrivenL2BlockStream | undefined;
|
|
29
29
|
private provenBlockNumber;
|
|
30
30
|
constructor(merkleTreeDb: MerkleTreeAdminDatabase, l2BlockSource: L2BlockSource & L1ToL2MessageSource, config: WorldStateConfig, instrumentation?: WorldStateInstrumentation, log?: Logger);
|
|
31
31
|
getCommitted(): MerkleTreeReadOperations;
|
|
32
32
|
getSnapshot(blockNumber: BlockNumber): MerkleTreeReadOperations;
|
|
33
|
+
getVerifiedSnapshot(blockNumber: BlockNumber, blockHash: BlockHash): Promise<MerkleTreeReadOperations>;
|
|
33
34
|
fork(blockNumber?: BlockNumber, opts?: {
|
|
34
35
|
closeDelayMs?: number;
|
|
35
36
|
}): Promise<MerkleTreeWriteOperations>;
|
|
36
37
|
backupTo(dstPath: string, compact?: boolean): Promise<Record<Exclude<SnapshotDataKeys, 'archiver'>, string>>;
|
|
37
38
|
clear(): Promise<void>;
|
|
38
39
|
start(): Promise<void | import("@aztec/foundation/promise").PromiseWithResolvers<void>>;
|
|
39
|
-
protected createBlockStream():
|
|
40
|
+
protected createBlockStream(): EventDrivenL2BlockStream;
|
|
40
41
|
stop(): Promise<void>;
|
|
41
42
|
status(): Promise<WorldStateSynchronizerStatus>;
|
|
42
43
|
getLatestBlockNumber(): Promise<BlockNumber>;
|
|
@@ -70,4 +71,4 @@ export declare class ServerWorldStateSynchronizer implements WorldStateSynchroni
|
|
|
70
71
|
*/
|
|
71
72
|
private setCurrentState;
|
|
72
73
|
}
|
|
73
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
74
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyX3dvcmxkX3N0YXRlX3N5bmNocm9uaXplci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3N5bmNocm9uaXplci9zZXJ2ZXJfd29ybGRfc3RhdGVfc3luY2hyb25pemVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxXQUFXLEVBQW9CLE1BQU0saUNBQWlDLENBQUM7QUFFaEYsT0FBTyxFQUFFLEtBQUssTUFBTSxFQUFnQixNQUFNLHVCQUF1QixDQUFDO0FBR2xFLE9BQU8sRUFDTCxLQUFLLFNBQVMsRUFDZCx3QkFBd0IsRUFFeEIsS0FBSyxhQUFhLEVBQ2xCLEtBQUssa0JBQWtCLEVBQ3ZCLEtBQUsseUJBQXlCLEVBQzlCLEtBQUssOEJBQThCLEVBQ25DLEtBQUssY0FBYyxFQUNwQixNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sRUFHTCxLQUFLLHNCQUFzQixFQUMzQixLQUFLLDRCQUE0QixFQUNsQyxNQUFNLGlDQUFpQyxDQUFDO0FBQ3pDLE9BQU8sS0FBSyxFQUFFLG1CQUFtQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDbkUsT0FBTyxLQUFLLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUVoRSxPQUFPLEVBQWdCLEtBQUssd0JBQXdCLEVBQUUsS0FBSyx5QkFBeUIsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBR2xILE9BQU8sRUFBRSx5QkFBeUIsRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBRWxGLE9BQU8sS0FBSyxFQUFFLHVCQUF1QixFQUFFLE1BQU0scUNBQXFDLENBQUM7QUFDbkYsT0FBTyxLQUFLLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFHcEQsWUFBWSxFQUFFLGdCQUFnQixFQUFFLENBQUM7QUFFakM7Ozs7R0FJRztBQUNILHFCQUFhLDRCQUNYLFlBQVcsc0JBQXNCLEVBQUUsOEJBQThCLEVBQUUseUJBQXlCO0lBZ0IxRixPQUFP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
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server_world_state_synchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/server_world_state_synchronizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAoB,MAAM,iCAAiC,CAAC;AAEhF,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAGlE,OAAO,EACL,KAAK,SAAS,
|
|
1
|
+
{"version":3,"file":"server_world_state_synchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/server_world_state_synchronizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAoB,MAAM,iCAAiC,CAAC;AAEhF,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAGlE,OAAO,EACL,KAAK,SAAS,EACd,wBAAwB,EAExB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAC9B,KAAK,8BAA8B,EACnC,KAAK,cAAc,EACpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAGL,KAAK,sBAAsB,EAC3B,KAAK,4BAA4B,EAClC,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,OAAO,EAAgB,KAAK,wBAAwB,EAAE,KAAK,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAGlH,OAAO,EAAE,yBAAyB,EAAE,MAAM,uCAAuC,CAAC;AAElF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AACnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGpD,YAAY,EAAE,gBAAgB,EAAE,CAAC;AAEjC;;;;GAIG;AACH,qBAAa,4BACX,YAAW,sBAAsB,EAAE,8BAA8B,EAAE,yBAAyB;IAgB1F,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,eAAe;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAlBtB,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAA2B;IAE/D,OAAO,CAAC,wBAAwB,CAAoB;IACpD,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,YAAY,CAAuD;IAE3E,OAAO,CAAC,WAAW,CAAgC;IACnD,SAAS,CAAC,WAAW,EAAE,wBAAwB,GAAG,SAAS,CAAC;IAI5D,OAAO,CAAC,iBAAiB,CAA0B;IAEnD,YACmB,YAAY,EAAE,uBAAuB,EACrC,aAAa,EAAE,aAAa,GAAG,mBAAmB,EAClD,MAAM,EAAE,gBAAgB,EACjC,eAAe,4BAAsD,EAC5D,GAAG,GAAE,MAAoC,EAS3D;IAEM,YAAY,IAAI,wBAAwB,CAE9C;IAEM,WAAW,CAAC,WAAW,EAAE,WAAW,GAAG,wBAAwB,CAErE;IAEY,mBAAmB,CAAC,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAsClH;IAEM,IAAI,CAAC,WAAW,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAE3G;IAEM,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC,CAElH;IAEM,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAE5B;IAEY,KAAK,mFA4BjB;IAED,SAAS,CAAC,iBAAiB,IAAI,wBAAwB,CAOtD;IAEY,IAAI,kBAOhB;IAEY,MAAM,IAAI,OAAO,CAAC,4BAA4B,CAAC,CAa3D;IAEY,oBAAoB,yBAEhC;IAEY,QAAQ,kBAIpB;IAEM,UAAU,SAOhB;IAED;;;;;OAKG;IACU,aAAa,CAAC,iBAAiB,CAAC,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CA2EvG;IAED,oGAAoG;IACvF,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAK5E;IAED;;;;OAIG;IACU,SAAS,IAAI,OAAO,CAAC,cAAc,CAAC,CAuBhD;IAED,oDAAoD;IACvC,sBAAsB,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB5E;YAOa,cAAc;YAyCd,aAAa;YAkBb,oBAAoB;IAuDlC,OAAO,CAAC,iBAAiB;YAMX,iBAAiB;IAS/B;;;OAGG;IACH,OAAO,CAAC,eAAe;CAIxB"}
|
|
@@ -2,7 +2,7 @@ import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
|
2
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
3
3
|
import { promiseWithResolvers } from '@aztec/foundation/promise';
|
|
4
4
|
import { elapsed } from '@aztec/foundation/timer';
|
|
5
|
-
import {
|
|
5
|
+
import { EventDrivenL2BlockStream } from '@aztec/stdlib/block';
|
|
6
6
|
import { WorldStateRunningState } from '@aztec/stdlib/interfaces/server';
|
|
7
7
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
8
8
|
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
@@ -46,6 +46,39 @@ import { WorldStateSynchronizerError } from './errors.js';
|
|
|
46
46
|
getSnapshot(blockNumber) {
|
|
47
47
|
return this.merkleTreeDb.getSnapshot(blockNumber);
|
|
48
48
|
}
|
|
49
|
+
async getVerifiedSnapshot(blockNumber, blockHash) {
|
|
50
|
+
const snapshot = this.merkleTreeDb.getSnapshot(blockNumber);
|
|
51
|
+
// Block 0's snapshot is the pre-genesis archive view (size 0), so archive leaf 0 is not visible from it;
|
|
52
|
+
// verify against the initial header hash instead. For later blocks, read archive leaf `blockNumber` from the
|
|
53
|
+
// snapshot's own view so the exact handle we return is validated against the requested fork.
|
|
54
|
+
const actualHash = blockNumber === BlockNumber.ZERO ? (await this.merkleTreeCommitted.getInitialHeader().hash()).toString() : (await snapshot.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(blockNumber)))?.toString();
|
|
55
|
+
if (actualHash === undefined) {
|
|
56
|
+
// A missing archive leaf means either the block's history has been pruned away (permanent: the block predates
|
|
57
|
+
// the oldest historical block kept by world state) or a reorg flipped the fork between the sync and this read
|
|
58
|
+
// (transient). Only the latter is worth retrying, so it alone surfaces as WorldStateSynchronizerError.
|
|
59
|
+
const { oldestHistoricalBlock } = await this.merkleTreeDb.getStatusSummary();
|
|
60
|
+
if (blockNumber < oldestHistoricalBlock) {
|
|
61
|
+
throw new Error(`Unable to find leaf for block ${blockNumber} in the archive tree: world state history has been pruned to block ${oldestHistoricalBlock}`);
|
|
62
|
+
}
|
|
63
|
+
throw new WorldStateSynchronizerError(`Unable to read block hash at block ${blockNumber} to verify snapshot`, {
|
|
64
|
+
cause: {
|
|
65
|
+
reason: 'block_not_available',
|
|
66
|
+
targetBlockNumber: blockNumber
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
if (actualHash !== blockHash.toString()) {
|
|
71
|
+
throw new WorldStateSynchronizerError(`Block hash mismatch at block ${blockNumber} (expected ${blockHash} but got ${actualHash})`, {
|
|
72
|
+
cause: {
|
|
73
|
+
reason: 'block_hash_mismatch',
|
|
74
|
+
targetBlockNumber: blockNumber,
|
|
75
|
+
expectedHash: blockHash.toString(),
|
|
76
|
+
actualHash
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
return snapshot;
|
|
81
|
+
}
|
|
49
82
|
fork(blockNumber, opts) {
|
|
50
83
|
return this.merkleTreeDb.fork(blockNumber, opts);
|
|
51
84
|
}
|
|
@@ -82,7 +115,7 @@ import { WorldStateSynchronizerError } from './errors.js';
|
|
|
82
115
|
}
|
|
83
116
|
createBlockStream() {
|
|
84
117
|
const logger = createLogger('world-state:block_stream');
|
|
85
|
-
return new
|
|
118
|
+
return new EventDrivenL2BlockStream(this.l2BlockSource, this, this, logger, {
|
|
86
119
|
pollIntervalMS: this.config.worldStateBlockCheckIntervalMS,
|
|
87
120
|
batchSize: this.config.worldStateBlockRequestBatchSize,
|
|
88
121
|
ignoreCheckpoints: true
|
package/dest/testing.d.ts
CHANGED
|
@@ -3,9 +3,9 @@ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
|
3
3
|
import { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
|
|
4
4
|
import type { GenesisData } from '@aztec/stdlib/world-state';
|
|
5
5
|
export declare const defaultInitialAccountFeeJuice: Fr;
|
|
6
|
-
export declare function getGenesisValues(initialAccounts: AztecAddress[], initialAccountFeeJuice?: Fr, genesisPublicData?: PublicDataTreeLeaf[], genesisTimestamp?: bigint): Promise<{
|
|
6
|
+
export declare function getGenesisValues(initialAccounts: AztecAddress[], initialAccountFeeJuice?: Fr, genesisPublicData?: PublicDataTreeLeaf[], genesisTimestamp?: bigint, prefilledNullifiers?: Fr[]): Promise<{
|
|
7
7
|
genesisArchiveRoot: Fr;
|
|
8
8
|
genesis: GenesisData;
|
|
9
9
|
fundingNeeded: bigint;
|
|
10
10
|
}>;
|
|
11
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
11
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdGluZy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3Rlc3RpbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRXBELE9BQU8sS0FBSyxFQUFFLFlBQVksRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ2hFLE9BQU8sRUFBZ0Isa0JBQWtCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN2RSxPQUFPLEtBQUssRUFBRSxXQUFXLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQTBCN0QsZUFBTyxNQUFNLDZCQUE2QixJQUFxQixDQUFDO0FBRWhFLHdCQUFzQixnQkFBZ0IsQ0FDcEMsZUFBZSxFQUFFLFlBQVksRUFBRSxFQUMvQixzQkFBc0IsS0FBZ0MsRUFDdEQsaUJBQWlCLEdBQUUsa0JBQWtCLEVBQU8sRUFDNUMsZ0JBQWdCLEdBQUUsTUFBVyxFQUM3QixtQkFBbUIsR0FBRSxFQUFFLEVBQU87Ozs7R0EwQi9CIn0=
|
package/dest/testing.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAEpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAgB,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAEpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAgB,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AA0B7D,eAAO,MAAM,6BAA6B,IAAqB,CAAC;AAEhE,wBAAsB,gBAAgB,CACpC,eAAe,EAAE,YAAY,EAAE,EAC/B,sBAAsB,KAAgC,EACtD,iBAAiB,GAAE,kBAAkB,EAAO,EAC5C,gBAAgB,GAAE,MAAW,EAC7B,mBAAmB,GAAE,EAAE,EAAO;;;;GA0B/B"}
|
package/dest/testing.js
CHANGED
|
@@ -4,13 +4,18 @@ import { computeFeePayerBalanceLeafSlot } from '@aztec/protocol-contracts/fee-ju
|
|
|
4
4
|
import { MerkleTreeId, PublicDataTreeLeaf } from '@aztec/stdlib/trees';
|
|
5
5
|
import { NativeWorldStateService } from './native/index.js';
|
|
6
6
|
async function generateGenesisValues(genesis) {
|
|
7
|
-
|
|
7
|
+
// The GENESIS_ARCHIVE_ROOT constant reflects the canonical empty genesis (no public data, no prefilled nullifiers,
|
|
8
|
+
// timestamp 0), so we can only short-circuit when this genesis adds none of those on top.
|
|
9
|
+
if (!genesis.prefilledPublicData.length && genesis.genesisTimestamp === 0n && !genesis.prefilledNullifiers?.length) {
|
|
8
10
|
return {
|
|
9
11
|
genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT)
|
|
10
12
|
};
|
|
11
13
|
}
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
+
// Compute the genesis values on a throwaway world state. The archive root derives deterministically from the
|
|
15
|
+
// prefilled public data, the prefilled nullifiers, and the genesis timestamp, so the fsync-off ephemeral store (no
|
|
16
|
+
// version manager, no crash-recoverability) produces an identical root while skipping the fsync overhead that `tmp`
|
|
17
|
+
// pays. close() removes the tmpdir.
|
|
18
|
+
const ws = await NativeWorldStateService.ephemeral(genesis);
|
|
14
19
|
const genesisArchiveRoot = new Fr((await ws.getCommitted().getTreeInfo(MerkleTreeId.ARCHIVE)).root);
|
|
15
20
|
await ws.close();
|
|
16
21
|
return {
|
|
@@ -18,14 +23,20 @@ async function generateGenesisValues(genesis) {
|
|
|
18
23
|
};
|
|
19
24
|
}
|
|
20
25
|
export const defaultInitialAccountFeeJuice = new Fr(10n ** 22n);
|
|
21
|
-
export async function getGenesisValues(initialAccounts, initialAccountFeeJuice = defaultInitialAccountFeeJuice, genesisPublicData = [], genesisTimestamp = 0n) {
|
|
26
|
+
export async function getGenesisValues(initialAccounts, initialAccountFeeJuice = defaultInitialAccountFeeJuice, genesisPublicData = [], genesisTimestamp = 0n, prefilledNullifiers = []) {
|
|
22
27
|
// Top up the accounts with fee juice.
|
|
23
28
|
let prefilledPublicData = await Promise.all(initialAccounts.map(async (address)=>new PublicDataTreeLeaf(await computeFeePayerBalanceLeafSlot(address), initialAccountFeeJuice)));
|
|
24
29
|
// Add user-defined public data
|
|
25
30
|
prefilledPublicData = prefilledPublicData.concat(genesisPublicData);
|
|
26
31
|
prefilledPublicData.sort((a, b)=>b.slot.lt(a.slot) ? 1 : -1);
|
|
32
|
+
// The indexed nullifier tree requires its prefilled leaves to be unique and strictly increasing, so sort ascending
|
|
33
|
+
// here (a copy, to avoid mutating the caller's array) rather than relying on the caller's ordering.
|
|
34
|
+
const sortedNullifiers = [
|
|
35
|
+
...prefilledNullifiers
|
|
36
|
+
].sort((a, b)=>a.toBigInt() < b.toBigInt() ? -1 : 1);
|
|
27
37
|
const genesis = {
|
|
28
38
|
prefilledPublicData,
|
|
39
|
+
prefilledNullifiers: sortedNullifiers,
|
|
29
40
|
genesisTimestamp
|
|
30
41
|
};
|
|
31
42
|
const { genesisArchiveRoot } = await generateGenesisValues(genesis);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/world-state",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dest/index.js",
|
|
@@ -64,20 +64,20 @@
|
|
|
64
64
|
]
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@aztec/bb.js": "5.0.
|
|
68
|
-
"@aztec/constants": "5.0.
|
|
69
|
-
"@aztec/foundation": "5.0.
|
|
70
|
-
"@aztec/kv-store": "5.0.
|
|
71
|
-
"@aztec/native": "5.0.
|
|
72
|
-
"@aztec/protocol-contracts": "5.0.
|
|
73
|
-
"@aztec/stdlib": "5.0.
|
|
74
|
-
"@aztec/telemetry-client": "5.0.
|
|
67
|
+
"@aztec/bb.js": "5.0.1",
|
|
68
|
+
"@aztec/constants": "5.0.1",
|
|
69
|
+
"@aztec/foundation": "5.0.1",
|
|
70
|
+
"@aztec/kv-store": "5.0.1",
|
|
71
|
+
"@aztec/native": "5.0.1",
|
|
72
|
+
"@aztec/protocol-contracts": "5.0.1",
|
|
73
|
+
"@aztec/stdlib": "5.0.1",
|
|
74
|
+
"@aztec/telemetry-client": "5.0.1",
|
|
75
75
|
"msgpackr": "^1.11.2",
|
|
76
76
|
"tslib": "^2.4.0",
|
|
77
77
|
"zod": "^4"
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
|
-
"@aztec/archiver": "5.0.
|
|
80
|
+
"@aztec/archiver": "5.0.1",
|
|
81
81
|
"@jest/globals": "^30.0.0",
|
|
82
82
|
"@types/jest": "^30.0.0",
|
|
83
83
|
"@types/node": "^22.15.17",
|
|
@@ -71,6 +71,18 @@ export class NativeWorldState implements NativeWorldStateInstance {
|
|
|
71
71
|
d.slot.toBuffer(),
|
|
72
72
|
d.value.toBuffer(),
|
|
73
73
|
]);
|
|
74
|
+
// Nullifiers to pre-insert into the genesis nullifier tree (empty by default, so production genesis roots are
|
|
75
|
+
// unchanged). The native indexed nullifier tree requires its prefilled leaves to be unique and strictly
|
|
76
|
+
// increasing, so we enforce that here before handing them over rather than failing deep inside the C++ tree
|
|
77
|
+
// construction.
|
|
78
|
+
const prefilledNullifiers = genesis.prefilledNullifiers ?? [];
|
|
79
|
+
for (let i = 1; i < prefilledNullifiers.length; i++) {
|
|
80
|
+
assert(
|
|
81
|
+
prefilledNullifiers[i].toBigInt() > prefilledNullifiers[i - 1].toBigInt(),
|
|
82
|
+
'Prefilled genesis nullifiers must be unique and strictly increasing',
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
const prefilledNullifiersBufferArray = prefilledNullifiers.map(n => n.toBuffer());
|
|
74
86
|
const ws = new BaseNativeWorldState(
|
|
75
87
|
dataDir,
|
|
76
88
|
{
|
|
@@ -85,6 +97,7 @@ export class NativeWorldState implements NativeWorldStateInstance {
|
|
|
85
97
|
[MerkleTreeId.PUBLIC_DATA_TREE]: 2 * MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
|
|
86
98
|
},
|
|
87
99
|
prefilledPublicDataBufferArray,
|
|
100
|
+
prefilledNullifiersBufferArray,
|
|
88
101
|
DomainSeparator.BLOCK_HEADER_HASH,
|
|
89
102
|
Number(genesis.genesisTimestamp),
|
|
90
103
|
{
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown by {@link ServerWorldStateSynchronizer.syncImmediate} when world state cannot be synced to the requested
|
|
3
|
+
* target: either the block is not available from the block source (`block_not_available`, e.g. it was pruned away)
|
|
4
|
+
* or the synced block does not match the requested hash (`block_hash_mismatch`, i.e. a reorg). Both causes are
|
|
5
|
+
* transient from the caller's perspective: re-resolving the query against the current chain and retrying may succeed
|
|
6
|
+
* or produce a more precise error.
|
|
7
|
+
*/
|
|
1
8
|
export class WorldStateSynchronizerError extends Error {
|
|
2
9
|
constructor(message: string, options?: ErrorOptions) {
|
|
3
10
|
super(message, options);
|
|
11
|
+
this.name = 'WorldStateSynchronizerError';
|
|
4
12
|
}
|
|
5
13
|
}
|
|
@@ -5,9 +5,9 @@ import { promiseWithResolvers } from '@aztec/foundation/promise';
|
|
|
5
5
|
import { elapsed } from '@aztec/foundation/timer';
|
|
6
6
|
import {
|
|
7
7
|
type BlockHash,
|
|
8
|
+
EventDrivenL2BlockStream,
|
|
8
9
|
type L2Block,
|
|
9
10
|
type L2BlockSource,
|
|
10
|
-
L2BlockStream,
|
|
11
11
|
type L2BlockStreamEvent,
|
|
12
12
|
type L2BlockStreamEventHandler,
|
|
13
13
|
type L2BlockStreamLocalDataProvider,
|
|
@@ -48,7 +48,7 @@ export class ServerWorldStateSynchronizer
|
|
|
48
48
|
private currentState: WorldStateRunningState = WorldStateRunningState.IDLE;
|
|
49
49
|
|
|
50
50
|
private syncPromise = promiseWithResolvers<void>();
|
|
51
|
-
protected blockStream:
|
|
51
|
+
protected blockStream: EventDrivenL2BlockStream | undefined;
|
|
52
52
|
|
|
53
53
|
// WorldState doesn't track the proven block number, it only tracks the latest tips of the pending chain and the finalized chain
|
|
54
54
|
// store the proven block number here, in the synchronizer, so that we don't end up spamming the logs with 'chain-proved' events
|
|
@@ -78,6 +78,46 @@ export class ServerWorldStateSynchronizer
|
|
|
78
78
|
return this.merkleTreeDb.getSnapshot(blockNumber);
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
public async getVerifiedSnapshot(blockNumber: BlockNumber, blockHash: BlockHash): Promise<MerkleTreeReadOperations> {
|
|
82
|
+
const snapshot = this.merkleTreeDb.getSnapshot(blockNumber);
|
|
83
|
+
// Block 0's snapshot is the pre-genesis archive view (size 0), so archive leaf 0 is not visible from it;
|
|
84
|
+
// verify against the initial header hash instead. For later blocks, read archive leaf `blockNumber` from the
|
|
85
|
+
// snapshot's own view so the exact handle we return is validated against the requested fork.
|
|
86
|
+
const actualHash =
|
|
87
|
+
blockNumber === BlockNumber.ZERO
|
|
88
|
+
? (await this.merkleTreeCommitted.getInitialHeader().hash()).toString()
|
|
89
|
+
: (await snapshot.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(blockNumber)))?.toString();
|
|
90
|
+
|
|
91
|
+
if (actualHash === undefined) {
|
|
92
|
+
// A missing archive leaf means either the block's history has been pruned away (permanent: the block predates
|
|
93
|
+
// the oldest historical block kept by world state) or a reorg flipped the fork between the sync and this read
|
|
94
|
+
// (transient). Only the latter is worth retrying, so it alone surfaces as WorldStateSynchronizerError.
|
|
95
|
+
const { oldestHistoricalBlock } = await this.merkleTreeDb.getStatusSummary();
|
|
96
|
+
if (blockNumber < oldestHistoricalBlock) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
`Unable to find leaf for block ${blockNumber} in the archive tree: world state history has been pruned to block ${oldestHistoricalBlock}`,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
throw new WorldStateSynchronizerError(`Unable to read block hash at block ${blockNumber} to verify snapshot`, {
|
|
102
|
+
cause: { reason: 'block_not_available', targetBlockNumber: blockNumber },
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (actualHash !== blockHash.toString()) {
|
|
106
|
+
throw new WorldStateSynchronizerError(
|
|
107
|
+
`Block hash mismatch at block ${blockNumber} (expected ${blockHash} but got ${actualHash})`,
|
|
108
|
+
{
|
|
109
|
+
cause: {
|
|
110
|
+
reason: 'block_hash_mismatch',
|
|
111
|
+
targetBlockNumber: blockNumber,
|
|
112
|
+
expectedHash: blockHash.toString(),
|
|
113
|
+
actualHash,
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
return snapshot;
|
|
119
|
+
}
|
|
120
|
+
|
|
81
121
|
public fork(blockNumber?: BlockNumber, opts?: { closeDelayMs?: number }): Promise<MerkleTreeWriteOperations> {
|
|
82
122
|
return this.merkleTreeDb.fork(blockNumber, opts);
|
|
83
123
|
}
|
|
@@ -120,9 +160,9 @@ export class ServerWorldStateSynchronizer
|
|
|
120
160
|
return this.syncPromise.promise;
|
|
121
161
|
}
|
|
122
162
|
|
|
123
|
-
protected createBlockStream():
|
|
163
|
+
protected createBlockStream(): EventDrivenL2BlockStream {
|
|
124
164
|
const logger = createLogger('world-state:block_stream');
|
|
125
|
-
return new
|
|
165
|
+
return new EventDrivenL2BlockStream(this.l2BlockSource, this, this, logger, {
|
|
126
166
|
pollIntervalMS: this.config.worldStateBlockCheckIntervalMS,
|
|
127
167
|
batchSize: this.config.worldStateBlockRequestBatchSize,
|
|
128
168
|
ignoreCheckpoints: true,
|
package/src/testing.ts
CHANGED
|
@@ -8,14 +8,19 @@ import type { GenesisData } from '@aztec/stdlib/world-state';
|
|
|
8
8
|
import { NativeWorldStateService } from './native/index.js';
|
|
9
9
|
|
|
10
10
|
async function generateGenesisValues(genesis: GenesisData) {
|
|
11
|
-
|
|
11
|
+
// The GENESIS_ARCHIVE_ROOT constant reflects the canonical empty genesis (no public data, no prefilled nullifiers,
|
|
12
|
+
// timestamp 0), so we can only short-circuit when this genesis adds none of those on top.
|
|
13
|
+
if (!genesis.prefilledPublicData.length && genesis.genesisTimestamp === 0n && !genesis.prefilledNullifiers?.length) {
|
|
12
14
|
return {
|
|
13
15
|
genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT),
|
|
14
16
|
};
|
|
15
17
|
}
|
|
16
18
|
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
+
// Compute the genesis values on a throwaway world state. The archive root derives deterministically from the
|
|
20
|
+
// prefilled public data, the prefilled nullifiers, and the genesis timestamp, so the fsync-off ephemeral store (no
|
|
21
|
+
// version manager, no crash-recoverability) produces an identical root while skipping the fsync overhead that `tmp`
|
|
22
|
+
// pays. close() removes the tmpdir.
|
|
23
|
+
const ws = await NativeWorldStateService.ephemeral(genesis);
|
|
19
24
|
const genesisArchiveRoot = new Fr((await ws.getCommitted().getTreeInfo(MerkleTreeId.ARCHIVE)).root);
|
|
20
25
|
await ws.close();
|
|
21
26
|
|
|
@@ -31,6 +36,7 @@ export async function getGenesisValues(
|
|
|
31
36
|
initialAccountFeeJuice = defaultInitialAccountFeeJuice,
|
|
32
37
|
genesisPublicData: PublicDataTreeLeaf[] = [],
|
|
33
38
|
genesisTimestamp: bigint = 0n,
|
|
39
|
+
prefilledNullifiers: Fr[] = [],
|
|
34
40
|
) {
|
|
35
41
|
// Top up the accounts with fee juice.
|
|
36
42
|
let prefilledPublicData = await Promise.all(
|
|
@@ -44,7 +50,11 @@ export async function getGenesisValues(
|
|
|
44
50
|
|
|
45
51
|
prefilledPublicData.sort((a, b) => (b.slot.lt(a.slot) ? 1 : -1));
|
|
46
52
|
|
|
47
|
-
|
|
53
|
+
// The indexed nullifier tree requires its prefilled leaves to be unique and strictly increasing, so sort ascending
|
|
54
|
+
// here (a copy, to avoid mutating the caller's array) rather than relying on the caller's ordering.
|
|
55
|
+
const sortedNullifiers = [...prefilledNullifiers].sort((a, b) => (a.toBigInt() < b.toBigInt() ? -1 : 1));
|
|
56
|
+
|
|
57
|
+
const genesis: GenesisData = { prefilledPublicData, prefilledNullifiers: sortedNullifiers, genesisTimestamp };
|
|
48
58
|
const { genesisArchiveRoot } = await generateGenesisValues(genesis);
|
|
49
59
|
|
|
50
60
|
return {
|