@aztec/world-state 0.56.0 → 0.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dest/index.d.ts +1 -0
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +2 -1
- package/dest/native/merkle_trees_facade.d.ts +34 -0
- package/dest/native/merkle_trees_facade.d.ts.map +1 -0
- package/dest/native/merkle_trees_facade.js +193 -0
- package/dest/native/message.d.ts +78 -19
- package/dest/native/message.d.ts.map +1 -1
- package/dest/native/message.js +27 -26
- package/dest/native/native_world_state.d.ts +39 -38
- package/dest/native/native_world_state.d.ts.map +1 -1
- package/dest/native/native_world_state.js +108 -254
- package/dest/native/native_world_state_instance.d.ts +40 -0
- package/dest/native/native_world_state_instance.d.ts.map +1 -0
- package/dest/native/native_world_state_instance.js +183 -0
- package/dest/synchronizer/config.d.ts +2 -2
- package/dest/synchronizer/config.d.ts.map +1 -1
- package/dest/synchronizer/config.js +6 -7
- package/dest/synchronizer/factory.d.ts +3 -0
- package/dest/synchronizer/factory.d.ts.map +1 -1
- package/dest/synchronizer/factory.js +13 -4
- package/dest/synchronizer/server_world_state_synchronizer.d.ts +41 -41
- package/dest/synchronizer/server_world_state_synchronizer.d.ts.map +1 -1
- package/dest/synchronizer/server_world_state_synchronizer.js +128 -163
- package/dest/test/utils.d.ts +14 -0
- package/dest/test/utils.d.ts.map +1 -0
- package/dest/test/utils.js +67 -0
- package/dest/world-state-db/index.d.ts +1 -1
- package/dest/world-state-db/index.d.ts.map +1 -1
- package/dest/world-state-db/merkle_tree_db.d.ts +42 -32
- package/dest/world-state-db/merkle_tree_db.d.ts.map +1 -1
- package/dest/world-state-db/merkle_tree_db.js +1 -1
- package/dest/world-state-db/merkle_tree_operations_facade.d.ts +8 -37
- package/dest/world-state-db/merkle_tree_operations_facade.d.ts.map +1 -1
- package/dest/world-state-db/merkle_tree_operations_facade.js +6 -45
- package/dest/world-state-db/merkle_tree_snapshot_operations_facade.d.ts +4 -13
- package/dest/world-state-db/merkle_tree_snapshot_operations_facade.d.ts.map +1 -1
- package/dest/world-state-db/merkle_tree_snapshot_operations_facade.js +2 -29
- package/dest/world-state-db/merkle_trees.d.ts +17 -19
- package/dest/world-state-db/merkle_trees.d.ts.map +1 -1
- package/dest/world-state-db/merkle_trees.js +39 -36
- package/package.json +18 -12
- package/src/index.ts +1 -0
- package/src/native/merkle_trees_facade.ts +279 -0
- package/src/native/message.ts +97 -20
- package/src/native/native_world_state.ts +125 -346
- package/src/native/native_world_state_instance.ts +262 -0
- package/src/synchronizer/config.ts +8 -9
- package/src/synchronizer/factory.ts +20 -3
- package/src/synchronizer/server_world_state_synchronizer.ts +160 -186
- package/src/test/utils.ts +123 -0
- package/src/world-state-db/index.ts +1 -1
- package/src/world-state-db/merkle_tree_db.ts +55 -49
- package/src/world-state-db/merkle_tree_operations_facade.ts +10 -55
- package/src/world-state-db/merkle_tree_snapshot_operations_facade.ts +7 -46
- package/src/world-state-db/merkle_trees.ts +50 -45
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
type BatchInsertionResult,
|
|
3
|
-
type HandleL2BlockAndMessagesResult,
|
|
4
2
|
type IndexedTreeId,
|
|
5
3
|
type L2Block,
|
|
6
|
-
type MerkleTreeAdminOperations,
|
|
7
4
|
MerkleTreeId,
|
|
8
|
-
type
|
|
9
|
-
|
|
10
|
-
type TreeInfo,
|
|
5
|
+
type MerkleTreeReadOperations,
|
|
6
|
+
type MerkleTreeWriteOperations,
|
|
11
7
|
TxEffect,
|
|
12
8
|
} from '@aztec/circuit-types';
|
|
13
9
|
import {
|
|
10
|
+
EthAddress,
|
|
14
11
|
Fr,
|
|
15
12
|
Header,
|
|
16
13
|
MAX_NOTE_HASHES_PER_TX,
|
|
@@ -18,279 +15,120 @@ import {
|
|
|
18
15
|
MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
|
|
19
16
|
NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
20
17
|
NullifierLeaf,
|
|
21
|
-
NullifierLeafPreimage,
|
|
18
|
+
type NullifierLeafPreimage,
|
|
22
19
|
PartialStateReference,
|
|
23
20
|
PublicDataTreeLeaf,
|
|
24
|
-
PublicDataTreeLeafPreimage,
|
|
25
21
|
StateReference,
|
|
26
22
|
} from '@aztec/circuits.js';
|
|
27
23
|
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
28
|
-
import {
|
|
29
|
-
import { serializeToBuffer } from '@aztec/foundation/serialize';
|
|
30
|
-
import type { IndexedTreeLeafPreimage } from '@aztec/foundation/trees';
|
|
24
|
+
import { createDebugLogger } from '@aztec/foundation/log';
|
|
31
25
|
|
|
32
|
-
import
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
26
|
+
import assert from 'assert/strict';
|
|
27
|
+
import { mkdir, mkdtemp, readFile, rm, writeFile } from 'fs/promises';
|
|
28
|
+
import { tmpdir } from 'os';
|
|
29
|
+
import { join } from 'path';
|
|
35
30
|
|
|
36
|
-
import { type
|
|
37
|
-
import {
|
|
31
|
+
import { type MerkleTreeAdminDatabase as MerkleTreeDatabase } from '../world-state-db/merkle_tree_db.js';
|
|
32
|
+
import { MerkleTreesFacade, MerkleTreesForkFacade, serializeLeaf } from './merkle_trees_facade.js';
|
|
38
33
|
import {
|
|
39
|
-
MessageHeader,
|
|
40
|
-
type SerializedIndexedLeaf,
|
|
41
|
-
type SerializedLeafValue,
|
|
42
|
-
TypedMessage,
|
|
43
34
|
WorldStateMessageType,
|
|
44
|
-
type
|
|
45
|
-
type WorldStateResponse,
|
|
35
|
+
type WorldStateStatus,
|
|
46
36
|
blockStateReference,
|
|
47
37
|
treeStateReferenceToSnapshot,
|
|
48
38
|
worldStateRevision,
|
|
49
39
|
} from './message.js';
|
|
40
|
+
import { NativeWorldState } from './native_world_state_instance.js';
|
|
50
41
|
|
|
51
|
-
|
|
52
|
-
// this only works for writes. Unpacking from C++ can't create Fr instances because the data is passed
|
|
53
|
-
// as raw, untagged, buffers. On the NodeJS side we don't know what the buffer represents
|
|
54
|
-
// Adding a tag would be a solution, but it would have to be done on both sides and it's unclear where else
|
|
55
|
-
// C++ fr instances are sent/received/stored.
|
|
56
|
-
addExtension({
|
|
57
|
-
Class: Fr,
|
|
58
|
-
write: fr => fr.toBuffer(),
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
export interface NativeInstance {
|
|
62
|
-
call(msg: Buffer | Uint8Array): Promise<any>;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export class NativeWorldStateService implements MerkleTreeDb {
|
|
66
|
-
private nextMessageId = 1;
|
|
67
|
-
|
|
68
|
-
private encoder = new Encoder({
|
|
69
|
-
// always encode JS objects as MessagePack maps
|
|
70
|
-
// this makes it compatible with other MessagePack decoders
|
|
71
|
-
useRecords: false,
|
|
72
|
-
int64AsType: 'bigint',
|
|
73
|
-
});
|
|
42
|
+
const ROLLUP_ADDRESS_FILE = 'rollup_address';
|
|
74
43
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
int64AsType: 'bigint',
|
|
78
|
-
});
|
|
44
|
+
export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
45
|
+
protected initialHeader: Header | undefined;
|
|
79
46
|
|
|
80
|
-
|
|
47
|
+
protected constructor(
|
|
48
|
+
protected readonly instance: NativeWorldState,
|
|
49
|
+
protected readonly log = createDebugLogger('aztec:world-state:database'),
|
|
50
|
+
private readonly cleanup = () => Promise.resolve(),
|
|
51
|
+
) {}
|
|
81
52
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
static async create(
|
|
53
|
+
static async new(
|
|
54
|
+
rollupAddress: EthAddress,
|
|
87
55
|
dataDir: string,
|
|
88
|
-
|
|
89
|
-
|
|
56
|
+
log = createDebugLogger('aztec:world-state:database'),
|
|
57
|
+
cleanup = () => Promise.resolve(),
|
|
90
58
|
): Promise<NativeWorldStateService> {
|
|
91
|
-
const
|
|
92
|
-
const
|
|
93
|
-
const
|
|
94
|
-
await worldState.init();
|
|
95
|
-
return worldState;
|
|
96
|
-
}
|
|
59
|
+
const rollupAddressFile = join(dataDir, ROLLUP_ADDRESS_FILE);
|
|
60
|
+
const currentRollupStr = await readFile(rollupAddressFile, 'utf8').catch(() => undefined);
|
|
61
|
+
const currentRollupAddress = currentRollupStr ? EthAddress.fromString(currentRollupStr.trim()) : undefined;
|
|
97
62
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
// TODO (alexg) move this to the native module
|
|
102
|
-
// const header = await this.buildInitialHeader(true);
|
|
103
|
-
// await this.appendLeaves(MerkleTreeId.ARCHIVE, [header.hash()]);
|
|
104
|
-
// await this.commit();
|
|
63
|
+
if (currentRollupAddress && !rollupAddress.equals(currentRollupAddress)) {
|
|
64
|
+
log.warn('Rollup address changed, deleting database');
|
|
65
|
+
await rm(dataDir, { recursive: true, force: true });
|
|
105
66
|
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
public asLatest(): MerkleTreeAdminOperations {
|
|
109
|
-
return new MerkleTreeAdminOperationsFacade(this, true);
|
|
110
|
-
}
|
|
111
67
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
// return new Header(
|
|
115
|
-
// AppendOnlyTreeSnapshot.zero(),
|
|
116
|
-
// ContentCommitment.empty(),
|
|
117
|
-
// state,
|
|
118
|
-
// GlobalVariables.empty(),
|
|
119
|
-
// Fr.ZERO,
|
|
120
|
-
// );
|
|
121
|
-
// }
|
|
68
|
+
await mkdir(dataDir, { recursive: true });
|
|
69
|
+
await writeFile(rollupAddressFile, rollupAddress.toString(), 'utf8');
|
|
122
70
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
71
|
+
const instance = new NativeWorldState(dataDir);
|
|
72
|
+
const worldState = new this(instance, log, cleanup);
|
|
73
|
+
await worldState.init();
|
|
74
|
+
return worldState;
|
|
126
75
|
}
|
|
127
76
|
|
|
128
|
-
async
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
});
|
|
133
|
-
}
|
|
77
|
+
static async tmp(rollupAddress = EthAddress.ZERO, cleanupTmpDir = true): Promise<NativeWorldStateService> {
|
|
78
|
+
const log = createDebugLogger('aztec:world-state:database');
|
|
79
|
+
const dataDir = await mkdtemp(join(tmpdir(), 'aztec-world-state-'));
|
|
80
|
+
log.debug(`Created temporary world state database: ${dataDir}`);
|
|
134
81
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
return {
|
|
144
|
-
newSubtreeSiblingPath: new SiblingPath<SubtreeSiblingPathHeight>(
|
|
145
|
-
resp.subtree_path.length as any,
|
|
146
|
-
resp.subtree_path,
|
|
147
|
-
),
|
|
148
|
-
sortedNewLeaves: resp.sorted_leaves
|
|
149
|
-
.map(([leaf]) => leaf)
|
|
150
|
-
.map(deserializeLeafValue)
|
|
151
|
-
.map(serializeToBuffer),
|
|
152
|
-
sortedNewLeavesIndexes: resp.sorted_leaves.map(([, index]) => index),
|
|
153
|
-
lowLeavesWitnessData: resp.low_leaf_witness_data.map(data => ({
|
|
154
|
-
index: BigInt(data.index),
|
|
155
|
-
leafPreimage: deserializeIndexedLeaf(data.leaf),
|
|
156
|
-
siblingPath: new SiblingPath<TreeHeight>(data.path.length as any, data.path),
|
|
157
|
-
})),
|
|
82
|
+
// pass a cleanup callback because process.on('beforeExit', cleanup) does not work under Jest
|
|
83
|
+
const cleanup = async () => {
|
|
84
|
+
if (cleanupTmpDir) {
|
|
85
|
+
await rm(dataDir, { recursive: true, force: true });
|
|
86
|
+
log.debug(`Deleted temporary world state database: ${dataDir}`);
|
|
87
|
+
} else {
|
|
88
|
+
log.debug(`Leaving temporary world state database: ${dataDir}`);
|
|
89
|
+
}
|
|
158
90
|
};
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
async commit(): Promise<void> {
|
|
162
|
-
await this.call(WorldStateMessageType.COMMIT, void 0);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
findLeafIndex(
|
|
166
|
-
treeId: MerkleTreeId,
|
|
167
|
-
value: MerkleTreeLeafType<MerkleTreeId>,
|
|
168
|
-
includeUncommitted: boolean,
|
|
169
|
-
): Promise<bigint | undefined> {
|
|
170
|
-
return this.findLeafIndexAfter(treeId, value, 0n, includeUncommitted);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
async findLeafIndexAfter(
|
|
174
|
-
treeId: MerkleTreeId,
|
|
175
|
-
leaf: MerkleTreeLeafType<MerkleTreeId>,
|
|
176
|
-
startIndex: bigint,
|
|
177
|
-
includeUncommitted: boolean,
|
|
178
|
-
): Promise<bigint | undefined> {
|
|
179
|
-
const index = await this.call(WorldStateMessageType.FIND_LEAF_INDEX, {
|
|
180
|
-
leaf: serializeLeaf(hydrateLeaf(treeId, leaf)),
|
|
181
|
-
revision: worldStateRevision(includeUncommitted),
|
|
182
|
-
treeId,
|
|
183
|
-
startIndex,
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
if (typeof index === 'number' || typeof index === 'bigint') {
|
|
187
|
-
return BigInt(index);
|
|
188
|
-
} else {
|
|
189
|
-
return undefined;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
91
|
|
|
193
|
-
|
|
194
|
-
treeId: IndexedTreeId,
|
|
195
|
-
leafIndex: bigint,
|
|
196
|
-
args: boolean,
|
|
197
|
-
): Promise<IndexedTreeLeafPreimage | undefined> {
|
|
198
|
-
const resp = await this.call(WorldStateMessageType.GET_LEAF_PREIMAGE, {
|
|
199
|
-
leafIndex,
|
|
200
|
-
revision: worldStateRevision(args),
|
|
201
|
-
treeId,
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
return resp ? deserializeIndexedLeaf(resp) : undefined;
|
|
92
|
+
return this.new(rollupAddress, dataDir, log, cleanup);
|
|
205
93
|
}
|
|
206
94
|
|
|
207
|
-
async
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
includeUncommitted: boolean,
|
|
211
|
-
): Promise<MerkleTreeLeafType<MerkleTreeId> | undefined> {
|
|
212
|
-
const resp = await this.call(WorldStateMessageType.GET_LEAF_VALUE, {
|
|
213
|
-
leafIndex,
|
|
214
|
-
revision: worldStateRevision(includeUncommitted),
|
|
215
|
-
treeId,
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
if (!resp) {
|
|
219
|
-
return undefined;
|
|
220
|
-
}
|
|
95
|
+
protected async init() {
|
|
96
|
+
this.initialHeader = await this.buildInitialHeader();
|
|
97
|
+
const committed = this.getCommitted();
|
|
221
98
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
return leaf.toBuffer();
|
|
99
|
+
// validate the initial state
|
|
100
|
+
const archive = await committed.getTreeInfo(MerkleTreeId.ARCHIVE);
|
|
101
|
+
if (archive.size === 0n) {
|
|
102
|
+
throw new Error("Archive tree can't be empty");
|
|
227
103
|
}
|
|
228
|
-
}
|
|
229
104
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
): Promise<{ index: bigint; alreadyPresent: boolean } | undefined> {
|
|
235
|
-
const resp = await this.call(WorldStateMessageType.FIND_LOW_LEAF, {
|
|
236
|
-
key: new Fr(value),
|
|
237
|
-
revision: worldStateRevision(includeUncommitted),
|
|
238
|
-
treeId,
|
|
239
|
-
});
|
|
240
|
-
return {
|
|
241
|
-
alreadyPresent: resp.alreadyPresent,
|
|
242
|
-
index: BigInt(resp.index),
|
|
243
|
-
};
|
|
105
|
+
// the initial header _must_ be the first element in the archive tree
|
|
106
|
+
// if this assertion fails, check that the hashing done in Header in yarn-project matches the initial header hash done in world_state.cpp
|
|
107
|
+
const initialHeaderIndex = await committed.findLeafIndex(MerkleTreeId.ARCHIVE, this.initialHeader.hash());
|
|
108
|
+
assert.strictEqual(initialHeaderIndex, 0n, 'Invalid initial archive state');
|
|
244
109
|
}
|
|
245
110
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
leafIndex: bigint,
|
|
249
|
-
includeUncommitted: boolean,
|
|
250
|
-
): Promise<SiblingPath<number>> {
|
|
251
|
-
const siblingPath = await this.call(WorldStateMessageType.GET_SIBLING_PATH, {
|
|
252
|
-
leafIndex,
|
|
253
|
-
revision: worldStateRevision(includeUncommitted),
|
|
254
|
-
treeId,
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
return new SiblingPath(siblingPath.length, siblingPath);
|
|
111
|
+
public getCommitted(): MerkleTreeReadOperations {
|
|
112
|
+
return new MerkleTreesFacade(this.instance, this.initialHeader!, worldStateRevision(false, 0, 0));
|
|
258
113
|
}
|
|
259
114
|
|
|
260
|
-
getSnapshot(
|
|
261
|
-
return
|
|
115
|
+
public getSnapshot(blockNumber: number): MerkleTreeReadOperations {
|
|
116
|
+
return new MerkleTreesFacade(this.instance, this.initialHeader!, worldStateRevision(false, 0, blockNumber));
|
|
262
117
|
}
|
|
263
118
|
|
|
264
|
-
async
|
|
265
|
-
const resp = await this.call(WorldStateMessageType.
|
|
266
|
-
|
|
119
|
+
public async fork(blockNumber?: number): Promise<MerkleTreeWriteOperations> {
|
|
120
|
+
const resp = await this.instance.call(WorldStateMessageType.CREATE_FORK, {
|
|
121
|
+
latest: blockNumber === undefined,
|
|
122
|
+
blockNumber: blockNumber ?? 0,
|
|
267
123
|
});
|
|
268
|
-
|
|
269
|
-
return new StateReference(
|
|
270
|
-
treeStateReferenceToSnapshot(resp.state[MerkleTreeId.L1_TO_L2_MESSAGE_TREE]),
|
|
271
|
-
new PartialStateReference(
|
|
272
|
-
treeStateReferenceToSnapshot(resp.state[MerkleTreeId.NOTE_HASH_TREE]),
|
|
273
|
-
treeStateReferenceToSnapshot(resp.state[MerkleTreeId.NULLIFIER_TREE]),
|
|
274
|
-
treeStateReferenceToSnapshot(resp.state[MerkleTreeId.PUBLIC_DATA_TREE]),
|
|
275
|
-
),
|
|
276
|
-
);
|
|
124
|
+
return new MerkleTreesForkFacade(this.instance, this.initialHeader!, worldStateRevision(true, resp.forkId, 0));
|
|
277
125
|
}
|
|
278
126
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
treeId: treeId,
|
|
282
|
-
revision: worldStateRevision(includeUncommitted),
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
return {
|
|
286
|
-
depth: resp.depth,
|
|
287
|
-
root: resp.root,
|
|
288
|
-
size: BigInt(resp.size),
|
|
289
|
-
treeId,
|
|
290
|
-
};
|
|
127
|
+
public getInitialHeader(): Header {
|
|
128
|
+
return this.initialHeader!;
|
|
291
129
|
}
|
|
292
130
|
|
|
293
|
-
async handleL2BlockAndMessages(l2Block: L2Block, l1ToL2Messages: Fr[]): Promise<
|
|
131
|
+
public async handleL2BlockAndMessages(l2Block: L2Block, l1ToL2Messages: Fr[]): Promise<WorldStateStatus> {
|
|
294
132
|
// We have to pad both the tx effects and the values within tx effects because that's how the trees are built
|
|
295
133
|
// by circuits.
|
|
296
134
|
const paddedTxEffects = padArrayEnd(
|
|
@@ -321,142 +159,83 @@ export class NativeWorldStateService implements MerkleTreeDb {
|
|
|
321
159
|
batchesOfPaddedPublicDataWrites.push(batch);
|
|
322
160
|
}
|
|
323
161
|
|
|
324
|
-
|
|
325
|
-
|
|
162
|
+
const response = await this.instance.call(WorldStateMessageType.SYNC_BLOCK, {
|
|
163
|
+
blockNumber: l2Block.number,
|
|
164
|
+
blockHeaderHash: l2Block.header.hash(),
|
|
326
165
|
paddedL1ToL2Messages: paddedL1ToL2Messages.map(serializeLeaf),
|
|
327
166
|
paddedNoteHashes: paddedNoteHashes.map(serializeLeaf),
|
|
328
167
|
paddedNullifiers: paddedNullifiers.map(serializeLeaf),
|
|
329
168
|
batchesOfPaddedPublicDataWrites: batchesOfPaddedPublicDataWrites.map(batch => batch.map(serializeLeaf)),
|
|
330
169
|
blockStateRef: blockStateReference(l2Block.header.state),
|
|
331
170
|
});
|
|
171
|
+
return response.status;
|
|
332
172
|
}
|
|
333
173
|
|
|
334
|
-
async
|
|
335
|
-
await this.
|
|
174
|
+
public async close(): Promise<void> {
|
|
175
|
+
await this.instance.close();
|
|
176
|
+
await this.cleanup();
|
|
336
177
|
}
|
|
337
178
|
|
|
338
|
-
async
|
|
339
|
-
await this.
|
|
340
|
-
|
|
341
|
-
blockStateRef: blockStateReference(header.state),
|
|
342
|
-
});
|
|
179
|
+
private async buildInitialHeader(): Promise<Header> {
|
|
180
|
+
const state = await this.getInitialStateReference();
|
|
181
|
+
return Header.empty({ state });
|
|
343
182
|
}
|
|
344
183
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
184
|
+
/**
|
|
185
|
+
* Advances the finalised block number to be the number provided
|
|
186
|
+
* @param toBlockNumber The block number that is now the tip of the finalised chain
|
|
187
|
+
* @returns The new WorldStateStatus
|
|
188
|
+
*/
|
|
189
|
+
public async setFinalised(toBlockNumber: bigint) {
|
|
190
|
+
return await this.instance.call(WorldStateMessageType.FINALISE_BLOCKS, {
|
|
191
|
+
toBlockNumber,
|
|
192
|
+
});
|
|
351
193
|
}
|
|
352
194
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
const encodedResponse = await this.instance.call(encodedRequest);
|
|
362
|
-
|
|
363
|
-
const buf = Buffer.isBuffer(encodedResponse)
|
|
364
|
-
? encodedResponse
|
|
365
|
-
: isAnyArrayBuffer(encodedResponse)
|
|
366
|
-
? Buffer.from(encodedResponse)
|
|
367
|
-
: encodedResponse;
|
|
368
|
-
|
|
369
|
-
if (!Buffer.isBuffer(buf)) {
|
|
370
|
-
throw new TypeError(
|
|
371
|
-
'Invalid encoded response: expected Buffer or ArrayBuffer, got ' +
|
|
372
|
-
(encodedResponse === null ? 'null' : typeof encodedResponse),
|
|
373
|
-
);
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
const decodedResponse = this.decoder.unpack(buf);
|
|
377
|
-
if (!TypedMessage.isTypedMessageLike(decodedResponse)) {
|
|
378
|
-
throw new TypeError(
|
|
379
|
-
'Invalid response: expected TypedMessageLike, got ' +
|
|
380
|
-
(decodedResponse === null ? 'null' : typeof decodedResponse),
|
|
381
|
-
);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
const response = TypedMessage.fromMessagePack<T, WorldStateResponse[T]>(decodedResponse);
|
|
385
|
-
|
|
386
|
-
if (response.header.requestId !== request.header.messageId) {
|
|
387
|
-
throw new Error(
|
|
388
|
-
'Response ID does not match request: ' + response.header.requestId + ' != ' + request.header.messageId,
|
|
389
|
-
);
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
if (response.msgType !== messageType) {
|
|
393
|
-
throw new Error('Invalid response message type: ' + response.msgType + ' != ' + messageType);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
return response.value;
|
|
195
|
+
/**
|
|
196
|
+
* Removes all historical snapshots up to but not including the given block number
|
|
197
|
+
* @param toBlockNumber The block number of the new oldest historical block
|
|
198
|
+
* @returns The new WorldStateStatus
|
|
199
|
+
*/
|
|
200
|
+
public async removeHistoricalBlocks(toBlockNumber: bigint) {
|
|
201
|
+
return await this.instance.call(WorldStateMessageType.REMOVE_HISTORICAL_BLOCKS, {
|
|
202
|
+
toBlockNumber,
|
|
397
203
|
});
|
|
398
204
|
}
|
|
399
205
|
|
|
400
|
-
|
|
401
|
-
|
|
206
|
+
/**
|
|
207
|
+
* Removes all pending blocks down to but not including the given block number
|
|
208
|
+
* @param toBlockNumber The block number of the new tip of the pending chain,
|
|
209
|
+
* @returns The new WorldStateStatus
|
|
210
|
+
*/
|
|
211
|
+
public async unwindBlocks(toBlockNumber: bigint) {
|
|
212
|
+
return await this.instance.call(WorldStateMessageType.UNWIND_BLOCKS, {
|
|
213
|
+
toBlockNumber,
|
|
214
|
+
});
|
|
402
215
|
}
|
|
403
216
|
|
|
404
|
-
public
|
|
405
|
-
return
|
|
217
|
+
public async getStatus() {
|
|
218
|
+
return await this.instance.call(WorldStateMessageType.GET_STATUS, void 0);
|
|
406
219
|
}
|
|
407
220
|
|
|
408
|
-
|
|
221
|
+
updateLeaf<ID extends IndexedTreeId>(
|
|
222
|
+
_treeId: ID,
|
|
223
|
+
_leaf: NullifierLeafPreimage | Buffer,
|
|
224
|
+
_index: bigint,
|
|
225
|
+
): Promise<void> {
|
|
409
226
|
return Promise.reject(new Error('Method not implemented'));
|
|
410
227
|
}
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
function hydrateLeaf<ID extends MerkleTreeId>(treeId: ID, leaf: Fr | Buffer) {
|
|
414
|
-
if (leaf instanceof Fr) {
|
|
415
|
-
return leaf;
|
|
416
|
-
} else if (treeId === MerkleTreeId.NULLIFIER_TREE) {
|
|
417
|
-
return NullifierLeaf.fromBuffer(leaf);
|
|
418
|
-
} else if (treeId === MerkleTreeId.PUBLIC_DATA_TREE) {
|
|
419
|
-
return PublicDataTreeLeaf.fromBuffer(leaf);
|
|
420
|
-
} else {
|
|
421
|
-
return Fr.fromBuffer(leaf);
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
function serializeLeaf(leaf: Fr | NullifierLeaf | PublicDataTreeLeaf): SerializedLeafValue {
|
|
426
|
-
if (leaf instanceof Fr) {
|
|
427
|
-
return leaf.toBuffer();
|
|
428
|
-
} else if (leaf instanceof NullifierLeaf) {
|
|
429
|
-
return { value: leaf.nullifier.toBuffer() };
|
|
430
|
-
} else {
|
|
431
|
-
return { value: leaf.value.toBuffer(), slot: leaf.slot.toBuffer() };
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
228
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
return Fr.fromBuffer(leaf);
|
|
438
|
-
} else if ('slot' in leaf) {
|
|
439
|
-
return new PublicDataTreeLeaf(Fr.fromBuffer(leaf.slot), Fr.fromBuffer(leaf.value));
|
|
440
|
-
} else {
|
|
441
|
-
return new NullifierLeaf(Fr.fromBuffer(leaf.value));
|
|
442
|
-
}
|
|
443
|
-
}
|
|
229
|
+
private async getInitialStateReference(): Promise<StateReference> {
|
|
230
|
+
const resp = await this.instance.call(WorldStateMessageType.GET_INITIAL_STATE_REFERENCE, void 0);
|
|
444
231
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
);
|
|
453
|
-
} else if ('value' in leaf.value) {
|
|
454
|
-
return new NullifierLeafPreimage(
|
|
455
|
-
Fr.fromBuffer(leaf.value.value),
|
|
456
|
-
Fr.fromBuffer(leaf.nextValue),
|
|
457
|
-
BigInt(leaf.nextIndex),
|
|
232
|
+
return new StateReference(
|
|
233
|
+
treeStateReferenceToSnapshot(resp.state[MerkleTreeId.L1_TO_L2_MESSAGE_TREE]),
|
|
234
|
+
new PartialStateReference(
|
|
235
|
+
treeStateReferenceToSnapshot(resp.state[MerkleTreeId.NOTE_HASH_TREE]),
|
|
236
|
+
treeStateReferenceToSnapshot(resp.state[MerkleTreeId.NULLIFIER_TREE]),
|
|
237
|
+
treeStateReferenceToSnapshot(resp.state[MerkleTreeId.PUBLIC_DATA_TREE]),
|
|
238
|
+
),
|
|
458
239
|
);
|
|
459
|
-
} else {
|
|
460
|
-
throw new Error('Invalid leaf type');
|
|
461
240
|
}
|
|
462
241
|
}
|