@aztec/sequencer-client 0.1.0-alpha42 → 0.1.0-alpha44
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/.tsbuildinfo +1 -1
- package/dest/block_builder/solo_block_builder.d.ts.map +1 -1
- package/dest/block_builder/solo_block_builder.js +7 -4
- package/dest/sequencer/public_processor.d.ts +6 -0
- package/dest/sequencer/public_processor.d.ts.map +1 -1
- package/dest/sequencer/public_processor.js +84 -16
- package/dest/sequencer/utils.js +2 -2
- package/package.json +10 -10
- package/src/block_builder/solo_block_builder.ts +7 -4
- package/src/sequencer/public_processor.ts +137 -16
- package/src/sequencer/utils.ts +1 -1
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
PublicExecution,
|
|
3
|
+
PublicExecutionResult,
|
|
4
|
+
PublicExecutor,
|
|
5
|
+
collectPublicDataReads,
|
|
6
|
+
collectPublicDataUpdateRequests,
|
|
7
|
+
isPublicExecutionResult,
|
|
8
|
+
} from '@aztec/acir-simulator';
|
|
2
9
|
import {
|
|
3
10
|
AztecAddress,
|
|
4
11
|
CircuitsWasm,
|
|
@@ -13,20 +20,24 @@ import {
|
|
|
13
20
|
MAX_NEW_NULLIFIERS_PER_CALL,
|
|
14
21
|
MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL,
|
|
15
22
|
MAX_PUBLIC_DATA_READS_PER_CALL,
|
|
23
|
+
MAX_PUBLIC_DATA_READS_PER_TX,
|
|
16
24
|
MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL,
|
|
25
|
+
MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
|
|
17
26
|
MembershipWitness,
|
|
18
27
|
PreviousKernelData,
|
|
19
28
|
Proof,
|
|
20
29
|
PublicCallData,
|
|
21
30
|
PublicCallStackItem,
|
|
22
31
|
PublicCircuitPublicInputs,
|
|
32
|
+
PublicDataRead,
|
|
33
|
+
PublicDataUpdateRequest,
|
|
23
34
|
PublicKernelInputs,
|
|
24
35
|
PublicKernelPublicInputs,
|
|
25
36
|
RETURN_VALUES_LENGTH,
|
|
26
37
|
VK_TREE_HEIGHT,
|
|
27
38
|
} from '@aztec/circuits.js';
|
|
28
39
|
import { computeCallStackItemHash, computeVarArgsHash } from '@aztec/circuits.js/abis';
|
|
29
|
-
import { isArrayEmpty, padArrayEnd, padArrayStart } from '@aztec/foundation/collection';
|
|
40
|
+
import { arrayNonEmptyLength, isArrayEmpty, padArrayEnd, padArrayStart } from '@aztec/foundation/collection';
|
|
30
41
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
31
42
|
import { Tuple, mapTuple, to2Fields } from '@aztec/foundation/serialize';
|
|
32
43
|
import { ContractDataSource, FunctionL2Logs, L1ToL2MessageSource, MerkleTreeId, Tx } from '@aztec/types';
|
|
@@ -138,24 +149,42 @@ export class PublicProcessor {
|
|
|
138
149
|
this.log(`Executing enqueued public calls for tx ${await tx.getTxHash()}`);
|
|
139
150
|
if (!tx.enqueuedPublicFunctionCalls) throw new Error(`Missing preimages for enqueued public calls`);
|
|
140
151
|
|
|
141
|
-
const executionStack: (PublicExecution | PublicExecutionResult)[] = [...tx.enqueuedPublicFunctionCalls];
|
|
142
|
-
|
|
143
152
|
let kernelOutput = tx.data;
|
|
144
153
|
let kernelProof = tx.proof;
|
|
145
154
|
const newUnencryptedFunctionLogs: FunctionL2Logs[] = [];
|
|
146
155
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
executionStack
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
156
|
+
// TODO(#1684): Should multiple separately enqueued public calls be treated as
|
|
157
|
+
// separate public callstacks to be proven by separate public kernel sequences
|
|
158
|
+
// and submitted separately to the base rollup?
|
|
159
|
+
|
|
160
|
+
// TODO(dbanks12): why must these be reversed?
|
|
161
|
+
const enqueuedCallsReversed = tx.enqueuedPublicFunctionCalls.slice().reverse();
|
|
162
|
+
for (const enqueuedCall of enqueuedCallsReversed) {
|
|
163
|
+
const executionStack: (PublicExecution | PublicExecutionResult)[] = [enqueuedCall];
|
|
164
|
+
|
|
165
|
+
// Keep track of which result is for the top/enqueued call
|
|
166
|
+
let enqueuedExecutionResult: PublicExecutionResult | undefined;
|
|
167
|
+
|
|
168
|
+
while (executionStack.length) {
|
|
169
|
+
const current = executionStack.pop()!;
|
|
170
|
+
const isExecutionRequest = !isPublicExecutionResult(current);
|
|
171
|
+
const result = isExecutionRequest ? await this.publicExecutor.execute(current, this.globalVariables) : current;
|
|
172
|
+
newUnencryptedFunctionLogs.push(result.unencryptedLogs);
|
|
173
|
+
const functionSelector = result.execution.functionData.functionSelectorBuffer.toString('hex');
|
|
174
|
+
this.log(
|
|
175
|
+
`Running public kernel circuit for ${functionSelector}@${result.execution.contractAddress.toString()}`,
|
|
176
|
+
);
|
|
177
|
+
executionStack.push(...result.nestedExecutions);
|
|
178
|
+
const preimages = await this.getPublicCallStackPreimages(result);
|
|
179
|
+
const callData = await this.getPublicCallData(result, preimages, isExecutionRequest);
|
|
180
|
+
|
|
181
|
+
[kernelOutput, kernelProof] = await this.runKernelCircuit(callData, kernelOutput, kernelProof);
|
|
182
|
+
|
|
183
|
+
if (!enqueuedExecutionResult) enqueuedExecutionResult = result;
|
|
184
|
+
}
|
|
185
|
+
// HACK(#1622): Manually patches the ordering of public state actions
|
|
186
|
+
// TODO(#757): Enforce proper ordering of public state actions
|
|
187
|
+
await this.patchPublicStorageActionOrdering(kernelOutput, enqueuedExecutionResult!);
|
|
159
188
|
}
|
|
160
189
|
|
|
161
190
|
return [kernelOutput, kernelProof, newUnencryptedFunctionLogs];
|
|
@@ -286,4 +315,96 @@ export class PublicProcessor {
|
|
|
286
315
|
const proof = await this.publicProver.getPublicCircuitProof(callStackItem.publicInputs);
|
|
287
316
|
return new PublicCallData(callStackItem, preimages, proof, portalContractAddress, bytecodeHash);
|
|
288
317
|
}
|
|
318
|
+
|
|
319
|
+
// HACK(#1622): this is a hack to fix ordering of public state in the call stack. Since the private kernel
|
|
320
|
+
// cannot keep track of side effects that happen after or before a nested call, we override the public
|
|
321
|
+
// state actions it emits with whatever we got from the simulator. As a sanity check, we at least verify
|
|
322
|
+
// that the elements are the same, so we are only tweaking their ordering.
|
|
323
|
+
// See yarn-project/end-to-end/src/e2e_ordering.test.ts
|
|
324
|
+
// See https://github.com/AztecProtocol/aztec-packages/issues/1616
|
|
325
|
+
// TODO(#757): Enforce proper ordering of public state actions
|
|
326
|
+
/**
|
|
327
|
+
* Patch the ordering of storage actions output from the public kernel.
|
|
328
|
+
* @param publicInputs - to be patched here: public inputs to the kernel iteration up to this point
|
|
329
|
+
* @param execResult - result of the top/first execution for this enqueued public call
|
|
330
|
+
*/
|
|
331
|
+
private async patchPublicStorageActionOrdering(
|
|
332
|
+
publicInputs: KernelCircuitPublicInputs,
|
|
333
|
+
execResult: PublicExecutionResult,
|
|
334
|
+
) {
|
|
335
|
+
// Convert ContractStorage* objects to PublicData* objects and sort them in execution order
|
|
336
|
+
const wasm = await CircuitsWasm.get();
|
|
337
|
+
const simPublicDataReads = collectPublicDataReads(wasm, execResult);
|
|
338
|
+
const simPublicDataUpdateRequests = collectPublicDataUpdateRequests(wasm, execResult);
|
|
339
|
+
|
|
340
|
+
const { publicDataReads, publicDataUpdateRequests } = publicInputs.end; // from kernel
|
|
341
|
+
|
|
342
|
+
// Validate all items in enqueued public calls are in the kernel emitted stack
|
|
343
|
+
const readsAreEqual = simPublicDataReads.reduce(
|
|
344
|
+
(accum, read) =>
|
|
345
|
+
accum && !!publicDataReads.find(item => item.leafIndex.equals(read.leafIndex) && item.value.equals(read.value)),
|
|
346
|
+
true,
|
|
347
|
+
);
|
|
348
|
+
const updatesAreEqual = simPublicDataUpdateRequests.reduce(
|
|
349
|
+
(accum, update) =>
|
|
350
|
+
accum &&
|
|
351
|
+
!!publicDataUpdateRequests.find(
|
|
352
|
+
item =>
|
|
353
|
+
item.leafIndex.equals(update.leafIndex) &&
|
|
354
|
+
item.oldValue.equals(update.oldValue) &&
|
|
355
|
+
item.newValue.equals(update.newValue),
|
|
356
|
+
),
|
|
357
|
+
true,
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
if (!readsAreEqual) {
|
|
361
|
+
throw new Error(
|
|
362
|
+
`Public data reads from simulator do not match those from public kernel.\nFrom simulator: ${simPublicDataReads
|
|
363
|
+
.map(p => p.toFriendlyJSON())
|
|
364
|
+
.join(', ')}\nFrom public kernel: ${publicDataReads.map(i => i.toFriendlyJSON()).join(', ')}`,
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
if (!updatesAreEqual) {
|
|
368
|
+
throw new Error(
|
|
369
|
+
`Public data update requests from simulator do not match those from public kernel.\nFrom simulator: ${simPublicDataUpdateRequests
|
|
370
|
+
.map(p => p.toFriendlyJSON())
|
|
371
|
+
.join(', ')}\nFrom public kernel: ${publicDataUpdateRequests.map(i => i.toFriendlyJSON()).join(', ')}`,
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Assume that kernel public inputs has the right number of items.
|
|
376
|
+
// We only want to reorder the items from the public inputs of the
|
|
377
|
+
// most recently processed top/enqueued call.
|
|
378
|
+
const numTotalReadsInKernel = arrayNonEmptyLength(
|
|
379
|
+
publicInputs.end.publicDataReads,
|
|
380
|
+
f => f.leafIndex.equals(Fr.ZERO) && f.value.equals(Fr.ZERO),
|
|
381
|
+
);
|
|
382
|
+
const numTotalUpdatesInKernel = arrayNonEmptyLength(
|
|
383
|
+
publicInputs.end.publicDataUpdateRequests,
|
|
384
|
+
f => f.leafIndex.equals(Fr.ZERO) && f.oldValue.equals(Fr.ZERO) && f.newValue.equals(Fr.ZERO),
|
|
385
|
+
);
|
|
386
|
+
const numReadsBeforeThisEnqueuedCall = numTotalReadsInKernel - simPublicDataReads.length;
|
|
387
|
+
const numUpdatesBeforeThisEnqueuedCall = numTotalUpdatesInKernel - simPublicDataUpdateRequests.length;
|
|
388
|
+
|
|
389
|
+
// Override kernel output
|
|
390
|
+
publicInputs.end.publicDataReads = padArrayEnd(
|
|
391
|
+
[
|
|
392
|
+
// do not mess with items from previous top/enqueued calls in kernel output
|
|
393
|
+
...publicDataReads.slice(0, numReadsBeforeThisEnqueuedCall),
|
|
394
|
+
...simPublicDataReads,
|
|
395
|
+
],
|
|
396
|
+
PublicDataRead.empty(),
|
|
397
|
+
MAX_PUBLIC_DATA_READS_PER_TX,
|
|
398
|
+
);
|
|
399
|
+
// Override kernel output
|
|
400
|
+
publicInputs.end.publicDataUpdateRequests = padArrayEnd(
|
|
401
|
+
[
|
|
402
|
+
// do not mess with items from previous top/enqueued calls in kernel output
|
|
403
|
+
...publicDataUpdateRequests.slice(0, numUpdatesBeforeThisEnqueuedCall),
|
|
404
|
+
...simPublicDataUpdateRequests,
|
|
405
|
+
],
|
|
406
|
+
PublicDataUpdateRequest.empty(),
|
|
407
|
+
MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
|
|
408
|
+
);
|
|
409
|
+
}
|
|
289
410
|
}
|
package/src/sequencer/utils.ts
CHANGED
|
@@ -11,7 +11,7 @@ export async function getHistoricBlockData(
|
|
|
11
11
|
) {
|
|
12
12
|
const wasm = await CircuitsWasm.get();
|
|
13
13
|
const prevGlobalsHash = computeGlobalsHash(wasm, prevBlockGlobalVariables);
|
|
14
|
-
const roots = db.getTreeRoots();
|
|
14
|
+
const roots = await db.getTreeRoots();
|
|
15
15
|
|
|
16
16
|
return new HistoricBlockData(
|
|
17
17
|
Fr.fromBuffer(roots.privateDataTreeRoot),
|