@aztec/simulator 0.71.0 → 0.73.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/README.md +1 -1
  2. package/dest/acvm/oracle/oracle.d.ts +0 -1
  3. package/dest/acvm/oracle/oracle.d.ts.map +1 -1
  4. package/dest/acvm/oracle/oracle.js +1 -5
  5. package/dest/acvm/oracle/typed_oracle.d.ts +0 -1
  6. package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
  7. package/dest/acvm/oracle/typed_oracle.js +1 -4
  8. package/dest/avm/avm_simulator.d.ts +0 -1
  9. package/dest/avm/avm_simulator.d.ts.map +1 -1
  10. package/dest/avm/avm_simulator.js +4 -19
  11. package/dest/avm/avm_tree.d.ts +9 -8
  12. package/dest/avm/avm_tree.d.ts.map +1 -1
  13. package/dest/avm/avm_tree.js +35 -30
  14. package/dest/avm/errors.d.ts +6 -0
  15. package/dest/avm/errors.d.ts.map +1 -1
  16. package/dest/avm/errors.js +10 -1
  17. package/dest/avm/fixtures/avm_simulation_tester.d.ts +21 -0
  18. package/dest/avm/fixtures/avm_simulation_tester.d.ts.map +1 -0
  19. package/dest/avm/fixtures/avm_simulation_tester.js +74 -0
  20. package/dest/avm/fixtures/base_avm_simulation_tester.d.ts +35 -0
  21. package/dest/avm/fixtures/base_avm_simulation_tester.d.ts.map +1 -0
  22. package/dest/avm/fixtures/base_avm_simulation_tester.js +76 -0
  23. package/dest/avm/fixtures/index.d.ts +6 -2
  24. package/dest/avm/fixtures/index.d.ts.map +1 -1
  25. package/dest/avm/fixtures/index.js +28 -14
  26. package/dest/avm/fixtures/simple_contract_data_source.d.ts +31 -0
  27. package/dest/avm/fixtures/simple_contract_data_source.d.ts.map +1 -0
  28. package/dest/avm/fixtures/simple_contract_data_source.js +75 -0
  29. package/dest/avm/journal/journal.d.ts +5 -6
  30. package/dest/avm/journal/journal.d.ts.map +1 -1
  31. package/dest/avm/journal/journal.js +28 -26
  32. package/dest/avm/opcodes/accrued_substate.d.ts.map +1 -1
  33. package/dest/avm/opcodes/accrued_substate.js +4 -3
  34. package/dest/avm/opcodes/conversion.d.ts.map +1 -1
  35. package/dest/avm/opcodes/conversion.js +10 -7
  36. package/dest/avm/opcodes/ec_add.js +2 -2
  37. package/dest/avm/opcodes/hashing.js +2 -2
  38. package/dest/avm/opcodes/multi_scalar_mul.d.ts.map +1 -1
  39. package/dest/avm/opcodes/multi_scalar_mul.js +9 -7
  40. package/dest/avm/test_utils.d.ts +1 -1
  41. package/dest/avm/test_utils.d.ts.map +1 -1
  42. package/dest/avm/test_utils.js +4 -3
  43. package/dest/client/client_execution_context.d.ts +2 -6
  44. package/dest/client/client_execution_context.d.ts.map +1 -1
  45. package/dest/client/client_execution_context.js +23 -26
  46. package/dest/client/execution_note_cache.d.ts +3 -3
  47. package/dest/client/execution_note_cache.d.ts.map +1 -1
  48. package/dest/client/execution_note_cache.js +10 -10
  49. package/dest/client/pick_notes.js +5 -5
  50. package/dest/client/simulator.js +4 -4
  51. package/dest/client/view_data_oracle.js +2 -2
  52. package/dest/common/hashed_values_cache.d.ts +1 -1
  53. package/dest/common/hashed_values_cache.d.ts.map +1 -1
  54. package/dest/common/hashed_values_cache.js +5 -5
  55. package/dest/providers/acvm_wasm.d.ts +2 -0
  56. package/dest/providers/acvm_wasm.d.ts.map +1 -1
  57. package/dest/providers/acvm_wasm.js +15 -2
  58. package/dest/public/execution.d.ts +8 -26
  59. package/dest/public/execution.d.ts.map +1 -1
  60. package/dest/public/execution.js +3 -3
  61. package/dest/public/fee_payment.d.ts +2 -2
  62. package/dest/public/fee_payment.d.ts.map +1 -1
  63. package/dest/public/fee_payment.js +3 -3
  64. package/dest/public/fixtures/index.d.ts +2 -37
  65. package/dest/public/fixtures/index.d.ts.map +1 -1
  66. package/dest/public/fixtures/index.js +3 -247
  67. package/dest/public/fixtures/public_tx_simulation_tester.d.ts +21 -0
  68. package/dest/public/fixtures/public_tx_simulation_tester.d.ts.map +1 -0
  69. package/dest/public/fixtures/public_tx_simulation_tester.js +89 -0
  70. package/dest/public/fixtures/utils.d.ts +17 -0
  71. package/dest/public/fixtures/utils.d.ts.map +1 -0
  72. package/dest/public/fixtures/utils.js +66 -0
  73. package/dest/public/index.d.ts +1 -1
  74. package/dest/public/index.d.ts.map +1 -1
  75. package/dest/public/index.js +2 -2
  76. package/dest/public/public_db_sources.d.ts +2 -1
  77. package/dest/public/public_db_sources.d.ts.map +1 -1
  78. package/dest/public/public_db_sources.js +27 -21
  79. package/dest/public/public_processor.d.ts +4 -5
  80. package/dest/public/public_processor.d.ts.map +1 -1
  81. package/dest/public/public_processor.js +28 -28
  82. package/dest/public/public_tx_context.d.ts +5 -5
  83. package/dest/public/public_tx_context.d.ts.map +1 -1
  84. package/dest/public/public_tx_context.js +44 -18
  85. package/dest/public/public_tx_simulator.d.ts.map +1 -1
  86. package/dest/public/public_tx_simulator.js +9 -12
  87. package/dest/public/{enqueued_call_side_effect_trace.d.ts → side_effect_trace.d.ts} +12 -15
  88. package/dest/public/side_effect_trace.d.ts.map +1 -0
  89. package/dest/public/side_effect_trace.js +350 -0
  90. package/dest/public/side_effect_trace_interface.d.ts +4 -5
  91. package/dest/public/side_effect_trace_interface.d.ts.map +1 -1
  92. package/dest/test/utils.d.ts +1 -1
  93. package/dest/test/utils.d.ts.map +1 -1
  94. package/dest/test/utils.js +3 -3
  95. package/package.json +10 -10
  96. package/src/acvm/oracle/oracle.ts +0 -5
  97. package/src/acvm/oracle/typed_oracle.ts +0 -4
  98. package/src/avm/avm_simulator.ts +3 -27
  99. package/src/avm/avm_tree.ts +39 -37
  100. package/src/avm/errors.ts +10 -0
  101. package/src/avm/fixtures/avm_simulation_tester.ts +105 -0
  102. package/src/avm/fixtures/base_avm_simulation_tester.ts +104 -0
  103. package/src/avm/fixtures/index.ts +46 -17
  104. package/src/avm/fixtures/simple_contract_data_source.ts +98 -0
  105. package/src/avm/journal/journal.ts +28 -26
  106. package/src/avm/opcodes/accrued_substate.ts +3 -2
  107. package/src/avm/opcodes/conversion.ts +15 -6
  108. package/src/avm/opcodes/ec_add.ts +1 -1
  109. package/src/avm/opcodes/hashing.ts +1 -1
  110. package/src/avm/opcodes/multi_scalar_mul.ts +8 -6
  111. package/src/avm/test_utils.ts +3 -4
  112. package/src/client/client_execution_context.ts +29 -30
  113. package/src/client/execution_note_cache.ts +19 -14
  114. package/src/client/pick_notes.ts +4 -4
  115. package/src/client/simulator.ts +3 -3
  116. package/src/client/view_data_oracle.ts +1 -1
  117. package/src/common/hashed_values_cache.ts +4 -4
  118. package/src/providers/acvm_wasm.ts +13 -2
  119. package/src/public/execution.ts +10 -34
  120. package/src/public/fee_payment.ts +2 -2
  121. package/src/public/fixtures/index.ts +2 -381
  122. package/src/public/fixtures/public_tx_simulation_tester.ts +174 -0
  123. package/src/public/fixtures/utils.ts +110 -0
  124. package/src/public/index.ts +1 -1
  125. package/src/public/public_db_sources.ts +31 -20
  126. package/src/public/public_processor.ts +32 -30
  127. package/src/public/public_tx_context.ts +87 -28
  128. package/src/public/public_tx_simulator.ts +7 -14
  129. package/src/public/{enqueued_call_side_effect_trace.ts → side_effect_trace.ts} +29 -41
  130. package/src/public/side_effect_trace_interface.ts +4 -4
  131. package/src/test/utils.ts +2 -2
  132. package/dest/public/enqueued_call_side_effect_trace.d.ts.map +0 -1
  133. package/dest/public/enqueued_call_side_effect_trace.js +0 -357
  134. package/dest/public/transitional_adapters.d.ts +0 -4
  135. package/dest/public/transitional_adapters.d.ts.map +0 -1
  136. package/dest/public/transitional_adapters.js +0 -29
  137. package/src/public/transitional_adapters.ts +0 -113
@@ -0,0 +1,104 @@
1
+ import { MerkleTreeId, type MerkleTreeWriteOperations } from '@aztec/circuit-types';
2
+ import {
3
+ type ContractClassPublic,
4
+ type ContractInstanceWithAddress,
5
+ DEPLOYER_CONTRACT_ADDRESS,
6
+ PUBLIC_DISPATCH_SELECTOR,
7
+ PublicDataWrite,
8
+ computeInitializationHash,
9
+ } from '@aztec/circuits.js';
10
+ import { computePublicDataTreeLeafSlot, siloNullifier } from '@aztec/circuits.js/hash';
11
+ import { makeContractClassPublic, makeContractInstanceFromClassId } from '@aztec/circuits.js/testing';
12
+ import { type ContractArtifact, FunctionSelector } from '@aztec/foundation/abi';
13
+ import { AztecAddress } from '@aztec/foundation/aztec-address';
14
+ import { type Fr } from '@aztec/foundation/fields';
15
+ import { createLogger } from '@aztec/foundation/log';
16
+ import { ProtocolContractAddress } from '@aztec/protocol-contracts';
17
+
18
+ import { computeFeePayerBalanceStorageSlot } from '../../server.js';
19
+ import { PUBLIC_DISPATCH_FN_NAME, getContractFunctionArtifact } from './index.js';
20
+ import { type SimpleContractDataSource } from './simple_contract_data_source.js';
21
+
22
+ /**
23
+ * An abstract test class that enables tests of real apps in the AVM without requiring e2e tests.
24
+ * It enables this by letting us (1) perform pseudo-contract-deployments (and registrations)
25
+ * that trigger merkle tree operations and (2) maintain a contract data source to store
26
+ * and retrieve contract classes and instances.
27
+ *
28
+ * This class is meant to be extended when writing tests for a specific simulation interface.
29
+ * For example, has been extended for testing of the core AvmSimulator, and again for the PublicTxSimulator,
30
+ * both of which benefit from such pseudo-deployments by populating merkle trees and a contract data source
31
+ * with contract information.
32
+ */
33
+ export abstract class BaseAvmSimulationTester {
34
+ public logger = createLogger('avm-simulation-tester');
35
+
36
+ constructor(
37
+ public contractDataSource: SimpleContractDataSource,
38
+ public merkleTrees: MerkleTreeWriteOperations,
39
+ /* May want to skip contract deployment tree ops to test failed contract address nullifier checks on CALL */
40
+ private skipContractDeployments = false,
41
+ ) {}
42
+
43
+ async setFeePayerBalance(feePayer: AztecAddress, balance: Fr) {
44
+ const feeJuiceAddress = ProtocolContractAddress.FeeJuice;
45
+ const balanceSlot = await computeFeePayerBalanceStorageSlot(feePayer);
46
+ await this.setPublicStorage(feeJuiceAddress, balanceSlot, balance);
47
+ }
48
+
49
+ async setPublicStorage(address: AztecAddress, slot: Fr, value: Fr) {
50
+ const leafSlot = await computePublicDataTreeLeafSlot(address, slot);
51
+ // get existing preimage
52
+ const publicDataWrite = new PublicDataWrite(leafSlot, value);
53
+ await this.merkleTrees.batchInsert(MerkleTreeId.PUBLIC_DATA_TREE, [publicDataWrite.toBuffer()], 0);
54
+ }
55
+
56
+ /**
57
+ * Derive the contract class and instance with some seed.
58
+ * Add both to the contract data source along with the contract artifact.
59
+ */
60
+ async registerAndDeployContract(
61
+ constructorArgs: any[],
62
+ deployer: AztecAddress,
63
+ contractArtifact: ContractArtifact,
64
+ seed = 0,
65
+ ): Promise<ContractInstanceWithAddress> {
66
+ const bytecode = getContractFunctionArtifact(PUBLIC_DISPATCH_FN_NAME, contractArtifact)!.bytecode;
67
+ const contractClass = await makeContractClassPublic(
68
+ seed,
69
+ /*publicDispatchFunction=*/ { bytecode, selector: new FunctionSelector(PUBLIC_DISPATCH_SELECTOR) },
70
+ );
71
+
72
+ const constructorAbi = getContractFunctionArtifact('constructor', contractArtifact);
73
+ const initializationHash = await computeInitializationHash(constructorAbi, constructorArgs);
74
+ const contractInstance = await makeContractInstanceFromClassId(contractClass.id, seed, {
75
+ deployer,
76
+ initializationHash,
77
+ });
78
+
79
+ await this.addContractClass(contractClass, contractArtifact);
80
+ await this.addContractInstance(contractInstance);
81
+ return contractInstance;
82
+ }
83
+
84
+ getFirstContractInstance(): ContractInstanceWithAddress {
85
+ return this.contractDataSource.getFirstContractInstance();
86
+ }
87
+
88
+ addContractClass(contractClass: ContractClassPublic, contractArtifact: ContractArtifact): Promise<void> {
89
+ this.logger.debug(`Adding contract class with Id ${contractClass.id}`);
90
+ this.contractDataSource.addContractArtifact(contractClass.id, contractArtifact);
91
+ return this.contractDataSource.addContractClass(contractClass);
92
+ }
93
+
94
+ async addContractInstance(contractInstance: ContractInstanceWithAddress) {
95
+ if (!this.skipContractDeployments) {
96
+ const contractAddressNullifier = await siloNullifier(
97
+ AztecAddress.fromNumber(DEPLOYER_CONTRACT_ADDRESS),
98
+ contractInstance.address.toField(),
99
+ );
100
+ await this.merkleTrees.batchInsert(MerkleTreeId.NULLIFIER_TREE, [contractAddressNullifier.toBuffer()], 0);
101
+ }
102
+ await this.contractDataSource.addContractInstance(contractInstance);
103
+ }
104
+ }
@@ -1,6 +1,6 @@
1
1
  import { isNoirCallStackUnresolved } from '@aztec/circuit-types';
2
2
  import { GasFees, GlobalVariables, MAX_L2_GAS_PER_TX_PUBLIC_PORTION } from '@aztec/circuits.js';
3
- import { type FunctionArtifact, FunctionSelector } from '@aztec/foundation/abi';
3
+ import { type ContractArtifact, type FunctionArtifact, FunctionSelector } from '@aztec/foundation/abi';
4
4
  import { AztecAddress } from '@aztec/foundation/aztec-address';
5
5
  import { EthAddress } from '@aztec/foundation/eth-address';
6
6
  import { Fr } from '@aztec/foundation/fields';
@@ -23,6 +23,8 @@ import { AvmPersistableStateManager } from '../journal/journal.js';
23
23
  import { NullifierManager } from '../journal/nullifiers.js';
24
24
  import { PublicStorage } from '../journal/public_storage.js';
25
25
 
26
+ export const PUBLIC_DISPATCH_FN_NAME = 'public_dispatch';
27
+
26
28
  /**
27
29
  * Create a new AVM context with default values.
28
30
  */
@@ -124,15 +126,51 @@ export function randomMemoryFields(length: number): Field[] {
124
126
  return [...Array(length)].map(_ => new Field(Fr.random()));
125
127
  }
126
128
 
127
- export function getAvmTestContractFunctionSelector(functionName: string): FunctionSelector {
128
- const artifact = AvmTestContractArtifact.functions.find(f => f.name === functionName)!;
129
- assert(!!artifact, `Function ${functionName} not found in AvmTestContractArtifact`);
130
- const params = artifact.parameters;
131
- return FunctionSelector.fromNameAndParameters(artifact.name, params);
129
+ export function getFunctionSelector(
130
+ functionName: string,
131
+ contractArtifact: ContractArtifact,
132
+ ): Promise<FunctionSelector> {
133
+ const fnArtifact = contractArtifact.functions.find(f => f.name === functionName)!;
134
+ assert(!!fnArtifact, `Function ${functionName} not found in ${contractArtifact.name}`);
135
+ const params = fnArtifact.parameters;
136
+ return FunctionSelector.fromNameAndParameters(fnArtifact.name, params);
137
+ }
138
+
139
+ export function getContractFunctionArtifact(
140
+ functionName: string,
141
+ contractArtifact: ContractArtifact,
142
+ ): FunctionArtifact | undefined {
143
+ const artifact = contractArtifact.functions.find(f => f.name === functionName)!;
144
+ if (!artifact) {
145
+ return undefined;
146
+ }
147
+ return artifact;
148
+ }
149
+
150
+ export function resolveContractAssertionMessage(
151
+ functionName: string,
152
+ revertReason: AvmRevertReason,
153
+ output: Fr[],
154
+ contractArtifact: ContractArtifact,
155
+ ): string | undefined {
156
+ traverseCauseChain(revertReason, cause => {
157
+ revertReason = cause as AvmRevertReason;
158
+ });
159
+
160
+ const functionArtifact = contractArtifact.functions.find(f => f.name === functionName);
161
+ if (!functionArtifact || !revertReason.noirCallStack || !isNoirCallStackUnresolved(revertReason.noirCallStack)) {
162
+ return undefined;
163
+ }
164
+
165
+ return resolveAssertionMessageFromRevertData(output, functionArtifact);
166
+ }
167
+
168
+ export function getAvmTestContractFunctionSelector(functionName: string): Promise<FunctionSelector> {
169
+ return getFunctionSelector(functionName, AvmTestContractArtifact);
132
170
  }
133
171
 
134
172
  export function getAvmTestContractArtifact(functionName: string): FunctionArtifact {
135
- const artifact = AvmTestContractArtifact.functions.find(f => f.name === functionName)!;
173
+ const artifact = getContractFunctionArtifact(functionName, AvmTestContractArtifact);
136
174
  assert(
137
175
  !!artifact?.bytecode,
138
176
  `No bytecode found for function ${functionName}. Try re-running bootstrap.sh on the repository root.`,
@@ -150,14 +188,5 @@ export function resolveAvmTestContractAssertionMessage(
150
188
  revertReason: AvmRevertReason,
151
189
  output: Fr[],
152
190
  ): string | undefined {
153
- traverseCauseChain(revertReason, cause => {
154
- revertReason = cause as AvmRevertReason;
155
- });
156
-
157
- const functionArtifact = AvmTestContractArtifact.functions.find(f => f.name === functionName);
158
- if (!functionArtifact || !revertReason.noirCallStack || !isNoirCallStackUnresolved(revertReason.noirCallStack)) {
159
- return undefined;
160
- }
161
-
162
- return resolveAssertionMessageFromRevertData(output, functionArtifact);
191
+ return resolveContractAssertionMessage(functionName, revertReason, output, AvmTestContractArtifact);
163
192
  }
@@ -0,0 +1,98 @@
1
+ import {
2
+ type ContractClassPublic,
3
+ type ContractDataSource,
4
+ type ContractInstanceWithAddress,
5
+ type FunctionSelector,
6
+ type PublicFunction,
7
+ computePublicBytecodeCommitment,
8
+ } from '@aztec/circuits.js';
9
+ import { type ContractArtifact } from '@aztec/foundation/abi';
10
+ import { type AztecAddress } from '@aztec/foundation/aztec-address';
11
+ import { type Fr } from '@aztec/foundation/fields';
12
+ import { createLogger } from '@aztec/foundation/log';
13
+
14
+ import { PUBLIC_DISPATCH_FN_NAME } from './index.js';
15
+
16
+ /**
17
+ * This class is used during public/avm testing to function as a database of
18
+ * contract contract classes and instances. Tests can populate it with classes
19
+ * and instances and then probe it via the ContractDataSource interface.
20
+ *
21
+ * This class does not include any real merkle trees & merkle operations.
22
+ */
23
+ export class SimpleContractDataSource implements ContractDataSource {
24
+ public logger = createLogger('simple-contract-data-source');
25
+
26
+ // maps contract class ID to class
27
+ private contractClasses: Map<string, ContractClassPublic> = new Map();
28
+ // maps contract instance address to instance
29
+ private contractInstances: Map<string, ContractInstanceWithAddress> = new Map();
30
+ // maps contract instance address to address
31
+ private contractArtifacts: Map<string, ContractArtifact> = new Map();
32
+
33
+ /////////////////////////////////////////////////////////////
34
+ // Helper functions not in the contract data source interface
35
+ getFirstContractInstance(): ContractInstanceWithAddress {
36
+ return this.contractInstances.values().next().value;
37
+ }
38
+
39
+ addContractArtifact(classId: Fr, artifact: ContractArtifact): void {
40
+ this.contractArtifacts.set(classId.toString(), artifact);
41
+ }
42
+
43
+ /////////////////////////////////////////////////////////////
44
+ // ContractDataSource function impelementations
45
+ getPublicFunction(_address: AztecAddress, _selector: FunctionSelector): Promise<PublicFunction> {
46
+ throw new Error('Method not implemented.');
47
+ }
48
+
49
+ getBlockNumber(): Promise<number> {
50
+ throw new Error('Method not implemented.');
51
+ }
52
+
53
+ getContractClass(id: Fr): Promise<ContractClassPublic | undefined> {
54
+ return Promise.resolve(this.contractClasses.get(id.toString()));
55
+ }
56
+
57
+ async getBytecodeCommitment(id: Fr): Promise<Fr | undefined> {
58
+ const contractClass = await this.getContractClass(id);
59
+ return Promise.resolve(computePublicBytecodeCommitment(contractClass!.packedBytecode));
60
+ }
61
+
62
+ getContract(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined> {
63
+ return Promise.resolve(this.contractInstances.get(address.toString()));
64
+ }
65
+
66
+ getContractClassIds(): Promise<Fr[]> {
67
+ throw new Error('Method not implemented.');
68
+ }
69
+
70
+ async getContractArtifact(address: AztecAddress): Promise<ContractArtifact | undefined> {
71
+ const contractInstance = await this.getContract(address);
72
+ if (!contractInstance) {
73
+ this.logger.warn(`Contract not found at address: ${address}`);
74
+ return undefined;
75
+ }
76
+ this.logger.debug(`Retrieved contract artifact for address: ${address}`);
77
+ this.logger.debug(`Contract class ID: ${contractInstance.contractClassId}`);
78
+ return Promise.resolve(this.contractArtifacts.get(contractInstance!.contractClassId.toString()));
79
+ }
80
+
81
+ getContractFunctionName(_address: AztecAddress, _selector: FunctionSelector): Promise<string> {
82
+ return Promise.resolve(PUBLIC_DISPATCH_FN_NAME);
83
+ }
84
+
85
+ registerContractFunctionSignatures(_address: AztecAddress, _signatures: string[]): Promise<void> {
86
+ return Promise.resolve();
87
+ }
88
+
89
+ addContractClass(contractClass: ContractClassPublic): Promise<void> {
90
+ this.contractClasses.set(contractClass.id.toString(), contractClass);
91
+ return Promise.resolve();
92
+ }
93
+
94
+ addContractInstance(contractInstance: ContractInstanceWithAddress): Promise<void> {
95
+ this.contractInstances.set(contractInstance.address.toString(), contractInstance);
96
+ return Promise.resolve();
97
+ }
98
+ }
@@ -72,7 +72,7 @@ export class AvmPersistableStateManager {
72
72
  trace: PublicSideEffectTraceInterface,
73
73
  doMerkleOperations: boolean = false,
74
74
  firstNullifier: Fr,
75
- ) {
75
+ ): Promise<AvmPersistableStateManager> {
76
76
  const ephemeralForest = await AvmEphemeralForest.create(worldStateDB.getMerkleInterface());
77
77
  return new AvmPersistableStateManager(
78
78
  worldStateDB,
@@ -126,11 +126,12 @@ export class AvmPersistableStateManager {
126
126
  this.trace.merge(forkedState.trace, reverted);
127
127
  if (reverted) {
128
128
  if (this.doMerkleOperations) {
129
- this.log.debug(
129
+ this.log.trace(
130
130
  `Rolled back nullifier tree to root ${this.merkleTrees.treeMap.get(MerkleTreeId.NULLIFIER_TREE)!.getRoot()}`,
131
131
  );
132
132
  }
133
133
  } else {
134
+ this.log.trace('Merging forked state into parent...');
134
135
  this.merkleTrees = forkedState.merkleTrees;
135
136
  }
136
137
  }
@@ -144,7 +145,7 @@ export class AvmPersistableStateManager {
144
145
  */
145
146
  public async writeStorage(contractAddress: AztecAddress, slot: Fr, value: Fr, protocolWrite = false): Promise<void> {
146
147
  this.log.debug(`Storage write (address=${contractAddress}, slot=${slot}): value=${value}`);
147
- const leafSlot = computePublicDataTreeLeafSlot(contractAddress, slot);
148
+ const leafSlot = await computePublicDataTreeLeafSlot(contractAddress, slot);
148
149
  this.log.debug(`leafSlot=${leafSlot}`);
149
150
  // Cache storage writes for later reference/reads
150
151
  this.publicStorage.write(contractAddress, slot, value);
@@ -169,7 +170,7 @@ export class AvmPersistableStateManager {
169
170
  );
170
171
  }
171
172
 
172
- this.trace.tracePublicStorageWrite(
173
+ await this.trace.tracePublicStorageWrite(
173
174
  contractAddress,
174
175
  slot,
175
176
  value,
@@ -181,7 +182,7 @@ export class AvmPersistableStateManager {
181
182
  insertionPath,
182
183
  );
183
184
  } else {
184
- this.trace.tracePublicStorageWrite(contractAddress, slot, value, protocolWrite);
185
+ await this.trace.tracePublicStorageWrite(contractAddress, slot, value, protocolWrite);
185
186
  }
186
187
  }
187
188
 
@@ -195,7 +196,7 @@ export class AvmPersistableStateManager {
195
196
  public async readStorage(contractAddress: AztecAddress, slot: Fr): Promise<Fr> {
196
197
  const { value, cached } = await this.publicStorage.read(contractAddress, slot);
197
198
  this.log.debug(`Storage read (address=${contractAddress}, slot=${slot}): value=${value}, cached=${cached}`);
198
- const leafSlot = computePublicDataTreeLeafSlot(contractAddress, slot);
199
+ const leafSlot = await computePublicDataTreeLeafSlot(contractAddress, slot);
199
200
  this.log.debug(`leafSlot=${leafSlot}`);
200
201
 
201
202
  if (this.doMerkleOperations) {
@@ -283,34 +284,34 @@ export class AvmPersistableStateManager {
283
284
  * Write a raw note hash, silo it and make it unique, then trace the write.
284
285
  * @param noteHash - the unsiloed note hash to write
285
286
  */
286
- public writeNoteHash(contractAddress: AztecAddress, noteHash: Fr): void {
287
- const siloedNoteHash = siloNoteHash(contractAddress, noteHash);
287
+ public async writeNoteHash(contractAddress: AztecAddress, noteHash: Fr): Promise<void> {
288
+ const siloedNoteHash = await siloNoteHash(contractAddress, noteHash);
288
289
 
289
- this.writeSiloedNoteHash(siloedNoteHash);
290
+ await this.writeSiloedNoteHash(siloedNoteHash);
290
291
  }
291
292
 
292
293
  /**
293
294
  * Write a note hash, make it unique, trace the write.
294
295
  * @param noteHash - the non unique note hash to write
295
296
  */
296
- public writeSiloedNoteHash(noteHash: Fr): void {
297
- const nonce = computeNoteHashNonce(this.firstNullifier, this.trace.getNoteHashCount());
298
- const uniqueNoteHash = computeUniqueNoteHash(nonce, noteHash);
297
+ public async writeSiloedNoteHash(noteHash: Fr): Promise<void> {
298
+ const nonce = await computeNoteHashNonce(this.firstNullifier, this.trace.getNoteHashCount());
299
+ const uniqueNoteHash = await computeUniqueNoteHash(nonce, noteHash);
299
300
 
300
- this.writeUniqueNoteHash(uniqueNoteHash);
301
+ await this.writeUniqueNoteHash(uniqueNoteHash);
301
302
  }
302
303
 
303
304
  /**
304
305
  * Write a note hash, trace the write.
305
306
  * @param noteHash - the siloed unique hash to write
306
307
  */
307
- public writeUniqueNoteHash(noteHash: Fr): void {
308
+ public async writeUniqueNoteHash(noteHash: Fr): Promise<void> {
308
309
  this.log.debug(`noteHashes += @${noteHash}.`);
309
310
 
310
311
  if (this.doMerkleOperations) {
311
312
  // Should write a helper for this
312
313
  const leafIndex = new Fr(this.merkleTrees.treeMap.get(MerkleTreeId.NOTE_HASH_TREE)!.leafCount);
313
- const insertionPath = this.merkleTrees.appendNoteHash(noteHash);
314
+ const insertionPath = await this.merkleTrees.appendNoteHash(noteHash);
314
315
  this.trace.traceNewNoteHash(noteHash, leafIndex, insertionPath);
315
316
  } else {
316
317
  this.trace.traceNewNoteHash(noteHash);
@@ -325,7 +326,7 @@ export class AvmPersistableStateManager {
325
326
  */
326
327
  public async checkNullifierExists(contractAddress: AztecAddress, nullifier: Fr): Promise<boolean> {
327
328
  this.log.debug(`Checking existence of nullifier (address=${contractAddress}, nullifier=${nullifier})`);
328
- const siloedNullifier = siloNullifier(contractAddress, nullifier);
329
+ const siloedNullifier = await siloNullifier(contractAddress, nullifier);
329
330
  const [exists, leafOrLowLeafPreimage, leafOrLowLeafIndex, leafOrLowLeafPath] = await this.getNullifierMembership(
330
331
  siloedNullifier,
331
332
  );
@@ -407,7 +408,7 @@ export class AvmPersistableStateManager {
407
408
  */
408
409
  public async writeNullifier(contractAddress: AztecAddress, nullifier: Fr) {
409
410
  this.log.debug(`Inserting new nullifier (address=${nullifier}, nullifier=${contractAddress})`);
410
- const siloedNullifier = siloNullifier(contractAddress, nullifier);
411
+ const siloedNullifier = await siloNullifier(contractAddress, nullifier);
411
412
  await this.writeSiloedNullifier(siloedNullifier);
412
413
  }
413
414
 
@@ -447,13 +448,15 @@ export class AvmPersistableStateManager {
447
448
  await this.nullifiers.append(siloedNullifier);
448
449
  // We append the new nullifier
449
450
  this.log.debug(
450
- `Nullifier tree root before insertion ${this.merkleTrees.treeMap
451
+ `Nullifier tree root before insertion ${await this.merkleTrees.treeMap
451
452
  .get(MerkleTreeId.NULLIFIER_TREE)!
452
453
  .getRoot()}`,
453
454
  );
454
455
  const appendResult = await this.merkleTrees.appendNullifier(siloedNullifier);
455
456
  this.log.debug(
456
- `Nullifier tree root after insertion ${this.merkleTrees.treeMap.get(MerkleTreeId.NULLIFIER_TREE)!.getRoot()}`,
457
+ `Nullifier tree root after insertion ${await this.merkleTrees.treeMap
458
+ .get(MerkleTreeId.NULLIFIER_TREE)!
459
+ .getRoot()}`,
457
460
  );
458
461
  const lowLeafPreimage = appendResult.lowWitness.preimage as NullifierLeafPreimage;
459
462
  const lowLeafIndex = appendResult.lowWitness.index;
@@ -524,14 +527,13 @@ export class AvmPersistableStateManager {
524
527
  }
525
528
 
526
529
  /**
527
- * Write an unencrypted log
530
+ * Write a public log
528
531
  * @param contractAddress - address of the contract that emitted the log
529
- * @param event - log event selector
530
532
  * @param log - log contents
531
533
  */
532
- public writeUnencryptedLog(contractAddress: AztecAddress, log: Fr[]) {
533
- this.log.debug(`UnencryptedL2Log(${contractAddress}) += event with ${log.length} fields.`);
534
- this.trace.traceUnencryptedLog(contractAddress, log);
534
+ public writePublicLog(contractAddress: AztecAddress, log: Fr[]) {
535
+ this.log.debug(`PublicLog(${contractAddress}) += event with ${log.length} fields.`);
536
+ this.trace.tracePublicLog(contractAddress, log);
535
537
  }
536
538
 
537
539
  /**
@@ -551,7 +553,7 @@ export class AvmPersistableStateManager {
551
553
  new Array<Fr>(),
552
554
  ];
553
555
  if (!contractAddressIsCanonical(contractAddress)) {
554
- const contractAddressNullifier = siloNullifier(
556
+ const contractAddressNullifier = await siloNullifier(
555
557
  AztecAddress.fromNumber(DEPLOYER_CONTRACT_ADDRESS),
556
558
  contractAddress.toField(),
557
559
  );
@@ -616,7 +618,7 @@ export class AvmPersistableStateManager {
616
618
  new Array<Fr>(),
617
619
  ];
618
620
  if (!contractAddressIsCanonical(contractAddress)) {
619
- const contractAddressNullifier = siloNullifier(
621
+ const contractAddressNullifier = await siloNullifier(
620
622
  AztecAddress.fromNumber(DEPLOYER_CONTRACT_ADDRESS),
621
623
  contractAddress.toField(),
622
624
  );
@@ -70,7 +70,7 @@ export class EmitNoteHash extends Instruction {
70
70
  }
71
71
 
72
72
  const noteHash = memory.get(noteHashOffset).toFr();
73
- context.persistableState.writeNoteHash(context.environment.address, noteHash);
73
+ await context.persistableState.writeNoteHash(context.environment.address, noteHash);
74
74
 
75
75
  memory.assert({ reads: 1, addressing });
76
76
  }
@@ -201,6 +201,7 @@ export class L1ToL2MessageExists extends Instruction {
201
201
  }
202
202
 
203
203
  export class EmitUnencryptedLog extends Instruction {
204
+ // TODO(#11124): rename unencrypted -> public
204
205
  static type: string = 'EMITUNENCRYPTEDLOG';
205
206
  static readonly opcode: Opcode = Opcode.EMITUNENCRYPTEDLOG;
206
207
  // Informs (de)serialization. See Instruction.deserialize.
@@ -228,7 +229,7 @@ export class EmitUnencryptedLog extends Instruction {
228
229
 
229
230
  context.machineState.consumeGas(this.gasCost(logSize));
230
231
  const log = memory.getSlice(logOffset, logSize).map(f => f.toFr());
231
- context.persistableState.writeUnencryptedLog(contractAddress, log);
232
+ context.persistableState.writePublicLog(contractAddress, log);
232
233
 
233
234
  memory.assert({ reads: 1 + logSize, addressing });
234
235
  }
@@ -1,12 +1,12 @@
1
1
  import { type AvmContext } from '../avm_context.js';
2
2
  import { TypeTag, Uint1, Uint8 } from '../avm_memory_types.js';
3
- import { InstructionExecutionError } from '../errors.js';
3
+ import { InvalidToRadixInputsError } from '../errors.js';
4
4
  import { Opcode, OperandType } from '../serialization/instruction_serialization.js';
5
5
  import { Addressing } from './addressing_mode.js';
6
6
  import { Instruction } from './instruction.js';
7
7
 
8
8
  export class ToRadixBE extends Instruction {
9
- static type: string = 'TORADIXLE';
9
+ static type: string = 'TORADIXBE';
10
10
  static readonly opcode: Opcode = Opcode.TORADIXBE;
11
11
 
12
12
  // Informs (de)serialization. See Instruction.deserialize.
@@ -49,12 +49,21 @@ export class ToRadixBE extends Instruction {
49
49
 
50
50
  let value: bigint = memory.get(srcOffset).toBigInt();
51
51
  const radix: bigint = memory.get(radixOffset).toBigInt();
52
- if (numLimbs < 1) {
53
- throw new InstructionExecutionError(`ToRadixBE instruction's numLimbs should be > 0 (was ${numLimbs})`);
52
+
53
+ if (radix < 2 || radix > 256) {
54
+ throw new InvalidToRadixInputsError(`ToRadixBE instruction's radix should be in range [2,256] (was ${radix}).`);
54
55
  }
55
- if (radix > 256) {
56
- throw new InstructionExecutionError(`ToRadixBE instruction's radix should be <= 256 (was ${radix})`);
56
+
57
+ if (numLimbs < 1 && value != BigInt(0n)) {
58
+ throw new InvalidToRadixInputsError(
59
+ `ToRadixBE instruction's input value is not zero (was ${value}) but numLimbs zero.`,
60
+ );
57
61
  }
62
+
63
+ if (outputBits != 0 && radix != BigInt(2n)) {
64
+ throw new InvalidToRadixInputsError(`Radix ${radix} is not equal to 2 and bit mode is activated.`);
65
+ }
66
+
58
67
  const radixBN: bigint = BigInt(radix);
59
68
  const limbArray = new Array(numLimbs);
60
69
 
@@ -81,7 +81,7 @@ export class EcAdd extends Instruction {
81
81
  } else if (p2IsInfinite) {
82
82
  dest = p1;
83
83
  } else {
84
- dest = grumpkin.add(p1, p2);
84
+ dest = await grumpkin.add(p1, p2);
85
85
  }
86
86
 
87
87
  // Important to use setSlice() and not set() in the two following statements as
@@ -34,7 +34,7 @@ export class Poseidon2 extends Instruction {
34
34
  const inputState = memory.getSlice(inputOffset, Poseidon2.stateSize);
35
35
  memory.checkTagsRange(TypeTag.FIELD, inputOffset, Poseidon2.stateSize);
36
36
 
37
- const outputState = poseidon2Permutation(inputState);
37
+ const outputState = await poseidon2Permutation(inputState);
38
38
  memory.setSlice(
39
39
  outputOffset,
40
40
  outputState.map(word => new Field(word)),
@@ -95,20 +95,22 @@ export class MultiScalarMul extends Instruction {
95
95
  const [firstBaseScalarPair, ...rest]: Array<[Point, Fq]> = grumpkinPoints.map((p, idx) => [p, scalarFqVector[idx]]);
96
96
  // Fold the points and scalars into a single point
97
97
  // We have to ensure get the first point, since the identity element (point at infinity) isn't quite working in ts
98
- const outputPoint = rest.reduce((acc, curr) => {
98
+ let acc = await grumpkin.mul(firstBaseScalarPair[0], firstBaseScalarPair[1]);
99
+ for (const curr of rest) {
99
100
  if (curr[1] === Fq.ZERO) {
100
101
  // If we multiply by 0, the result will the point at infinity - so we ignore it
101
- return acc;
102
+ continue;
102
103
  } else if (curr[0].inf) {
103
104
  // If we multiply the point at infinity by a scalar, it's still the point at infinity
104
- return acc;
105
+ continue;
105
106
  } else if (acc.inf) {
106
107
  // If we accumulator is the point at infinity, we can just return the current point
107
- return curr[0];
108
+ acc = curr[0];
108
109
  } else {
109
- return grumpkin.add(acc, grumpkin.mul(curr[0], curr[1]));
110
+ acc = await grumpkin.add(acc, await grumpkin.mul(curr[0], curr[1]));
110
111
  }
111
- }, grumpkin.mul(firstBaseScalarPair[0], firstBaseScalarPair[1]));
112
+ }
113
+ const outputPoint = acc;
112
114
 
113
115
  // Important to use setSlice() and not set() in the two following statements as
114
116
  // this checks that the offsets lie within memory range.
@@ -11,11 +11,10 @@ import { mock } from 'jest-mock-extended';
11
11
  import { type WorldStateDB } from '../public/public_db_sources.js';
12
12
  import { type PublicSideEffectTraceInterface } from '../public/side_effect_trace_interface.js';
13
13
 
14
- export function mockGetBytecode(worldStateDB: WorldStateDB, bytecode: Buffer) {
14
+ export async function mockGetBytecode(worldStateDB: WorldStateDB, bytecode: Buffer) {
15
+ const commitment = await computePublicBytecodeCommitment(bytecode);
15
16
  (worldStateDB as jest.Mocked<WorldStateDB>).getBytecode.mockResolvedValue(bytecode);
16
- (worldStateDB as jest.Mocked<WorldStateDB>).getBytecodeCommitment.mockResolvedValue(
17
- computePublicBytecodeCommitment(bytecode),
18
- );
17
+ (worldStateDB as jest.Mocked<WorldStateDB>).getBytecodeCommitment.mockResolvedValue(commitment);
19
18
  }
20
19
 
21
20
  export function mockTraceFork(trace: PublicSideEffectTraceInterface, nestedTrace?: PublicSideEffectTraceInterface) {