@aztec/txe 0.0.1-commit.85d7d01 → 0.0.1-commit.8655d4a

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 (126) hide show
  1. package/dest/ContractClassRegistry-KKNT527R.js +3 -0
  2. package/dest/ContractClassRegistry-KKNT527R.js.map +7 -0
  3. package/dest/ContractInstanceRegistry-GSKBNL3Q.js +3 -0
  4. package/dest/ContractInstanceRegistry-GSKBNL3Q.js.map +7 -0
  5. package/dest/FeeJuice-GUJ5O6GB.js +3 -0
  6. package/dest/FeeJuice-GUJ5O6GB.js.map +7 -0
  7. package/dest/MultiCallEntrypoint-ZQPCKVKL.js +3 -0
  8. package/dest/MultiCallEntrypoint-ZQPCKVKL.js.map +7 -0
  9. package/dest/SchnorrAccount-QIXE5DXA.js +3 -0
  10. package/dest/SchnorrAccount-QIXE5DXA.js.map +7 -0
  11. package/dest/bin/check_txe_oracle_version.d.ts +2 -0
  12. package/dest/bin/check_txe_oracle_version.d.ts.map +1 -0
  13. package/dest/bin/check_txe_oracle_version.js +32 -0
  14. package/dest/bin/index.js +3 -30
  15. package/dest/bin/index.js.map +7 -0
  16. package/dest/chunk-BJVAAXNA.js +3 -0
  17. package/dest/chunk-BJVAAXNA.js.map +7 -0
  18. package/dest/chunk-DF6RMOC6.js +304 -0
  19. package/dest/chunk-DF6RMOC6.js.map +7 -0
  20. package/dest/chunk-PPJTNNUG.js +265 -0
  21. package/dest/chunk-PPJTNNUG.js.map +7 -0
  22. package/dest/constants.d.ts +3 -1
  23. package/dest/constants.d.ts.map +1 -1
  24. package/dest/constants.js +5 -0
  25. package/dest/dispatcher_pool.d.ts +67 -0
  26. package/dest/dispatcher_pool.d.ts.map +1 -0
  27. package/dest/dispatcher_pool.js +284 -0
  28. package/dest/index.d.ts +188 -7
  29. package/dest/index.d.ts.map +1 -1
  30. package/dest/index.js +160 -119
  31. package/dest/metafile.json +38147 -0
  32. package/dest/msgpackr_fr_extension.d.ts +2 -0
  33. package/dest/msgpackr_fr_extension.d.ts.map +1 -0
  34. package/dest/msgpackr_fr_extension.js +21 -0
  35. package/dest/oracle/interfaces.d.ts +39 -28
  36. package/dest/oracle/interfaces.d.ts.map +1 -1
  37. package/dest/oracle/txe_oracle_public_context.d.ts +18 -13
  38. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  39. package/dest/oracle/txe_oracle_public_context.js +27 -12
  40. package/dest/oracle/txe_oracle_top_level_context.d.ts +36 -20
  41. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  42. package/dest/oracle/txe_oracle_top_level_context.js +125 -66
  43. package/dest/oracle/txe_private_execution_oracle.d.ts +17 -0
  44. package/dest/oracle/txe_private_execution_oracle.d.ts.map +1 -0
  45. package/dest/oracle/txe_private_execution_oracle.js +15 -0
  46. package/dest/rpc_server.d.ts +14 -0
  47. package/dest/rpc_server.d.ts.map +1 -0
  48. package/dest/rpc_server.js +78 -0
  49. package/dest/rpc_translator.d.ts +139 -83
  50. package/dest/rpc_translator.d.ts.map +1 -1
  51. package/dest/rpc_translator.js +567 -243
  52. package/dest/server.bundle.js +3 -0
  53. package/dest/server.bundle.js.map +7 -0
  54. package/dest/state_machine/archiver.d.ts +4 -4
  55. package/dest/state_machine/archiver.d.ts.map +1 -1
  56. package/dest/state_machine/archiver.js +22 -20
  57. package/dest/state_machine/dummy_p2p_client.d.ts +13 -7
  58. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  59. package/dest/state_machine/dummy_p2p_client.js +16 -4
  60. package/dest/state_machine/global_variable_builder.d.ts +9 -4
  61. package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
  62. package/dest/state_machine/global_variable_builder.js +9 -3
  63. package/dest/state_machine/index.d.ts +7 -3
  64. package/dest/state_machine/index.d.ts.map +1 -1
  65. package/dest/state_machine/index.js +23 -5
  66. package/dest/state_machine/mock_epoch_cache.d.ts +18 -3
  67. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  68. package/dest/state_machine/mock_epoch_cache.js +35 -2
  69. package/dest/state_machine/synchronizer.d.ts +5 -5
  70. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  71. package/dest/state_machine/synchronizer.js +4 -4
  72. package/dest/txe_oracle_version.d.ts +17 -0
  73. package/dest/txe_oracle_version.d.ts.map +1 -0
  74. package/dest/txe_oracle_version.js +14 -0
  75. package/dest/txe_session.d.ts +64 -6
  76. package/dest/txe_session.d.ts.map +1 -1
  77. package/dest/txe_session.js +159 -31
  78. package/dest/utils/encoding.d.ts +191 -0
  79. package/dest/utils/encoding.d.ts.map +1 -0
  80. package/dest/{util → utils}/encoding.js +7 -2
  81. package/dest/{util → utils}/expected_failure_error.d.ts +1 -1
  82. package/dest/utils/expected_failure_error.d.ts.map +1 -0
  83. package/dest/{util → utils}/txe_account_store.d.ts +1 -1
  84. package/dest/utils/txe_account_store.d.ts.map +1 -0
  85. package/dest/utils/txe_public_contract_data_source.d.ts +20 -0
  86. package/dest/utils/txe_public_contract_data_source.d.ts.map +1 -0
  87. package/dest/{util → utils}/txe_public_contract_data_source.js +1 -3
  88. package/dest/worker.bundle.js +3 -0
  89. package/dest/worker.bundle.js.map +7 -0
  90. package/dest/worker.d.ts +2 -0
  91. package/dest/worker.d.ts.map +1 -0
  92. package/dest/worker.js +92 -0
  93. package/package.json +37 -21
  94. package/src/bin/check_txe_oracle_version.ts +37 -0
  95. package/src/bin/index.ts +11 -2
  96. package/src/constants.ts +6 -0
  97. package/src/dispatcher_pool.ts +316 -0
  98. package/src/index.ts +178 -126
  99. package/src/msgpackr_fr_extension.ts +23 -0
  100. package/src/oracle/interfaces.ts +43 -34
  101. package/src/oracle/txe_oracle_public_context.ts +42 -12
  102. package/src/oracle/txe_oracle_top_level_context.ts +146 -77
  103. package/src/oracle/txe_private_execution_oracle.ts +30 -0
  104. package/src/rpc_server.ts +87 -0
  105. package/src/rpc_translator.ts +646 -326
  106. package/src/state_machine/archiver.ts +33 -18
  107. package/src/state_machine/dummy_p2p_client.ts +31 -11
  108. package/src/state_machine/global_variable_builder.ts +18 -3
  109. package/src/state_machine/index.ts +25 -6
  110. package/src/state_machine/mock_epoch_cache.ts +46 -3
  111. package/src/state_machine/synchronizer.ts +5 -5
  112. package/src/txe_oracle_version.ts +17 -0
  113. package/src/txe_session.ts +253 -33
  114. package/src/{util → utils}/encoding.ts +8 -2
  115. package/src/{util → utils}/txe_public_contract_data_source.ts +0 -2
  116. package/src/worker.ts +98 -0
  117. package/dest/util/encoding.d.ts +0 -720
  118. package/dest/util/encoding.d.ts.map +0 -1
  119. package/dest/util/expected_failure_error.d.ts.map +0 -1
  120. package/dest/util/txe_account_store.d.ts.map +0 -1
  121. package/dest/util/txe_public_contract_data_source.d.ts +0 -20
  122. package/dest/util/txe_public_contract_data_source.d.ts.map +0 -1
  123. /package/dest/{util → utils}/expected_failure_error.js +0 -0
  124. /package/dest/{util → utils}/txe_account_store.js +0 -0
  125. /package/src/{util → utils}/expected_failure_error.ts +0 -0
  126. /package/src/{util → utils}/txe_account_store.ts +0 -0
@@ -1,10 +1,10 @@
1
- import { CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS, DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT, DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
1
+ import { CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS, MAX_PRIVATE_LOGS_PER_TX, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
2
2
  import { BlockNumber } from '@aztec/foundation/branded-types';
3
3
  import { Schnorr } from '@aztec/foundation/crypto/schnorr';
4
4
  import { Fr } from '@aztec/foundation/curves/bn254';
5
5
  import { LogLevels, applyStringFormatting, createLogger } from '@aztec/foundation/log';
6
6
  import { TestDateProvider } from '@aztec/foundation/timer';
7
- import { ORACLE_VERSION, enrichPublicSimulationError } from '@aztec/pxe/server';
7
+ import { CapsuleService, ORACLE_VERSION_MAJOR, composeHooks, enrichPublicSimulationError } from '@aztec/pxe/server';
8
8
  import { ExecutionNoteCache, ExecutionTaggingIndexCache, HashedValuesCache, Oracle, PrivateExecutionOracle, UtilityExecutionOracle, executePrivateFunction, generateSimulatedProvingResult } from '@aztec/pxe/simulator';
9
9
  import { ExecutionError, WASMSimulator, createSimulationError, extractCallStack, resolveAssertionMessageFromError, toACVMWitness, witnessMapToFields } from '@aztec/simulator/client';
10
10
  import { CppPublicTxSimulator, GuardedMerkleTreeOperations, PublicContractsDB, PublicProcessor } from '@aztec/simulator/server';
@@ -13,17 +13,18 @@ import { AuthWitness } from '@aztec/stdlib/auth-witness';
13
13
  import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
14
14
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
15
15
  import { computePartialAddress } from '@aztec/stdlib/contract';
16
- import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
16
+ import { Gas, GasFees } from '@aztec/stdlib/gas';
17
17
  import { computeCalldataHash, computeProtocolNullifier, siloNullifier } from '@aztec/stdlib/hash';
18
18
  import { PartialPrivateTailPublicInputsForPublic, PrivateKernelTailCircuitPublicInputs, PrivateToPublicAccumulatedData, PublicCallRequest } from '@aztec/stdlib/kernel';
19
+ import { hashPublicKey } from '@aztec/stdlib/keys';
19
20
  import { ChonkProof } from '@aztec/stdlib/proofs';
20
21
  import { makeGlobalVariables } from '@aztec/stdlib/testing';
21
22
  import { MerkleTreeId } from '@aztec/stdlib/trees';
22
23
  import { CallContext, HashedValues, PrivateExecutionResult, Tx, TxConstantData, TxContext, TxEffect, TxHash, collectNested } from '@aztec/stdlib/tx';
23
- import { ForkCheckpoint } from '@aztec/world-state';
24
+ import { ForkCheckpoint } from '@aztec/world-state/native';
24
25
  import { DEFAULT_ADDRESS } from '../constants.js';
25
- import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
26
26
  import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
27
+ import { TXEPublicContractDataSource } from '../utils/txe_public_contract_data_source.js';
27
28
  export class TXEOracleTopLevelContext {
28
29
  stateMachine;
29
30
  contractStore;
@@ -64,18 +65,28 @@ export class TXEOracleTopLevelContext {
64
65
  this.logger = createLogger('txe:top_level_context');
65
66
  this.logger.debug('Entering Top Level Context');
66
67
  }
67
- utilityAssertCompatibleOracleVersion(version) {
68
- if (version !== ORACLE_VERSION) {
69
- throw new Error(`Incompatible oracle version. TXE is using version '${ORACLE_VERSION}', but got a request for '${version}'.`);
68
+ contractOracleVersion;
69
+ assertCompatibleOracleVersion(major, minor) {
70
+ if (major !== ORACLE_VERSION_MAJOR) {
71
+ const hint = major > ORACLE_VERSION_MAJOR ? 'The contract was compiled with a newer version of Aztec.nr than this aztec cli version supports. Upgrade your aztec cli version to a compatible version.' : 'The contract was compiled with an older version of Aztec.nr than this aztec cli version supports. Recompile the contract with a compatible version of Aztec.nr.';
72
+ throw new Error(`Incompatible aztec cli version: ${hint} See https://docs.aztec.network/errors/8 (expected oracle major version ${ORACLE_VERSION_MAJOR}, got ${major})`);
70
73
  }
74
+ this.contractOracleVersion = {
75
+ major,
76
+ minor
77
+ };
78
+ }
79
+ // Prefixed with "nonOracleFunction" as it is not used as an oracle handler.
80
+ nonOracleFunctionGetContractOracleVersion() {
81
+ return this.contractOracleVersion;
71
82
  }
72
83
  // This is typically only invoked in private contexts, but it is convenient to also have it in top-level for testing
73
84
  // setup.
74
- utilityGetRandomField() {
85
+ getRandomField() {
75
86
  return Fr.random();
76
87
  }
77
88
  // We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
78
- utilityLog(level, message, fields) {
89
+ log(level, message, fields) {
79
90
  if (!LogLevels[level]) {
80
91
  throw new Error(`Invalid log level: ${level}`);
81
92
  }
@@ -85,35 +96,42 @@ export class TXEOracleTopLevelContext {
85
96
  });
86
97
  return Promise.resolve();
87
98
  }
88
- txeGetDefaultAddress() {
99
+ getDefaultAddress() {
89
100
  return DEFAULT_ADDRESS;
90
101
  }
91
- async txeGetNextBlockNumber() {
102
+ async getNextBlockNumber() {
92
103
  return BlockNumber(await this.getLastBlockNumber() + 1);
93
104
  }
94
- txeGetNextBlockTimestamp() {
105
+ getNextBlockTimestamp() {
95
106
  return Promise.resolve(this.nextBlockTimestamp);
96
107
  }
97
- async txeGetLastBlockTimestamp() {
98
- return (await this.stateMachine.node.getBlockHeader('latest')).globalVariables.timestamp;
108
+ async getLastBlockTimestamp() {
109
+ return (await this.stateMachine.node.getBlockData('latest')).header.globalVariables.timestamp;
99
110
  }
100
- async txeGetLastTxEffects() {
111
+ async getLastTxEffects() {
101
112
  const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
102
- const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
113
+ const block = await this.stateMachine.archiver.getBlock({
114
+ number: latestBlockNumber
115
+ });
103
116
  if (block.body.txEffects.length != 1) {
104
117
  // Note that calls like env.mine() will result in blocks with no transactions, hitting this
105
118
  throw new Error(`Expected a single transaction in the last block, found ${block.body.txEffects.length}`);
106
119
  }
107
120
  const txEffects = block.body.txEffects[0];
121
+ const privateLogs = txEffects.privateLogs;
122
+ if (privateLogs.length > MAX_PRIVATE_LOGS_PER_TX) {
123
+ throw new Error(`${privateLogs.length} private logs exceed max ${MAX_PRIVATE_LOGS_PER_TX}`);
124
+ }
108
125
  return {
109
126
  txHash: txEffects.txHash,
110
127
  noteHashes: txEffects.noteHashes,
111
- nullifiers: txEffects.nullifiers
128
+ nullifiers: txEffects.nullifiers,
129
+ privateLogs
112
130
  };
113
131
  }
114
132
  async syncContractNonOracleMethod(contractAddress, scope, jobId) {
115
133
  if (contractAddress.equals(DEFAULT_ADDRESS)) {
116
- this.logger.debug(`Skipping sync in txeGetPrivateEvents because the events correspond to the default address.`);
134
+ this.logger.debug(`Skipping sync in getPrivateEvents because the events correspond to the default address.`);
117
135
  return;
118
136
  }
119
137
  const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
@@ -123,7 +141,7 @@ export class TXEOracleTopLevelContext {
123
141
  scope
124
142
  ]);
125
143
  }
126
- async txeGetPrivateEvents(selector, contractAddress, scope) {
144
+ async getPrivateEvents(selector, contractAddress, scope) {
127
145
  return (await this.privateEventStore.getPrivateEvents(selector, {
128
146
  contractAddress,
129
147
  scopes: [
@@ -133,32 +151,42 @@ export class TXEOracleTopLevelContext {
133
151
  toBlock: await this.getLastBlockNumber() + 1
134
152
  })).map((e)=>e.packedEvent);
135
153
  }
136
- async txeAdvanceBlocksBy(blocks) {
154
+ async advanceBlocksBy(blocks) {
137
155
  this.logger.debug(`time traveling ${blocks} blocks`);
138
156
  for(let i = 0; i < blocks; i++){
139
157
  await this.mineBlock();
140
158
  }
141
159
  }
142
- txeAdvanceTimestampBy(duration) {
160
+ advanceTimestampBy(duration) {
143
161
  this.logger.debug(`time traveling ${duration} seconds`);
144
162
  this.nextBlockTimestamp += duration;
145
163
  }
146
- async txeDeploy(artifact, instance, secret) {
164
+ deploymentNullifier(address) {
165
+ return siloNullifier(AztecAddress.fromNumber(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS), address.toField());
166
+ }
167
+ async deploy(artifact, instance, secret) {
147
168
  // Emit deployment nullifier
148
169
  await this.mineBlock({
149
170
  nullifiers: [
150
- await siloNullifier(AztecAddress.fromNumber(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS), instance.address.toField())
171
+ await this.deploymentNullifier(instance.address)
151
172
  ]
152
173
  });
153
174
  if (!secret.equals(Fr.ZERO)) {
154
- await this.txeAddAccount(artifact, instance, secret);
175
+ await this.addAccount(artifact, instance, secret);
155
176
  } else {
156
177
  await this.contractStore.addContractInstance(instance);
157
178
  await this.contractStore.addContractArtifact(artifact);
158
179
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
159
180
  }
160
181
  }
161
- async txeAddAccount(artifact, instance, secret) {
182
+ /**
183
+ * Mines a single block containing only the deployment nullifiers for the contracts at the given addresses.
184
+ */ async mineDeploymentNullifiers(addresses) {
185
+ await this.mineBlock({
186
+ nullifiers: await Promise.all(addresses.map((address)=>this.deploymentNullifier(address)))
187
+ });
188
+ }
189
+ async addAccount(artifact, instance, secret) {
162
190
  const partialAddress = await computePartialAddress(instance);
163
191
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
164
192
  await this.contractStore.addContractInstance(instance);
@@ -169,7 +197,7 @@ export class TXEOracleTopLevelContext {
169
197
  this.logger.debug(`Created account ${completeAddress.address}`);
170
198
  return completeAddress;
171
199
  }
172
- async txeCreateAccount(secret) {
200
+ async createAccount(secret) {
173
201
  // This is a foot gun !
174
202
  const completeAddress = await this.keyStore.addAccount(secret, secret);
175
203
  await this.accountStore.setAccount(completeAddress.address, completeAddress);
@@ -177,18 +205,17 @@ export class TXEOracleTopLevelContext {
177
205
  this.logger.debug(`Created account ${completeAddress.address}`);
178
206
  return completeAddress;
179
207
  }
180
- async txeAddAuthWitness(address, messageHash) {
208
+ async addAuthWitness(address, messageHash) {
181
209
  const account = await this.accountStore.getAccount(address);
182
- const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
210
+ const ivpkMHash = await hashPublicKey(account.publicKeys.ivpkM);
211
+ const privateKey = await this.keyStore.getMasterSecretKey(ivpkMHash);
183
212
  const schnorr = new Schnorr();
184
- const signature = await schnorr.constructSignature(messageHash.toBuffer(), privateKey);
185
- const authWitness = new AuthWitness(messageHash, [
186
- ...signature.toBuffer()
187
- ]);
213
+ const signature = await schnorr.constructSignature(messageHash, privateKey);
214
+ const authWitness = new AuthWitness(messageHash, signature.toLimbFields());
188
215
  this.authwits.set(authWitness.requestHash.toString(), authWitness);
189
216
  }
190
217
  async mineBlock(options = {}) {
191
- const blockNumber = await this.txeGetNextBlockNumber();
218
+ const blockNumber = await this.getNextBlockNumber();
192
219
  const txEffect = TxEffect.empty();
193
220
  txEffect.nullifiers = [
194
221
  getSingleTxBlockRequestHash(blockNumber),
@@ -210,29 +237,26 @@ export class TXEOracleTopLevelContext {
210
237
  this.logger.info(`Created block ${blockNumber} with timestamp ${block.header.globalVariables.timestamp}`);
211
238
  await this.stateMachine.handleL2Block(block);
212
239
  }
213
- async txePrivateCallNewFlow(from, targetContractAddress = AztecAddress.zero(), functionSelector = FunctionSelector.empty(), args, argsHash = Fr.zero(), isStaticCall = false, jobId) {
240
+ async privateCallNewFlow(from, targetContractAddress = AztecAddress.zero(), functionSelector = FunctionSelector.empty(), args, argsHash = Fr.zero(), isStaticCall = false, additionalScopes = [], jobId, authorizedUtilityCallTargets, gasSettings) {
214
241
  this.logger.verbose(`Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`);
215
242
  const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
216
243
  if (!artifact) {
217
244
  const message = functionSelector.equals(await FunctionSelector.fromSignature('verify_private_authwit(Field)')) ? 'Found no account contract artifact for a private authwit check - use `create_contract_account` instead of `create_light_account` for authwit support.' : 'Function Artifact does not exist';
218
245
  throw new Error(message);
219
246
  }
220
- // When `from` is the zero address (e.g. when deploying a new account contract), we return an
221
- // empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
222
- const effectiveScopes = from.isZero() ? [] : [
223
- from
247
+ const scopes = from === undefined ? additionalScopes : [
248
+ from,
249
+ ...additionalScopes
224
250
  ];
225
251
  // Sync notes before executing private function to discover notes from previous transactions
226
252
  const utilityExecutor = async (call, execScopes)=>{
227
253
  await this.executeUtilityCall(call, execScopes, jobId);
228
254
  };
229
255
  const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
230
- await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, utilityExecutor, blockHeader, jobId, effectiveScopes);
231
- const blockNumber = await this.txeGetNextBlockNumber();
232
- const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
233
- const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
234
- const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
235
- const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
256
+ await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, utilityExecutor, blockHeader, jobId, scopes);
257
+ const blockNumber = await this.getNextBlockNumber();
258
+ const msgSender = from ?? AztecAddress.NULL_MSG_SENDER;
259
+ const callContext = new CallContext(msgSender, targetContractAddress, functionSelector, isStaticCall);
236
260
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
237
261
  const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
238
262
  const noteCache = new ExecutionNoteCache(protocolNullifier);
@@ -264,17 +288,22 @@ export class TXEOracleTopLevelContext {
264
288
  senderTaggingStore: this.senderTaggingStore,
265
289
  recipientTaggingStore: this.recipientTaggingStore,
266
290
  senderAddressBookStore: this.senderAddressBookStore,
267
- capsuleStore: this.capsuleStore,
291
+ capsuleService: new CapsuleService(this.capsuleStore, scopes),
268
292
  privateEventStore: this.privateEventStore,
269
293
  contractSyncService: this.stateMachine.contractSyncService,
270
294
  jobId,
271
295
  totalPublicCalldataCount: 0,
272
296
  sideEffectCounter: minRevertibleSideEffectCounter,
273
- scopes: effectiveScopes,
297
+ scopes,
274
298
  // In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
275
299
  // contract would perform, including setting senderForTags.
276
300
  senderForTags: from,
277
- simulator
301
+ simulator,
302
+ messageContextService: this.stateMachine.messageContextService,
303
+ l2TipsStore: this.stateMachine.l2TipsProvider,
304
+ hooks: composeHooks({
305
+ authorizeUtilityCall: this.buildAuthorizeUtilityCallHook(isStaticCall ? 'private view' : 'private', authorizedUtilityCallTargets)
306
+ })
278
307
  });
279
308
  // 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.
280
309
  let result;
@@ -287,7 +316,7 @@ export class TXEOracleTopLevelContext {
287
316
  r.publicInputs.publicTeardownCallRequest
288
317
  ]));
289
318
  const publicFunctionsCalldata = await Promise.all(publicCallRequests.map(async (r)=>{
290
- const calldata = await privateExecutionOracle.privateLoadFromExecutionCache(r.calldataHash);
319
+ const calldata = await privateExecutionOracle.getHashPreimage(r.calldataHash);
291
320
  return new HashedValues(calldata, r.calldataHash);
292
321
  }));
293
322
  noteCache.finish();
@@ -346,10 +375,20 @@ export class TXEOracleTopLevelContext {
346
375
  throw new Error('Contract execution has reverted');
347
376
  }
348
377
  }
378
+ // Walk the nested private-call tree and collect every offchain effect the transaction emitted.
379
+ // PXE stores these on each `PrivateCallExecutionResult` and they never reach TXE via the
380
+ // `aztec_utl_emitOffchainEffect` foreign-call path (that path only fires at the top-level), so
381
+ // we pull them out here and the RPC wrapper will hand them to `TXESession` for buffering.
382
+ const offchainEffects = collectNested([
383
+ executionResult
384
+ ], (r)=>r.offchainEffects.map((e)=>e.data));
349
385
  if (isStaticCall) {
350
386
  await checkpoint.revert();
351
387
  await forkedWorldTrees.close();
352
- return executionResult.returnValues ?? [];
388
+ return {
389
+ returnValues: executionResult.returnValues ?? [],
390
+ offchainEffects
391
+ };
353
392
  }
354
393
  const txEffect = TxEffect.empty();
355
394
  txEffect.noteHashes = processedTx.txEffect.noteHashes;
@@ -365,14 +404,14 @@ export class TXEOracleTopLevelContext {
365
404
  ]);
366
405
  await this.stateMachine.handleL2Block(l2Block);
367
406
  await forkedWorldTrees.close();
368
- return executionResult.returnValues ?? [];
407
+ return {
408
+ returnValues: executionResult.returnValues ?? [],
409
+ offchainEffects
410
+ };
369
411
  }
370
- async txePublicCallNewFlow(from, targetContractAddress, calldata, isStaticCall) {
412
+ async publicCallNewFlow(from, targetContractAddress, calldata, isStaticCall, gasSettings) {
371
413
  this.logger.verbose(`Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`);
372
- const blockNumber = await this.txeGetNextBlockNumber();
373
- const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
374
- const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
375
- const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
414
+ const blockNumber = await this.getNextBlockNumber();
376
415
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
377
416
  const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
378
417
  const calldataHash = await computeCalldataHash(calldata);
@@ -405,7 +444,7 @@ export class TXEOracleTopLevelContext {
405
444
  // The enqueued public call itself we make be revertible so that the public execution is itself revertible, as tests
406
445
  // may require producing reverts.
407
446
  const revertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
408
- revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(from, targetContractAddress, isStaticCall, calldataHash);
447
+ revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(from ?? AztecAddress.NULL_MSG_SENDER, targetContractAddress, isStaticCall, calldataHash);
409
448
  const inputsForPublic = new PartialPrivateTailPublicInputsForPublic(nonRevertibleAccumulatedData, revertibleAccumulatedData, PublicCallRequest.empty());
410
449
  const constantData = new TxConstantData(anchorBlockHeader, txContext, Fr.zero(), Fr.zero());
411
450
  const txData = new PrivateKernelTailCircuitPublicInputs(constantData, /*gasUsed=*/ new Gas(0, 0), /*feePayer=*/ AztecAddress.zero(), /*expirationTimestamp=*/ 0n, inputsForPublic, undefined);
@@ -461,7 +500,7 @@ export class TXEOracleTopLevelContext {
461
500
  await forkedWorldTrees.close();
462
501
  return returnValues ?? [];
463
502
  }
464
- async txeExecuteUtilityFunction(targetContractAddress, functionSelector, args, jobId) {
503
+ async executeUtilityFunction(targetContractAddress, functionSelector, args, jobId, authorizedUtilityCallTargets) {
465
504
  const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
466
505
  if (!artifact) {
467
506
  throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
@@ -470,7 +509,7 @@ export class TXEOracleTopLevelContext {
470
509
  const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
471
510
  await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, async (call, execScopes)=>{
472
511
  await this.executeUtilityCall(call, execScopes, jobId);
473
- }, blockHeader, jobId, 'ALL_SCOPES');
512
+ }, blockHeader, jobId, await this.keyStore.getAccounts());
474
513
  const call = FunctionCall.from({
475
514
  name: artifact.name,
476
515
  to: targetContractAddress,
@@ -481,9 +520,9 @@ export class TXEOracleTopLevelContext {
481
520
  args,
482
521
  returnTypes: []
483
522
  });
484
- return this.executeUtilityCall(call, 'ALL_SCOPES', jobId);
523
+ return this.executeUtilityCall(call, await this.keyStore.getAccounts(), jobId, authorizedUtilityCallTargets);
485
524
  }
486
- async executeUtilityCall(call, scopes, jobId) {
525
+ async executeUtilityCall(call, scopes, jobId, authorizedUtilityCallTargets = []) {
487
526
  const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
488
527
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
489
528
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
@@ -494,6 +533,10 @@ export class TXEOracleTopLevelContext {
494
533
  });
495
534
  try {
496
535
  const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
536
+ const simulator = new WASMSimulator();
537
+ const utilityExecutor = async (syncCall, execScopes)=>{
538
+ await this.executeUtilityCall(syncCall, execScopes, jobId);
539
+ };
497
540
  const oracle = new UtilityExecutionOracle({
498
541
  contractAddress: call.to,
499
542
  authWitnesses: [],
@@ -506,12 +549,20 @@ export class TXEOracleTopLevelContext {
506
549
  aztecNode: this.stateMachine.node,
507
550
  recipientTaggingStore: this.recipientTaggingStore,
508
551
  senderAddressBookStore: this.senderAddressBookStore,
509
- capsuleStore: this.capsuleStore,
552
+ capsuleService: new CapsuleService(this.capsuleStore, scopes),
510
553
  privateEventStore: this.privateEventStore,
554
+ messageContextService: this.stateMachine.messageContextService,
555
+ contractSyncService: this.stateMachine.contractSyncService,
556
+ l2TipsStore: this.stateMachine.l2TipsProvider,
511
557
  jobId,
512
- scopes
558
+ scopes,
559
+ simulator,
560
+ hooks: composeHooks({
561
+ authorizeUtilityCall: this.buildAuthorizeUtilityCallHook('utility', authorizedUtilityCallTargets)
562
+ }),
563
+ utilityExecutor
513
564
  });
514
- const acirExecutionResult = await new WASMSimulator().executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback()).catch((err)=>{
565
+ const acirExecutionResult = await simulator.executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback()).catch((err)=>{
515
566
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
516
567
  throw new ExecutionError(err.message, {
517
568
  contractAddress: call.to,
@@ -534,7 +585,15 @@ export class TXEOracleTopLevelContext {
534
585
  ];
535
586
  }
536
587
  async getLastBlockNumber() {
537
- const header = await this.stateMachine.node.getBlockHeader('latest');
538
- return header ? header.globalVariables.blockNumber : BlockNumber.ZERO;
588
+ const block = await this.stateMachine.node.getBlock('latest');
589
+ return block ? block.header.globalVariables.blockNumber : BlockNumber.ZERO;
590
+ }
591
+ buildAuthorizeUtilityCallHook(callerContext, authorizedTargets) {
592
+ if (authorizedTargets.length === 0) {
593
+ return undefined;
594
+ }
595
+ return (req)=>Promise.resolve({
596
+ authorized: req.callerContext === callerContext && authorizedTargets.some((t)=>t.equals(req.target))
597
+ });
539
598
  }
540
599
  }
@@ -0,0 +1,17 @@
1
+ import type { Fr } from '@aztec/foundation/curves/bn254';
2
+ import { PrivateExecutionOracle } from '@aztec/pxe/simulator';
3
+ import type { FunctionSelector } from '@aztec/stdlib/abi';
4
+ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
5
+ /**
6
+ * TXE-specific subclass of PrivateExecutionOracle that forbids operations not supported in
7
+ * TestEnvironment::private_context. TXE uses dedicated oracle flows (e.g. private_call) instead.
8
+ */
9
+ export declare class TXEPrivateExecutionOracle extends PrivateExecutionOracle {
10
+ callPrivateFunction(_targetContractAddress: AztecAddress, _functionSelector: FunctionSelector, _argsHash: Fr, _sideEffectCounter: number, _isStaticCall: boolean): Promise<{
11
+ endSideEffectCounter: Fr;
12
+ returnsHash: Fr;
13
+ }>;
14
+ assertValidPublicCalldata(_calldataHash: Fr): Promise<void>;
15
+ notifyRevertiblePhaseStart(_minRevertibleSideEffectCounter: number): Promise<void>;
16
+ }
17
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHhlX3ByaXZhdGVfZXhlY3V0aW9uX29yYWNsZS5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL29yYWNsZS90eGVfcHJpdmF0ZV9leGVjdXRpb25fb3JhY2xlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLEVBQUUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ3pELE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzlELE9BQU8sS0FBSyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDMUQsT0FBTyxLQUFLLEVBQUUsWUFBWSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFFaEU7OztHQUdHO0FBQ0gscUJBQWEseUJBQTBCLFNBQVEsc0JBQXNCO0lBQzFELG1CQUFtQixDQUMxQixzQkFBc0IsRUFBRSxZQUFZLEVBQ3BDLGlCQUFpQixFQUFFLGdCQUFnQixFQUNuQyxTQUFTLEVBQUUsRUFBRSxFQUNiLGtCQUFrQixFQUFFLE1BQU0sRUFDMUIsYUFBYSxFQUFFLE9BQU8sR0FDckIsT0FBTyxDQUFDO1FBQUUsb0JBQW9CLEVBQUUsRUFBRSxDQUFDO1FBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQTtLQUFFLENBQUMsQ0FJeEQ7SUFFUSx5QkFBeUIsQ0FBQyxhQUFhLEVBQUUsRUFBRSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FFbkU7SUFFUSwwQkFBMEIsQ0FBQywrQkFBK0IsRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUUxRjtDQUNGIn0=
@@ -0,0 +1 @@
1
+ {"version":3,"file":"txe_private_execution_oracle.d.ts","sourceRoot":"","sources":["../../src/oracle/txe_private_execution_oracle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEhE;;;GAGG;AACH,qBAAa,yBAA0B,SAAQ,sBAAsB;IAC1D,mBAAmB,CAC1B,sBAAsB,EAAE,YAAY,EACpC,iBAAiB,EAAE,gBAAgB,EACnC,SAAS,EAAE,EAAE,EACb,kBAAkB,EAAE,MAAM,EAC1B,aAAa,EAAE,OAAO,GACrB,OAAO,CAAC;QAAE,oBAAoB,EAAE,EAAE,CAAC;QAAC,WAAW,EAAE,EAAE,CAAA;KAAE,CAAC,CAIxD;IAEQ,yBAAyB,CAAC,aAAa,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAEnE;IAEQ,0BAA0B,CAAC,+BAA+B,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE1F;CACF"}
@@ -0,0 +1,15 @@
1
+ import { PrivateExecutionOracle } from '@aztec/pxe/simulator';
2
+ /**
3
+ * TXE-specific subclass of PrivateExecutionOracle that forbids operations not supported in
4
+ * TestEnvironment::private_context. TXE uses dedicated oracle flows (e.g. private_call) instead.
5
+ */ export class TXEPrivateExecutionOracle extends PrivateExecutionOracle {
6
+ callPrivateFunction(_targetContractAddress, _functionSelector, _argsHash, _sideEffectCounter, _isStaticCall) {
7
+ throw new Error('Contract calls are forbidden inside a `TestEnvironment::private_context`, use `private_call` instead');
8
+ }
9
+ assertValidPublicCalldata(_calldataHash) {
10
+ throw new Error('Enqueueing public calls is not supported in TestEnvironment::private_context');
11
+ }
12
+ notifyRevertiblePhaseStart(_minRevertibleSideEffectCounter) {
13
+ throw new Error('Enqueueing public calls is not supported in TestEnvironment::private_context');
14
+ }
15
+ }
@@ -0,0 +1,14 @@
1
+ import type { Logger } from '@aztec/foundation/log';
2
+ /**
3
+ * Creates the TXE RPC server. With `TXE_WORKERS=1` oracle calls run on the main thread (no
4
+ * worker_threads, no IPC overhead). With any other value oracle calls are
5
+ * routed to a pool of worker threads sized to that value, sticky by `session_id`.
6
+ *
7
+ * Each incoming TCP socket is tagged with the `session_id` of the first oracle call it carries —
8
+ * nargo uses one HTTP client per test, so the socket-to-session mapping is 1:1. When the socket
9
+ * closes (end of test), the dispatcher disposes the session and frees its world state + LMDB.
10
+ *
11
+ * Lives in its own module so the worker bundle does not pull in the HTTP server stack.
12
+ */
13
+ export declare function createTXERpcServer(logger: Logger): Promise<import("@aztec/foundation/json-rpc/server").SafeJsonRpcServer>;
14
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnBjX3NlcnZlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3JwY19zZXJ2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFlcEQ7Ozs7Ozs7Ozs7R0FVRztBQUNILHdCQUFzQixrQkFBa0IsQ0FBQyxNQUFNLEVBQUUsTUFBTSwwRUE0Q3REIn0=
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rpc_server.d.ts","sourceRoot":"","sources":["../src/rpc_server.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAepD;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,0EA4CtD"}
@@ -0,0 +1,78 @@
1
+ import { createSafeJsonRpcServer } from '@aztec/foundation/json-rpc/server';
2
+ import { TXEDispatcherPool, buildSharedContractStore } from './dispatcher_pool.js';
3
+ import { TXEDispatcher, TXEDispatcherApiSchema } from './index.js';
4
+ /**
5
+ * Symbol used to tag an incoming TCP socket with the `session_id` it has been associated with.
6
+ * Hidden under a Symbol so we don't risk colliding with anything koa or http core adds.
7
+ */ const SESSION_SYMBOL = Symbol('txeSessionId');
8
+ /**
9
+ * Creates the TXE RPC server. With `TXE_WORKERS=1` oracle calls run on the main thread (no
10
+ * worker_threads, no IPC overhead). With any other value oracle calls are
11
+ * routed to a pool of worker threads sized to that value, sticky by `session_id`.
12
+ *
13
+ * Each incoming TCP socket is tagged with the `session_id` of the first oracle call it carries —
14
+ * nargo uses one HTTP client per test, so the socket-to-session mapping is 1:1. When the socket
15
+ * closes (end of test), the dispatcher disposes the session and frees its world state + LMDB.
16
+ *
17
+ * Lives in its own module so the worker bundle does not pull in the HTTP server stack.
18
+ */ export async function createTXERpcServer(logger) {
19
+ const workerCount = Number(process.env.TXE_WORKERS);
20
+ let dispatcher;
21
+ if (workerCount === 1) {
22
+ const { dataDir, schnorrClassId } = await buildSharedContractStore();
23
+ dispatcher = new TXEDispatcher(logger, {
24
+ contractStoreSourceDir: dataDir,
25
+ schnorrClassId
26
+ });
27
+ } else {
28
+ dispatcher = new TXEDispatcherPool(logger, {
29
+ workers: Number.isFinite(workerCount) && workerCount > 1 ? workerCount : undefined
30
+ });
31
+ }
32
+ const server = createSafeJsonRpcServer(dispatcher, TXEDispatcherApiSchema, {
33
+ http200OnError: true,
34
+ middlewares: [
35
+ async (ctx, next)=>{
36
+ // The body parser runs further down the chain, so `ctx.request.body` is populated only
37
+ // after `next()` resolves.
38
+ await next();
39
+ const socket = ctx.req.socket;
40
+ if (socket[SESSION_SYMBOL] !== undefined) {
41
+ return;
42
+ }
43
+ const body = ctx.request.body;
44
+ const sessionId = body && typeof body === 'object' && 'params' in body ? extractSessionId(body.params) : undefined;
45
+ if (sessionId === undefined) {
46
+ return;
47
+ }
48
+ socket[SESSION_SYMBOL] = sessionId;
49
+ logger.debug(`Tagged socket with session`, {
50
+ sessionId,
51
+ remoteAddress: socket.remoteAddress,
52
+ remotePort: socket.remotePort
53
+ });
54
+ socket.once('close', ()=>{
55
+ logger.debug(`Disposing session on socket close`, {
56
+ sessionId
57
+ });
58
+ void dispatcher.disposeSession(sessionId);
59
+ });
60
+ }
61
+ ]
62
+ });
63
+ return server;
64
+ }
65
+ // Extracts `session_id` from a JSON-RPC `params` array. Always a `number` because session_id
66
+ // comes off `JSON.parse`, which never produces BigInt; values above MAX_SAFE_INTEGER lose
67
+ // precision but still work as a Map key.
68
+ function extractSessionId(params) {
69
+ if (!Array.isArray(params) || params.length === 0) {
70
+ return undefined;
71
+ }
72
+ const first = params[0];
73
+ if (first && typeof first === 'object' && 'session_id' in first) {
74
+ const sid = first.session_id;
75
+ return typeof sid === 'number' ? sid : undefined;
76
+ }
77
+ return undefined;
78
+ }