@aztec/world-state 0.0.1-commit.fcb71a6 → 0.0.1-commit.ff7989d6c
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/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/merkle_trees_facade.d.ts +2 -2
- package/dest/native/merkle_trees_facade.d.ts.map +1 -1
- package/dest/native/merkle_trees_facade.js +15 -4
- package/dest/native/message.d.ts +3 -2
- package/dest/native/message.d.ts.map +1 -1
- package/dest/native/native_world_state.d.ts +7 -7
- package/dest/native/native_world_state.d.ts.map +1 -1
- package/dest/native/native_world_state.js +9 -8
- package/dest/native/native_world_state_instance.d.ts +3 -3
- package/dest/native/native_world_state_instance.d.ts.map +1 -1
- package/dest/native/native_world_state_instance.js +4 -4
- package/dest/synchronizer/config.d.ts +3 -5
- package/dest/synchronizer/config.d.ts.map +1 -1
- package/dest/synchronizer/config.js +7 -9
- 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/server_world_state_synchronizer.d.ts +2 -3
- package/dest/synchronizer/server_world_state_synchronizer.d.ts.map +1 -1
- package/dest/synchronizer/server_world_state_synchronizer.js +81 -33
- package/dest/test/utils.d.ts +7 -7
- package/dest/test/utils.d.ts.map +1 -1
- package/dest/test/utils.js +5 -5
- package/dest/world-state-db/merkle_tree_db.d.ts +3 -3
- package/dest/world-state-db/merkle_tree_db.d.ts.map +1 -1
- package/package.json +11 -11
- package/src/instrumentation/instrumentation.ts +17 -41
- package/src/native/merkle_trees_facade.ts +11 -2
- package/src/native/message.ts +2 -1
- package/src/native/native_world_state.ts +22 -10
- package/src/native/native_world_state_instance.ts +6 -4
- package/src/synchronizer/config.ts +8 -19
- package/src/synchronizer/factory.ts +7 -1
- package/src/synchronizer/server_world_state_synchronizer.ts +83 -44
- package/src/test/utils.ts +6 -6
- package/src/world-state-db/merkle_tree_db.ts +2 -2
|
@@ -4,9 +4,9 @@ import { fromEntries, padArrayEnd } from '@aztec/foundation/collection';
|
|
|
4
4
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
5
5
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
6
6
|
import { tryRmDir } from '@aztec/foundation/fs';
|
|
7
|
-
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
8
|
-
import type {
|
|
9
|
-
import { DatabaseVersionManager } from '@aztec/stdlib/database-version';
|
|
7
|
+
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
8
|
+
import type { L2Block } from '@aztec/stdlib/block';
|
|
9
|
+
import { DatabaseVersionManager } from '@aztec/stdlib/database-version/manager';
|
|
10
10
|
import type {
|
|
11
11
|
IndexedTreeId,
|
|
12
12
|
MerkleTreeReadOperations,
|
|
@@ -52,7 +52,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
52
52
|
protected constructor(
|
|
53
53
|
protected instance: NativeWorldState,
|
|
54
54
|
protected readonly worldStateInstrumentation: WorldStateInstrumentation,
|
|
55
|
-
protected readonly log: Logger
|
|
55
|
+
protected readonly log: Logger,
|
|
56
56
|
private readonly cleanup = () => Promise.resolve(),
|
|
57
57
|
) {}
|
|
58
58
|
|
|
@@ -62,9 +62,10 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
62
62
|
wsTreeMapSizes: WorldStateTreeMapSizes,
|
|
63
63
|
prefilledPublicData: PublicDataTreeLeaf[] = [],
|
|
64
64
|
instrumentation = new WorldStateInstrumentation(getTelemetryClient()),
|
|
65
|
-
|
|
65
|
+
bindings?: LoggerBindings,
|
|
66
66
|
cleanup = () => Promise.resolve(),
|
|
67
67
|
): Promise<NativeWorldStateService> {
|
|
68
|
+
const log = createLogger('world-state:database', bindings);
|
|
68
69
|
const worldStateDirectory = join(dataDir, WORLD_STATE_DIR);
|
|
69
70
|
// Create a version manager to handle versioning
|
|
70
71
|
const versionManager = new DatabaseVersionManager({
|
|
@@ -72,7 +73,9 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
72
73
|
rollupAddress,
|
|
73
74
|
dataDirectory: worldStateDirectory,
|
|
74
75
|
onOpen: (dir: string) => {
|
|
75
|
-
return Promise.resolve(
|
|
76
|
+
return Promise.resolve(
|
|
77
|
+
new NativeWorldState(dir, wsTreeMapSizes, prefilledPublicData, instrumentation, bindings),
|
|
78
|
+
);
|
|
76
79
|
},
|
|
77
80
|
});
|
|
78
81
|
|
|
@@ -93,8 +96,9 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
93
96
|
cleanupTmpDir = true,
|
|
94
97
|
prefilledPublicData: PublicDataTreeLeaf[] = [],
|
|
95
98
|
instrumentation = new WorldStateInstrumentation(getTelemetryClient()),
|
|
99
|
+
bindings?: LoggerBindings,
|
|
96
100
|
): Promise<NativeWorldStateService> {
|
|
97
|
-
const log = createLogger('world-state:database');
|
|
101
|
+
const log = createLogger('world-state:database', bindings);
|
|
98
102
|
const dataDir = await mkdtemp(join(tmpdir(), 'aztec-world-state-'));
|
|
99
103
|
const dbMapSizeKb = 10 * 1024 * 1024;
|
|
100
104
|
const worldStateTreeMapSizes: WorldStateTreeMapSizes = {
|
|
@@ -116,7 +120,15 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
116
120
|
}
|
|
117
121
|
};
|
|
118
122
|
|
|
119
|
-
return this.new(
|
|
123
|
+
return this.new(
|
|
124
|
+
rollupAddress,
|
|
125
|
+
dataDir,
|
|
126
|
+
worldStateTreeMapSizes,
|
|
127
|
+
prefilledPublicData,
|
|
128
|
+
instrumentation,
|
|
129
|
+
bindings,
|
|
130
|
+
cleanup,
|
|
131
|
+
);
|
|
120
132
|
}
|
|
121
133
|
|
|
122
134
|
protected async init() {
|
|
@@ -135,7 +147,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
135
147
|
|
|
136
148
|
// the initial header _must_ be the first element in the archive tree
|
|
137
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
|
|
138
|
-
const indices = await committed.findLeafIndices(MerkleTreeId.ARCHIVE, [await this.initialHeader.hash()]);
|
|
150
|
+
const indices = await committed.findLeafIndices(MerkleTreeId.ARCHIVE, [(await this.initialHeader.hash()).toFr()]);
|
|
139
151
|
const initialHeaderIndex = indices[0];
|
|
140
152
|
assert.strictEqual(initialHeaderIndex, 0n, 'Invalid initial archive state');
|
|
141
153
|
}
|
|
@@ -184,7 +196,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
184
196
|
return this.initialHeader!;
|
|
185
197
|
}
|
|
186
198
|
|
|
187
|
-
public async handleL2BlockAndMessages(l2Block:
|
|
199
|
+
public async handleL2BlockAndMessages(l2Block: L2Block, l1ToL2Messages: Fr[]): Promise<WorldStateStatusFull> {
|
|
188
200
|
const isFirstBlock = l2Block.indexWithinCheckpoint === 0;
|
|
189
201
|
if (!isFirstBlock && l1ToL2Messages.length > 0) {
|
|
190
202
|
throw new Error(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ARCHIVE_HEIGHT,
|
|
3
|
-
|
|
3
|
+
DomainSeparator,
|
|
4
4
|
L1_TO_L2_MSG_TREE_HEIGHT,
|
|
5
5
|
MAX_NULLIFIERS_PER_TX,
|
|
6
6
|
MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
|
|
@@ -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';
|
|
@@ -57,7 +57,8 @@ export class NativeWorldState implements NativeWorldStateInstance {
|
|
|
57
57
|
private readonly wsTreeMapSizes: WorldStateTreeMapSizes,
|
|
58
58
|
private readonly prefilledPublicData: PublicDataTreeLeaf[] = [],
|
|
59
59
|
private readonly instrumentation: WorldStateInstrumentation,
|
|
60
|
-
|
|
60
|
+
bindings?: LoggerBindings,
|
|
61
|
+
private readonly log: Logger = createLogger('world-state:database', bindings),
|
|
61
62
|
) {
|
|
62
63
|
const threads = Math.min(cpus().length, MAX_WORLD_STATE_THREADS);
|
|
63
64
|
log.info(
|
|
@@ -80,7 +81,7 @@ export class NativeWorldState implements NativeWorldStateInstance {
|
|
|
80
81
|
[MerkleTreeId.PUBLIC_DATA_TREE]: 2 * MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
|
|
81
82
|
},
|
|
82
83
|
prefilledPublicDataBufferArray,
|
|
83
|
-
|
|
84
|
+
DomainSeparator.BLOCK_HEADER_HASH,
|
|
84
85
|
{
|
|
85
86
|
[MerkleTreeId.NULLIFIER_TREE]: wsTreeMapSizes.nullifierTreeMapSizeKb,
|
|
86
87
|
[MerkleTreeId.NOTE_HASH_TREE]: wsTreeMapSizes.noteHashTreeMapSizeKb,
|
|
@@ -105,6 +106,7 @@ export class NativeWorldState implements NativeWorldStateInstance {
|
|
|
105
106
|
this.wsTreeMapSizes,
|
|
106
107
|
this.prefilledPublicData,
|
|
107
108
|
this.instrumentation,
|
|
109
|
+
this.log.getBindings(),
|
|
108
110
|
this.log,
|
|
109
111
|
);
|
|
110
112
|
}
|
|
@@ -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
|
|
|
@@ -37,8 +29,8 @@ export interface WorldStateConfig {
|
|
|
37
29
|
/** Optional directory for the world state DB, if unspecified will default to the general data directory */
|
|
38
30
|
worldStateDataDirectory?: string;
|
|
39
31
|
|
|
40
|
-
/** The number of historic blocks to maintain */
|
|
41
|
-
|
|
32
|
+
/** The number of historic checkpoints worth of blocks to maintain */
|
|
33
|
+
worldStateCheckpointHistory: number;
|
|
42
34
|
}
|
|
43
35
|
|
|
44
36
|
export const worldStateConfigMappings: ConfigMappingsType<WorldStateConfig> = {
|
|
@@ -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),
|
|
@@ -97,9 +84,11 @@ export const worldStateConfigMappings: ConfigMappingsType<WorldStateConfig> = {
|
|
|
97
84
|
env: 'WS_DATA_DIRECTORY',
|
|
98
85
|
description: 'Optional directory for the world state database',
|
|
99
86
|
},
|
|
100
|
-
|
|
101
|
-
env: '
|
|
102
|
-
description:
|
|
87
|
+
worldStateCheckpointHistory: {
|
|
88
|
+
env: 'WS_NUM_HISTORIC_CHECKPOINTS',
|
|
89
|
+
description:
|
|
90
|
+
'The number of historic checkpoints worth of blocks to maintain. Values less than 1 mean all history is maintained',
|
|
91
|
+
fallback: ['WS_NUM_HISTORIC_BLOCKS'],
|
|
103
92
|
...numberConfigHelper(64),
|
|
104
93
|
},
|
|
105
94
|
};
|
|
@@ -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;
|
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { GENESIS_BLOCK_HEADER_HASH, INITIAL_L2_BLOCK_NUM, INITIAL_L2_CHECKPOINT_NUM } from '@aztec/constants';
|
|
2
|
+
import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
2
3
|
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
4
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
4
5
|
import { promiseWithResolvers } from '@aztec/foundation/promise';
|
|
5
6
|
import { elapsed } from '@aztec/foundation/timer';
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
import {
|
|
8
|
+
GENESIS_CHECKPOINT_HEADER_HASH,
|
|
9
|
+
type L2Block,
|
|
10
|
+
type L2BlockId,
|
|
11
|
+
type L2BlockSource,
|
|
10
12
|
L2BlockStream,
|
|
11
|
-
L2BlockStreamEvent,
|
|
12
|
-
L2BlockStreamEventHandler,
|
|
13
|
-
L2BlockStreamLocalDataProvider,
|
|
14
|
-
L2Tips,
|
|
13
|
+
type L2BlockStreamEvent,
|
|
14
|
+
type L2BlockStreamEventHandler,
|
|
15
|
+
type L2BlockStreamLocalDataProvider,
|
|
16
|
+
type L2Tips,
|
|
15
17
|
} from '@aztec/stdlib/block';
|
|
16
18
|
import {
|
|
17
19
|
WorldStateRunningState,
|
|
@@ -23,7 +25,7 @@ import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
|
23
25
|
import type { SnapshotDataKeys } from '@aztec/stdlib/snapshots';
|
|
24
26
|
import type { L2BlockHandledStats } from '@aztec/stdlib/stats';
|
|
25
27
|
import { MerkleTreeId, type MerkleTreeReadOperations, type MerkleTreeWriteOperations } from '@aztec/stdlib/trees';
|
|
26
|
-
import {
|
|
28
|
+
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
27
29
|
|
|
28
30
|
import { WorldStateInstrumentation } from '../instrumentation/instrumentation.js';
|
|
29
31
|
import type { WorldStateStatusFull } from '../native/message.js';
|
|
@@ -46,7 +48,6 @@ export class ServerWorldStateSynchronizer
|
|
|
46
48
|
private latestBlockNumberAtStart = BlockNumber.ZERO;
|
|
47
49
|
private historyToKeep: number | undefined;
|
|
48
50
|
private currentState: WorldStateRunningState = WorldStateRunningState.IDLE;
|
|
49
|
-
private latestBlockHashQuery: { blockNumber: BlockNumber; hash: string | undefined } | undefined = undefined;
|
|
50
51
|
|
|
51
52
|
private syncPromise = promiseWithResolvers<void>();
|
|
52
53
|
protected blockStream: L2BlockStream | undefined;
|
|
@@ -63,7 +64,7 @@ export class ServerWorldStateSynchronizer
|
|
|
63
64
|
private readonly log: Logger = createLogger('world_state'),
|
|
64
65
|
) {
|
|
65
66
|
this.merkleTreeCommitted = this.merkleTreeDb.getCommitted();
|
|
66
|
-
this.historyToKeep = config.
|
|
67
|
+
this.historyToKeep = config.worldStateCheckpointHistory < 1 ? undefined : config.worldStateCheckpointHistory;
|
|
67
68
|
this.log.info(
|
|
68
69
|
`Created world state synchroniser with block history of ${
|
|
69
70
|
this.historyToKeep === undefined ? 'infinity' : this.historyToKeep
|
|
@@ -100,11 +101,7 @@ export class ServerWorldStateSynchronizer
|
|
|
100
101
|
}
|
|
101
102
|
|
|
102
103
|
// Get the current latest block number
|
|
103
|
-
this.latestBlockNumberAtStart = BlockNumber(
|
|
104
|
-
await (this.config.worldStateProvenBlocksOnly
|
|
105
|
-
? this.l2BlockSource.getProvenBlockNumber()
|
|
106
|
-
: this.l2BlockSource.getBlockNumber()),
|
|
107
|
-
);
|
|
104
|
+
this.latestBlockNumberAtStart = BlockNumber(await this.l2BlockSource.getBlockNumber());
|
|
108
105
|
|
|
109
106
|
const blockToDownloadFrom = (await this.getLatestBlockNumber()) + 1;
|
|
110
107
|
|
|
@@ -126,12 +123,11 @@ export class ServerWorldStateSynchronizer
|
|
|
126
123
|
}
|
|
127
124
|
|
|
128
125
|
protected createBlockStream(): L2BlockStream {
|
|
129
|
-
const tracer = this.instrumentation.telemetry.getTracer('WorldStateL2BlockStream');
|
|
130
126
|
const logger = createLogger('world-state:block_stream');
|
|
131
|
-
return new
|
|
132
|
-
proven: this.config.worldStateProvenBlocksOnly,
|
|
127
|
+
return new L2BlockStream(this.l2BlockSource, this, this, logger, {
|
|
133
128
|
pollIntervalMS: this.config.worldStateBlockCheckIntervalMS,
|
|
134
129
|
batchSize: this.config.worldStateBlockRequestBatchSize,
|
|
130
|
+
ignoreCheckpoints: true,
|
|
135
131
|
});
|
|
136
132
|
}
|
|
137
133
|
|
|
@@ -160,7 +156,7 @@ export class ServerWorldStateSynchronizer
|
|
|
160
156
|
}
|
|
161
157
|
|
|
162
158
|
public async getLatestBlockNumber() {
|
|
163
|
-
return (await this.getL2Tips()).
|
|
159
|
+
return (await this.getL2Tips()).proposed.number;
|
|
164
160
|
}
|
|
165
161
|
|
|
166
162
|
public async stopSync() {
|
|
@@ -239,27 +235,44 @@ export class ServerWorldStateSynchronizer
|
|
|
239
235
|
if (number === BlockNumber.ZERO) {
|
|
240
236
|
return (await this.merkleTreeCommitted.getInitialHeader().hash()).toString();
|
|
241
237
|
}
|
|
242
|
-
|
|
243
|
-
this.latestBlockHashQuery = {
|
|
244
|
-
hash: await this.merkleTreeCommitted
|
|
245
|
-
.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(number))
|
|
246
|
-
.then(leaf => leaf?.toString()),
|
|
247
|
-
blockNumber: number,
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
return this.latestBlockHashQuery.hash;
|
|
238
|
+
return this.merkleTreeCommitted.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(number)).then(leaf => leaf?.toString());
|
|
251
239
|
}
|
|
252
240
|
|
|
253
241
|
/** Returns the latest L2 block number for each tip of the chain (latest, proven, finalized). */
|
|
254
242
|
public async getL2Tips(): Promise<L2Tips> {
|
|
255
243
|
const status = await this.merkleTreeDb.getStatusSummary();
|
|
256
|
-
const
|
|
244
|
+
const unfinalizedBlockHashPromise = this.getL2BlockHash(status.unfinalizedBlockNumber);
|
|
245
|
+
const finalizedBlockHashPromise = this.getL2BlockHash(status.finalizedBlockNumber);
|
|
246
|
+
|
|
247
|
+
const provenBlockNumber = this.provenBlockNumber ?? status.finalizedBlockNumber;
|
|
248
|
+
const provenBlockHashPromise =
|
|
249
|
+
this.provenBlockNumber === undefined ? finalizedBlockHashPromise : this.getL2BlockHash(this.provenBlockNumber);
|
|
250
|
+
|
|
251
|
+
const [unfinalizedBlockHash, finalizedBlockHash, provenBlockHash] = await Promise.all([
|
|
252
|
+
unfinalizedBlockHashPromise,
|
|
253
|
+
finalizedBlockHashPromise,
|
|
254
|
+
provenBlockHashPromise,
|
|
255
|
+
]);
|
|
257
256
|
const latestBlockId: L2BlockId = { number: status.unfinalizedBlockNumber, hash: unfinalizedBlockHash! };
|
|
258
257
|
|
|
258
|
+
// World state doesn't track checkpointed blocks or checkpoints themselves.
|
|
259
|
+
// but we use a block stream so we need to provide 'local' L2Tips.
|
|
260
|
+
// We configure the block stream to ignore checkpoints and set checkpoint values to genesis here.
|
|
261
|
+
const genesisCheckpointHeaderHash = GENESIS_CHECKPOINT_HEADER_HASH.toString();
|
|
259
262
|
return {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
+
proposed: latestBlockId,
|
|
264
|
+
checkpointed: {
|
|
265
|
+
block: { number: INITIAL_L2_BLOCK_NUM, hash: GENESIS_BLOCK_HEADER_HASH.toString() },
|
|
266
|
+
checkpoint: { number: INITIAL_L2_CHECKPOINT_NUM, hash: genesisCheckpointHeaderHash },
|
|
267
|
+
},
|
|
268
|
+
finalized: {
|
|
269
|
+
block: { number: status.finalizedBlockNumber, hash: finalizedBlockHash ?? '' },
|
|
270
|
+
checkpoint: { number: INITIAL_L2_CHECKPOINT_NUM, hash: genesisCheckpointHeaderHash },
|
|
271
|
+
},
|
|
272
|
+
proven: {
|
|
273
|
+
block: { number: provenBlockNumber, hash: provenBlockHash ?? '' },
|
|
274
|
+
checkpoint: { number: INITIAL_L2_CHECKPOINT_NUM, hash: genesisCheckpointHeaderHash },
|
|
275
|
+
},
|
|
263
276
|
};
|
|
264
277
|
}
|
|
265
278
|
|
|
@@ -267,7 +280,7 @@ export class ServerWorldStateSynchronizer
|
|
|
267
280
|
public async handleBlockStreamEvent(event: L2BlockStreamEvent): Promise<void> {
|
|
268
281
|
switch (event.type) {
|
|
269
282
|
case 'blocks-added':
|
|
270
|
-
await this.handleL2Blocks(event.blocks
|
|
283
|
+
await this.handleL2Blocks(event.blocks);
|
|
271
284
|
break;
|
|
272
285
|
case 'chain-pruned':
|
|
273
286
|
await this.handleChainPruned(event.block.number);
|
|
@@ -286,8 +299,8 @@ export class ServerWorldStateSynchronizer
|
|
|
286
299
|
* @param l2Blocks - The L2 blocks to handle.
|
|
287
300
|
* @returns Whether the block handled was produced by this same node.
|
|
288
301
|
*/
|
|
289
|
-
private async handleL2Blocks(l2Blocks:
|
|
290
|
-
this.log.
|
|
302
|
+
private async handleL2Blocks(l2Blocks: L2Block[]) {
|
|
303
|
+
this.log.debug(`Handling L2 blocks ${l2Blocks[0].number} to ${l2Blocks.at(-1)!.number}`);
|
|
291
304
|
|
|
292
305
|
// Fetch the L1->L2 messages for the first block in a checkpoint.
|
|
293
306
|
const messagesForBlocks = new Map<BlockNumber, Fr[]>();
|
|
@@ -327,11 +340,13 @@ export class ServerWorldStateSynchronizer
|
|
|
327
340
|
* @param l1ToL2Messages - The L1 to L2 messages for the block.
|
|
328
341
|
* @returns Whether the block handled was produced by this same node.
|
|
329
342
|
*/
|
|
330
|
-
private async handleL2Block(l2Block:
|
|
331
|
-
this.log.
|
|
343
|
+
private async handleL2Block(l2Block: L2Block, l1ToL2Messages: Fr[]): Promise<WorldStateStatusFull> {
|
|
344
|
+
this.log.debug(`Pushing L2 block ${l2Block.number} to merkle tree db `, {
|
|
332
345
|
blockNumber: l2Block.number,
|
|
333
346
|
blockHash: await l2Block.hash().then(h => h.toString()),
|
|
334
347
|
l1ToL2Messages: l1ToL2Messages.map(msg => msg.toString()),
|
|
348
|
+
blockHeader: l2Block.header.toInspect(),
|
|
349
|
+
blockStats: l2Block.getStats(),
|
|
335
350
|
});
|
|
336
351
|
const result = await this.merkleTreeDb.handleL2BlockAndMessages(l2Block, l1ToL2Messages);
|
|
337
352
|
|
|
@@ -349,12 +364,37 @@ export class ServerWorldStateSynchronizer
|
|
|
349
364
|
if (this.historyToKeep === undefined) {
|
|
350
365
|
return;
|
|
351
366
|
}
|
|
352
|
-
|
|
353
|
-
|
|
367
|
+
// Get the checkpointed block for the finalized block number
|
|
368
|
+
const finalisedCheckpoint = await this.l2BlockSource.getCheckpointedBlock(summary.finalizedBlockNumber);
|
|
369
|
+
if (finalisedCheckpoint === undefined) {
|
|
370
|
+
this.log.warn(
|
|
371
|
+
`Failed to retrieve checkpointed block for finalized block number: ${summary.finalizedBlockNumber}`,
|
|
372
|
+
);
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
// Compute the required historic checkpoint number
|
|
376
|
+
const newHistoricCheckpointNumber = finalisedCheckpoint.checkpointNumber - this.historyToKeep + 1;
|
|
377
|
+
if (newHistoricCheckpointNumber <= 1) {
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
// Retrieve the historic checkpoint
|
|
381
|
+
const historicCheckpoints = await this.l2BlockSource.getCheckpoints(
|
|
382
|
+
CheckpointNumber(newHistoricCheckpointNumber),
|
|
383
|
+
1,
|
|
384
|
+
);
|
|
385
|
+
if (historicCheckpoints.length === 0 || historicCheckpoints[0] === undefined) {
|
|
386
|
+
this.log.warn(`Failed to retrieve checkpoint number ${newHistoricCheckpointNumber} from Archiver`);
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
const historicCheckpoint = historicCheckpoints[0];
|
|
390
|
+
if (historicCheckpoint.checkpoint.blocks.length === 0 || historicCheckpoint.checkpoint.blocks[0] === undefined) {
|
|
391
|
+
this.log.warn(`Retrieved checkpoint number ${newHistoricCheckpointNumber} has no blocks!`);
|
|
354
392
|
return;
|
|
355
393
|
}
|
|
356
|
-
|
|
357
|
-
const
|
|
394
|
+
// Find the block at the start of the checkpoint and remove blocks up to this one
|
|
395
|
+
const newHistoricBlock = historicCheckpoint.checkpoint.blocks[0];
|
|
396
|
+
this.log.verbose(`Pruning historic blocks to ${newHistoricBlock.number}`);
|
|
397
|
+
const status = await this.merkleTreeDb.removeHistoricalBlocks(BlockNumber(newHistoricBlock.number));
|
|
358
398
|
this.log.debug(`World state summary `, status.summary);
|
|
359
399
|
}
|
|
360
400
|
|
|
@@ -367,7 +407,6 @@ export class ServerWorldStateSynchronizer
|
|
|
367
407
|
private async handleChainPruned(blockNumber: BlockNumber) {
|
|
368
408
|
this.log.warn(`Chain pruned to block ${blockNumber}`);
|
|
369
409
|
const status = await this.merkleTreeDb.unwindBlocks(blockNumber);
|
|
370
|
-
this.latestBlockHashQuery = undefined;
|
|
371
410
|
this.provenBlockNumber = undefined;
|
|
372
411
|
this.instrumentation.updateWorldStateMetrics(status);
|
|
373
412
|
}
|
package/src/test/utils.ts
CHANGED
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
6
6
|
} from '@aztec/constants';
|
|
7
7
|
import { asyncMap } from '@aztec/foundation/async-map';
|
|
8
|
-
import { BlockNumber, type CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
8
|
+
import { BlockNumber, type CheckpointNumber, IndexWithinCheckpoint } from '@aztec/foundation/branded-types';
|
|
9
9
|
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
10
10
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
11
|
-
import {
|
|
11
|
+
import { L2Block } from '@aztec/stdlib/block';
|
|
12
12
|
import type {
|
|
13
13
|
IndexedTreeId,
|
|
14
14
|
MerkleTreeReadOperations,
|
|
@@ -20,7 +20,7 @@ import { BlockHeader } from '@aztec/stdlib/tx';
|
|
|
20
20
|
|
|
21
21
|
import type { NativeWorldStateService } from '../native/native_world_state.js';
|
|
22
22
|
|
|
23
|
-
export async function updateBlockState(block:
|
|
23
|
+
export async function updateBlockState(block: L2Block, l1ToL2Messages: Fr[], fork: MerkleTreeWriteOperations) {
|
|
24
24
|
const insertData = async (
|
|
25
25
|
treeId: IndexedTreeId,
|
|
26
26
|
data: Buffer[][],
|
|
@@ -76,8 +76,8 @@ export async function mockBlock(
|
|
|
76
76
|
numL1ToL2Messages: number = NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
77
77
|
isFirstBlockInCheckpoint: boolean = true,
|
|
78
78
|
) {
|
|
79
|
-
const block = await
|
|
80
|
-
indexWithinCheckpoint: isFirstBlockInCheckpoint ? 0 : 1,
|
|
79
|
+
const block = await L2Block.random(blockNum, {
|
|
80
|
+
indexWithinCheckpoint: isFirstBlockInCheckpoint ? IndexWithinCheckpoint(0) : IndexWithinCheckpoint(1),
|
|
81
81
|
txsPerBlock: size,
|
|
82
82
|
txOptions: { maxEffects },
|
|
83
83
|
});
|
|
@@ -92,7 +92,7 @@ export async function mockBlock(
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
export async function mockEmptyBlock(blockNum: BlockNumber, fork: MerkleTreeWriteOperations) {
|
|
95
|
-
const l2Block =
|
|
95
|
+
const l2Block = L2Block.empty();
|
|
96
96
|
const l1ToL2Messages = Array(16).fill(0).map(Fr.zero);
|
|
97
97
|
|
|
98
98
|
l2Block.header.globalVariables.blockNumber = blockNum;
|
|
@@ -2,7 +2,7 @@ import { MAX_NULLIFIERS_PER_TX, MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX } f
|
|
|
2
2
|
import type { BlockNumber } from '@aztec/foundation/branded-types';
|
|
3
3
|
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
4
|
import type { IndexedTreeSnapshot, TreeSnapshot } from '@aztec/merkle-tree';
|
|
5
|
-
import type {
|
|
5
|
+
import type { L2Block } from '@aztec/stdlib/block';
|
|
6
6
|
import type {
|
|
7
7
|
ForkMerkleTreeOperations,
|
|
8
8
|
MerkleTreeReadOperations,
|
|
@@ -45,7 +45,7 @@ export interface MerkleTreeAdminDatabase extends ForkMerkleTreeOperations, Reado
|
|
|
45
45
|
* @param block - The L2 block to handle.
|
|
46
46
|
* @param l1ToL2Messages - The L1 to L2 messages for the block.
|
|
47
47
|
*/
|
|
48
|
-
handleL2BlockAndMessages(block:
|
|
48
|
+
handleL2BlockAndMessages(block: L2Block, l1ToL2Messages: Fr[]): Promise<WorldStateStatusFull>;
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* Gets a handle that allows reading the latest committed state
|