@aztec/txe 0.0.1-commit.c7c42ec → 0.0.1-commit.cf93bcc56

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.
Files changed (56) hide show
  1. package/dest/constants.d.ts +3 -0
  2. package/dest/constants.d.ts.map +1 -0
  3. package/dest/constants.js +2 -0
  4. package/dest/oracle/interfaces.d.ts +3 -3
  5. package/dest/oracle/interfaces.d.ts.map +1 -1
  6. package/dest/oracle/txe_oracle_public_context.d.ts +3 -3
  7. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  8. package/dest/oracle/txe_oracle_public_context.js +6 -6
  9. package/dest/oracle/txe_oracle_top_level_context.d.ts +5 -3
  10. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  11. package/dest/oracle/txe_oracle_top_level_context.js +108 -33
  12. package/dest/rpc_translator.d.ts +20 -14
  13. package/dest/rpc_translator.d.ts.map +1 -1
  14. package/dest/rpc_translator.js +76 -51
  15. package/dest/state_machine/archiver.d.ts +20 -67
  16. package/dest/state_machine/archiver.d.ts.map +1 -1
  17. package/dest/state_machine/archiver.js +59 -178
  18. package/dest/state_machine/dummy_p2p_client.d.ts +18 -14
  19. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  20. package/dest/state_machine/dummy_p2p_client.js +35 -23
  21. package/dest/state_machine/global_variable_builder.d.ts +2 -2
  22. package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
  23. package/dest/state_machine/global_variable_builder.js +1 -1
  24. package/dest/state_machine/index.d.ts +5 -5
  25. package/dest/state_machine/index.d.ts.map +1 -1
  26. package/dest/state_machine/index.js +35 -12
  27. package/dest/state_machine/mock_epoch_cache.d.ts +9 -6
  28. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  29. package/dest/state_machine/mock_epoch_cache.js +14 -7
  30. package/dest/state_machine/synchronizer.d.ts +3 -3
  31. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  32. package/dest/txe_session.d.ts +6 -4
  33. package/dest/txe_session.d.ts.map +1 -1
  34. package/dest/txe_session.js +116 -22
  35. package/dest/util/encoding.d.ts +17 -17
  36. package/dest/utils/block_creation.d.ts +4 -4
  37. package/dest/utils/block_creation.d.ts.map +1 -1
  38. package/dest/utils/block_creation.js +18 -5
  39. package/dest/utils/tx_effect_creation.d.ts +2 -3
  40. package/dest/utils/tx_effect_creation.d.ts.map +1 -1
  41. package/dest/utils/tx_effect_creation.js +3 -6
  42. package/package.json +16 -16
  43. package/src/constants.ts +3 -0
  44. package/src/oracle/interfaces.ts +2 -2
  45. package/src/oracle/txe_oracle_public_context.ts +6 -8
  46. package/src/oracle/txe_oracle_top_level_context.ts +136 -72
  47. package/src/rpc_translator.ts +79 -53
  48. package/src/state_machine/archiver.ts +54 -220
  49. package/src/state_machine/dummy_p2p_client.ts +50 -31
  50. package/src/state_machine/global_variable_builder.ts +1 -1
  51. package/src/state_machine/index.ts +49 -11
  52. package/src/state_machine/mock_epoch_cache.ts +15 -11
  53. package/src/state_machine/synchronizer.ts +2 -2
  54. package/src/txe_session.ts +137 -61
  55. package/src/utils/block_creation.ts +19 -16
  56. package/src/utils/tx_effect_creation.ts +3 -11
@@ -1,9 +1,10 @@
1
1
  import { MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, NULLIFIER_SUBTREE_HEIGHT, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
2
+ import { CheckpointNumber, IndexWithinCheckpoint } from '@aztec/foundation/branded-types';
2
3
  import { padArrayEnd } from '@aztec/foundation/collection';
3
4
  import { Fr } from '@aztec/foundation/curves/bn254';
4
- import { Body, L2Block, L2BlockHeader } from '@aztec/stdlib/block';
5
- import { makeContentCommitment } from '@aztec/stdlib/testing';
5
+ import { Body, L2Block } from '@aztec/stdlib/block';
6
6
  import { AppendOnlyTreeSnapshot, MerkleTreeId } from '@aztec/stdlib/trees';
7
+ import { BlockHeader } from '@aztec/stdlib/tx';
7
8
  /**
8
9
  * Returns a transaction request hash that is valid for transactions that are the only ones in a block.
9
10
  * @param blockNumber The number for the block in which there is a single transaction.
@@ -20,7 +21,14 @@ export async function insertTxEffectIntoWorldTrees(txEffect, worldTrees) {
20
21
  export async function makeTXEBlockHeader(worldTrees, globalVariables) {
21
22
  const stateReference = await worldTrees.getStateReference();
22
23
  const archiveInfo = await worldTrees.getTreeInfo(MerkleTreeId.ARCHIVE);
23
- return new L2BlockHeader(new AppendOnlyTreeSnapshot(new Fr(archiveInfo.root), Number(archiveInfo.size)), makeContentCommitment(), stateReference, globalVariables, Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO);
24
+ return BlockHeader.from({
25
+ lastArchive: new AppendOnlyTreeSnapshot(new Fr(archiveInfo.root), Number(archiveInfo.size)),
26
+ spongeBlobHash: Fr.ZERO,
27
+ state: stateReference,
28
+ globalVariables,
29
+ totalFees: Fr.ZERO,
30
+ totalManaUsed: Fr.ZERO
31
+ });
24
32
  }
25
33
  /**
26
34
  * Creates an L2Block with proper archive chaining.
@@ -37,9 +45,14 @@ export async function makeTXEBlockHeader(worldTrees, globalVariables) {
37
45
  */ export async function makeTXEBlock(worldTrees, globalVariables, txEffects) {
38
46
  const header = await makeTXEBlockHeader(worldTrees, globalVariables);
39
47
  // Update the archive tree with this block's header hash
40
- await worldTrees.updateArchive(header.toBlockHeader());
48
+ await worldTrees.updateArchive(header);
41
49
  // Get the new archive state after updating
42
50
  const newArchiveInfo = await worldTrees.getTreeInfo(MerkleTreeId.ARCHIVE);
43
51
  const newArchive = new AppendOnlyTreeSnapshot(new Fr(newArchiveInfo.root), Number(newArchiveInfo.size));
44
- return new L2Block(newArchive, header, new Body(txEffects));
52
+ // L2Block requires checkpointNumber and indexWithinCheckpoint.
53
+ // TXE uses 1-block-per-checkpoint for testing simplicity, so we can use block number as checkpoint number.
54
+ // This uses the deprecated fromBlockNumber method intentionally for the TXE testing environment.
55
+ const checkpointNumber = CheckpointNumber.fromBlockNumber(globalVariables.blockNumber);
56
+ const indexWithinCheckpoint = IndexWithinCheckpoint(0);
57
+ return new L2Block(newArchive, header, new Body(txEffects), checkpointNumber, indexWithinCheckpoint);
45
58
  }
@@ -1,6 +1,5 @@
1
1
  import { BlockNumber } from '@aztec/foundation/branded-types';
2
- import { Fr } from '@aztec/foundation/curves/bn254';
3
2
  import type { ExecutionNoteCache } from '@aztec/pxe/simulator';
4
3
  import { TxEffect } from '@aztec/stdlib/tx';
5
- export declare function makeTxEffect(noteCache: ExecutionNoteCache, protocolNullifier: Fr, txBlockNumber: BlockNumber): Promise<TxEffect>;
6
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHhfZWZmZWN0X2NyZWF0aW9uLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvdHhfZWZmZWN0X2NyZWF0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUM5RCxPQUFPLEVBQUUsRUFBRSxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDcEQsT0FBTyxLQUFLLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUUvRCxPQUFPLEVBQUUsUUFBUSxFQUFVLE1BQU0sa0JBQWtCLENBQUM7QUFFcEQsd0JBQXNCLFlBQVksQ0FDaEMsU0FBUyxFQUFFLGtCQUFrQixFQUM3QixpQkFBaUIsRUFBRSxFQUFFLEVBQ3JCLGFBQWEsRUFBRSxXQUFXLEdBQ3pCLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0EyQm5CIn0=
4
+ export declare function makeTxEffect(noteCache: ExecutionNoteCache, txBlockNumber: BlockNumber): Promise<TxEffect>;
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHhfZWZmZWN0X2NyZWF0aW9uLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvdHhfZWZmZWN0X2NyZWF0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUU5RCxPQUFPLEtBQUssRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBRS9ELE9BQU8sRUFBRSxRQUFRLEVBQVUsTUFBTSxrQkFBa0IsQ0FBQztBQUVwRCx3QkFBc0IsWUFBWSxDQUFDLFNBQVMsRUFBRSxrQkFBa0IsRUFBRSxhQUFhLEVBQUUsV0FBVyxHQUFHLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0F1Qi9HIn0=
@@ -1 +1 @@
1
- {"version":3,"file":"tx_effect_creation.d.ts","sourceRoot":"","sources":["../../src/utils/tx_effect_creation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAAE,QAAQ,EAAU,MAAM,kBAAkB,CAAC;AAEpD,wBAAsB,YAAY,CAChC,SAAS,EAAE,kBAAkB,EAC7B,iBAAiB,EAAE,EAAE,EACrB,aAAa,EAAE,WAAW,GACzB,OAAO,CAAC,QAAQ,CAAC,CA2BnB"}
1
+ {"version":3,"file":"tx_effect_creation.d.ts","sourceRoot":"","sources":["../../src/utils/tx_effect_creation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAE9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAAE,QAAQ,EAAU,MAAM,kBAAkB,CAAC;AAEpD,wBAAsB,YAAY,CAAC,SAAS,EAAE,kBAAkB,EAAE,aAAa,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAuB/G"}
@@ -1,16 +1,13 @@
1
1
  import { Fr } from '@aztec/foundation/curves/bn254';
2
2
  import { computeNoteHashNonce, computeUniqueNoteHash, siloNoteHash } from '@aztec/stdlib/hash';
3
3
  import { TxEffect, TxHash } from '@aztec/stdlib/tx';
4
- export async function makeTxEffect(noteCache, protocolNullifier, txBlockNumber) {
4
+ export async function makeTxEffect(noteCache, txBlockNumber) {
5
5
  const txEffect = TxEffect.empty();
6
- const { usedProtocolNullifierForNonces } = noteCache.finish();
7
- const nonceGenerator = usedProtocolNullifierForNonces ? protocolNullifier : noteCache.getAllNullifiers()[0];
6
+ noteCache.finish();
7
+ const nonceGenerator = noteCache.getNonceGenerator();
8
8
  txEffect.noteHashes = await Promise.all(noteCache.getAllNotes().map(async (pendingNote, i)=>computeUniqueNoteHash(await computeNoteHashNonce(nonceGenerator, i), await siloNoteHash(pendingNote.note.contractAddress, pendingNote.noteHashForConsumption))));
9
9
  // Nullifiers are already siloed
10
10
  txEffect.nullifiers = noteCache.getAllNullifiers();
11
- if (usedProtocolNullifierForNonces) {
12
- txEffect.nullifiers.unshift(protocolNullifier);
13
- }
14
11
  txEffect.txHash = new TxHash(new Fr(txBlockNumber));
15
12
  return txEffect;
16
13
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/txe",
3
- "version": "0.0.1-commit.c7c42ec",
3
+ "version": "0.0.1-commit.cf93bcc56",
4
4
  "type": "module",
5
5
  "exports": "./dest/index.js",
6
6
  "bin": "./dest/bin/index.js",
@@ -61,27 +61,27 @@
61
61
  ]
62
62
  },
63
63
  "dependencies": {
64
- "@aztec/accounts": "0.0.1-commit.c7c42ec",
65
- "@aztec/archiver": "0.0.1-commit.c7c42ec",
66
- "@aztec/aztec-node": "0.0.1-commit.c7c42ec",
67
- "@aztec/aztec.js": "0.0.1-commit.c7c42ec",
68
- "@aztec/bb-prover": "0.0.1-commit.c7c42ec",
69
- "@aztec/constants": "0.0.1-commit.c7c42ec",
70
- "@aztec/foundation": "0.0.1-commit.c7c42ec",
71
- "@aztec/key-store": "0.0.1-commit.c7c42ec",
72
- "@aztec/kv-store": "0.0.1-commit.c7c42ec",
73
- "@aztec/protocol-contracts": "0.0.1-commit.c7c42ec",
74
- "@aztec/pxe": "0.0.1-commit.c7c42ec",
75
- "@aztec/simulator": "0.0.1-commit.c7c42ec",
76
- "@aztec/stdlib": "0.0.1-commit.c7c42ec",
77
- "@aztec/world-state": "0.0.1-commit.c7c42ec",
64
+ "@aztec/accounts": "0.0.1-commit.cf93bcc56",
65
+ "@aztec/archiver": "0.0.1-commit.cf93bcc56",
66
+ "@aztec/aztec-node": "0.0.1-commit.cf93bcc56",
67
+ "@aztec/aztec.js": "0.0.1-commit.cf93bcc56",
68
+ "@aztec/bb-prover": "0.0.1-commit.cf93bcc56",
69
+ "@aztec/constants": "0.0.1-commit.cf93bcc56",
70
+ "@aztec/foundation": "0.0.1-commit.cf93bcc56",
71
+ "@aztec/key-store": "0.0.1-commit.cf93bcc56",
72
+ "@aztec/kv-store": "0.0.1-commit.cf93bcc56",
73
+ "@aztec/protocol-contracts": "0.0.1-commit.cf93bcc56",
74
+ "@aztec/pxe": "0.0.1-commit.cf93bcc56",
75
+ "@aztec/simulator": "0.0.1-commit.cf93bcc56",
76
+ "@aztec/stdlib": "0.0.1-commit.cf93bcc56",
77
+ "@aztec/world-state": "0.0.1-commit.cf93bcc56",
78
78
  "zod": "^3.23.8"
79
79
  },
80
80
  "devDependencies": {
81
81
  "@jest/globals": "^30.0.0",
82
82
  "@types/jest": "^30.0.0",
83
83
  "@types/node": "^22.15.17",
84
- "@typescript/native-preview": "7.0.0-dev.20251126.1",
84
+ "@typescript/native-preview": "7.0.0-dev.20260113.1",
85
85
  "jest": "^30.0.0",
86
86
  "jest-mock-extended": "^4.0.0",
87
87
  "ts-node": "^10.9.1",
@@ -0,0 +1,3 @@
1
+ import { AztecAddress } from '@aztec/stdlib/aztec-address';
2
+
3
+ export const DEFAULT_ADDRESS = AztecAddress.fromNumber(42);
@@ -33,9 +33,9 @@ export interface IAvmExecutionOracle {
33
33
  avmOpcodeVersion(): Promise<Fr>;
34
34
  avmOpcodeEmitNullifier(nullifier: Fr): Promise<void>;
35
35
  avmOpcodeEmitNoteHash(noteHash: Fr): Promise<void>;
36
- avmOpcodeNullifierExists(innerNullifier: Fr, targetAddress: AztecAddress): Promise<boolean>;
36
+ avmOpcodeNullifierExists(siloedNullifier: Fr): Promise<boolean>;
37
37
  avmOpcodeStorageWrite(slot: Fr, value: Fr): Promise<void>;
38
- avmOpcodeStorageRead(slot: Fr): Promise<Fr>;
38
+ avmOpcodeStorageRead(slot: Fr, contractAddress: AztecAddress): Promise<Fr>;
39
39
  }
40
40
 
41
41
  /**
@@ -78,13 +78,11 @@ export class TXEOraclePublicContext implements IAvmExecutionOracle {
78
78
  this.transientUniqueNoteHashes.push(siloedNoteHash);
79
79
  }
80
80
 
81
- async avmOpcodeNullifierExists(innerNullifier: Fr, targetAddress: AztecAddress): Promise<boolean> {
82
- const nullifier = await siloNullifier(targetAddress, innerNullifier!);
83
-
81
+ async avmOpcodeNullifierExists(siloedNullifier: Fr): Promise<boolean> {
84
82
  const treeIndex = (
85
- await this.forkedWorldTrees.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()])
83
+ await this.forkedWorldTrees.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [siloedNullifier.toBuffer()])
86
84
  )[0];
87
- const transientIndex = this.transientSiloedNullifiers.find(n => n.equals(nullifier));
85
+ const transientIndex = this.transientSiloedNullifiers.find(n => n.equals(siloedNullifier));
88
86
 
89
87
  return treeIndex !== undefined || transientIndex !== undefined;
90
88
  }
@@ -101,8 +99,8 @@ export class TXEOraclePublicContext implements IAvmExecutionOracle {
101
99
  ]);
102
100
  }
103
101
 
104
- async avmOpcodeStorageRead(slot: Fr): Promise<Fr> {
105
- const leafSlot = await computePublicDataTreeLeafSlot(this.contractAddress, slot);
102
+ async avmOpcodeStorageRead(slot: Fr, contractAddress: AztecAddress): Promise<Fr> {
103
+ const leafSlot = await computePublicDataTreeLeafSlot(contractAddress, slot);
106
104
 
107
105
  const lowLeafResult = await this.forkedWorldTrees.getPreviousValueIndex(
108
106
  MerkleTreeId.PUBLIC_DATA_TREE,
@@ -119,7 +117,7 @@ export class TXEOraclePublicContext implements IAvmExecutionOracle {
119
117
  )) as PublicDataTreeLeafPreimage
120
118
  ).leaf.value;
121
119
 
122
- this.logger.debug('AVM storage read', { slot, value });
120
+ this.logger.debug('AVM storage read', { slot, contractAddress, value });
123
121
 
124
122
  return value;
125
123
  }
@@ -12,6 +12,7 @@ import { Fr } from '@aztec/foundation/curves/bn254';
12
12
  import { LogLevels, type Logger, applyStringFormatting, createLogger } from '@aztec/foundation/log';
13
13
  import { TestDateProvider } from '@aztec/foundation/timer';
14
14
  import type { KeyStore } from '@aztec/key-store';
15
+ import type { AccessScopes } from '@aztec/pxe/client/lazy';
15
16
  import {
16
17
  AddressStore,
17
18
  CapsuleStore,
@@ -49,7 +50,7 @@ import {
49
50
  PublicContractsDB,
50
51
  PublicProcessor,
51
52
  } from '@aztec/simulator/server';
52
- import { type ContractArtifact, EventSelector, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
53
+ import { type ContractArtifact, EventSelector, FunctionCall, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
53
54
  import { AuthWitness } from '@aztec/stdlib/auth-witness';
54
55
  import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
55
56
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
@@ -80,8 +81,8 @@ import {
80
81
  import type { UInt64 } from '@aztec/stdlib/types';
81
82
  import { ForkCheckpoint } from '@aztec/world-state';
82
83
 
84
+ import { DEFAULT_ADDRESS } from '../constants.js';
83
85
  import type { TXEStateMachine } from '../state_machine/index.js';
84
- import { DEFAULT_ADDRESS } from '../txe_session.js';
85
86
  import type { TXEAccountStore } from '../util/txe_account_store.js';
86
87
  import type { TXEContractStore } from '../util/txe_contract_store.js';
87
88
  import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
@@ -106,6 +107,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
106
107
  private senderAddressBookStore: SenderAddressBookStore,
107
108
  private capsuleStore: CapsuleStore,
108
109
  private privateEventStore: PrivateEventStore,
110
+ private jobId: string,
109
111
  private nextBlockTimestamp: bigint,
110
112
  private version: Fr,
111
113
  private chainId: Fr,
@@ -130,13 +132,14 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
130
132
  }
131
133
 
132
134
  // We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
133
- utilityDebugLog(level: number, message: string, fields: Fr[]): void {
135
+ utilityLog(level: number, message: string, fields: Fr[]): Promise<void> {
134
136
  if (!LogLevels[level]) {
135
- throw new Error(`Invalid debug log level: ${level}`);
137
+ throw new Error(`Invalid log level: ${level}`);
136
138
  }
137
139
  const levelName = LogLevels[level];
138
140
 
139
141
  this.logger[levelName](`${applyStringFormatting(message, fields)}`, { module: `${this.logger.module}:debug_log` });
142
+ return Promise.resolve();
140
143
  }
141
144
 
142
145
  txeGetDefaultAddress(): AztecAddress {
@@ -156,7 +159,8 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
156
159
  }
157
160
 
158
161
  async txeGetLastTxEffects() {
159
- const block = await this.stateMachine.archiver.getL2Block('latest');
162
+ const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
163
+ const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
160
164
 
161
165
  if (block!.body.txEffects.length != 1) {
162
166
  // Note that calls like env.mine() will result in blocks with no transactions, hitting this
@@ -294,61 +298,77 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
294
298
  throw new Error(message);
295
299
  }
296
300
 
301
+ // When `from` is the zero address (e.g. when deploying a new account contract), we return an
302
+ // empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
303
+ const effectiveScopes = from.isZero() ? [] : [from];
304
+
305
+ // Sync notes before executing private function to discover notes from previous transactions
306
+ const utilityExecutor = async (call: FunctionCall, execScopes: AccessScopes) => {
307
+ await this.executeUtilityCall(call, execScopes);
308
+ };
309
+
310
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
311
+ await this.stateMachine.contractSyncService.ensureContractSynced(
312
+ targetContractAddress,
313
+ functionSelector,
314
+ utilityExecutor,
315
+ blockHeader,
316
+ this.jobId,
317
+ effectiveScopes,
318
+ );
319
+
297
320
  const blockNumber = await this.txeGetNextBlockNumber();
298
321
 
299
322
  const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
300
323
 
301
324
  const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
302
-
303
325
  const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
304
-
305
326
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
306
327
 
307
328
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
308
329
 
309
- const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
310
-
311
330
  const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
312
331
  const noteCache = new ExecutionNoteCache(protocolNullifier);
332
+ // In production, the account contract sets the min revertible counter before calling the app function.
333
+ // Since TXE bypasses the account contract, we simulate this by setting minRevertibleSideEffectCounter to 1,
334
+ // marking all side effects as revertible.
335
+ const minRevertibleSideEffectCounter = 1;
336
+ await noteCache.setMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter);
313
337
  const taggingIndexCache = new ExecutionTaggingIndexCache();
314
338
 
315
339
  const simulator = new WASMSimulator();
316
340
 
317
- const privateExecutionOracle = new PrivateExecutionOracle(
341
+ const privateExecutionOracle = new PrivateExecutionOracle({
318
342
  argsHash,
319
343
  txContext,
320
344
  callContext,
321
- /** Header of a block whose state is used during private execution (not the block the transaction is included in). */
322
- blockHeader,
323
- /** List of transient auth witnesses to be used during this simulation */
324
- Array.from(this.authwits.values()),
325
- /** List of transient auth witnesses to be used during this simulation */
326
- [],
327
- HashedValuesCache.create([new HashedValues(args, argsHash)]),
345
+ anchorBlockHeader: blockHeader,
346
+ utilityExecutor,
347
+ authWitnesses: Array.from(this.authwits.values()),
348
+ capsules: [],
349
+ executionCache: HashedValuesCache.create([new HashedValues(args, argsHash)]),
328
350
  noteCache,
329
351
  taggingIndexCache,
330
- this.contractStore,
331
- this.noteStore,
332
- this.keyStore,
333
- this.addressStore,
334
- this.stateMachine.node,
335
- this.stateMachine.anchorBlockStore,
336
- this.senderTaggingStore,
337
- this.recipientTaggingStore,
338
- this.senderAddressBookStore,
339
- this.capsuleStore,
340
- this.privateEventStore,
341
- 0,
342
- 1,
343
- undefined, // log
344
- undefined, // scopes
345
- /**
346
- * In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
347
- * contract would perform, including setting senderForTags.
348
- */
349
- from,
352
+ contractStore: this.contractStore,
353
+ noteStore: this.noteStore,
354
+ keyStore: this.keyStore,
355
+ addressStore: this.addressStore,
356
+ aztecNode: this.stateMachine.node,
357
+ senderTaggingStore: this.senderTaggingStore,
358
+ recipientTaggingStore: this.recipientTaggingStore,
359
+ senderAddressBookStore: this.senderAddressBookStore,
360
+ capsuleStore: this.capsuleStore,
361
+ privateEventStore: this.privateEventStore,
362
+ contractSyncService: this.stateMachine.contractSyncService,
363
+ jobId: this.jobId,
364
+ totalPublicCalldataCount: 0,
365
+ sideEffectCounter: minRevertibleSideEffectCounter,
366
+ scopes: effectiveScopes,
367
+ // In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
368
+ // contract would perform, including setting senderForTags.
369
+ senderForTags: from,
350
370
  simulator,
351
- );
371
+ });
352
372
 
353
373
  // 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.
354
374
  let result: PrivateExecutionResult;
@@ -375,19 +395,22 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
375
395
  }),
376
396
  );
377
397
 
378
- // TXE's top level context does not track side effect counters, and as such, minRevertibleSideEffectCounter is always 0.
379
- // This has the unfortunate consequence of always producing revertible nullifiers, which means we
380
- // must set the firstNullifierHint to Fr.ZERO so the txRequestHash is always used as nonce generator
381
- result = new PrivateExecutionResult(executionResult, Fr.ZERO, publicFunctionsCalldata);
398
+ noteCache.finish();
399
+ const nonceGenerator = noteCache.getNonceGenerator();
400
+ result = new PrivateExecutionResult(executionResult, nonceGenerator, publicFunctionsCalldata);
382
401
  } catch (err) {
383
402
  throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
384
403
  }
385
404
 
386
- // According to the protocol rules, the nonce generator for the note hashes
387
- // can either be the first nullifier in the tx or the hash of the initial tx request
388
- // if there are none.
389
- const nonceGenerator = result.firstNullifier.equals(Fr.ZERO) ? protocolNullifier : result.firstNullifier;
390
- const { publicInputs } = await generateSimulatedProvingResult(result, nonceGenerator, this.contractStore);
405
+ // According to the protocol rules, there must be at least one nullifier in the tx. The first nullifier is used as
406
+ // the nonce generator for the note hashes.
407
+ // We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
408
+ const { publicInputs } = await generateSimulatedProvingResult(
409
+ result,
410
+ (addr, sel) => this.contractStore.getDebugFunctionName(addr, sel),
411
+ this.stateMachine.node,
412
+ minRevertibleSideEffectCounter,
413
+ );
391
414
 
392
415
  const globals = makeGlobalVariables();
393
416
  globals.blockNumber = blockNumber;
@@ -398,7 +421,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
398
421
 
399
422
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
400
423
 
401
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore));
424
+ const bindings = this.logger.getBindings();
425
+ const contractsDB = new PublicContractsDB(
426
+ new TXEPublicContractDataSource(blockNumber, this.contractStore),
427
+ bindings,
428
+ );
402
429
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
403
430
  const config = PublicSimulatorConfig.from({
404
431
  skipFeeEnforcement: true,
@@ -411,8 +438,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
411
438
  globals,
412
439
  guardedMerkleTrees,
413
440
  contractsDB,
414
- new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config),
441
+ new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings),
415
442
  new TestDateProvider(),
443
+ undefined,
444
+ createLogger('simulator:public-processor', bindings),
416
445
  );
417
446
 
418
447
  const tx = await Tx.create({
@@ -509,7 +538,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
509
538
 
510
539
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
511
540
 
512
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore));
541
+ const bindings2 = this.logger.getBindings();
542
+ const contractsDB = new PublicContractsDB(
543
+ new TXEPublicContractDataSource(blockNumber, this.contractStore),
544
+ bindings2,
545
+ );
513
546
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
514
547
  const config = PublicSimulatorConfig.from({
515
548
  skipFeeEnforcement: true,
@@ -518,8 +551,16 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
518
551
  collectStatistics: false,
519
552
  collectCallMetadata: true,
520
553
  });
521
- const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config);
522
- const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider());
554
+ const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
555
+ const processor = new PublicProcessor(
556
+ globals,
557
+ guardedMerkleTrees,
558
+ contractsDB,
559
+ simulator,
560
+ new TestDateProvider(),
561
+ undefined,
562
+ createLogger('simulator:public-processor', bindings2),
563
+ );
523
564
 
524
565
  // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
525
566
  // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
@@ -550,7 +591,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
550
591
  constantData,
551
592
  /*gasUsed=*/ new Gas(0, 0),
552
593
  /*feePayer=*/ AztecAddress.zero(),
553
- /*includeByTimestamp=*/ 0n,
594
+ /*expirationTimestamp=*/ 0n,
554
595
  inputsForPublic,
555
596
  undefined,
556
597
  );
@@ -628,12 +669,34 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
628
669
  throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
629
670
  }
630
671
 
631
- const call = {
672
+ // Sync notes before executing utility function to discover notes from previous transactions
673
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
674
+ await this.stateMachine.contractSyncService.ensureContractSynced(
675
+ targetContractAddress,
676
+ functionSelector,
677
+ async (call, execScopes) => {
678
+ await this.executeUtilityCall(call, execScopes);
679
+ },
680
+ blockHeader,
681
+ this.jobId,
682
+ 'ALL_SCOPES',
683
+ );
684
+
685
+ const call = FunctionCall.from({
632
686
  name: artifact.name,
633
- selector: functionSelector,
634
687
  to: targetContractAddress,
635
- };
688
+ selector: functionSelector,
689
+ type: FunctionType.UTILITY,
690
+ hideMsgSender: false,
691
+ isStatic: false,
692
+ args,
693
+ returnTypes: [],
694
+ });
636
695
 
696
+ return this.executeUtilityCall(call, 'ALL_SCOPES');
697
+ }
698
+
699
+ private async executeUtilityCall(call: FunctionCall, scopes: AccessScopes): Promise<Fr[]> {
637
700
  const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
638
701
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
639
702
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
@@ -646,24 +709,25 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
646
709
 
647
710
  try {
648
711
  const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
649
- const oracle = new UtilityExecutionOracle(
650
- call.to,
651
- [],
652
- [],
712
+ const oracle = new UtilityExecutionOracle({
713
+ contractAddress: call.to,
714
+ authWitnesses: [],
715
+ capsules: [],
653
716
  anchorBlockHeader,
654
- this.contractStore,
655
- this.noteStore,
656
- this.keyStore,
657
- this.addressStore,
658
- this.stateMachine.node,
659
- this.stateMachine.anchorBlockStore,
660
- this.recipientTaggingStore,
661
- this.senderAddressBookStore,
662
- this.capsuleStore,
663
- this.privateEventStore,
664
- );
717
+ contractStore: this.contractStore,
718
+ noteStore: this.noteStore,
719
+ keyStore: this.keyStore,
720
+ addressStore: this.addressStore,
721
+ aztecNode: this.stateMachine.node,
722
+ recipientTaggingStore: this.recipientTaggingStore,
723
+ senderAddressBookStore: this.senderAddressBookStore,
724
+ capsuleStore: this.capsuleStore,
725
+ privateEventStore: this.privateEventStore,
726
+ jobId: this.jobId,
727
+ scopes,
728
+ });
665
729
  const acirExecutionResult = await new WASMSimulator()
666
- .executeUserCircuit(toACVMWitness(0, args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
730
+ .executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
667
731
  .catch((err: Error) => {
668
732
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
669
733
  throw new ExecutionError(