@aztec/txe 0.86.0-starknet.1 → 0.87.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.
@@ -40,8 +40,20 @@ export function fromArray(obj) {
40
40
  const boundedStorage = storage.slice(0, fromSingle(length).toNumber());
41
41
  return Buffer.concat(boundedStorage.map((str)=>hexToBuffer(str).slice(-uintByteSize)));
42
42
  }
43
- export function toSingle(obj) {
44
- return obj.toString().slice(2);
43
+ // Just like toACVMField in yarn-project/simulator/src/private/acvm/serialize.ts but returns a ForeignCallSingle
44
+ // instead of an ACVMField.
45
+ export function toSingle(value) {
46
+ let valueAsField;
47
+ if (Buffer.isBuffer(value)) {
48
+ valueAsField = Fr.fromBuffer(value);
49
+ } else if (typeof value === 'boolean' || typeof value === 'number' || typeof value === 'bigint') {
50
+ valueAsField = new Fr(value);
51
+ } else if (typeof value === 'string') {
52
+ valueAsField = Fr.fromHexString(value);
53
+ } else {
54
+ valueAsField = value;
55
+ }
56
+ return valueAsField.toString().slice(2);
45
57
  }
46
58
  export function toArray(objs) {
47
59
  return objs.map((obj)=>obj.toString());
@@ -74,6 +86,30 @@ export function bufferToU8Array(buffer) {
74
86
  len
75
87
  ];
76
88
  }
89
+ /**
90
+ * Converts an array of arrays representing Noir BoundedVec of nested arrays into its Noir serialized form.
91
+ * @param bVecStorage - The array underlying the BoundedVec.
92
+ * @param maxLen - The max length of the BoundedVec (max num of the nested arrays in the BoundedVec).
93
+ * @param nestedArrayLength - The length of the nested arrays (each nested array has to have the same length).
94
+ * @returns Serialized BoundedVec following Noir intrinsic serialization.
95
+ */ export function arrayOfArraysToBoundedVecOfArrays(bVecStorage, maxLen, nestedArrayLength) {
96
+ if (bVecStorage.length > maxLen) {
97
+ throw new Error(`Array of length ${bVecStorage.length} larger than maxLen ${maxLen}`);
98
+ }
99
+ // Check that all nested arrays have length nestedArrayLength
100
+ if (!bVecStorage.every((nestedArray)=>nestedArray.length === nestedArrayLength)) {
101
+ throw new Error(`Nested array length passed in from Noir does not correspond to the length obtained in TS: ${nestedArrayLength} !== ${bVecStorage[0].length}`);
102
+ }
103
+ const flattenedStorage = bVecStorage.flat();
104
+ const numFieldsToPad = maxLen * nestedArrayLength - flattenedStorage.length;
105
+ const flattenedStorageWithPadding = flattenedStorage.concat(Array(numFieldsToPad).fill(new Fr(0)));
106
+ // At last we get the actual length of the BoundedVec and return the values.
107
+ const len = toSingle(new Fr(bVecStorage.length));
108
+ return [
109
+ flattenedStorageWithPadding,
110
+ len
111
+ ];
112
+ }
77
113
  export function toForeignCallResult(obj) {
78
114
  return {
79
115
  values: obj
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/txe",
3
- "version": "0.86.0-starknet.1",
3
+ "version": "0.87.0",
4
4
  "type": "module",
5
5
  "exports": "./dest/index.js",
6
6
  "bin": "./dest/bin/index.js",
@@ -57,30 +57,30 @@
57
57
  ]
58
58
  },
59
59
  "dependencies": {
60
- "@aztec/accounts": "0.86.0-starknet.1",
61
- "@aztec/archiver": "0.86.0-starknet.1",
62
- "@aztec/aztec-node": "0.86.0-starknet.1",
63
- "@aztec/aztec.js": "0.86.0-starknet.1",
64
- "@aztec/bb-prover": "0.86.0-starknet.1",
65
- "@aztec/constants": "0.86.0-starknet.1",
66
- "@aztec/foundation": "0.86.0-starknet.1",
67
- "@aztec/key-store": "0.86.0-starknet.1",
68
- "@aztec/kv-store": "0.86.0-starknet.1",
69
- "@aztec/protocol-contracts": "0.86.0-starknet.1",
70
- "@aztec/pxe": "0.86.0-starknet.1",
71
- "@aztec/simulator": "0.86.0-starknet.1",
72
- "@aztec/stdlib": "0.86.0-starknet.1",
73
- "@aztec/world-state": "0.86.0-starknet.1",
60
+ "@aztec/accounts": "0.87.0",
61
+ "@aztec/archiver": "0.87.0",
62
+ "@aztec/aztec-node": "0.87.0",
63
+ "@aztec/aztec.js": "0.87.0",
64
+ "@aztec/bb-prover": "0.87.0",
65
+ "@aztec/constants": "0.87.0",
66
+ "@aztec/foundation": "0.87.0",
67
+ "@aztec/key-store": "0.87.0",
68
+ "@aztec/kv-store": "0.87.0",
69
+ "@aztec/protocol-contracts": "0.87.0",
70
+ "@aztec/pxe": "0.87.0",
71
+ "@aztec/simulator": "0.87.0",
72
+ "@aztec/stdlib": "0.87.0",
73
+ "@aztec/world-state": "0.87.0",
74
74
  "zod": "^3.23.8"
75
75
  },
76
76
  "devDependencies": {
77
77
  "@jest/globals": "^29.5.0",
78
78
  "@types/jest": "^29.5.0",
79
- "@types/node": "^18.7.23",
79
+ "@types/node": "^22.15.17",
80
80
  "jest": "^29.5.0",
81
81
  "jest-mock-extended": "^3.0.3",
82
82
  "ts-node": "^10.9.1",
83
- "typescript": "^5.0.4"
83
+ "typescript": "^5.3.3"
84
84
  },
85
85
  "files": [
86
86
  "dest",
@@ -89,6 +89,6 @@
89
89
  ],
90
90
  "types": "./dest/index.d.ts",
91
91
  "engines": {
92
- "node": ">=18"
92
+ "node": ">=20.10"
93
93
  }
94
94
  }
@@ -1,8 +1,15 @@
1
1
  import { type AztecNode, Body, L2Block, Note } from '@aztec/aztec.js';
2
2
  import {
3
+ DEFAULT_GAS_LIMIT,
4
+ DEFAULT_TEARDOWN_GAS_LIMIT,
3
5
  type L1_TO_L2_MSG_TREE_HEIGHT,
6
+ MAX_CONTRACT_CLASS_LOGS_PER_TX,
7
+ MAX_ENQUEUED_CALLS_PER_TX,
8
+ MAX_L2_GAS_PER_TX_PUBLIC_PORTION,
9
+ MAX_L2_TO_L1_MSGS_PER_TX,
4
10
  MAX_NOTE_HASHES_PER_TX,
5
11
  MAX_NULLIFIERS_PER_TX,
12
+ MAX_PRIVATE_LOGS_PER_TX,
6
13
  NULLIFIER_SUBTREE_HEIGHT,
7
14
  type NULLIFIER_TREE_HEIGHT,
8
15
  NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
@@ -13,7 +20,7 @@ import { padArrayEnd } from '@aztec/foundation/collection';
13
20
  import { Aes128, Schnorr, poseidon2Hash } from '@aztec/foundation/crypto';
14
21
  import { Fr, Point } from '@aztec/foundation/fields';
15
22
  import { type Logger, applyStringFormatting } from '@aztec/foundation/log';
16
- import { Timer } from '@aztec/foundation/timer';
23
+ import { TestDateProvider, Timer } from '@aztec/foundation/timer';
17
24
  import { KeyStore } from '@aztec/key-store';
18
25
  import type { AztecAsyncKVStore } from '@aztec/kv-store';
19
26
  import type { ProtocolContract } from '@aztec/protocol-contracts';
@@ -34,8 +41,11 @@ import {
34
41
  type MessageLoadOracleInputs,
35
42
  type NoteData,
36
43
  Oracle,
44
+ PrivateExecutionOracle,
37
45
  type TypedOracle,
46
+ UtilityExecutionOracle,
38
47
  WASMSimulator,
48
+ executePrivateFunction,
39
49
  extractCallStack,
40
50
  extractPrivateCircuitPublicInputs,
41
51
  pickNotes,
@@ -46,6 +56,7 @@ import { createTxForPublicCalls } from '@aztec/simulator/public/fixtures';
46
56
  import {
47
57
  ExecutionError,
48
58
  PublicContractsDB,
59
+ PublicProcessor,
49
60
  type PublicTxResult,
50
61
  PublicTxSimulator,
51
62
  createSimulationError,
@@ -56,6 +67,7 @@ import {
56
67
  EventSelector,
57
68
  type FunctionAbi,
58
69
  FunctionSelector,
70
+ FunctionType,
59
71
  type NoteSelector,
60
72
  countArgumentsSize,
61
73
  } from '@aztec/stdlib/abi';
@@ -64,25 +76,33 @@ import { PublicDataWrite } from '@aztec/stdlib/avm';
64
76
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
65
77
  import type { ContractInstance, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
66
78
  import { SimulationError } from '@aztec/stdlib/errors';
67
- import { Gas, GasFees } from '@aztec/stdlib/gas';
79
+ import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
68
80
  import {
69
81
  computeNoteHashNonce,
70
82
  computePublicDataTreeLeafSlot,
71
83
  computeUniqueNoteHash,
84
+ computeVarArgsHash,
72
85
  siloNoteHash,
73
86
  siloNullifier,
74
87
  } from '@aztec/stdlib/hash';
75
88
  import type { MerkleTreeReadOperations, MerkleTreeWriteOperations } from '@aztec/stdlib/interfaces/server';
76
- import { type KeyValidationRequest, PrivateContextInputs, PublicCallRequest } from '@aztec/stdlib/kernel';
77
- import { deriveKeys } from '@aztec/stdlib/keys';
78
89
  import {
79
- ContractClassLog,
80
- IndexedTaggingSecret,
81
- LogWithTxData,
82
- type PrivateLog,
83
- type PublicLog,
84
- } from '@aztec/stdlib/logs';
90
+ type KeyValidationRequest,
91
+ PartialPrivateTailPublicInputsForPublic,
92
+ PartialPrivateTailPublicInputsForRollup,
93
+ PrivateContextInputs,
94
+ PrivateKernelTailCircuitPublicInputs,
95
+ PrivateToPublicAccumulatedData,
96
+ PrivateToRollupAccumulatedData,
97
+ PublicCallRequest,
98
+ RollupValidationRequests,
99
+ ScopedLogHash,
100
+ } from '@aztec/stdlib/kernel';
101
+ import { deriveKeys } from '@aztec/stdlib/keys';
102
+ import { ContractClassLog, IndexedTaggingSecret, LogWithTxData, PrivateLog, type PublicLog } from '@aztec/stdlib/logs';
103
+ import { ScopedL2ToL1Message } from '@aztec/stdlib/messaging';
85
104
  import type { NoteStatus } from '@aztec/stdlib/note';
105
+ import { ClientIvcProof } from '@aztec/stdlib/proofs';
86
106
  import type { CircuitWitnessGenerationStats } from '@aztec/stdlib/stats';
87
107
  import {
88
108
  makeAppendOnlyTreeSnapshot,
@@ -103,9 +123,15 @@ import {
103
123
  BlockHeader,
104
124
  CallContext,
105
125
  GlobalVariables,
126
+ HashedValues,
127
+ PrivateExecutionResult,
106
128
  PublicCallRequestWithCalldata,
129
+ Tx,
130
+ TxConstantData,
131
+ TxContext,
107
132
  TxEffect,
108
133
  TxHash,
134
+ collectNested,
109
135
  } from '@aztec/stdlib/tx';
110
136
  import { ForkCheckpoint, NativeWorldStateService } from '@aztec/world-state/native';
111
137
 
@@ -140,7 +166,7 @@ export class TXE implements TypedOracle {
140
166
 
141
167
  private simulationProvider = new WASMSimulator();
142
168
 
143
- private noteCache: ExecutionNoteCache;
169
+ public noteCache: ExecutionNoteCache;
144
170
 
145
171
  private authwits: Map<string, AuthWitness> = new Map();
146
172
 
@@ -385,9 +411,7 @@ export class TXE implements TypedOracle {
385
411
  addPublicLogs(logs: PublicLog[]) {
386
412
  logs.forEach(log => {
387
413
  try {
388
- // The first elt stores lengths => tag is in fields[1]
389
- const tag = log.log[1];
390
-
414
+ const tag = log.fields[0];
391
415
  this.logger.verbose(`Found tagged public log with tag ${tag.toString()} in block ${this.blockNumber}`);
392
416
  this.publicLogs.push(log);
393
417
  } catch (err) {
@@ -623,7 +647,6 @@ export class TXE implements TypedOracle {
623
647
  counter,
624
648
  );
625
649
  this.sideEffectCounter = counter + 1;
626
- return Promise.resolve();
627
650
  }
628
651
 
629
652
  async notifyNullifiedNote(innerNullifier: Fr, noteHash: Fr, counter: number) {
@@ -729,6 +752,7 @@ export class TXE implements TypedOracle {
729
752
  txEffect.noteHashes = [...uniqueNoteHashesFromPrivate, ...this.uniqueNoteHashesFromPublic];
730
753
 
731
754
  txEffect.nullifiers = [...this.siloedNullifiersFromPublic, ...this.noteCache.getAllNullifiers()];
755
+
732
756
  if (usedTxRequestHashForNonces) {
733
757
  txEffect.nullifiers.unshift(this.getTxRequestHash());
734
758
  }
@@ -812,6 +836,61 @@ export class TXE implements TypedOracle {
812
836
  throw new Error('Method not implemented.');
813
837
  }
814
838
 
839
+ async simulateUtilityFunction(targetContractAddress: AztecAddress, functionSelector: FunctionSelector, argsHash: Fr) {
840
+ const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
841
+ if (!artifact) {
842
+ throw new Error(`Cannot call ${functionSelector} as there is artifact found at ${targetContractAddress}.`);
843
+ }
844
+
845
+ const call = {
846
+ name: artifact.name,
847
+ selector: functionSelector,
848
+ to: targetContractAddress,
849
+ };
850
+
851
+ const entryPointArtifact = await this.pxeOracleInterface.getFunctionArtifact(call.to, call.selector);
852
+
853
+ if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
854
+ throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
855
+ }
856
+
857
+ const oracle = new UtilityExecutionOracle(call.to, [], [], this.pxeOracleInterface, undefined, undefined);
858
+
859
+ try {
860
+ this.logger.verbose(`Executing utility function ${entryPointArtifact.name}`, {
861
+ contract: call.to,
862
+ selector: call.selector,
863
+ });
864
+
865
+ const args = await this.loadFromExecutionCache(argsHash);
866
+ const initialWitness = toACVMWitness(0, args);
867
+ const acirExecutionResult = await this.simulationProvider
868
+ .executeUserCircuit(initialWitness, entryPointArtifact, new Oracle(oracle))
869
+ .catch((err: Error) => {
870
+ err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
871
+ throw new ExecutionError(
872
+ err.message,
873
+ {
874
+ contractAddress: call.to,
875
+ functionSelector: call.selector,
876
+ },
877
+ extractCallStack(err, entryPointArtifact.debug),
878
+ { cause: err },
879
+ );
880
+ });
881
+
882
+ const returnWitness = witnessMapToFields(acirExecutionResult.returnWitness);
883
+ this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
884
+
885
+ const returnHash = await computeVarArgsHash(returnWitness);
886
+
887
+ this.storeInExecutionCache(returnWitness, returnHash);
888
+ return returnHash;
889
+ } catch (err) {
890
+ throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
891
+ }
892
+ }
893
+
815
894
  async callPrivateFunction(
816
895
  targetContractAddress: AztecAddress,
817
896
  functionSelector: FunctionSelector,
@@ -944,6 +1023,8 @@ export class TXE implements TypedOracle {
944
1023
  contractsDB,
945
1024
  globalVariables,
946
1025
  /*doMerkleOperations=*/ false,
1026
+ /*skipFeeEnforcement=*/ false,
1027
+ /*clientInitiatedSimulation=*/ true,
947
1028
  );
948
1029
 
949
1030
  const { usedTxRequestHashForNonces } = this.noteCache.finish();
@@ -1267,4 +1348,276 @@ export class TXE implements TypedOracle {
1267
1348
  txIndexInBlock,
1268
1349
  );
1269
1350
  }
1351
+
1352
+ async privateCallNewFlow(
1353
+ from: AztecAddress,
1354
+ targetContractAddress: AztecAddress = AztecAddress.zero(),
1355
+ functionSelector: FunctionSelector = FunctionSelector.empty(),
1356
+ args: Fr[],
1357
+ argsHash: Fr = Fr.zero(),
1358
+ isStaticCall: boolean = false,
1359
+ ) {
1360
+ this.logger.verbose(
1361
+ `Executing external function ${await this.getDebugFunctionName(
1362
+ targetContractAddress,
1363
+ functionSelector,
1364
+ )}@${targetContractAddress} isStaticCall=${isStaticCall}`,
1365
+ );
1366
+
1367
+ const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
1368
+
1369
+ if (artifact === undefined) {
1370
+ throw new Error('Function Artifact does not exist');
1371
+ }
1372
+
1373
+ const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
1374
+
1375
+ const gasLimits = new Gas(DEFAULT_GAS_LIMIT, MAX_L2_GAS_PER_TX_PUBLIC_PORTION);
1376
+
1377
+ const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_GAS_LIMIT, MAX_L2_GAS_PER_TX_PUBLIC_PORTION);
1378
+
1379
+ const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
1380
+
1381
+ const txContext = new TxContext(this.CHAIN_ID, this.ROLLUP_VERSION, gasSettings);
1382
+
1383
+ const blockHeader = await this.pxeOracleInterface.getBlockHeader();
1384
+
1385
+ const noteCache = new ExecutionNoteCache(this.getTxRequestHash());
1386
+
1387
+ const context = new PrivateExecutionOracle(
1388
+ argsHash,
1389
+ txContext,
1390
+ callContext,
1391
+ /** Header of a block whose state is used during private execution (not the block the transaction is included in). */
1392
+ blockHeader,
1393
+ /** List of transient auth witnesses to be used during this simulation */
1394
+ [],
1395
+ /** List of transient auth witnesses to be used during this simulation */
1396
+ [],
1397
+ HashedValuesCache.create(),
1398
+ noteCache,
1399
+ this.pxeOracleInterface,
1400
+ this.simulationProvider,
1401
+ 0,
1402
+ 1,
1403
+ );
1404
+
1405
+ context.storeInExecutionCache(args, argsHash);
1406
+
1407
+ // Note: This is a slight modification of simulator.run without any of the checks. Maybe we should modify simulator.run with a boolean value to skip checks.
1408
+ let result;
1409
+ try {
1410
+ const executionResult = await executePrivateFunction(
1411
+ this.simulationProvider,
1412
+ context,
1413
+ artifact,
1414
+ targetContractAddress,
1415
+ functionSelector,
1416
+ );
1417
+ const { usedTxRequestHashForNonces } = noteCache.finish();
1418
+ const firstNullifierHint = usedTxRequestHashForNonces ? Fr.ZERO : noteCache.getAllNullifiers()[0];
1419
+
1420
+ const publicCallRequests = collectNested([executionResult], r => [
1421
+ ...r.publicInputs.publicCallRequests.map(r => r.inner),
1422
+ r.publicInputs.publicTeardownCallRequest,
1423
+ ]).filter(r => !r.isEmpty());
1424
+ const publicFunctionsCalldata = await Promise.all(
1425
+ publicCallRequests.map(async r => {
1426
+ const calldata = await context.loadFromExecutionCache(r.calldataHash);
1427
+ return new HashedValues(calldata, r.calldataHash);
1428
+ }),
1429
+ );
1430
+
1431
+ result = new PrivateExecutionResult(executionResult, firstNullifierHint, publicFunctionsCalldata);
1432
+ } catch (err) {
1433
+ throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
1434
+ }
1435
+
1436
+ const uniqueNoteHashes: Fr[] = [];
1437
+ const taggedPrivateLogs: PrivateLog[] = [];
1438
+ const nullifiers: Fr[] = result.firstNullifier.equals(Fr.ZERO)
1439
+ ? [this.getTxRequestHash()]
1440
+ : noteCache.getAllNullifiers();
1441
+ const l2ToL1Messages: ScopedL2ToL1Message[] = [];
1442
+ const contractClassLogsHashes: ScopedLogHash[] = [];
1443
+ const publicCallRequests: PublicCallRequest[] = [];
1444
+
1445
+ const nonceGenerator = nullifiers[0];
1446
+
1447
+ let publicTeardownCallRequest;
1448
+
1449
+ let noteHashIndexInTx = 0;
1450
+ const executions = [result.entrypoint];
1451
+ while (executions.length !== 0) {
1452
+ const execution = executions.shift()!;
1453
+ executions.unshift(...execution!.nestedExecutions);
1454
+
1455
+ const { contractAddress } = execution.publicInputs.callContext;
1456
+
1457
+ const noteHashesFromExecution = await Promise.all(
1458
+ execution.publicInputs.noteHashes
1459
+ .filter(noteHash => !noteHash.isEmpty())
1460
+ .map(async noteHash => {
1461
+ const nonce = await computeNoteHashNonce(nonceGenerator, noteHashIndexInTx++);
1462
+ const siloedNoteHash = await siloNoteHash(contractAddress, noteHash.value);
1463
+
1464
+ // We could defer this to the public processor, and pass this in as non-revertible.
1465
+ return computeUniqueNoteHash(nonce, siloedNoteHash);
1466
+ }),
1467
+ );
1468
+
1469
+ const privateLogsFromExecution = await Promise.all(
1470
+ execution.publicInputs.privateLogs
1471
+ .filter(privateLog => !privateLog.isEmpty())
1472
+ .map(async metadata => {
1473
+ metadata.log.fields[0] = await poseidon2Hash([contractAddress, metadata.log.fields[0]]);
1474
+
1475
+ return metadata.log;
1476
+ }),
1477
+ );
1478
+
1479
+ uniqueNoteHashes.push(...noteHashesFromExecution);
1480
+ taggedPrivateLogs.push(...privateLogsFromExecution);
1481
+ l2ToL1Messages.push(
1482
+ ...execution.publicInputs.l2ToL1Msgs
1483
+ .filter(l2ToL1Message => !l2ToL1Message.isEmpty())
1484
+ .map(message => message.scope(contractAddress)),
1485
+ );
1486
+ contractClassLogsHashes.push(
1487
+ ...execution.publicInputs.contractClassLogsHashes
1488
+ .filter(contractClassLogsHash => !contractClassLogsHash.isEmpty())
1489
+ .map(message => message.logHash.scope(contractAddress)),
1490
+ );
1491
+ publicCallRequests.push(
1492
+ ...execution.publicInputs.publicCallRequests
1493
+ .filter(publicCallRequest => !publicCallRequest.isEmpty())
1494
+ .map(callRequest => callRequest.inner),
1495
+ );
1496
+
1497
+ if (publicTeardownCallRequest !== undefined && !execution.publicInputs.publicTeardownCallRequest.isEmpty()) {
1498
+ throw new Error('Trying to set multiple teardown requests');
1499
+ }
1500
+
1501
+ publicTeardownCallRequest = execution.publicInputs.publicTeardownCallRequest.isEmpty()
1502
+ ? publicTeardownCallRequest
1503
+ : execution.publicInputs.publicTeardownCallRequest;
1504
+ }
1505
+
1506
+ const globals = makeGlobalVariables();
1507
+ globals.blockNumber = new Fr(this.blockNumber);
1508
+ globals.gasFees = GasFees.empty();
1509
+
1510
+ const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(this));
1511
+ const simulator = new PublicTxSimulator(this.baseFork, contractsDB, globals, true, true);
1512
+ const processor = new PublicProcessor(globals, this.baseFork, contractsDB, simulator, new TestDateProvider());
1513
+
1514
+ const constantData = new TxConstantData(blockHeader, txContext, Fr.zero(), Fr.zero());
1515
+
1516
+ const hasPublicCalls = result.publicFunctionCalldata.length !== 0;
1517
+ let inputsForRollup;
1518
+ let inputsForPublic;
1519
+
1520
+ // Private only
1521
+ if (result.publicFunctionCalldata.length === 0) {
1522
+ const accumulatedDataForRollup = new PrivateToRollupAccumulatedData(
1523
+ padArrayEnd(uniqueNoteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX),
1524
+ padArrayEnd(nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX),
1525
+ padArrayEnd(l2ToL1Messages, ScopedL2ToL1Message.empty(), MAX_L2_TO_L1_MSGS_PER_TX),
1526
+ padArrayEnd(taggedPrivateLogs, PrivateLog.empty(), MAX_PRIVATE_LOGS_PER_TX),
1527
+ padArrayEnd(contractClassLogsHashes, ScopedLogHash.empty(), MAX_CONTRACT_CLASS_LOGS_PER_TX),
1528
+ );
1529
+
1530
+ inputsForRollup = new PartialPrivateTailPublicInputsForRollup(accumulatedDataForRollup);
1531
+ } else {
1532
+ const accumulatedDataForPublic = new PrivateToPublicAccumulatedData(
1533
+ padArrayEnd(uniqueNoteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX),
1534
+ padArrayEnd(nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX),
1535
+ padArrayEnd(l2ToL1Messages, ScopedL2ToL1Message.empty(), MAX_L2_TO_L1_MSGS_PER_TX),
1536
+ padArrayEnd(taggedPrivateLogs, PrivateLog.empty(), MAX_PRIVATE_LOGS_PER_TX),
1537
+ padArrayEnd(contractClassLogsHashes, ScopedLogHash.empty(), MAX_CONTRACT_CLASS_LOGS_PER_TX),
1538
+ padArrayEnd(publicCallRequests, PublicCallRequest.empty(), MAX_ENQUEUED_CALLS_PER_TX),
1539
+ );
1540
+
1541
+ inputsForPublic = new PartialPrivateTailPublicInputsForPublic(
1542
+ // We are using non-revertible because we set the first nullifier to be used as a nonce generator, otherwise the tx hash is manually calculated.
1543
+ // nonrevertible
1544
+ accumulatedDataForPublic,
1545
+ // revertible
1546
+ PrivateToPublicAccumulatedData.empty(),
1547
+ publicTeardownCallRequest ?? PublicCallRequest.empty(),
1548
+ );
1549
+ }
1550
+
1551
+ const txData = new PrivateKernelTailCircuitPublicInputs(
1552
+ constantData,
1553
+ RollupValidationRequests.empty(),
1554
+ /*gasUsed=*/ new Gas(0, 0),
1555
+ /*feePayer=*/ AztecAddress.zero(),
1556
+ hasPublicCalls ? inputsForPublic : undefined,
1557
+ !hasPublicCalls ? inputsForRollup : undefined,
1558
+ );
1559
+
1560
+ const tx = new Tx(txData, ClientIvcProof.empty(), [], result.publicFunctionCalldata);
1561
+
1562
+ const results = await processor.process([tx]);
1563
+
1564
+ const processedTxs = results[0];
1565
+ const failedTxs = results[1];
1566
+
1567
+ if (failedTxs.length !== 0) {
1568
+ throw new Error('Public execution has failed');
1569
+ }
1570
+
1571
+ const fork = this.baseFork;
1572
+
1573
+ const txEffect = TxEffect.empty();
1574
+
1575
+ txEffect.noteHashes = processedTxs[0]!.txEffect.noteHashes;
1576
+ txEffect.nullifiers = processedTxs[0]!.txEffect.nullifiers;
1577
+ txEffect.privateLogs = taggedPrivateLogs;
1578
+ txEffect.publicLogs = processedTxs[0]!.txEffect.publicLogs;
1579
+ txEffect.publicDataWrites = processedTxs[0]!.txEffect.publicDataWrites;
1580
+
1581
+ txEffect.txHash = new TxHash(new Fr(this.blockNumber));
1582
+
1583
+ const body = new Body([txEffect]);
1584
+
1585
+ const l2Block = new L2Block(
1586
+ makeAppendOnlyTreeSnapshot(this.blockNumber + 1),
1587
+ makeHeader(0, this.blockNumber, this.blockNumber),
1588
+ body,
1589
+ );
1590
+
1591
+ const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
1592
+ await fork.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
1593
+
1594
+ const stateReference = await fork.getStateReference();
1595
+ const archiveInfo = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
1596
+
1597
+ const header = new BlockHeader(
1598
+ new AppendOnlyTreeSnapshot(new Fr(archiveInfo.root), Number(archiveInfo.size)),
1599
+ makeContentCommitment(),
1600
+ stateReference,
1601
+ globals,
1602
+ Fr.ZERO,
1603
+ Fr.ZERO,
1604
+ );
1605
+
1606
+ header.globalVariables.blockNumber = new Fr(this.blockNumber);
1607
+
1608
+ l2Block.header = header;
1609
+
1610
+ await fork.updateArchive(l2Block.header);
1611
+
1612
+ await this.stateMachine.handleL2Block(l2Block);
1613
+
1614
+ const txRequestHash = this.getTxRequestHash();
1615
+
1616
+ this.setBlockNumber(this.blockNumber + 1);
1617
+ return {
1618
+ endSideEffectCounter: result.entrypoint.publicInputs.endSideEffectCounter,
1619
+ returnsHash: result.entrypoint.publicInputs.returnsHash,
1620
+ txHash: txRequestHash,
1621
+ };
1622
+ }
1270
1623
  }
@@ -41,11 +41,11 @@ export class TXEArchiver extends ArchiverStoreHelper {
41
41
  }
42
42
 
43
43
  /**
44
- * Gets an l2 block. If a negative number is passed, the block returned is the most recent.
44
+ * Gets a published l2 block. If a negative number is passed, the block returned is the most recent.
45
45
  * @param number - The block number to return (inclusive).
46
46
  * @returns The requested L2 block.
47
47
  */
48
- public async getBlock(number: number): Promise<L2Block | undefined> {
48
+ public override async getPublishedBlock(number: number): Promise<PublishedL2Block | undefined> {
49
49
  // If the number provided is -ve, then return the latest block.
50
50
  if (number < 0) {
51
51
  number = await this.store.getSynchedL2BlockNumber();
@@ -54,7 +54,16 @@ export class TXEArchiver extends ArchiverStoreHelper {
54
54
  return undefined;
55
55
  }
56
56
  const blocks = await this.store.getPublishedBlocks(number, 1);
57
- return blocks.length === 0 ? undefined : blocks[0].block;
57
+ return blocks.length === 0 ? undefined : blocks[0];
58
+ }
59
+
60
+ /**
61
+ * Gets an l2 block. If a negative number is passed, the block returned is the most recent.
62
+ * @param number - The block number to return (inclusive).
63
+ * @returns The requested L2 block.
64
+ */
65
+ public getBlock(number: number): Promise<L2Block | undefined> {
66
+ return this.getPublishedBlock(number).then(block => block?.block);
58
67
  }
59
68
 
60
69
  /**
@@ -5,6 +5,14 @@ import type { BlockAttestation, BlockProposal } from '@aztec/stdlib/p2p';
5
5
  import type { Tx, TxHash } from '@aztec/stdlib/tx';
6
6
 
7
7
  export class DummyP2P implements P2P {
8
+ public validate(_txs: Tx[]): Promise<void> {
9
+ return Promise.resolve();
10
+ }
11
+
12
+ public clear(): Promise<void> {
13
+ throw new Error('DummyP2P does not implement "clear".');
14
+ }
15
+
8
16
  public getPendingTxs(): Promise<Tx[]> {
9
17
  throw new Error('DummyP2P does not implement "getPendingTxs"');
10
18
  }
@@ -17,7 +25,7 @@ export class DummyP2P implements P2P {
17
25
  throw new Error('DummyP2P does not implement "getPeers"');
18
26
  }
19
27
 
20
- public broadcastProposal(_proposal: BlockProposal): void {
28
+ public broadcastProposal(_proposal: BlockProposal): Promise<void> {
21
29
  throw new Error('DummyP2P does not implement "broadcastProposal"');
22
30
  }
23
31
 
@@ -152,4 +160,8 @@ export class DummyP2P implements P2P {
152
160
  public getSyncedLatestSlot(): Promise<bigint> {
153
161
  throw new Error('DummyP2P does not implement "getSyncedLatestSlot"');
154
162
  }
163
+
164
+ markTxsAsNonEvictable(_: TxHash[]): Promise<void> {
165
+ throw new Error('DummyP2P does not implement "markTxsAsNonEvictable".');
166
+ }
155
167
  }