@aztec/txe 0.0.1-commit.b6e433891 → 0.0.1-commit.b9865e97

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 (148) hide show
  1. package/dest/ContractClassRegistry-PII7Q556.js +3 -0
  2. package/dest/ContractClassRegistry-PII7Q556.js.map +7 -0
  3. package/dest/ContractInstanceRegistry-3MHLGFNZ.js +3 -0
  4. package/dest/ContractInstanceRegistry-3MHLGFNZ.js.map +7 -0
  5. package/dest/FeeJuice-TQV5AQK7.js +3 -0
  6. package/dest/FeeJuice-TQV5AQK7.js.map +7 -0
  7. package/dest/MultiCallEntrypoint-SBJUIJY7.js +3 -0
  8. package/dest/MultiCallEntrypoint-SBJUIJY7.js.map +7 -0
  9. package/dest/SchnorrAccount-MQXPIZ44.js +3 -0
  10. package/dest/SchnorrAccount-MQXPIZ44.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 +61 -0
  14. package/dest/bin/index.js +3 -30
  15. package/dest/bin/index.js.map +7 -0
  16. package/dest/bin/oracle_test_server.d.ts +3 -0
  17. package/dest/bin/oracle_test_server.d.ts.map +1 -0
  18. package/dest/bin/oracle_test_server.js +41 -0
  19. package/dest/chunk-BJVAAXNA.js +3 -0
  20. package/dest/chunk-BJVAAXNA.js.map +7 -0
  21. package/dest/chunk-CUSVOJA4.js +304 -0
  22. package/dest/chunk-CUSVOJA4.js.map +7 -0
  23. package/dest/chunk-OYLIPWI6.js +260 -0
  24. package/dest/chunk-OYLIPWI6.js.map +7 -0
  25. package/dest/constants.d.ts +5 -1
  26. package/dest/constants.d.ts.map +1 -1
  27. package/dest/constants.js +8 -0
  28. package/dest/dispatcher_pool.d.ts +67 -0
  29. package/dest/dispatcher_pool.d.ts.map +1 -0
  30. package/dest/dispatcher_pool.js +284 -0
  31. package/dest/index.d.ts +185 -7
  32. package/dest/index.d.ts.map +1 -1
  33. package/dest/index.js +70 -190
  34. package/dest/metafile.json +36863 -0
  35. package/dest/msgpackr_fr_extension.d.ts +2 -0
  36. package/dest/msgpackr_fr_extension.d.ts.map +1 -0
  37. package/dest/msgpackr_fr_extension.js +21 -0
  38. package/dest/oracle/interfaces.d.ts +33 -8
  39. package/dest/oracle/interfaces.d.ts.map +1 -1
  40. package/dest/oracle/test-resolver/fixtures.d.ts +43 -0
  41. package/dest/oracle/test-resolver/fixtures.d.ts.map +1 -0
  42. package/dest/oracle/test-resolver/fixtures.js +39 -0
  43. package/dest/oracle/test-resolver/index.d.ts +9 -0
  44. package/dest/oracle/test-resolver/index.d.ts.map +1 -0
  45. package/dest/oracle/test-resolver/index.js +33 -0
  46. package/dest/oracle/test-resolver/resolver.d.ts +34 -0
  47. package/dest/oracle/test-resolver/resolver.d.ts.map +1 -0
  48. package/dest/oracle/test-resolver/resolver.js +114 -0
  49. package/dest/oracle/txe_oracle_public_context.d.ts +26 -2
  50. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  51. package/dest/oracle/txe_oracle_public_context.js +43 -1
  52. package/dest/oracle/txe_oracle_registry.d.ts +147 -0
  53. package/dest/oracle/txe_oracle_registry.d.ts.map +1 -0
  54. package/dest/oracle/txe_oracle_registry.js +562 -0
  55. package/dest/oracle/txe_oracle_top_level_context.d.ts +33 -14
  56. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  57. package/dest/oracle/txe_oracle_top_level_context.js +149 -60
  58. package/dest/oracle/txe_oracle_version.d.ts +17 -0
  59. package/dest/oracle/txe_oracle_version.d.ts.map +1 -0
  60. package/dest/oracle/txe_oracle_version.js +14 -0
  61. package/dest/oracle/txe_private_execution_oracle.d.ts +17 -0
  62. package/dest/oracle/txe_private_execution_oracle.d.ts.map +1 -0
  63. package/dest/oracle/txe_private_execution_oracle.js +15 -0
  64. package/dest/rpc_server.d.ts +14 -0
  65. package/dest/rpc_server.d.ts.map +1 -0
  66. package/dest/rpc_server.js +78 -0
  67. package/dest/rpc_translator.d.ts +96 -233
  68. package/dest/rpc_translator.d.ts.map +1 -1
  69. package/dest/rpc_translator.js +706 -637
  70. package/dest/server.bundle.js +3 -0
  71. package/dest/server.bundle.js.map +7 -0
  72. package/dest/state_machine/archiver.d.ts +4 -3
  73. package/dest/state_machine/archiver.d.ts.map +1 -1
  74. package/dest/state_machine/archiver.js +26 -15
  75. package/dest/state_machine/dummy_p2p_client.d.ts +13 -7
  76. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  77. package/dest/state_machine/dummy_p2p_client.js +16 -4
  78. package/dest/state_machine/global_variable_builder.d.ts +9 -4
  79. package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
  80. package/dest/state_machine/global_variable_builder.js +9 -3
  81. package/dest/state_machine/index.d.ts +4 -2
  82. package/dest/state_machine/index.d.ts.map +1 -1
  83. package/dest/state_machine/index.js +17 -3
  84. package/dest/state_machine/mock_epoch_cache.d.ts +1 -2
  85. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  86. package/dest/state_machine/mock_epoch_cache.js +0 -3
  87. package/dest/state_machine/synchronizer.js +1 -1
  88. package/dest/txe_session.d.ts +75 -14
  89. package/dest/txe_session.d.ts.map +1 -1
  90. package/dest/txe_session.js +170 -41
  91. package/dest/utils/encoding.d.ts +191 -0
  92. package/dest/utils/encoding.d.ts.map +1 -0
  93. package/dest/{util → utils}/encoding.js +7 -2
  94. package/dest/{util → utils}/expected_failure_error.d.ts +1 -1
  95. package/dest/utils/expected_failure_error.d.ts.map +1 -0
  96. package/dest/{util → utils}/txe_account_store.d.ts +1 -1
  97. package/dest/utils/txe_account_store.d.ts.map +1 -0
  98. package/dest/utils/txe_artifact_resolver.d.ts +37 -0
  99. package/dest/utils/txe_artifact_resolver.d.ts.map +1 -0
  100. package/dest/utils/txe_artifact_resolver.js +161 -0
  101. package/dest/utils/txe_public_contract_data_source.d.ts +20 -0
  102. package/dest/utils/txe_public_contract_data_source.d.ts.map +1 -0
  103. package/dest/{util → utils}/txe_public_contract_data_source.js +1 -3
  104. package/dest/worker.bundle.js +3 -0
  105. package/dest/worker.bundle.js.map +7 -0
  106. package/dest/worker.d.ts +2 -0
  107. package/dest/worker.d.ts.map +1 -0
  108. package/dest/worker.js +92 -0
  109. package/package.json +38 -21
  110. package/src/bin/check_txe_oracle_version.ts +70 -0
  111. package/src/bin/index.ts +11 -2
  112. package/src/bin/oracle_test_server.ts +51 -0
  113. package/src/constants.ts +10 -0
  114. package/src/dispatcher_pool.ts +316 -0
  115. package/src/index.ts +97 -227
  116. package/src/msgpackr_fr_extension.ts +23 -0
  117. package/src/oracle/interfaces.ts +29 -7
  118. package/src/oracle/test-resolver/fixtures.ts +84 -0
  119. package/src/oracle/test-resolver/index.ts +45 -0
  120. package/src/oracle/test-resolver/resolver.ts +165 -0
  121. package/src/oracle/txe_oracle_public_context.ts +60 -0
  122. package/src/oracle/txe_oracle_registry.ts +401 -0
  123. package/src/oracle/txe_oracle_top_level_context.ts +180 -67
  124. package/src/oracle/txe_oracle_version.ts +17 -0
  125. package/src/oracle/txe_private_execution_oracle.ts +30 -0
  126. package/src/rpc_server.ts +87 -0
  127. package/src/rpc_translator.ts +787 -925
  128. package/src/state_machine/archiver.ts +38 -16
  129. package/src/state_machine/dummy_p2p_client.ts +31 -11
  130. package/src/state_machine/global_variable_builder.ts +18 -3
  131. package/src/state_machine/index.ts +20 -5
  132. package/src/state_machine/mock_epoch_cache.ts +0 -4
  133. package/src/state_machine/synchronizer.ts +1 -1
  134. package/src/txe_session.ts +278 -45
  135. package/src/{util → utils}/encoding.ts +8 -2
  136. package/src/utils/txe_artifact_resolver.ts +217 -0
  137. package/src/{util → utils}/txe_public_contract_data_source.ts +0 -2
  138. package/src/worker.ts +98 -0
  139. package/dest/util/encoding.d.ts +0 -720
  140. package/dest/util/encoding.d.ts.map +0 -1
  141. package/dest/util/expected_failure_error.d.ts.map +0 -1
  142. package/dest/util/txe_account_store.d.ts.map +0 -1
  143. package/dest/util/txe_public_contract_data_source.d.ts +0 -20
  144. package/dest/util/txe_public_contract_data_source.d.ts.map +0 -1
  145. /package/dest/{util → utils}/expected_failure_error.js +0 -0
  146. /package/dest/{util → utils}/txe_account_store.js +0 -0
  147. /package/src/{util → utils}/expected_failure_error.ts +0 -0
  148. /package/src/{util → utils}/txe_account_store.ts +0 -0
@@ -1,29 +1,30 @@
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
- import { CppPublicTxSimulator, GuardedMerkleTreeOperations, PublicContractsDB, PublicProcessor } from '@aztec/simulator/server';
10
+ import { GuardedMerkleTreeOperations, PublicContractsDB, PublicProcessor, PublicTxSimulator } from '@aztec/simulator/server';
11
11
  import { FunctionCall, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
12
12
  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 { DEFAULT_ADDRESS } from '../constants.js';
25
- import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
24
+ import { ForkCheckpoint } from '@aztec/world-state/native';
25
+ import { DEFAULT_ADDRESS, MAX_PRIVATE_EVENTS_PER_TXE_QUERY, MAX_PRIVATE_EVENT_LEN } from '../constants.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;
@@ -40,11 +41,13 @@ export class TXEOracleTopLevelContext {
40
41
  version;
41
42
  chainId;
42
43
  authwits;
43
- contractSyncService;
44
+ artifactResolver;
45
+ rootPath;
46
+ packageName;
44
47
  isMisc;
45
48
  isTxe;
46
49
  logger;
47
- constructor(stateMachine, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore, senderAddressBookStore, capsuleStore, privateEventStore, nextBlockTimestamp, version, chainId, authwits, contractSyncService){
50
+ constructor(stateMachine, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore, senderAddressBookStore, capsuleStore, privateEventStore, nextBlockTimestamp, version, chainId, authwits, artifactResolver, rootPath, packageName){
48
51
  this.stateMachine = stateMachine;
49
52
  this.contractStore = contractStore;
50
53
  this.noteStore = noteStore;
@@ -60,16 +63,28 @@ export class TXEOracleTopLevelContext {
60
63
  this.version = version;
61
64
  this.chainId = chainId;
62
65
  this.authwits = authwits;
63
- this.contractSyncService = contractSyncService;
66
+ this.artifactResolver = artifactResolver;
67
+ this.rootPath = rootPath;
68
+ this.packageName = packageName;
64
69
  this.isMisc = true;
65
70
  this.isTxe = true;
66
71
  this.logger = createLogger('txe:top_level_context');
67
72
  this.logger.debug('Entering Top Level Context');
68
73
  }
69
- assertCompatibleOracleVersion(version) {
70
- if (version !== ORACLE_VERSION) {
71
- throw new Error(`Incompatible oracle version. TXE is using version '${ORACLE_VERSION}', but got a request for '${version}'.`);
74
+ contractOracleVersion;
75
+ assertCompatibleOracleVersion(major, minor) {
76
+ if (major !== ORACLE_VERSION_MAJOR) {
77
+ 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.';
78
+ throw new Error(`Incompatible aztec cli version: ${hint} See https://docs.aztec.network/errors/8 (expected oracle major version ${ORACLE_VERSION_MAJOR}, got ${major})`);
72
79
  }
80
+ this.contractOracleVersion = {
81
+ major,
82
+ minor
83
+ };
84
+ }
85
+ // Prefixed with "nonOracleFunction" as it is not used as an oracle handler.
86
+ nonOracleFunctionGetContractOracleVersion() {
87
+ return this.contractOracleVersion;
73
88
  }
74
89
  // This is typically only invoked in private contexts, but it is convenient to also have it in top-level for testing
75
90
  // setup.
@@ -77,7 +92,7 @@ export class TXEOracleTopLevelContext {
77
92
  return Fr.random();
78
93
  }
79
94
  // We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
80
- log(level, message, fields) {
95
+ log(level, message, _fieldsSize, fields) {
81
96
  if (!LogLevels[level]) {
82
97
  throw new Error(`Invalid log level: ${level}`);
83
98
  }
@@ -97,20 +112,27 @@ export class TXEOracleTopLevelContext {
97
112
  return Promise.resolve(this.nextBlockTimestamp);
98
113
  }
99
114
  async getLastBlockTimestamp() {
100
- return (await this.stateMachine.node.getBlockHeader('latest')).globalVariables.timestamp;
115
+ return (await this.stateMachine.node.getBlockData('latest')).header.globalVariables.timestamp;
101
116
  }
102
117
  async getLastTxEffects() {
103
118
  const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
104
- const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
119
+ const block = await this.stateMachine.archiver.getBlock({
120
+ number: latestBlockNumber
121
+ });
105
122
  if (block.body.txEffects.length != 1) {
106
123
  // Note that calls like env.mine() will result in blocks with no transactions, hitting this
107
124
  throw new Error(`Expected a single transaction in the last block, found ${block.body.txEffects.length}`);
108
125
  }
109
126
  const txEffects = block.body.txEffects[0];
127
+ const privateLogs = txEffects.privateLogs;
128
+ if (privateLogs.length > MAX_PRIVATE_LOGS_PER_TX) {
129
+ throw new Error(`${privateLogs.length} private logs exceed max ${MAX_PRIVATE_LOGS_PER_TX}`);
130
+ }
110
131
  return {
111
132
  txHash: txEffects.txHash,
112
133
  noteHashes: txEffects.noteHashes,
113
- nullifiers: txEffects.nullifiers
134
+ nullifiers: txEffects.nullifiers,
135
+ privateLogs
114
136
  };
115
137
  }
116
138
  async syncContractNonOracleMethod(contractAddress, scope, jobId) {
@@ -126,7 +148,7 @@ export class TXEOracleTopLevelContext {
126
148
  ]);
127
149
  }
128
150
  async getPrivateEvents(selector, contractAddress, scope) {
129
- return (await this.privateEventStore.getPrivateEvents(selector, {
151
+ const events = (await this.privateEventStore.getPrivateEvents(selector, {
130
152
  contractAddress,
131
153
  scopes: [
132
154
  scope
@@ -134,6 +156,13 @@ export class TXEOracleTopLevelContext {
134
156
  fromBlock: 0,
135
157
  toBlock: await this.getLastBlockNumber() + 1
136
158
  })).map((e)=>e.packedEvent);
159
+ if (events.length > MAX_PRIVATE_EVENTS_PER_TXE_QUERY) {
160
+ throw new Error(`Array of length ${events.length} larger than maxLen ${MAX_PRIVATE_EVENTS_PER_TXE_QUERY}`);
161
+ }
162
+ if (events.some((e)=>e.length > MAX_PRIVATE_EVENT_LEN)) {
163
+ throw new Error(`Some private event has length larger than maxLen ${MAX_PRIVATE_EVENT_LEN}`);
164
+ }
165
+ return events;
137
166
  }
138
167
  async advanceBlocksBy(blocks) {
139
168
  this.logger.debug(`time traveling ${blocks} blocks`);
@@ -145,22 +174,54 @@ export class TXEOracleTopLevelContext {
145
174
  this.logger.debug(`time traveling ${duration} seconds`);
146
175
  this.nextBlockTimestamp += duration;
147
176
  }
148
- async deploy(artifact, instance, secret) {
177
+ deploymentNullifier(address) {
178
+ return siloNullifier(AztecAddress.fromNumber(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS), address.toField());
179
+ }
180
+ async deploy(contractPath, initializer, args, secret, salt, deployer) {
181
+ const { artifact, instance } = await this.artifactResolver.resolveDeployArtifact({
182
+ rootPath: this.rootPath,
183
+ packageName: this.packageName,
184
+ contractPath,
185
+ initializer,
186
+ args,
187
+ secret,
188
+ salt,
189
+ deployer
190
+ });
149
191
  // Emit deployment nullifier
150
192
  await this.mineBlock({
151
193
  nullifiers: [
152
- await siloNullifier(AztecAddress.fromNumber(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS), instance.address.toField())
194
+ await this.deploymentNullifier(instance.address)
153
195
  ]
154
196
  });
155
197
  if (!secret.equals(Fr.ZERO)) {
156
- await this.addAccount(artifact, instance, secret);
198
+ await this.registerContractAndAddAccount(artifact, instance, secret);
157
199
  } else {
158
200
  await this.contractStore.addContractInstance(instance);
159
201
  await this.contractStore.addContractArtifact(artifact);
160
202
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
161
203
  }
204
+ return [
205
+ instance.salt,
206
+ instance.deployer.toField(),
207
+ instance.currentContractClassId,
208
+ instance.initializationHash,
209
+ instance.immutablesHash,
210
+ ...instance.publicKeys.toFields()
211
+ ];
162
212
  }
163
- async addAccount(artifact, instance, secret) {
213
+ /**
214
+ * Mines a single block containing only the deployment nullifiers for the contracts at the given addresses.
215
+ */ async mineDeploymentNullifiers(addresses) {
216
+ await this.mineBlock({
217
+ nullifiers: await Promise.all(addresses.map((address)=>this.deploymentNullifier(address)))
218
+ });
219
+ }
220
+ async addAccount(secret) {
221
+ const { artifact, instance } = await this.artifactResolver.resolveAccountArtifact(secret);
222
+ return this.registerContractAndAddAccount(artifact, instance, secret);
223
+ }
224
+ async registerContractAndAddAccount(artifact, instance, secret) {
164
225
  const partialAddress = await computePartialAddress(instance);
165
226
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
166
227
  await this.contractStore.addContractInstance(instance);
@@ -181,12 +242,11 @@ export class TXEOracleTopLevelContext {
181
242
  }
182
243
  async addAuthWitness(address, messageHash) {
183
244
  const account = await this.accountStore.getAccount(address);
184
- const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
245
+ const ivpkMHash = await hashPublicKey(account.publicKeys.ivpkM);
246
+ const privateKey = await this.keyStore.getMasterSecretKey(ivpkMHash);
185
247
  const schnorr = new Schnorr();
186
- const signature = await schnorr.constructSignature(messageHash.toBuffer(), privateKey);
187
- const authWitness = new AuthWitness(messageHash, [
188
- ...signature.toBuffer()
189
- ]);
248
+ const signature = await schnorr.constructSignature(messageHash, privateKey);
249
+ const authWitness = new AuthWitness(messageHash, signature.toLimbFields());
190
250
  this.authwits.set(authWitness.requestHash.toString(), authWitness);
191
251
  }
192
252
  async mineBlock(options = {}) {
@@ -212,29 +272,26 @@ export class TXEOracleTopLevelContext {
212
272
  this.logger.info(`Created block ${blockNumber} with timestamp ${block.header.globalVariables.timestamp}`);
213
273
  await this.stateMachine.handleL2Block(block);
214
274
  }
215
- async privateCallNewFlow(from, targetContractAddress = AztecAddress.zero(), functionSelector = FunctionSelector.empty(), args, argsHash = Fr.zero(), isStaticCall = false, jobId) {
275
+ async privateCallNewFlow(from, targetContractAddress = AztecAddress.zero(), functionSelector = FunctionSelector.empty(), args, argsHash = Fr.zero(), isStaticCall = false, additionalScopes = [], jobId, authorizedUtilityCallTargets, gasSettings) {
216
276
  this.logger.verbose(`Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`);
217
277
  const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
218
278
  if (!artifact) {
219
279
  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';
220
280
  throw new Error(message);
221
281
  }
222
- // When `from` is the zero address (e.g. when deploying a new account contract), we return an
223
- // empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
224
- const effectiveScopes = from.isZero() ? [] : [
225
- from
282
+ const scopes = from === undefined ? additionalScopes : [
283
+ from,
284
+ ...additionalScopes
226
285
  ];
227
286
  // Sync notes before executing private function to discover notes from previous transactions
228
287
  const utilityExecutor = async (call, execScopes)=>{
229
288
  await this.executeUtilityCall(call, execScopes, jobId);
230
289
  };
231
290
  const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
232
- await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, utilityExecutor, blockHeader, jobId, effectiveScopes);
291
+ await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, utilityExecutor, blockHeader, jobId, scopes);
233
292
  const blockNumber = await this.getNextBlockNumber();
234
- const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
235
- const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
236
- const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
237
- const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
293
+ const msgSender = from ?? AztecAddress.NULL_MSG_SENDER;
294
+ const callContext = new CallContext(msgSender, targetContractAddress, functionSelector, isStaticCall);
238
295
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
239
296
  const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
240
297
  const noteCache = new ExecutionNoteCache(protocolNullifier);
@@ -266,18 +323,22 @@ export class TXEOracleTopLevelContext {
266
323
  senderTaggingStore: this.senderTaggingStore,
267
324
  recipientTaggingStore: this.recipientTaggingStore,
268
325
  senderAddressBookStore: this.senderAddressBookStore,
269
- capsuleStore: this.capsuleStore,
326
+ capsuleService: new CapsuleService(this.capsuleStore, scopes),
270
327
  privateEventStore: this.privateEventStore,
271
328
  contractSyncService: this.stateMachine.contractSyncService,
272
329
  jobId,
273
330
  totalPublicCalldataCount: 0,
274
331
  sideEffectCounter: minRevertibleSideEffectCounter,
275
- scopes: effectiveScopes,
332
+ scopes,
276
333
  // In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
277
334
  // contract would perform, including setting senderForTags.
278
335
  senderForTags: from,
279
336
  simulator,
280
- messageContextService: this.stateMachine.messageContextService
337
+ messageContextService: this.stateMachine.messageContextService,
338
+ l2TipsStore: this.stateMachine.l2TipsProvider,
339
+ hooks: composeHooks({
340
+ authorizeUtilityCall: this.buildAuthorizeUtilityCallHook(isStaticCall ? 'private view' : 'private', authorizedUtilityCallTargets)
341
+ })
281
342
  });
282
343
  // 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.
283
344
  let result;
@@ -290,7 +351,7 @@ export class TXEOracleTopLevelContext {
290
351
  r.publicInputs.publicTeardownCallRequest
291
352
  ]));
292
353
  const publicFunctionsCalldata = await Promise.all(publicCallRequests.map(async (r)=>{
293
- const calldata = await privateExecutionOracle.loadFromExecutionCache(r.calldataHash);
354
+ const calldata = await privateExecutionOracle.getHashPreimage(r.calldataHash);
294
355
  return new HashedValues(calldata, r.calldataHash);
295
356
  }));
296
357
  noteCache.finish();
@@ -320,7 +381,7 @@ export class TXEOracleTopLevelContext {
320
381
  collectStatistics: false,
321
382
  collectCallMetadata: true
322
383
  });
323
- const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings), new TestDateProvider(), undefined, createLogger('simulator:public-processor', bindings));
384
+ const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings), new TestDateProvider(), undefined, createLogger('simulator:public-processor', bindings));
324
385
  const tx = await Tx.create({
325
386
  data: publicInputs,
326
387
  chonkProof: ChonkProof.empty(),
@@ -349,10 +410,20 @@ export class TXEOracleTopLevelContext {
349
410
  throw new Error('Contract execution has reverted');
350
411
  }
351
412
  }
413
+ // Walk the nested private-call tree and collect every offchain effect the transaction emitted.
414
+ // PXE stores these on each `PrivateCallExecutionResult` and they never reach TXE via the
415
+ // `aztec_utl_emitOffchainEffect` foreign-call path (that path only fires at the top-level), so
416
+ // we pull them out here and the RPC wrapper will hand them to `TXESession` for buffering.
417
+ const offchainEffects = collectNested([
418
+ executionResult
419
+ ], (r)=>r.offchainEffects.map((e)=>e.data));
352
420
  if (isStaticCall) {
353
421
  await checkpoint.revert();
354
422
  await forkedWorldTrees.close();
355
- return executionResult.returnValues ?? [];
423
+ return {
424
+ returnValues: executionResult.returnValues ?? [],
425
+ offchainEffects
426
+ };
356
427
  }
357
428
  const txEffect = TxEffect.empty();
358
429
  txEffect.noteHashes = processedTx.txEffect.noteHashes;
@@ -368,14 +439,14 @@ export class TXEOracleTopLevelContext {
368
439
  ]);
369
440
  await this.stateMachine.handleL2Block(l2Block);
370
441
  await forkedWorldTrees.close();
371
- return executionResult.returnValues ?? [];
442
+ return {
443
+ returnValues: executionResult.returnValues ?? [],
444
+ offchainEffects
445
+ };
372
446
  }
373
- async publicCallNewFlow(from, targetContractAddress, calldata, isStaticCall) {
447
+ async publicCallNewFlow(from, targetContractAddress, calldata, isStaticCall, gasSettings) {
374
448
  this.logger.verbose(`Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`);
375
449
  const blockNumber = await this.getNextBlockNumber();
376
- const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
377
- const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
378
- const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
379
450
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
380
451
  const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
381
452
  const calldataHash = await computeCalldataHash(calldata);
@@ -397,7 +468,7 @@ export class TXEOracleTopLevelContext {
397
468
  collectStatistics: false,
398
469
  collectCallMetadata: true
399
470
  });
400
- const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
471
+ const simulator = new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
401
472
  const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider(), undefined, createLogger('simulator:public-processor', bindings2));
402
473
  // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
403
474
  // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
@@ -408,7 +479,7 @@ export class TXEOracleTopLevelContext {
408
479
  // The enqueued public call itself we make be revertible so that the public execution is itself revertible, as tests
409
480
  // may require producing reverts.
410
481
  const revertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
411
- revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(from, targetContractAddress, isStaticCall, calldataHash);
482
+ revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(from ?? AztecAddress.NULL_MSG_SENDER, targetContractAddress, isStaticCall, calldataHash);
412
483
  const inputsForPublic = new PartialPrivateTailPublicInputsForPublic(nonRevertibleAccumulatedData, revertibleAccumulatedData, PublicCallRequest.empty());
413
484
  const constantData = new TxConstantData(anchorBlockHeader, txContext, Fr.zero(), Fr.zero());
414
485
  const txData = new PrivateKernelTailCircuitPublicInputs(constantData, /*gasUsed=*/ new Gas(0, 0), /*feePayer=*/ AztecAddress.zero(), /*expirationTimestamp=*/ 0n, inputsForPublic, undefined);
@@ -464,7 +535,7 @@ export class TXEOracleTopLevelContext {
464
535
  await forkedWorldTrees.close();
465
536
  return returnValues ?? [];
466
537
  }
467
- async executeUtilityFunction(targetContractAddress, functionSelector, args, jobId) {
538
+ async executeUtilityFunction(targetContractAddress, functionSelector, args, jobId, authorizedUtilityCallTargets) {
468
539
  const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
469
540
  if (!artifact) {
470
541
  throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
@@ -473,7 +544,7 @@ export class TXEOracleTopLevelContext {
473
544
  const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
474
545
  await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, async (call, execScopes)=>{
475
546
  await this.executeUtilityCall(call, execScopes, jobId);
476
- }, blockHeader, jobId, 'ALL_SCOPES');
547
+ }, blockHeader, jobId, await this.keyStore.getAccounts());
477
548
  const call = FunctionCall.from({
478
549
  name: artifact.name,
479
550
  to: targetContractAddress,
@@ -484,9 +555,9 @@ export class TXEOracleTopLevelContext {
484
555
  args,
485
556
  returnTypes: []
486
557
  });
487
- return this.executeUtilityCall(call, 'ALL_SCOPES', jobId);
558
+ return this.executeUtilityCall(call, await this.keyStore.getAccounts(), jobId, authorizedUtilityCallTargets);
488
559
  }
489
- async executeUtilityCall(call, scopes, jobId) {
560
+ async executeUtilityCall(call, scopes, jobId, authorizedUtilityCallTargets = []) {
490
561
  const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
491
562
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
492
563
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
@@ -497,6 +568,10 @@ export class TXEOracleTopLevelContext {
497
568
  });
498
569
  try {
499
570
  const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
571
+ const simulator = new WASMSimulator();
572
+ const utilityExecutor = async (syncCall, execScopes)=>{
573
+ await this.executeUtilityCall(syncCall, execScopes, jobId);
574
+ };
500
575
  const oracle = new UtilityExecutionOracle({
501
576
  contractAddress: call.to,
502
577
  authWitnesses: [],
@@ -509,14 +584,20 @@ export class TXEOracleTopLevelContext {
509
584
  aztecNode: this.stateMachine.node,
510
585
  recipientTaggingStore: this.recipientTaggingStore,
511
586
  senderAddressBookStore: this.senderAddressBookStore,
512
- capsuleStore: this.capsuleStore,
587
+ capsuleService: new CapsuleService(this.capsuleStore, scopes),
513
588
  privateEventStore: this.privateEventStore,
514
589
  messageContextService: this.stateMachine.messageContextService,
515
- contractSyncService: this.contractSyncService,
590
+ contractSyncService: this.stateMachine.contractSyncService,
591
+ l2TipsStore: this.stateMachine.l2TipsProvider,
516
592
  jobId,
517
- scopes
593
+ scopes,
594
+ simulator,
595
+ hooks: composeHooks({
596
+ authorizeUtilityCall: this.buildAuthorizeUtilityCallHook('utility', authorizedUtilityCallTargets)
597
+ }),
598
+ utilityExecutor
518
599
  });
519
- const acirExecutionResult = await new WASMSimulator().executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback()).catch((err)=>{
600
+ const acirExecutionResult = await simulator.executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback()).catch((err)=>{
520
601
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
521
602
  throw new ExecutionError(err.message, {
522
603
  contractAddress: call.to,
@@ -539,7 +620,15 @@ export class TXEOracleTopLevelContext {
539
620
  ];
540
621
  }
541
622
  async getLastBlockNumber() {
542
- const header = await this.stateMachine.node.getBlockHeader('latest');
543
- return header ? header.globalVariables.blockNumber : BlockNumber.ZERO;
623
+ const block = await this.stateMachine.node.getBlock('latest');
624
+ return block ? block.header.globalVariables.blockNumber : BlockNumber.ZERO;
625
+ }
626
+ buildAuthorizeUtilityCallHook(callerContext, authorizedTargets) {
627
+ if (authorizedTargets.length === 0) {
628
+ return undefined;
629
+ }
630
+ return (req)=>Promise.resolve({
631
+ authorized: req.callerContext === callerContext && authorizedTargets.some((t)=>t.equals(req.target))
632
+ });
544
633
  }
545
634
  }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * The TXE oracle version constants are used to check that the oracle interface used for tests is in sync between
3
+ * TXE and Aztec.nr. This is separate from the contract oracle version in `pxe/src/oracle_version.ts`, which covers
4
+ * oracles used during contract execution by PXE.
5
+ *
6
+ * The Noir counterparts are in `noir-projects/aztec-nr/aztec/src/test/helpers/txe_oracles.nr`.
7
+ */
8
+ export declare const TXE_ORACLE_VERSION_MAJOR = 1;
9
+ export declare const TXE_ORACLE_VERSION_MINOR = 2;
10
+ /**
11
+ * This hash is computed from the TXE oracle interfaces (IAvmExecutionOracle and ITxeExecutionOracle) and is used to
12
+ * detect when those interfaces change. When it does, bump:
13
+ * - TXE_ORACLE_VERSION_MAJOR (and reset MINOR to 0) for breaking changes, or
14
+ * - TXE_ORACLE_VERSION_MINOR for additive changes (new oracle method added).
15
+ */
16
+ export declare const TXE_ORACLE_INTERFACE_HASH = "9e5f6ad5fd170d1de5ddd417f19cce47b17382567e08360dc6a783154828e218";
17
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHhlX29yYWNsZV92ZXJzaW9uLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvb3JhY2xlL3R4ZV9vcmFjbGVfdmVyc2lvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFDSCxlQUFPLE1BQU0sd0JBQXdCLElBQUksQ0FBQztBQUMxQyxlQUFPLE1BQU0sd0JBQXdCLElBQUksQ0FBQztBQUUxQzs7Ozs7R0FLRztBQUNILGVBQU8sTUFBTSx5QkFBeUIscUVBQXFFLENBQUMifQ==
@@ -0,0 +1 @@
1
+ {"version":3,"file":"txe_oracle_version.d.ts","sourceRoot":"","sources":["../../src/oracle/txe_oracle_version.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAC1C,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,qEAAqE,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The TXE oracle version constants are used to check that the oracle interface used for tests is in sync between
3
+ * TXE and Aztec.nr. This is separate from the contract oracle version in `pxe/src/oracle_version.ts`, which covers
4
+ * oracles used during contract execution by PXE.
5
+ *
6
+ * The Noir counterparts are in `noir-projects/aztec-nr/aztec/src/test/helpers/txe_oracles.nr`.
7
+ */ export const TXE_ORACLE_VERSION_MAJOR = 1;
8
+ export const TXE_ORACLE_VERSION_MINOR = 2;
9
+ /**
10
+ * This hash is computed from the TXE oracle interfaces (IAvmExecutionOracle and ITxeExecutionOracle) and is used to
11
+ * detect when those interfaces change. When it does, bump:
12
+ * - TXE_ORACLE_VERSION_MAJOR (and reset MINOR to 0) for breaking changes, or
13
+ * - TXE_ORACLE_VERSION_MINOR for additive changes (new oracle method added).
14
+ */ export const TXE_ORACLE_INTERFACE_HASH = '9e5f6ad5fd170d1de5ddd417f19cce47b17382567e08360dc6a783154828e218';
@@ -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
+ }