@aztec/world-state 0.0.1-commit.b655e406 → 0.0.1-commit.c31f2472
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/index.d.ts +1 -1
- package/dest/instrumentation/instrumentation.d.ts +1 -1
- package/dest/instrumentation/instrumentation.d.ts.map +1 -1
- package/dest/instrumentation/instrumentation.js +17 -41
- package/dest/native/bench_metrics.d.ts +1 -1
- package/dest/native/bench_metrics.d.ts.map +1 -1
- package/dest/native/fork_checkpoint.d.ts +1 -1
- package/dest/native/fork_checkpoint.d.ts.map +1 -1
- package/dest/native/index.d.ts +1 -1
- package/dest/native/merkle_trees_facade.d.ts +12 -6
- package/dest/native/merkle_trees_facade.d.ts.map +1 -1
- package/dest/native/merkle_trees_facade.js +39 -8
- package/dest/native/message.d.ts +12 -11
- package/dest/native/message.d.ts.map +1 -1
- package/dest/native/message.js +14 -13
- package/dest/native/native_world_state.d.ts +15 -12
- package/dest/native/native_world_state.d.ts.map +1 -1
- package/dest/native/native_world_state.js +22 -17
- package/dest/native/native_world_state_instance.d.ts +12 -3
- package/dest/native/native_world_state_instance.d.ts.map +1 -1
- package/dest/native/native_world_state_instance.js +24 -3
- package/dest/native/world_state_ops_queue.d.ts +1 -1
- package/dest/native/world_state_ops_queue.d.ts.map +1 -1
- package/dest/synchronizer/config.d.ts +1 -3
- package/dest/synchronizer/config.d.ts.map +1 -1
- package/dest/synchronizer/config.js +1 -6
- package/dest/synchronizer/errors.d.ts +1 -1
- package/dest/synchronizer/errors.d.ts.map +1 -1
- package/dest/synchronizer/factory.d.ts +4 -3
- package/dest/synchronizer/factory.d.ts.map +1 -1
- package/dest/synchronizer/factory.js +5 -5
- package/dest/synchronizer/index.d.ts +1 -1
- package/dest/synchronizer/server_world_state_synchronizer.d.ts +10 -27
- package/dest/synchronizer/server_world_state_synchronizer.d.ts.map +1 -1
- package/dest/synchronizer/server_world_state_synchronizer.js +79 -69
- package/dest/test/index.d.ts +1 -1
- package/dest/test/utils.d.ts +12 -5
- package/dest/test/utils.d.ts.map +1 -1
- package/dest/test/utils.js +54 -50
- package/dest/testing.d.ts +2 -2
- package/dest/testing.d.ts.map +1 -1
- package/dest/testing.js +1 -1
- package/dest/world-state-db/index.d.ts +1 -1
- package/dest/world-state-db/merkle_tree_db.d.ts +9 -10
- package/dest/world-state-db/merkle_tree_db.d.ts.map +1 -1
- package/package.json +13 -12
- package/src/instrumentation/instrumentation.ts +17 -41
- package/src/native/merkle_trees_facade.ts +42 -8
- package/src/native/message.ts +23 -22
- package/src/native/native_world_state.ts +53 -27
- package/src/native/native_world_state_instance.ts +33 -3
- package/src/synchronizer/config.ts +1 -14
- package/src/synchronizer/factory.ts +7 -1
- package/src/synchronizer/server_world_state_synchronizer.ts +94 -96
- package/src/test/utils.ts +87 -92
- package/src/testing.ts +1 -1
- package/src/world-state-db/merkle_tree_db.ts +12 -9
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
Metrics,
|
|
8
8
|
type TelemetryClient,
|
|
9
9
|
type UpDownCounter,
|
|
10
|
-
|
|
10
|
+
createUpDownCounterWithDefault,
|
|
11
11
|
} from '@aztec/telemetry-client';
|
|
12
12
|
|
|
13
13
|
import {
|
|
@@ -46,55 +46,31 @@ export class WorldStateInstrumentation {
|
|
|
46
46
|
private log: Logger = createLogger('world-state:instrumentation'),
|
|
47
47
|
) {
|
|
48
48
|
const meter = telemetry.getMeter('World State');
|
|
49
|
-
this.dbMapSize = meter.createGauge(Metrics.WORLD_STATE_DB_MAP_SIZE
|
|
50
|
-
description: `The current configured map size for each merkle tree`,
|
|
51
|
-
valueType: ValueType.INT,
|
|
52
|
-
});
|
|
49
|
+
this.dbMapSize = meter.createGauge(Metrics.WORLD_STATE_DB_MAP_SIZE);
|
|
53
50
|
|
|
54
|
-
this.dbPhysicalSize = meter.createGauge(Metrics.WORLD_STATE_DB_PHYSICAL_SIZE
|
|
55
|
-
description: `The current physical disk space used for each database`,
|
|
56
|
-
valueType: ValueType.INT,
|
|
57
|
-
});
|
|
51
|
+
this.dbPhysicalSize = meter.createGauge(Metrics.WORLD_STATE_DB_PHYSICAL_SIZE);
|
|
58
52
|
|
|
59
|
-
this.treeSize = meter.createGauge(Metrics.WORLD_STATE_TREE_SIZE
|
|
60
|
-
description: `The current number of leaves in each merkle tree`,
|
|
61
|
-
valueType: ValueType.INT,
|
|
62
|
-
});
|
|
53
|
+
this.treeSize = meter.createGauge(Metrics.WORLD_STATE_TREE_SIZE);
|
|
63
54
|
|
|
64
|
-
this.unfinalizedHeight = meter.createGauge(Metrics.WORLD_STATE_UNFINALIZED_HEIGHT
|
|
65
|
-
description: `The unfinalized block height of each merkle tree`,
|
|
66
|
-
valueType: ValueType.INT,
|
|
67
|
-
});
|
|
55
|
+
this.unfinalizedHeight = meter.createGauge(Metrics.WORLD_STATE_UNFINALIZED_HEIGHT);
|
|
68
56
|
|
|
69
|
-
this.finalizedHeight = meter.createGauge(Metrics.WORLD_STATE_FINALIZED_HEIGHT
|
|
70
|
-
description: `The finalized block height of each merkle tree`,
|
|
71
|
-
valueType: ValueType.INT,
|
|
72
|
-
});
|
|
57
|
+
this.finalizedHeight = meter.createGauge(Metrics.WORLD_STATE_FINALIZED_HEIGHT);
|
|
73
58
|
|
|
74
|
-
this.oldestBlock = meter.createGauge(Metrics.WORLD_STATE_OLDEST_BLOCK
|
|
75
|
-
description: `The oldest historical block of each merkle tree`,
|
|
76
|
-
valueType: ValueType.INT,
|
|
77
|
-
});
|
|
59
|
+
this.oldestBlock = meter.createGauge(Metrics.WORLD_STATE_OLDEST_BLOCK);
|
|
78
60
|
|
|
79
|
-
this.dbUsedSize = meter.createGauge(Metrics.WORLD_STATE_DB_USED_SIZE
|
|
80
|
-
description: `The current used database size for each db of each merkle tree`,
|
|
81
|
-
valueType: ValueType.INT,
|
|
82
|
-
});
|
|
61
|
+
this.dbUsedSize = meter.createGauge(Metrics.WORLD_STATE_DB_USED_SIZE);
|
|
83
62
|
|
|
84
|
-
this.dbNumItems = meter.createGauge(Metrics.WORLD_STATE_DB_NUM_ITEMS
|
|
85
|
-
description: `The current number of items in each database of each merkle tree`,
|
|
86
|
-
valueType: ValueType.INT,
|
|
87
|
-
});
|
|
63
|
+
this.dbNumItems = meter.createGauge(Metrics.WORLD_STATE_DB_NUM_ITEMS);
|
|
88
64
|
|
|
89
|
-
this.requestHistogram = meter.createHistogram(Metrics.WORLD_STATE_REQUEST_TIME
|
|
90
|
-
description: 'The round trip time of world state requests',
|
|
91
|
-
unit: 'us',
|
|
92
|
-
valueType: ValueType.INT,
|
|
93
|
-
});
|
|
65
|
+
this.requestHistogram = meter.createHistogram(Metrics.WORLD_STATE_REQUEST_TIME);
|
|
94
66
|
|
|
95
|
-
this.criticalErrors = meter
|
|
96
|
-
|
|
97
|
-
|
|
67
|
+
this.criticalErrors = createUpDownCounterWithDefault(meter, Metrics.WORLD_STATE_CRITICAL_ERROR_COUNT, {
|
|
68
|
+
[Attributes.ERROR_TYPE]: [
|
|
69
|
+
'synch_pending_block',
|
|
70
|
+
'finalize_block',
|
|
71
|
+
'prune_pending_block',
|
|
72
|
+
'prune_historical_block',
|
|
73
|
+
],
|
|
98
74
|
});
|
|
99
75
|
}
|
|
100
76
|
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
2
4
|
import { serializeToBuffer } from '@aztec/foundation/serialize';
|
|
5
|
+
import { sleep } from '@aztec/foundation/sleep';
|
|
3
6
|
import { type IndexedTreeLeafPreimage, SiblingPath } from '@aztec/foundation/trees';
|
|
4
7
|
import type {
|
|
5
8
|
BatchInsertionResult,
|
|
@@ -18,7 +21,7 @@ import {
|
|
|
18
21
|
PublicDataTreeLeafPreimage,
|
|
19
22
|
} from '@aztec/stdlib/trees';
|
|
20
23
|
import { type BlockHeader, PartialStateReference, StateReference } from '@aztec/stdlib/tx';
|
|
21
|
-
import type
|
|
24
|
+
import { type WorldStateRevision, WorldStateRevisionWithHandle } from '@aztec/stdlib/world-state';
|
|
22
25
|
|
|
23
26
|
import assert from 'assert';
|
|
24
27
|
|
|
@@ -42,8 +45,8 @@ export class MerkleTreesFacade implements MerkleTreeReadOperations {
|
|
|
42
45
|
return this.initialHeader;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
getRevision():
|
|
46
|
-
return this.revision;
|
|
48
|
+
getRevision(): WorldStateRevisionWithHandle {
|
|
49
|
+
return WorldStateRevisionWithHandle.fromWorldStateRevision(this.revision, this.instance.getHandle());
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
findLeafIndices(treeId: MerkleTreeId, values: MerkleTreeLeafType<MerkleTreeId>[]): Promise<(bigint | undefined)[]> {
|
|
@@ -191,19 +194,26 @@ export class MerkleTreesFacade implements MerkleTreeReadOperations {
|
|
|
191
194
|
async getBlockNumbersForLeafIndices<ID extends MerkleTreeId>(
|
|
192
195
|
treeId: ID,
|
|
193
196
|
leafIndices: bigint[],
|
|
194
|
-
): Promise<(
|
|
197
|
+
): Promise<(BlockNumber | undefined)[]> {
|
|
195
198
|
const response = await this.instance.call(WorldStateMessageType.GET_BLOCK_NUMBERS_FOR_LEAF_INDICES, {
|
|
196
199
|
treeId,
|
|
197
200
|
revision: this.revision,
|
|
198
201
|
leafIndices,
|
|
199
202
|
});
|
|
200
203
|
|
|
201
|
-
return response.blockNumbers.map(x => (x === undefined || x === null ? undefined :
|
|
204
|
+
return response.blockNumbers.map(x => (x === undefined || x === null ? undefined : BlockNumber(Number(x))));
|
|
202
205
|
}
|
|
203
206
|
}
|
|
204
207
|
|
|
205
208
|
export class MerkleTreesForkFacade extends MerkleTreesFacade implements MerkleTreeWriteOperations {
|
|
206
|
-
|
|
209
|
+
private log = createLogger('world-state:merkle-trees-fork-facade');
|
|
210
|
+
|
|
211
|
+
constructor(
|
|
212
|
+
instance: NativeWorldStateInstance,
|
|
213
|
+
initialHeader: BlockHeader,
|
|
214
|
+
revision: WorldStateRevision,
|
|
215
|
+
private opts: { closeDelayMs?: number },
|
|
216
|
+
) {
|
|
207
217
|
assert.notEqual(revision.forkId, 0, 'Fork ID must be set');
|
|
208
218
|
assert.equal(revision.includeUncommitted, true, 'Fork must include uncommitted data');
|
|
209
219
|
super(instance, initialHeader, revision);
|
|
@@ -282,7 +292,31 @@ export class MerkleTreesForkFacade extends MerkleTreesFacade implements MerkleTr
|
|
|
282
292
|
|
|
283
293
|
public async close(): Promise<void> {
|
|
284
294
|
assert.notEqual(this.revision.forkId, 0, 'Fork ID must be set');
|
|
285
|
-
|
|
295
|
+
try {
|
|
296
|
+
await this.instance.call(WorldStateMessageType.DELETE_FORK, { forkId: this.revision.forkId });
|
|
297
|
+
} catch (err: any) {
|
|
298
|
+
// Ignore errors due to native instance being closed during shutdown.
|
|
299
|
+
// This can happen when validators are still processing block proposals while the node is stopping.
|
|
300
|
+
if (err?.message === 'Native instance is closed') {
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
throw err;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
async [Symbol.dispose](): Promise<void> {
|
|
308
|
+
if (this.opts.closeDelayMs) {
|
|
309
|
+
void sleep(this.opts.closeDelayMs)
|
|
310
|
+
.then(() => this.close())
|
|
311
|
+
.catch(err => {
|
|
312
|
+
if (err && 'message' in err && err.message === 'Native instance is closed') {
|
|
313
|
+
return; // Ignore errors due to native instance being closed
|
|
314
|
+
}
|
|
315
|
+
this.log.warn('Error closing MerkleTreesForkFacade after delay', { err });
|
|
316
|
+
});
|
|
317
|
+
} else {
|
|
318
|
+
await this.close();
|
|
319
|
+
}
|
|
286
320
|
}
|
|
287
321
|
|
|
288
322
|
public async createCheckpoint(): Promise<void> {
|
package/src/native/message.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
2
3
|
import type { Tuple } from '@aztec/foundation/serialize';
|
|
3
4
|
import { AppendOnlyTreeSnapshot, MerkleTreeId } from '@aztec/stdlib/trees';
|
|
4
5
|
import type { StateReference } from '@aztec/stdlib/tx';
|
|
@@ -56,11 +57,11 @@ interface WithTreeId {
|
|
|
56
57
|
|
|
57
58
|
export interface WorldStateStatusSummary {
|
|
58
59
|
/** Last block number that can still be unwound. */
|
|
59
|
-
unfinalizedBlockNumber:
|
|
60
|
+
unfinalizedBlockNumber: BlockNumber;
|
|
60
61
|
/** Last block number that is finalized and cannot be unwound. */
|
|
61
|
-
finalizedBlockNumber:
|
|
62
|
+
finalizedBlockNumber: BlockNumber;
|
|
62
63
|
/** Oldest block still available for historical queries and forks. */
|
|
63
|
-
oldestHistoricalBlock:
|
|
64
|
+
oldestHistoricalBlock: BlockNumber;
|
|
64
65
|
/** Whether the trees are in sync with each other */
|
|
65
66
|
treesAreSynched: boolean;
|
|
66
67
|
}
|
|
@@ -81,11 +82,11 @@ export interface TreeMeta {
|
|
|
81
82
|
/** The tree's initial root value */
|
|
82
83
|
initialRoot: Fr;
|
|
83
84
|
/** The current oldest historical block number of the tree */
|
|
84
|
-
oldestHistoricBlock:
|
|
85
|
+
oldestHistoricBlock: BlockNumber;
|
|
85
86
|
/** The current unfinalized block number of the tree */
|
|
86
|
-
unfinalizedBlockHeight:
|
|
87
|
+
unfinalizedBlockHeight: BlockNumber;
|
|
87
88
|
/** The current finalized block number of the tree */
|
|
88
|
-
finalizedBlockHeight:
|
|
89
|
+
finalizedBlockHeight: BlockNumber;
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
export interface DBStats {
|
|
@@ -173,9 +174,9 @@ export function buildEmptyTreeMeta() {
|
|
|
173
174
|
depth: 0,
|
|
174
175
|
size: 0n,
|
|
175
176
|
committedSize: 0n,
|
|
176
|
-
unfinalizedBlockHeight:
|
|
177
|
-
finalizedBlockHeight:
|
|
178
|
-
oldestHistoricBlock:
|
|
177
|
+
unfinalizedBlockHeight: BlockNumber.ZERO,
|
|
178
|
+
finalizedBlockHeight: BlockNumber.ZERO,
|
|
179
|
+
oldestHistoricBlock: BlockNumber.ZERO,
|
|
179
180
|
root: Fr.ZERO,
|
|
180
181
|
initialRoot: Fr.ZERO,
|
|
181
182
|
initialSize: 0n,
|
|
@@ -204,9 +205,9 @@ export function buildEmptyWorldStateDBStats() {
|
|
|
204
205
|
|
|
205
206
|
export function buildEmptyWorldStateSummary() {
|
|
206
207
|
return {
|
|
207
|
-
unfinalizedBlockNumber:
|
|
208
|
-
finalizedBlockNumber:
|
|
209
|
-
oldestHistoricalBlock:
|
|
208
|
+
unfinalizedBlockNumber: BlockNumber.ZERO,
|
|
209
|
+
finalizedBlockNumber: BlockNumber.ZERO,
|
|
210
|
+
oldestHistoricalBlock: BlockNumber.ZERO,
|
|
210
211
|
treesAreSynched: true,
|
|
211
212
|
} as WorldStateStatusSummary;
|
|
212
213
|
}
|
|
@@ -220,9 +221,9 @@ export function buildEmptyWorldStateStatusFull() {
|
|
|
220
221
|
}
|
|
221
222
|
|
|
222
223
|
export function sanitizeSummary(summary: WorldStateStatusSummary) {
|
|
223
|
-
summary.finalizedBlockNumber = BigInt(summary.finalizedBlockNumber);
|
|
224
|
-
summary.unfinalizedBlockNumber = BigInt(summary.unfinalizedBlockNumber);
|
|
225
|
-
summary.oldestHistoricalBlock = BigInt(summary.oldestHistoricalBlock);
|
|
224
|
+
summary.finalizedBlockNumber = BlockNumber.fromBigInt(BigInt(summary.finalizedBlockNumber));
|
|
225
|
+
summary.unfinalizedBlockNumber = BlockNumber.fromBigInt(BigInt(summary.unfinalizedBlockNumber));
|
|
226
|
+
summary.oldestHistoricalBlock = BlockNumber.fromBigInt(BigInt(summary.oldestHistoricalBlock));
|
|
226
227
|
return summary;
|
|
227
228
|
}
|
|
228
229
|
|
|
@@ -234,11 +235,11 @@ export function sanitizeDBStats(stats: DBStats) {
|
|
|
234
235
|
|
|
235
236
|
export function sanitizeMeta(meta: TreeMeta) {
|
|
236
237
|
meta.committedSize = BigInt(meta.committedSize);
|
|
237
|
-
meta.finalizedBlockHeight = BigInt(meta.finalizedBlockHeight);
|
|
238
|
+
meta.finalizedBlockHeight = BlockNumber.fromBigInt(BigInt(meta.finalizedBlockHeight));
|
|
238
239
|
meta.initialSize = BigInt(meta.initialSize);
|
|
239
|
-
meta.oldestHistoricBlock = BigInt(meta.oldestHistoricBlock);
|
|
240
|
+
meta.oldestHistoricBlock = BlockNumber.fromBigInt(BigInt(meta.oldestHistoricBlock));
|
|
240
241
|
meta.size = BigInt(meta.size);
|
|
241
|
-
meta.unfinalizedBlockHeight = BigInt(meta.unfinalizedBlockHeight);
|
|
242
|
+
meta.unfinalizedBlockHeight = BlockNumber.fromBigInt(BigInt(meta.unfinalizedBlockHeight));
|
|
242
243
|
return meta;
|
|
243
244
|
}
|
|
244
245
|
|
|
@@ -310,7 +311,7 @@ interface WithLeafValues {
|
|
|
310
311
|
}
|
|
311
312
|
|
|
312
313
|
interface BlockShiftRequest extends WithCanonicalForkId {
|
|
313
|
-
toBlockNumber:
|
|
314
|
+
toBlockNumber: BlockNumber;
|
|
314
315
|
}
|
|
315
316
|
|
|
316
317
|
interface WithLeaves {
|
|
@@ -409,7 +410,7 @@ interface UpdateArchiveRequest extends WithForkId {
|
|
|
409
410
|
}
|
|
410
411
|
|
|
411
412
|
interface SyncBlockRequest extends WithCanonicalForkId {
|
|
412
|
-
blockNumber:
|
|
413
|
+
blockNumber: BlockNumber;
|
|
413
414
|
blockStateRef: BlockStateReference;
|
|
414
415
|
blockHeaderHash: Fr;
|
|
415
416
|
paddedNoteHashes: readonly SerializedLeafValue[];
|
|
@@ -420,7 +421,7 @@ interface SyncBlockRequest extends WithCanonicalForkId {
|
|
|
420
421
|
|
|
421
422
|
interface CreateForkRequest extends WithCanonicalForkId {
|
|
422
423
|
latest: boolean;
|
|
423
|
-
blockNumber:
|
|
424
|
+
blockNumber: BlockNumber;
|
|
424
425
|
}
|
|
425
426
|
|
|
426
427
|
interface CreateForkResponse {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
|
|
2
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
3
|
import { fromEntries, padArrayEnd } from '@aztec/foundation/collection';
|
|
4
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
5
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
4
|
-
import { Fr } from '@aztec/foundation/fields';
|
|
5
6
|
import { tryRmDir } from '@aztec/foundation/fs';
|
|
6
|
-
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
7
|
+
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
7
8
|
import type { L2Block } from '@aztec/stdlib/block';
|
|
8
9
|
import { DatabaseVersionManager } from '@aztec/stdlib/database-version';
|
|
9
10
|
import type {
|
|
@@ -51,7 +52,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
51
52
|
protected constructor(
|
|
52
53
|
protected instance: NativeWorldState,
|
|
53
54
|
protected readonly worldStateInstrumentation: WorldStateInstrumentation,
|
|
54
|
-
protected readonly log: Logger
|
|
55
|
+
protected readonly log: Logger,
|
|
55
56
|
private readonly cleanup = () => Promise.resolve(),
|
|
56
57
|
) {}
|
|
57
58
|
|
|
@@ -61,9 +62,10 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
61
62
|
wsTreeMapSizes: WorldStateTreeMapSizes,
|
|
62
63
|
prefilledPublicData: PublicDataTreeLeaf[] = [],
|
|
63
64
|
instrumentation = new WorldStateInstrumentation(getTelemetryClient()),
|
|
64
|
-
|
|
65
|
+
bindings?: LoggerBindings,
|
|
65
66
|
cleanup = () => Promise.resolve(),
|
|
66
67
|
): Promise<NativeWorldStateService> {
|
|
68
|
+
const log = createLogger('world-state:database', bindings);
|
|
67
69
|
const worldStateDirectory = join(dataDir, WORLD_STATE_DIR);
|
|
68
70
|
// Create a version manager to handle versioning
|
|
69
71
|
const versionManager = new DatabaseVersionManager({
|
|
@@ -71,7 +73,9 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
71
73
|
rollupAddress,
|
|
72
74
|
dataDirectory: worldStateDirectory,
|
|
73
75
|
onOpen: (dir: string) => {
|
|
74
|
-
return Promise.resolve(
|
|
76
|
+
return Promise.resolve(
|
|
77
|
+
new NativeWorldState(dir, wsTreeMapSizes, prefilledPublicData, instrumentation, bindings),
|
|
78
|
+
);
|
|
75
79
|
},
|
|
76
80
|
});
|
|
77
81
|
|
|
@@ -92,8 +96,9 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
92
96
|
cleanupTmpDir = true,
|
|
93
97
|
prefilledPublicData: PublicDataTreeLeaf[] = [],
|
|
94
98
|
instrumentation = new WorldStateInstrumentation(getTelemetryClient()),
|
|
99
|
+
bindings?: LoggerBindings,
|
|
95
100
|
): Promise<NativeWorldStateService> {
|
|
96
|
-
const log = createLogger('world-state:database');
|
|
101
|
+
const log = createLogger('world-state:database', bindings);
|
|
97
102
|
const dataDir = await mkdtemp(join(tmpdir(), 'aztec-world-state-'));
|
|
98
103
|
const dbMapSizeKb = 10 * 1024 * 1024;
|
|
99
104
|
const worldStateTreeMapSizes: WorldStateTreeMapSizes = {
|
|
@@ -115,7 +120,15 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
115
120
|
}
|
|
116
121
|
};
|
|
117
122
|
|
|
118
|
-
return this.new(
|
|
123
|
+
return this.new(
|
|
124
|
+
rollupAddress,
|
|
125
|
+
dataDir,
|
|
126
|
+
worldStateTreeMapSizes,
|
|
127
|
+
prefilledPublicData,
|
|
128
|
+
instrumentation,
|
|
129
|
+
bindings,
|
|
130
|
+
cleanup,
|
|
131
|
+
);
|
|
119
132
|
}
|
|
120
133
|
|
|
121
134
|
protected async init() {
|
|
@@ -134,7 +147,9 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
134
147
|
|
|
135
148
|
// the initial header _must_ be the first element in the archive tree
|
|
136
149
|
// if this assertion fails, check that the hashing done in Header in yarn-project matches the initial header hash done in world_state.cpp
|
|
137
|
-
const indices = await committed.findLeafIndices(MerkleTreeId.ARCHIVE, [
|
|
150
|
+
const indices = await committed.findLeafIndices(MerkleTreeId.ARCHIVE, [
|
|
151
|
+
(await this.initialHeader.hash()).toField(),
|
|
152
|
+
]);
|
|
138
153
|
const initialHeaderIndex = indices[0];
|
|
139
154
|
assert.strictEqual(initialHeaderIndex, 0n, 'Invalid initial archive state');
|
|
140
155
|
}
|
|
@@ -150,7 +165,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
150
165
|
return new MerkleTreesFacade(this.instance, this.initialHeader!, WorldStateRevision.empty());
|
|
151
166
|
}
|
|
152
167
|
|
|
153
|
-
public getSnapshot(blockNumber:
|
|
168
|
+
public getSnapshot(blockNumber: BlockNumber): MerkleTreeReadOperations {
|
|
154
169
|
return new MerkleTreesFacade(
|
|
155
170
|
this.instance,
|
|
156
171
|
this.initialHeader!,
|
|
@@ -158,16 +173,24 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
158
173
|
);
|
|
159
174
|
}
|
|
160
175
|
|
|
161
|
-
public async fork(
|
|
176
|
+
public async fork(
|
|
177
|
+
blockNumber?: BlockNumber,
|
|
178
|
+
opts: { closeDelayMs?: number } = {},
|
|
179
|
+
): Promise<MerkleTreeWriteOperations> {
|
|
162
180
|
const resp = await this.instance.call(WorldStateMessageType.CREATE_FORK, {
|
|
163
181
|
latest: blockNumber === undefined,
|
|
164
|
-
blockNumber: blockNumber ??
|
|
182
|
+
blockNumber: blockNumber ?? BlockNumber.ZERO,
|
|
165
183
|
canonical: true,
|
|
166
184
|
});
|
|
167
185
|
return new MerkleTreesForkFacade(
|
|
168
186
|
this.instance,
|
|
169
187
|
this.initialHeader!,
|
|
170
|
-
new WorldStateRevision(
|
|
188
|
+
new WorldStateRevision(
|
|
189
|
+
/*forkId=*/ resp.forkId,
|
|
190
|
+
/* blockNumber=*/ BlockNumber.ZERO,
|
|
191
|
+
/* includeUncommitted=*/ true,
|
|
192
|
+
),
|
|
193
|
+
opts,
|
|
171
194
|
);
|
|
172
195
|
}
|
|
173
196
|
|
|
@@ -175,21 +198,24 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
175
198
|
return this.initialHeader!;
|
|
176
199
|
}
|
|
177
200
|
|
|
178
|
-
public async handleL2BlockAndMessages(
|
|
179
|
-
l2Block
|
|
180
|
-
l1ToL2Messages
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
);
|
|
201
|
+
public async handleL2BlockAndMessages(l2Block: L2Block, l1ToL2Messages: Fr[]): Promise<WorldStateStatusFull> {
|
|
202
|
+
const isFirstBlock = l2Block.indexWithinCheckpoint === 0;
|
|
203
|
+
if (!isFirstBlock && l1ToL2Messages.length > 0) {
|
|
204
|
+
throw new Error(
|
|
205
|
+
`L1 to L2 messages must be empty for non-first blocks, but got ${l1ToL2Messages.length} messages for block ${l2Block.number}.`,
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// We have to pad the given l1 to l2 messages, and the note hashes and nullifiers within tx effects, because that's
|
|
210
|
+
// how the trees are built by circuits.
|
|
189
211
|
const paddedL1ToL2Messages = isFirstBlock
|
|
190
212
|
? padArrayEnd<Fr, number>(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP)
|
|
191
213
|
: [];
|
|
192
214
|
|
|
215
|
+
const paddedNoteHashes = l2Block.body.txEffects.flatMap(txEffect =>
|
|
216
|
+
padArrayEnd(txEffect.noteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX),
|
|
217
|
+
);
|
|
218
|
+
|
|
193
219
|
const paddedNullifiers = l2Block.body.txEffects
|
|
194
220
|
.flatMap(txEffect => padArrayEnd(txEffect.nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX))
|
|
195
221
|
.map(nullifier => new NullifierLeaf(nullifier));
|
|
@@ -208,7 +234,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
208
234
|
WorldStateMessageType.SYNC_BLOCK,
|
|
209
235
|
{
|
|
210
236
|
blockNumber: l2Block.number,
|
|
211
|
-
blockHeaderHash: await l2Block.
|
|
237
|
+
blockHeaderHash: await l2Block.hash(),
|
|
212
238
|
paddedL1ToL2Messages: paddedL1ToL2Messages.map(serializeLeaf),
|
|
213
239
|
paddedNoteHashes: paddedNoteHashes.map(serializeLeaf),
|
|
214
240
|
paddedNullifiers: paddedNullifiers.map(serializeLeaf),
|
|
@@ -256,7 +282,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
256
282
|
* @param toBlockNumber The block number that is now the tip of the finalized chain
|
|
257
283
|
* @returns The new WorldStateStatus
|
|
258
284
|
*/
|
|
259
|
-
public async setFinalized(toBlockNumber:
|
|
285
|
+
public async setFinalized(toBlockNumber: BlockNumber) {
|
|
260
286
|
try {
|
|
261
287
|
await this.instance.call(
|
|
262
288
|
WorldStateMessageType.FINALIZE_BLOCKS,
|
|
@@ -279,7 +305,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
279
305
|
* @param toBlockNumber The block number of the new oldest historical block
|
|
280
306
|
* @returns The new WorldStateStatus
|
|
281
307
|
*/
|
|
282
|
-
public async removeHistoricalBlocks(toBlockNumber:
|
|
308
|
+
public async removeHistoricalBlocks(toBlockNumber: BlockNumber) {
|
|
283
309
|
try {
|
|
284
310
|
return await this.instance.call(
|
|
285
311
|
WorldStateMessageType.REMOVE_HISTORICAL_BLOCKS,
|
|
@@ -301,7 +327,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
301
327
|
* @param toBlockNumber The block number of the new tip of the pending chain,
|
|
302
328
|
* @returns The new WorldStateStatus
|
|
303
329
|
*/
|
|
304
|
-
public async unwindBlocks(toBlockNumber:
|
|
330
|
+
public async unwindBlocks(toBlockNumber: BlockNumber) {
|
|
305
331
|
try {
|
|
306
332
|
return await this.instance.call(
|
|
307
333
|
WorldStateMessageType.UNWIND_BLOCKS,
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
NULLIFIER_TREE_HEIGHT,
|
|
9
9
|
PUBLIC_DATA_TREE_HEIGHT,
|
|
10
10
|
} from '@aztec/constants';
|
|
11
|
-
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
11
|
+
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
12
12
|
import { NativeWorldState as BaseNativeWorldState, MsgpackChannel } from '@aztec/native';
|
|
13
13
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
14
14
|
import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
|
|
@@ -36,6 +36,8 @@ export interface NativeWorldStateInstance {
|
|
|
36
36
|
messageType: T,
|
|
37
37
|
body: WorldStateRequest[T] & WorldStateRequestCategories,
|
|
38
38
|
): Promise<WorldStateResponse[T]>;
|
|
39
|
+
// TODO(dbanks12): this returns any type, but we should strongly type it
|
|
40
|
+
getHandle(): any;
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
/**
|
|
@@ -55,7 +57,8 @@ export class NativeWorldState implements NativeWorldStateInstance {
|
|
|
55
57
|
private readonly wsTreeMapSizes: WorldStateTreeMapSizes,
|
|
56
58
|
private readonly prefilledPublicData: PublicDataTreeLeaf[] = [],
|
|
57
59
|
private readonly instrumentation: WorldStateInstrumentation,
|
|
58
|
-
|
|
60
|
+
bindings?: LoggerBindings,
|
|
61
|
+
private readonly log: Logger = createLogger('world-state:database', bindings),
|
|
59
62
|
) {
|
|
60
63
|
const threads = Math.min(cpus().length, MAX_WORLD_STATE_THREADS);
|
|
61
64
|
log.info(
|
|
@@ -78,7 +81,7 @@ export class NativeWorldState implements NativeWorldStateInstance {
|
|
|
78
81
|
[MerkleTreeId.PUBLIC_DATA_TREE]: 2 * MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
|
|
79
82
|
},
|
|
80
83
|
prefilledPublicDataBufferArray,
|
|
81
|
-
GeneratorIndex.
|
|
84
|
+
GeneratorIndex.BLOCK_HEADER_HASH,
|
|
82
85
|
{
|
|
83
86
|
[MerkleTreeId.NULLIFIER_TREE]: wsTreeMapSizes.nullifierTreeMapSizeKb,
|
|
84
87
|
[MerkleTreeId.NOTE_HASH_TREE]: wsTreeMapSizes.noteHashTreeMapSizeKb,
|
|
@@ -103,10 +106,37 @@ export class NativeWorldState implements NativeWorldStateInstance {
|
|
|
103
106
|
this.wsTreeMapSizes,
|
|
104
107
|
this.prefilledPublicData,
|
|
105
108
|
this.instrumentation,
|
|
109
|
+
this.log.getBindings(),
|
|
106
110
|
this.log,
|
|
107
111
|
);
|
|
108
112
|
}
|
|
109
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Gets the native WorldState handle from the underlying native instance.
|
|
116
|
+
* We call the getHandle() method on the native WorldState to get a NAPI External
|
|
117
|
+
* that wraps the underlying C++ WorldState pointer.
|
|
118
|
+
* @returns The NAPI External handle to the native WorldState instance,since
|
|
119
|
+
* the NAPI external type is opaque, we return any (we could also use an opaque symbol type)
|
|
120
|
+
*/
|
|
121
|
+
public getHandle(): any {
|
|
122
|
+
const worldStateWrapper = (this.instance as any).dest;
|
|
123
|
+
|
|
124
|
+
if (!worldStateWrapper) {
|
|
125
|
+
throw new Error('No WorldStateWrapper found');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (typeof worldStateWrapper.getHandle !== 'function') {
|
|
129
|
+
throw new Error('WorldStateWrapper does not have getHandle method');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Call getHandle() to get the NAPI External
|
|
133
|
+
try {
|
|
134
|
+
return worldStateWrapper.getHandle();
|
|
135
|
+
} catch (error) {
|
|
136
|
+
this.log.error('Failed to get native WorldState handle', error);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
110
140
|
/**
|
|
111
141
|
* Sends a message to the native instance and returns the response.
|
|
112
142
|
* @param messageType - The type of message to send
|
|
@@ -1,18 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type ConfigMappingsType,
|
|
3
|
-
booleanConfigHelper,
|
|
4
|
-
getConfigFromMappings,
|
|
5
|
-
numberConfigHelper,
|
|
6
|
-
} from '@aztec/foundation/config';
|
|
1
|
+
import { type ConfigMappingsType, getConfigFromMappings, numberConfigHelper } from '@aztec/foundation/config';
|
|
7
2
|
|
|
8
3
|
/** World State synchronizer configuration values. */
|
|
9
4
|
export interface WorldStateConfig {
|
|
10
5
|
/** The frequency in which to check. */
|
|
11
6
|
worldStateBlockCheckIntervalMS: number;
|
|
12
7
|
|
|
13
|
-
/** Whether to follow only the proven chain. */
|
|
14
|
-
worldStateProvenBlocksOnly: boolean;
|
|
15
|
-
|
|
16
8
|
/** Size of the batch for each get-blocks request from the synchronizer to the archiver. */
|
|
17
9
|
worldStateBlockRequestBatchSize?: number;
|
|
18
10
|
|
|
@@ -48,11 +40,6 @@ export const worldStateConfigMappings: ConfigMappingsType<WorldStateConfig> = {
|
|
|
48
40
|
defaultValue: 100,
|
|
49
41
|
description: 'The frequency in which to check.',
|
|
50
42
|
},
|
|
51
|
-
worldStateProvenBlocksOnly: {
|
|
52
|
-
env: 'WS_PROVEN_BLOCKS_ONLY',
|
|
53
|
-
description: 'Whether to follow only the proven chain.',
|
|
54
|
-
...booleanConfigHelper(),
|
|
55
|
-
},
|
|
56
43
|
worldStateBlockRequestBatchSize: {
|
|
57
44
|
env: 'WS_BLOCK_REQUEST_BATCH_SIZE',
|
|
58
45
|
parseEnv: (val: string | undefined) => (val ? +val : undefined),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { LoggerBindings } from '@aztec/foundation/log';
|
|
1
2
|
import type { DataStoreConfig } from '@aztec/kv-store/config';
|
|
2
3
|
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
3
4
|
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
@@ -22,9 +23,10 @@ export async function createWorldStateSynchronizer(
|
|
|
22
23
|
l2BlockSource: L2BlockSource & L1ToL2MessageSource,
|
|
23
24
|
prefilledPublicData: PublicDataTreeLeaf[] = [],
|
|
24
25
|
client: TelemetryClient = getTelemetryClient(),
|
|
26
|
+
bindings?: LoggerBindings,
|
|
25
27
|
) {
|
|
26
28
|
const instrumentation = new WorldStateInstrumentation(client);
|
|
27
|
-
const merkleTrees = await createWorldState(config, prefilledPublicData, instrumentation);
|
|
29
|
+
const merkleTrees = await createWorldState(config, prefilledPublicData, instrumentation, bindings);
|
|
28
30
|
return new ServerWorldStateSynchronizer(merkleTrees, l2BlockSource, config, instrumentation);
|
|
29
31
|
}
|
|
30
32
|
|
|
@@ -42,6 +44,7 @@ export async function createWorldState(
|
|
|
42
44
|
Pick<DataStoreConfig, 'dataDirectory' | 'dataStoreMapSizeKb' | 'l1Contracts'>,
|
|
43
45
|
prefilledPublicData: PublicDataTreeLeaf[] = [],
|
|
44
46
|
instrumentation: WorldStateInstrumentation = new WorldStateInstrumentation(getTelemetryClient()),
|
|
47
|
+
bindings?: LoggerBindings,
|
|
45
48
|
) {
|
|
46
49
|
const dataDirectory = config.worldStateDataDirectory ?? config.dataDirectory;
|
|
47
50
|
const dataStoreMapSizeKb = config.worldStateDbMapSizeKb ?? config.dataStoreMapSizeKb;
|
|
@@ -65,11 +68,14 @@ export async function createWorldState(
|
|
|
65
68
|
wsTreeMapSizes,
|
|
66
69
|
prefilledPublicData,
|
|
67
70
|
instrumentation,
|
|
71
|
+
bindings,
|
|
68
72
|
)
|
|
69
73
|
: await NativeWorldStateService.tmp(
|
|
70
74
|
config.l1Contracts.rollupAddress,
|
|
71
75
|
!['true', '1'].includes(process.env.DEBUG_WORLD_STATE!),
|
|
72
76
|
prefilledPublicData,
|
|
77
|
+
instrumentation,
|
|
78
|
+
bindings,
|
|
73
79
|
);
|
|
74
80
|
|
|
75
81
|
return merkleTrees;
|