@aztec/txe 3.0.0-nightly.20250926 → 3.0.0-nightly.20250927

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.
@@ -185,10 +185,10 @@ export class TXEOracleTopLevelContext {
185
185
  const simulator = new WASMSimulator();
186
186
  const privateExecutionOracle = new PrivateExecutionOracle(argsHash, txContext, callContext, /** Header of a block whose state is used during private execution (not the block the transaction is included in). */ blockHeader, /** List of transient auth witnesses to be used during this simulation */ Array.from(this.authwits.values()), /** List of transient auth witnesses to be used during this simulation */ [], HashedValuesCache.create([
187
187
  new HashedValues(args, argsHash)
188
- ]), noteCache, this.pxeOracleInterface, simulator, 0, 1, undefined, undefined, /**
188
+ ]), noteCache, this.pxeOracleInterface, 0, 1, undefined, undefined, /**
189
189
  * In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
190
190
  * contract would perform, including setting senderForTags.
191
- */ from);
191
+ */ from, simulator);
192
192
  // 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.
193
193
  let result;
194
194
  let executionResult;
@@ -57,23 +57,23 @@ export class RPCTranslator {
57
57
  }
58
58
  // TXE session state transition functions - these get handled by the state handler
59
59
  async txeSetTopLevelTXEContext() {
60
- await this.stateHandler.setTopLevelContext();
60
+ await this.stateHandler.enterTopLevelState();
61
61
  return toForeignCallResult([]);
62
62
  }
63
63
  async txeSetPrivateTXEContext(foreignContractAddressIsSome, foreignContractAddressValue, foreignAnchorBlockNumberIsSome, foreignAnchorBlockNumberValue) {
64
64
  const contractAddress = fromSingle(foreignContractAddressIsSome).toBool() ? AztecAddress.fromField(fromSingle(foreignContractAddressValue)) : undefined;
65
65
  const anchorBlockNumber = fromSingle(foreignAnchorBlockNumberIsSome).toBool() ? fromSingle(foreignAnchorBlockNumberValue).toNumber() : undefined;
66
- const privateContextInputs = await this.stateHandler.setPrivateContext(contractAddress, anchorBlockNumber);
66
+ const privateContextInputs = await this.stateHandler.enterPrivateState(contractAddress, anchorBlockNumber);
67
67
  return toForeignCallResult(privateContextInputs.toFields().map(toSingle));
68
68
  }
69
69
  async txeSetPublicTXEContext(foreignContractAddressIsSome, foreignContractAddressValue) {
70
70
  const contractAddress = fromSingle(foreignContractAddressIsSome).toBool() ? AztecAddress.fromField(fromSingle(foreignContractAddressValue)) : undefined;
71
- await this.stateHandler.setPublicContext(contractAddress);
71
+ await this.stateHandler.enterPublicState(contractAddress);
72
72
  return toForeignCallResult([]);
73
73
  }
74
74
  async txeSetUtilityTXEContext(foreignContractAddressIsSome, foreignContractAddressValue) {
75
75
  const contractAddress = fromSingle(foreignContractAddressIsSome).toBool() ? AztecAddress.fromField(fromSingle(foreignContractAddressValue)) : undefined;
76
- await this.stateHandler.setUtilityContext(contractAddress);
76
+ await this.stateHandler.enterUtilityState(contractAddress);
77
77
  return toForeignCallResult([]);
78
78
  }
79
79
  // Other oracles - these get handled by the oracle handler
@@ -3,7 +3,7 @@ import { type Logger } from '@aztec/foundation/log';
3
3
  import { KeyStore } from '@aztec/key-store';
4
4
  import type { ProtocolContract } from '@aztec/protocol-contracts';
5
5
  import { AddressDataProvider, PXEOracleInterface } from '@aztec/pxe/server';
6
- import type { IPrivateExecutionOracle, IUtilityExecutionOracle } from '@aztec/pxe/simulator';
6
+ import { type IPrivateExecutionOracle, type IUtilityExecutionOracle } from '@aztec/pxe/simulator';
7
7
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
8
8
  import { PrivateContextInputs } from '@aztec/stdlib/kernel';
9
9
  import type { UInt32 } from '@aztec/stdlib/types';
@@ -22,10 +22,10 @@ type MethodNames<T> = {
22
22
  */
23
23
  export type TXEOracleFunctionName = MethodNames<RPCTranslator>;
24
24
  export interface TXESessionStateHandler {
25
- setTopLevelContext(): Promise<void>;
26
- setPublicContext(contractAddress?: AztecAddress): Promise<void>;
27
- setPrivateContext(contractAddress?: AztecAddress, anchorBlockNumber?: UInt32): Promise<PrivateContextInputs>;
28
- setUtilityContext(contractAddress?: AztecAddress): Promise<void>;
25
+ enterTopLevelState(): Promise<void>;
26
+ enterPublicState(contractAddress?: AztecAddress): Promise<void>;
27
+ enterPrivateState(contractAddress?: AztecAddress, anchorBlockNumber?: UInt32): Promise<PrivateContextInputs>;
28
+ enterUtilityState(contractAddress?: AztecAddress): Promise<void>;
29
29
  }
30
30
  /**
31
31
  * A `TXESession` corresponds to a Noir `#[test]` function, and handles all of its oracle calls, stores test-specific
@@ -54,16 +54,14 @@ export declare class TXESession implements TXESessionStateHandler {
54
54
  * @returns The oracle return values.
55
55
  */
56
56
  processFunction(functionName: TXEOracleFunctionName, inputs: ForeignCallArgs): Promise<ForeignCallResult>;
57
- setTopLevelContext(): Promise<void>;
58
- setPublicContext(contractAddress?: AztecAddress): Promise<void>;
59
- setPrivateContext(contractAddress?: AztecAddress, anchorBlockNumber?: UInt32): Promise<PrivateContextInputs>;
60
- setUtilityContext(contractAddress?: AztecAddress): Promise<void>;
61
- private exitTopLevelContext;
62
- private exitPublicContext;
63
- private exitPrivateContext;
57
+ enterTopLevelState(): Promise<void>;
58
+ enterPrivateState(contractAddress?: AztecAddress, anchorBlockNumber?: UInt32): Promise<PrivateContextInputs>;
59
+ enterPublicState(contractAddress?: AztecAddress): Promise<void>;
60
+ enterUtilityState(contractAddress?: AztecAddress): Promise<void>;
61
+ private exitTopLevelState;
62
+ private exitPrivateState;
63
+ private exitPublicState;
64
64
  private exitUtilityContext;
65
- private assertState;
66
- private getPrivateContextInputs;
67
65
  }
68
66
  export {};
69
67
  //# sourceMappingURL=txe_session.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"txe_session.d.ts","sourceRoot":"","sources":["../src/txe_session.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"txe_session.d.ts","sourceRoot":"","sources":["../src/txe_session.ts"],"names":[],"mappings":"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"}
@@ -3,42 +3,21 @@ import { createLogger } from '@aztec/foundation/log';
3
3
  import { KeyStore } from '@aztec/key-store';
4
4
  import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
5
5
  import { AddressDataProvider, CapsuleDataProvider, NoteDataProvider, PXEOracleInterface, PrivateEventDataProvider, TaggingDataProvider } from '@aztec/pxe/server';
6
+ import { ExecutionNoteCache, HashedValuesCache, PrivateExecutionOracle, UtilityExecutionOracle } from '@aztec/pxe/simulator';
6
7
  import { FunctionSelector } from '@aztec/stdlib/abi';
7
8
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
9
+ import { Body, L2Block } from '@aztec/stdlib/block';
8
10
  import { GasSettings } from '@aztec/stdlib/gas';
9
- import { PrivateContextInputs } from '@aztec/stdlib/kernel';
10
- import { makeGlobalVariables } from '@aztec/stdlib/testing';
11
- import { CallContext, GlobalVariables, TxContext } from '@aztec/stdlib/tx';
12
- import { TXE } from './oracle/txe_oracle.js';
11
+ import { makeAppendOnlyTreeSnapshot, makeGlobalVariables } from '@aztec/stdlib/testing';
12
+ import { CallContext, TxContext } from '@aztec/stdlib/tx';
13
13
  import { TXEOraclePublicContext } from './oracle/txe_oracle_public_context.js';
14
14
  import { TXEOracleTopLevelContext } from './oracle/txe_oracle_top_level_context.js';
15
15
  import { RPCTranslator } from './rpc_translator.js';
16
16
  import { TXEStateMachine } from './state_machine/index.js';
17
17
  import { TXEAccountDataProvider } from './util/txe_account_data_provider.js';
18
18
  import { TXEContractDataProvider } from './util/txe_contract_data_provider.js';
19
- import { getSingleTxBlockRequestHash } from './utils/block_creation.js';
20
- /**
21
- * A TXE Session can be ine one of four states, which change as the test progresses and different oracles are called.
22
- * The current state determines which oracles are available.
23
- */ var SessionState = /*#__PURE__*/ function(SessionState) {
24
- /**
25
- * The top-level state is the default state, before any other state has been entered. This is where contracts can be
26
- * deployed, accounts created, blocks mined, etc.
27
- */ SessionState[SessionState["TOP_LEVEL"] = 0] = "TOP_LEVEL";
28
- /**
29
- * The private state is entered via the `private_context` function. In this state the PXE oracles that `#[private]`
30
- * functions use are available, such as those related to note retrieval, notification of side-effects, capsule access,
31
- * etc. */ SessionState[SessionState["PRIVATE"] = 1] = "PRIVATE";
32
- /**
33
- * The public state is entered via the `public_context` function. In this state the AVM opcodes that `#[public]`
34
- * functions execute are resolved as oracles by TXE, since Noir tests are not transpiled. */ SessionState[SessionState["PUBLIC"] = 2] = "PUBLIC";
35
- /**
36
- * The utility state is entered via the `utility_context` function. In this state the PXE oracles that `#[utility]`
37
- * functions use are available, such as those related to (unconstrained) note retrieval, capsule access, public
38
- * storage reads, etc.
39
- */ SessionState[SessionState["UTILITY"] = 3] = "UTILITY";
40
- return SessionState;
41
- }(SessionState || {});
19
+ import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlockHeader } from './utils/block_creation.js';
20
+ import { makeTxEffect } from './utils/tx_effect_creation.js';
42
21
  const DEFAULT_ADDRESS = AztecAddress.fromNumber(42);
43
22
  /**
44
23
  * A `TXESession` corresponds to a Noir `#[test]` function, and handles all of its oracle calls, stores test-specific
@@ -69,7 +48,9 @@ const DEFAULT_ADDRESS = AztecAddress.fromNumber(42);
69
48
  this.version = version;
70
49
  this.nextBlockTimestamp = nextBlockTimestamp;
71
50
  this.pxeOracleInterface = pxeOracleInterface;
72
- this.state = 0;
51
+ this.state = {
52
+ name: 'TOP_LEVEL'
53
+ };
73
54
  this.authwits = new Map();
74
55
  }
75
56
  static async init(protocolContracts) {
@@ -106,30 +87,81 @@ const DEFAULT_ADDRESS = AztecAddress.fromNumber(42);
106
87
  return new RPCTranslator(this, this.oracleHandler)[functionName](...inputs);
107
88
  } catch (error) {
108
89
  if (error instanceof Error) {
109
- throw new Error(`Execution error while processing function ${functionName} in state ${SessionState[this.state]}: ${error.message}`);
90
+ throw new Error(`Execution error while processing function ${functionName} in state ${this.state.name}: ${error.message}`);
110
91
  } else {
111
- throw new Error(`Unknown execution error while processing function ${functionName} in state ${SessionState[this.state]}`);
92
+ throw new Error(`Unknown execution error while processing function ${functionName} in state ${this.state.name}`);
112
93
  }
113
94
  }
114
95
  }
115
- async setTopLevelContext() {
116
- if (this.state == 1) {
117
- await this.exitPrivateContext();
118
- } else if (this.state == 2) {
119
- await this.exitPublicContext();
120
- } else if (this.state == 3) {
121
- this.exitUtilityContext();
122
- } else if (this.state == 0) {
123
- throw new Error(`Expected to be in state other than ${SessionState[0]}`);
124
- } else {
125
- throw new Error(`Unexpected state '${this.state}'`);
96
+ async enterTopLevelState() {
97
+ switch(this.state.name){
98
+ case 'PRIVATE':
99
+ {
100
+ await this.exitPrivateState();
101
+ break;
102
+ }
103
+ case 'PUBLIC':
104
+ {
105
+ await this.exitPublicState();
106
+ break;
107
+ }
108
+ case 'UTILITY':
109
+ {
110
+ this.exitUtilityContext();
111
+ break;
112
+ }
113
+ case 'TOP_LEVEL':
114
+ {
115
+ throw new Error(`Expected to be in state other than TOP_LEVEL`);
116
+ }
117
+ default:
118
+ {
119
+ this.state;
120
+ }
126
121
  }
127
122
  this.oracleHandler = new TXEOracleTopLevelContext(this.stateMachine, this.contractDataProvider, this.keyStore, this.addressDataProvider, this.accountDataProvider, this.pxeOracleInterface, this.nextBlockTimestamp, this.version, this.chainId, this.authwits);
128
- this.state = 0;
129
- this.logger.debug(`Entered state ${SessionState[this.state]}`);
123
+ this.state = {
124
+ name: 'TOP_LEVEL'
125
+ };
126
+ this.logger.debug(`Entered state ${this.state.name}`);
127
+ }
128
+ async enterPrivateState(contractAddress = DEFAULT_ADDRESS, anchorBlockNumber) {
129
+ this.exitTopLevelState();
130
+ // There is no automatic message discovery and contract-driven syncing process in inlined private or utility
131
+ // contexts, which means that known nullifiers are also not searched for, since it is during the tagging sync that
132
+ // we perform this. We therefore search for known nullifiers now, as otherwise notes that were nullified would not
133
+ // be removed from the database.
134
+ // TODO(#12553): make the synchronizer sync here instead and remove this
135
+ await this.pxeOracleInterface.removeNullifiedNotes(contractAddress);
136
+ // Private execution has two associated block numbers: the anchor block (i.e. the historical block that is used to
137
+ // build the proof), and the *next* block, i.e. the one we'll create once the execution ends, and which will contain
138
+ // a single transaction with the effects of what was done in the test.
139
+ const anchorBlock = await this.stateMachine.node.getBlockHeader(anchorBlockNumber ?? 'latest');
140
+ const latestBlock = await this.stateMachine.node.getBlockHeader('latest');
141
+ const nextBlockGlobalVariables = makeGlobalVariables(undefined, {
142
+ blockNumber: latestBlock.globalVariables.blockNumber + 1,
143
+ timestamp: this.nextBlockTimestamp,
144
+ version: this.version,
145
+ chainId: this.chainId
146
+ });
147
+ const txRequestHash = getSingleTxBlockRequestHash(nextBlockGlobalVariables.blockNumber);
148
+ const noteCache = new ExecutionNoteCache(txRequestHash);
149
+ this.oracleHandler = new PrivateExecutionOracle(Fr.ZERO, new TxContext(this.chainId, this.version, GasSettings.empty()), new CallContext(AztecAddress.ZERO, contractAddress, FunctionSelector.empty(), false), anchorBlock, [], [], new HashedValuesCache(), noteCache, this.pxeOracleInterface);
150
+ // We store the note cache fed into the PrivateExecutionOracle (along with some other auxiliary data) in order to
151
+ // refer to it later, mimicking the way this object is used by the ContractFunctionSimulator. The difference resides
152
+ // in that the simulator has all information needed in order to run the simulation, while ours will be ongoing as
153
+ // the different oracles will be invoked from the Noir test, until eventually the private execution finishes.
154
+ this.state = {
155
+ name: 'PRIVATE',
156
+ nextBlockGlobalVariables,
157
+ txRequestHash,
158
+ noteCache
159
+ };
160
+ this.logger.debug(`Entered state ${this.state.name}`);
161
+ return this.oracleHandler.getPrivateContextInputs();
130
162
  }
131
- async setPublicContext(contractAddress) {
132
- this.exitTopLevelContext();
163
+ async enterPublicState(contractAddress) {
164
+ this.exitTopLevelState();
133
165
  // The PublicContext will create a block with a single transaction in it, containing the effects of what was done in
134
166
  // the test. The block therefore gets the *next* block number and timestamp.
135
167
  const latestBlockNumber = (await this.stateMachine.node.getBlockHeader('latest')).globalVariables.blockNumber;
@@ -140,45 +172,29 @@ const DEFAULT_ADDRESS = AztecAddress.fromNumber(42);
140
172
  chainId: this.chainId
141
173
  });
142
174
  this.oracleHandler = new TXEOraclePublicContext(contractAddress ?? DEFAULT_ADDRESS, await this.stateMachine.synchronizer.nativeWorldStateService.fork(), getSingleTxBlockRequestHash(globalVariables.blockNumber), globalVariables);
143
- this.state = 2;
144
- this.logger.debug(`Entered state ${SessionState[this.state]}`);
175
+ this.state = {
176
+ name: 'PUBLIC'
177
+ };
178
+ this.logger.debug(`Entered state ${this.state.name}`);
145
179
  }
146
- async setPrivateContext(contractAddress, anchorBlockNumber) {
147
- this.exitTopLevelContext();
148
- // A PrivateContext has two associated block numbers: the anchor block (i.e. the historical block that is used to build the
149
- // proof), and the *next* block, i.e. the one the PrivateContext will create with the single transaction that
150
- // contains the effects of what was done in the test.
151
- const anchorBlock = await this.stateMachine.node.getBlockHeader(anchorBlockNumber ?? 'latest');
152
- const latestBlock = await this.stateMachine.node.getBlockHeader('latest');
153
- const anchorBlockGlobalVariables = makeGlobalVariables(undefined, {
154
- blockNumber: anchorBlock.globalVariables.blockNumber,
155
- timestamp: anchorBlock.globalVariables.timestamp,
156
- version: this.version,
157
- chainId: this.chainId
158
- });
159
- const nextBlockGlobalVariables = makeGlobalVariables(undefined, {
160
- blockNumber: latestBlock.globalVariables.blockNumber + 1,
161
- timestamp: this.nextBlockTimestamp,
162
- version: this.version,
163
- chainId: this.chainId
164
- });
165
- const privateContextInputs = await this.getPrivateContextInputs(anchorBlockGlobalVariables.blockNumber, contractAddress ?? DEFAULT_ADDRESS);
166
- this.oracleHandler = await TXE.create(contractAddress ?? DEFAULT_ADDRESS, this.pxeOracleInterface, await this.stateMachine.synchronizer.nativeWorldStateService.fork(), anchorBlockGlobalVariables, nextBlockGlobalVariables, getSingleTxBlockRequestHash(nextBlockGlobalVariables.blockNumber));
167
- this.state = 1;
168
- this.logger.debug(`Entered state ${SessionState[this.state]}`);
169
- return privateContextInputs;
170
- }
171
- async setUtilityContext(contractAddress) {
172
- this.exitTopLevelContext();
173
- // A UtilityContext is built using the latest block as a reference, mimicking what would happen if PXE had synced
174
- // all the way to the tip of the chain.
175
- const latestBlock = await this.stateMachine.node.getBlockHeader('latest');
176
- this.oracleHandler = await TXE.create(contractAddress ?? DEFAULT_ADDRESS, this.pxeOracleInterface, await this.stateMachine.synchronizer.nativeWorldStateService.fork(), latestBlock.globalVariables, GlobalVariables.empty(), Fr.random());
177
- this.state = 3;
178
- this.logger.debug(`Entered state ${SessionState[this.state]}`);
180
+ async enterUtilityState(contractAddress = DEFAULT_ADDRESS) {
181
+ this.exitTopLevelState();
182
+ // There is no automatic message discovery and contract-driven syncing process in inlined private or utility
183
+ // contexts, which means that known nullifiers are also not searched for, since it is during the tagging sync that
184
+ // we perform this. We therefore search for known nullifiers now, as otherwise notes that were nullified would not
185
+ // be removed from the database.
186
+ // TODO(#12553): make the synchronizer sync here instead and remove this
187
+ await this.pxeOracleInterface.removeNullifiedNotes(contractAddress);
188
+ this.oracleHandler = new UtilityExecutionOracle(contractAddress, [], [], this.pxeOracleInterface);
189
+ this.state = {
190
+ name: 'UTILITY'
191
+ };
192
+ this.logger.debug(`Entered state ${this.state.name}`);
179
193
  }
180
- exitTopLevelContext() {
181
- this.assertState(0);
194
+ exitTopLevelState() {
195
+ if (this.state.name != 'TOP_LEVEL') {
196
+ throw new Error(`Expected to be in state 'TOP_LEVEL', but got '${this.state.name}' instead`);
197
+ }
182
198
  // Note that while all public and private contexts do is build a single block that we then process when exiting
183
199
  // those, the top level context performs a large number of actions not captured in the following 'close' call. Among
184
200
  // others, it will create empty blocks (via `txeAdvanceBlocksBy` and `deploy`), create blocks with transactions via
@@ -190,27 +206,39 @@ const DEFAULT_ADDRESS = AztecAddress.fromNumber(42);
190
206
  // Ideally authwits would be passed alongside a contract call instead of pre-seeded.
191
207
  [this.nextBlockTimestamp, this.authwits] = this.oracleHandler.close();
192
208
  }
193
- async exitPublicContext() {
194
- this.assertState(2);
195
- const block = await this.oracleHandler.close();
209
+ async exitPrivateState() {
210
+ if (this.state.name != 'PRIVATE') {
211
+ throw new Error(`Expected to be in state 'PRIVATE', but got '${this.state.name}' instead`);
212
+ }
213
+ this.logger.debug('Exiting Private state, building block with collected side effects', {
214
+ blockNumber: this.state.nextBlockGlobalVariables.blockNumber
215
+ });
216
+ // We rely on the note cache to determine the effects of the transaction. This is incomplete as it doesn't private
217
+ // logs (other effects like enqueued public calls don't need to be considered since those are not allowed).
218
+ const txEffect = await makeTxEffect(this.state.noteCache, this.state.txRequestHash, this.state.nextBlockGlobalVariables.blockNumber);
219
+ // We build a block holding just this transaction
220
+ const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
221
+ await insertTxEffectIntoWorldTrees(txEffect, forkedWorldTrees);
222
+ const block = new L2Block(makeAppendOnlyTreeSnapshot(), await makeTXEBlockHeader(forkedWorldTrees, this.state.nextBlockGlobalVariables), new Body([
223
+ txEffect
224
+ ]));
196
225
  await this.stateMachine.handleL2Block(block);
226
+ await forkedWorldTrees.close();
227
+ this.logger.debug('Exited PublicContext with built block', {
228
+ blockNumber: block.number,
229
+ txEffects: block.body.txEffects
230
+ });
197
231
  }
198
- async exitPrivateContext() {
199
- this.assertState(1);
232
+ async exitPublicState() {
233
+ if (this.state.name != 'PUBLIC') {
234
+ throw new Error(`Expected to be in state 'PUBLIC', but got '${this.state.name}' instead`);
235
+ }
200
236
  const block = await this.oracleHandler.close();
201
237
  await this.stateMachine.handleL2Block(block);
202
238
  }
203
239
  exitUtilityContext() {
204
- this.assertState(3);
205
- }
206
- assertState(state) {
207
- if (this.state != state) {
208
- throw new Error(`Expected to be in state ${SessionState[state]}, but got '${SessionState[this.state]}' instead`);
240
+ if (this.state.name != 'UTILITY') {
241
+ throw new Error(`Expected to be in state 'UTILITY', but got '${this.state.name}' instead`);
209
242
  }
210
243
  }
211
- async getPrivateContextInputs(anchorBlockNumber, contractAddress) {
212
- this.logger.info(`Creating private context for block ${anchorBlockNumber}`);
213
- const sender = await AztecAddress.random();
214
- return new PrivateContextInputs(new CallContext(sender, contractAddress, FunctionSelector.empty(), false), await this.stateMachine.node.getBlockHeader(anchorBlockNumber), new TxContext(this.chainId, this.version, GasSettings.empty()), 0);
215
- }
216
244
  }
@@ -0,0 +1,5 @@
1
+ import { Fr } from '@aztec/foundation/fields';
2
+ import type { ExecutionNoteCache } from '@aztec/pxe/simulator';
3
+ import { TxEffect } from '@aztec/stdlib/tx';
4
+ export declare function makeTxEffect(noteCache: ExecutionNoteCache, txRequestHash: Fr, txBlockNumber: number): Promise<TxEffect>;
5
+ //# sourceMappingURL=tx_effect_creation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tx_effect_creation.d.ts","sourceRoot":"","sources":["../../src/utils/tx_effect_creation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAC9C,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,aAAa,EAAE,EAAE,EACjB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,QAAQ,CAAC,CA2BnB"}
@@ -0,0 +1,16 @@
1
+ import { Fr } from '@aztec/foundation/fields';
2
+ import { computeNoteHashNonce, computeUniqueNoteHash, siloNoteHash } from '@aztec/stdlib/hash';
3
+ import { TxEffect, TxHash } from '@aztec/stdlib/tx';
4
+ export async function makeTxEffect(noteCache, txRequestHash, txBlockNumber) {
5
+ const txEffect = TxEffect.empty();
6
+ const { usedTxRequestHashForNonces } = noteCache.finish();
7
+ const nonceGenerator = usedTxRequestHashForNonces ? txRequestHash : noteCache.getAllNullifiers()[0];
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
+ // Nullifiers are already siloed
10
+ txEffect.nullifiers = noteCache.getAllNullifiers();
11
+ if (usedTxRequestHashForNonces) {
12
+ txEffect.nullifiers.unshift(txRequestHash);
13
+ }
14
+ txEffect.txHash = new TxHash(new Fr(txBlockNumber));
15
+ return txEffect;
16
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/txe",
3
- "version": "3.0.0-nightly.20250926",
3
+ "version": "3.0.0-nightly.20250927",
4
4
  "type": "module",
5
5
  "exports": "./dest/index.js",
6
6
  "bin": "./dest/bin/index.js",
@@ -61,20 +61,20 @@
61
61
  ]
62
62
  },
63
63
  "dependencies": {
64
- "@aztec/accounts": "3.0.0-nightly.20250926",
65
- "@aztec/archiver": "3.0.0-nightly.20250926",
66
- "@aztec/aztec-node": "3.0.0-nightly.20250926",
67
- "@aztec/aztec.js": "3.0.0-nightly.20250926",
68
- "@aztec/bb-prover": "3.0.0-nightly.20250926",
69
- "@aztec/constants": "3.0.0-nightly.20250926",
70
- "@aztec/foundation": "3.0.0-nightly.20250926",
71
- "@aztec/key-store": "3.0.0-nightly.20250926",
72
- "@aztec/kv-store": "3.0.0-nightly.20250926",
73
- "@aztec/protocol-contracts": "3.0.0-nightly.20250926",
74
- "@aztec/pxe": "3.0.0-nightly.20250926",
75
- "@aztec/simulator": "3.0.0-nightly.20250926",
76
- "@aztec/stdlib": "3.0.0-nightly.20250926",
77
- "@aztec/world-state": "3.0.0-nightly.20250926",
64
+ "@aztec/accounts": "3.0.0-nightly.20250927",
65
+ "@aztec/archiver": "3.0.0-nightly.20250927",
66
+ "@aztec/aztec-node": "3.0.0-nightly.20250927",
67
+ "@aztec/aztec.js": "3.0.0-nightly.20250927",
68
+ "@aztec/bb-prover": "3.0.0-nightly.20250927",
69
+ "@aztec/constants": "3.0.0-nightly.20250927",
70
+ "@aztec/foundation": "3.0.0-nightly.20250927",
71
+ "@aztec/key-store": "3.0.0-nightly.20250927",
72
+ "@aztec/kv-store": "3.0.0-nightly.20250927",
73
+ "@aztec/protocol-contracts": "3.0.0-nightly.20250927",
74
+ "@aztec/pxe": "3.0.0-nightly.20250927",
75
+ "@aztec/simulator": "3.0.0-nightly.20250927",
76
+ "@aztec/stdlib": "3.0.0-nightly.20250927",
77
+ "@aztec/world-state": "3.0.0-nightly.20250927",
78
78
  "zod": "^3.23.8"
79
79
  },
80
80
  "devDependencies": {
@@ -303,7 +303,6 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
303
303
  HashedValuesCache.create([new HashedValues(args, argsHash)]),
304
304
  noteCache,
305
305
  this.pxeOracleInterface,
306
- simulator,
307
306
  0,
308
307
  1,
309
308
  undefined, // log
@@ -313,6 +312,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
313
312
  * contract would perform, including setting senderForTags.
314
313
  */
315
314
  from,
315
+ simulator,
316
316
  );
317
317
 
318
318
  // 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.
@@ -97,7 +97,7 @@ export class RPCTranslator {
97
97
  // TXE session state transition functions - these get handled by the state handler
98
98
 
99
99
  async txeSetTopLevelTXEContext() {
100
- await this.stateHandler.setTopLevelContext();
100
+ await this.stateHandler.enterTopLevelState();
101
101
 
102
102
  return toForeignCallResult([]);
103
103
  }
@@ -116,7 +116,7 @@ export class RPCTranslator {
116
116
  ? fromSingle(foreignAnchorBlockNumberValue).toNumber()
117
117
  : undefined;
118
118
 
119
- const privateContextInputs = await this.stateHandler.setPrivateContext(contractAddress, anchorBlockNumber);
119
+ const privateContextInputs = await this.stateHandler.enterPrivateState(contractAddress, anchorBlockNumber);
120
120
 
121
121
  return toForeignCallResult(privateContextInputs.toFields().map(toSingle));
122
122
  }
@@ -129,7 +129,7 @@ export class RPCTranslator {
129
129
  ? AztecAddress.fromField(fromSingle(foreignContractAddressValue))
130
130
  : undefined;
131
131
 
132
- await this.stateHandler.setPublicContext(contractAddress);
132
+ await this.stateHandler.enterPublicState(contractAddress);
133
133
 
134
134
  return toForeignCallResult([]);
135
135
  }
@@ -142,7 +142,7 @@ export class RPCTranslator {
142
142
  ? AztecAddress.fromField(fromSingle(foreignContractAddressValue))
143
143
  : undefined;
144
144
 
145
- await this.stateHandler.setUtilityContext(contractAddress);
145
+ await this.stateHandler.enterUtilityState(contractAddress);
146
146
 
147
147
  return toForeignCallResult([]);
148
148
  }