@aztec/simulator 0.24.0 → 0.26.1

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 (129) hide show
  1. package/dest/acvm/deserialize.d.ts +5 -0
  2. package/dest/acvm/deserialize.d.ts.map +1 -1
  3. package/dest/acvm/deserialize.js +8 -1
  4. package/dest/acvm/oracle/oracle.d.ts +5 -4
  5. package/dest/acvm/oracle/oracle.d.ts.map +1 -1
  6. package/dest/acvm/oracle/oracle.js +24 -11
  7. package/dest/acvm/oracle/typed_oracle.d.ts +7 -9
  8. package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
  9. package/dest/acvm/oracle/typed_oracle.js +9 -9
  10. package/dest/avm/avm_context.d.ts +4 -4
  11. package/dest/avm/avm_context.d.ts.map +1 -1
  12. package/dest/avm/avm_context.js +6 -6
  13. package/dest/avm/avm_memory_types.d.ts +11 -2
  14. package/dest/avm/avm_memory_types.d.ts.map +1 -1
  15. package/dest/avm/avm_memory_types.js +11 -1
  16. package/dest/avm/avm_simulator.d.ts +6 -4
  17. package/dest/avm/avm_simulator.d.ts.map +1 -1
  18. package/dest/avm/avm_simulator.js +17 -18
  19. package/dest/avm/fixtures/index.d.ts +17 -5
  20. package/dest/avm/fixtures/index.d.ts.map +1 -1
  21. package/dest/avm/fixtures/index.js +19 -8
  22. package/dest/avm/journal/host_storage.d.ts.map +1 -1
  23. package/dest/avm/journal/host_storage.js +1 -1
  24. package/dest/avm/journal/journal.d.ts +78 -50
  25. package/dest/avm/journal/journal.d.ts.map +1 -1
  26. package/dest/avm/journal/journal.js +125 -169
  27. package/dest/avm/journal/nullifiers.d.ts +85 -0
  28. package/dest/avm/journal/nullifiers.d.ts.map +1 -0
  29. package/dest/avm/journal/nullifiers.js +147 -0
  30. package/dest/avm/journal/public_storage.d.ts +88 -0
  31. package/dest/avm/journal/public_storage.d.ts.map +1 -0
  32. package/dest/avm/journal/public_storage.js +135 -0
  33. package/dest/avm/journal/trace.d.ts +43 -0
  34. package/dest/avm/journal/trace.d.ts.map +1 -0
  35. package/dest/avm/journal/trace.js +204 -0
  36. package/dest/avm/journal/trace_types.d.ts +26 -0
  37. package/dest/avm/journal/trace_types.d.ts.map +1 -0
  38. package/dest/avm/journal/trace_types.js +6 -0
  39. package/dest/avm/opcodes/accrued_substate.d.ts +37 -4
  40. package/dest/avm/opcodes/accrued_substate.d.ts.map +1 -1
  41. package/dest/avm/opcodes/accrued_substate.js +109 -12
  42. package/dest/avm/opcodes/comparators.d.ts.map +1 -1
  43. package/dest/avm/opcodes/comparators.js +5 -8
  44. package/dest/avm/opcodes/environment_getters.d.ts +14 -13
  45. package/dest/avm/opcodes/environment_getters.d.ts.map +1 -1
  46. package/dest/avm/opcodes/environment_getters.js +1 -1
  47. package/dest/avm/opcodes/external_calls.js +5 -5
  48. package/dest/avm/opcodes/hashing.d.ts +48 -0
  49. package/dest/avm/opcodes/hashing.d.ts.map +1 -0
  50. package/dest/avm/opcodes/hashing.js +127 -0
  51. package/dest/avm/opcodes/memory.d.ts.map +1 -1
  52. package/dest/avm/opcodes/memory.js +1 -1
  53. package/dest/avm/opcodes/storage.d.ts.map +1 -1
  54. package/dest/avm/opcodes/storage.js +3 -3
  55. package/dest/avm/serialization/bytecode_serialization.d.ts.map +1 -1
  56. package/dest/avm/serialization/bytecode_serialization.js +12 -8
  57. package/dest/avm/serialization/instruction_serialization.d.ts +10 -7
  58. package/dest/avm/serialization/instruction_serialization.d.ts.map +1 -1
  59. package/dest/avm/serialization/instruction_serialization.js +12 -9
  60. package/dest/avm/temporary_executor_migration.d.ts.map +1 -1
  61. package/dest/avm/temporary_executor_migration.js +5 -5
  62. package/dest/client/client_execution_context.d.ts +9 -5
  63. package/dest/client/client_execution_context.d.ts.map +1 -1
  64. package/dest/client/client_execution_context.js +46 -24
  65. package/dest/client/db_oracle.d.ts +7 -0
  66. package/dest/client/db_oracle.d.ts.map +1 -1
  67. package/dest/client/db_oracle.js +1 -1
  68. package/dest/client/execution_note_cache.js +1 -1
  69. package/dest/client/execution_result.d.ts +2 -2
  70. package/dest/client/execution_result.d.ts.map +1 -1
  71. package/dest/client/private_execution.d.ts.map +1 -1
  72. package/dest/client/private_execution.js +4 -4
  73. package/dest/client/simulator.d.ts +1 -1
  74. package/dest/client/simulator.d.ts.map +1 -1
  75. package/dest/client/simulator.js +3 -2
  76. package/dest/client/view_data_oracle.d.ts +9 -2
  77. package/dest/client/view_data_oracle.d.ts.map +1 -1
  78. package/dest/client/view_data_oracle.js +13 -5
  79. package/dest/public/db.d.ts +17 -4
  80. package/dest/public/db.d.ts.map +1 -1
  81. package/dest/public/execution.d.ts +9 -4
  82. package/dest/public/execution.d.ts.map +1 -1
  83. package/dest/public/execution.js +17 -4
  84. package/dest/public/executor.d.ts.map +1 -1
  85. package/dest/public/executor.js +18 -9
  86. package/dest/public/public_execution_context.d.ts +5 -4
  87. package/dest/public/public_execution_context.d.ts.map +1 -1
  88. package/dest/public/public_execution_context.js +23 -12
  89. package/dest/public/state_actions.js +2 -2
  90. package/dest/test/utils.js +4 -4
  91. package/dest/utils.js +2 -3
  92. package/package.json +6 -5
  93. package/src/acvm/deserialize.ts +8 -0
  94. package/src/acvm/oracle/oracle.ts +30 -6
  95. package/src/acvm/oracle/typed_oracle.ts +13 -5
  96. package/src/avm/avm_context.ts +5 -5
  97. package/src/avm/avm_memory_types.ts +18 -3
  98. package/src/avm/avm_simulator.ts +22 -24
  99. package/src/avm/fixtures/index.ts +34 -9
  100. package/src/avm/journal/host_storage.ts +5 -11
  101. package/src/avm/journal/journal.ts +147 -182
  102. package/src/avm/journal/nullifiers.ts +170 -0
  103. package/src/avm/journal/public_storage.ts +149 -0
  104. package/src/avm/journal/trace.ts +223 -0
  105. package/src/avm/journal/trace_types.ts +79 -0
  106. package/src/avm/opcodes/accrued_substate.ts +132 -10
  107. package/src/avm/opcodes/comparators.ts +4 -7
  108. package/src/avm/opcodes/environment_getters.ts +15 -13
  109. package/src/avm/opcodes/external_calls.ts +4 -4
  110. package/src/avm/opcodes/hashing.ts +170 -0
  111. package/src/avm/opcodes/memory.ts +1 -0
  112. package/src/avm/opcodes/storage.ts +5 -2
  113. package/src/avm/serialization/bytecode_serialization.ts +13 -6
  114. package/src/avm/serialization/instruction_serialization.ts +6 -3
  115. package/src/avm/temporary_executor_migration.ts +4 -3
  116. package/src/client/client_execution_context.ts +53 -23
  117. package/src/client/db_oracle.ts +8 -0
  118. package/src/client/execution_note_cache.ts +1 -1
  119. package/src/client/execution_result.ts +2 -2
  120. package/src/client/private_execution.ts +5 -4
  121. package/src/client/simulator.ts +2 -1
  122. package/src/client/view_data_oracle.ts +14 -4
  123. package/src/public/db.ts +19 -4
  124. package/src/public/execution.ts +30 -6
  125. package/src/public/executor.ts +29 -9
  126. package/src/public/public_execution_context.ts +36 -12
  127. package/src/public/state_actions.ts +1 -1
  128. package/src/test/utils.ts +3 -3
  129. package/src/utils.ts +1 -1
@@ -1,139 +1,154 @@
1
+ import { UnencryptedL2Log } from '@aztec/circuit-types';
2
+ import { AztecAddress, EthAddress, L2ToL1Message } from '@aztec/circuits.js';
3
+ import { EventSelector } from '@aztec/foundation/abi';
4
+ import { Fr } from '@aztec/foundation/fields';
5
+ import { Nullifiers } from './nullifiers.js';
6
+ import { PublicStorage } from './public_storage.js';
7
+ import { WorldStateAccessTrace } from './trace.js';
1
8
  /**
2
- * A cache of the current state of the AVM
3
- * The interpreter should make any state queries through this object
9
+ * A class to manage persistable AVM state for contract calls.
10
+ * Maintains a cache of the current world state,
11
+ * a trace of all world state accesses, and a list of accrued substate items.
4
12
  *
5
- * When a nested context succeeds, it's journal is merge into the parent
6
- * When a call fails, it's journal is discarded and the parent is used from this point forward
7
- * When a call succeeds's we can merge a child into its parent
13
+ * The simulator should make any world state and accrued substate queries through this object.
14
+ *
15
+ * Manages merging of successful/reverted child state into current state.
8
16
  */
9
- export class AvmWorldStateJournal {
10
- constructor(hostStorage, parentJournal) {
11
- // Reading state - must be tracked for vm execution
12
- // contract address -> key -> value[] (array stored in order of reads)
13
- this.storageReads = new Map();
14
- this.storageWrites = new Map();
15
- // New written state
16
- this.newNoteHashes = [];
17
- this.newNullifiers = [];
18
- // New Substate
17
+ export class AvmPersistableStateManager {
18
+ constructor(hostStorage, parent) {
19
+ /** Accrued Substate **/
19
20
  this.newL1Messages = [];
20
21
  this.newLogs = [];
21
- // contract address -> key -> value
22
- this.currentStorageValue = new Map();
23
- // Create an instance of journalUpdate that appends to the read array
24
- this.journalRead = this.journalUpdate.bind(this, this.storageReads);
25
- // Create an instance of journalUpdate that appends to the writes array
26
- this.journalWrite = this.journalUpdate.bind(this, this.storageWrites);
27
22
  this.hostStorage = hostStorage;
28
- this.parentJournal = parentJournal;
23
+ this.publicStorage = new PublicStorage(hostStorage.publicStateDb, parent?.publicStorage);
24
+ this.nullifiers = new Nullifiers(hostStorage.commitmentsDb, parent?.nullifiers);
25
+ this.trace = new WorldStateAccessTrace(parent?.trace);
29
26
  }
30
27
  /**
31
- * Create a new world state journal forked from this one
28
+ * Create a new state manager forked from this one
32
29
  */
33
30
  fork() {
34
- return new AvmWorldStateJournal(this.hostStorage, this);
31
+ return new AvmPersistableStateManager(this.hostStorage, this);
35
32
  }
36
33
  /**
37
- * Write storage into journal
34
+ * Write to public storage, journal/trace the write.
38
35
  *
39
- * @param contractAddress -
40
- * @param key -
41
- * @param value -
36
+ * @param storageAddress - the address of the contract whose storage is being written to
37
+ * @param slot - the slot in the contract's storage being written to
38
+ * @param value - the value being written to the slot
42
39
  */
43
- writeStorage(contractAddress, key, value) {
44
- let contractMap = this.currentStorageValue.get(contractAddress.toBigInt());
45
- if (!contractMap) {
46
- contractMap = new Map();
47
- this.currentStorageValue.set(contractAddress.toBigInt(), contractMap);
48
- }
49
- contractMap.set(key.toBigInt(), value);
50
- // We want to keep track of all performed writes in the journal
51
- this.journalWrite(contractAddress, key, value);
40
+ writeStorage(storageAddress, slot, value) {
41
+ // Cache storage writes for later reference/reads
42
+ this.publicStorage.write(storageAddress, slot, value);
43
+ // Trace all storage writes (even reverted ones)
44
+ this.trace.tracePublicStorageWrite(storageAddress, slot, value);
52
45
  }
53
46
  /**
54
- * Read storage from journal
55
- * Read from host storage on cache miss
47
+ * Read from public storage, trace the read.
56
48
  *
57
- * @param contractAddress -
58
- * @param key -
59
- * @returns current value
49
+ * @param storageAddress - the address of the contract whose storage is being read from
50
+ * @param slot - the slot in the contract's storage being read from
51
+ * @returns the latest value written to slot, or 0 if never written to before
60
52
  */
61
- async readStorage(contractAddress, key) {
62
- // - We first try this journal's storage cache ( if written to before in this call frame )
63
- // - Then we try the parent journal's storage cache ( if it exists ) ( written to earlier in this block )
64
- // - Finally we try the host storage ( a trip to the database )
65
- // Do not early return as we want to keep track of reads in this.storageReads
66
- let value = this.currentStorageValue.get(contractAddress.toBigInt())?.get(key.toBigInt());
67
- if (!value && this.parentJournal) {
68
- value = await this.parentJournal?.readStorage(contractAddress, key);
69
- }
70
- if (!value) {
71
- value = await this.hostStorage.publicStateDb.storageRead(contractAddress, key);
72
- }
73
- this.journalRead(contractAddress, key, value);
53
+ async readStorage(storageAddress, slot) {
54
+ const [_exists, value] = await this.publicStorage.read(storageAddress, slot);
55
+ // We want to keep track of all performed reads (even reverted ones)
56
+ this.trace.tracePublicStorageRead(storageAddress, slot, value);
74
57
  return Promise.resolve(value);
75
58
  }
59
+ // TODO(4886): We currently don't silo note hashes.
76
60
  /**
77
- * We want to keep track of all performed reads in the journal
78
- * This information is hinted to the avm circuit
79
-
80
- * @param contractAddress -
81
- * @param key -
82
- * @param value -
61
+ * Check if a note hash exists at the given leaf index, trace the check.
62
+ *
63
+ * @param storageAddress - the address of the contract whose storage is being read from
64
+ * @param noteHash - the unsiloed note hash being checked
65
+ * @param leafIndex - the leaf index being checked
66
+ * @returns true if the note hash exists at the given leaf index, false otherwise
83
67
  */
84
- journalUpdate(map, contractAddress, key, value) {
85
- let contractMap = map.get(contractAddress.toBigInt());
86
- if (!contractMap) {
87
- contractMap = new Map();
88
- map.set(contractAddress.toBigInt(), contractMap);
89
- }
90
- let accessArray = contractMap.get(key.toBigInt());
91
- if (!accessArray) {
92
- accessArray = new Array();
93
- contractMap.set(key.toBigInt(), accessArray);
94
- }
95
- accessArray.push(value);
68
+ async checkNoteHashExists(storageAddress, noteHash, leafIndex) {
69
+ const gotLeafIndex = await this.hostStorage.commitmentsDb.getCommitmentIndex(noteHash);
70
+ const exists = gotLeafIndex === leafIndex.toBigInt();
71
+ this.trace.traceNoteHashCheck(storageAddress, noteHash, exists, leafIndex);
72
+ return Promise.resolve(exists);
96
73
  }
74
+ /**
75
+ * Write a note hash, trace the write.
76
+ * @param noteHash - the unsiloed note hash to write
77
+ */
97
78
  writeNoteHash(noteHash) {
98
- this.newNoteHashes.push(noteHash);
79
+ this.trace.traceNewNoteHash(/*storageAddress*/ Fr.ZERO, noteHash);
99
80
  }
100
- writeL1Message(message) {
101
- this.newL1Messages.push(message);
81
+ /**
82
+ * Check if a nullifier exists, trace the check.
83
+ * @param storageAddress - address of the contract that the nullifier is associated with
84
+ * @param nullifier - the unsiloed nullifier to check
85
+ * @returns exists - whether the nullifier exists in the nullifier set
86
+ */
87
+ async checkNullifierExists(storageAddress, nullifier) {
88
+ const [exists, isPending, leafIndex] = await this.nullifiers.checkExists(storageAddress, nullifier);
89
+ this.trace.traceNullifierCheck(storageAddress, nullifier, exists, isPending, leafIndex);
90
+ return Promise.resolve(exists);
102
91
  }
103
- writeNullifier(nullifier) {
104
- this.newNullifiers.push(nullifier);
92
+ /**
93
+ * Write a nullifier to the nullifier set, trace the write.
94
+ * @param storageAddress - address of the contract that the nullifier is associated with
95
+ * @param nullifier - the unsiloed nullifier to write
96
+ */
97
+ async writeNullifier(storageAddress, nullifier) {
98
+ // Cache pending nullifiers for later access
99
+ await this.nullifiers.append(storageAddress, nullifier);
100
+ // Trace all nullifier creations (even reverted ones)
101
+ this.trace.traceNewNullifier(storageAddress, nullifier);
105
102
  }
106
- writeLog(log) {
107
- this.newLogs.push(log);
103
+ /**
104
+ * Check if an L1 to L2 message exists, trace the check.
105
+ * @param msgHash - the message hash to check existence of
106
+ * @param msgLeafIndex - the message leaf index to use in the check
107
+ * @returns exists - whether the message exists in the L1 to L2 Messages tree
108
+ */
109
+ async checkL1ToL2MessageExists(msgHash, msgLeafIndex) {
110
+ let exists = false;
111
+ try {
112
+ const gotMessage = await this.hostStorage.commitmentsDb.getL1ToL2MembershipWitness(msgHash);
113
+ exists = gotMessage !== undefined && gotMessage.index == msgLeafIndex.toBigInt();
114
+ }
115
+ catch {
116
+ // error getting message - doesn't exist!
117
+ exists = false;
118
+ }
119
+ this.trace.traceL1ToL2MessageCheck(msgHash, msgLeafIndex, exists);
120
+ return Promise.resolve(exists);
108
121
  }
109
122
  /**
110
- * Accept nested world state, merging in its journal, and accepting its state modifications
111
- * - Utxo objects are concatenated
112
- * - Public state changes are merged, with the value in the incoming journal taking precedent
113
- * - Public state journals (r/w logs), with the accessing being appended in chronological order
123
+ * Write an L2 to L1 message.
124
+ * @param recipient - L1 contract address to send the message to.
125
+ * @param content - Message content.
114
126
  */
115
- acceptNestedWorldState(nestedJournal) {
116
- // Merge UTXOs
117
- this.newNoteHashes = this.newNoteHashes.concat(nestedJournal.newNoteHashes);
127
+ writeL1Message(recipient, content) {
128
+ const recipientAddress = recipient instanceof EthAddress ? recipient : EthAddress.fromField(recipient);
129
+ this.newL1Messages.push(new L2ToL1Message(recipientAddress, content));
130
+ }
131
+ writeLog(contractAddress, event, log) {
132
+ this.newLogs.push(new UnencryptedL2Log(AztecAddress.fromField(contractAddress), EventSelector.fromField(event), Buffer.concat(log.map(f => f.toBuffer()))));
133
+ }
134
+ /**
135
+ * Accept nested world state modifications, merging in its trace and accrued substate
136
+ */
137
+ acceptNestedCallState(nestedJournal) {
138
+ // Merge Public Storage
139
+ this.publicStorage.acceptAndMerge(nestedJournal.publicStorage);
140
+ // Merge World State Access Trace
141
+ this.trace.acceptAndMerge(nestedJournal.trace);
142
+ // Accrued Substate
118
143
  this.newL1Messages = this.newL1Messages.concat(nestedJournal.newL1Messages);
119
- this.newNullifiers = this.newNullifiers.concat(nestedJournal.newNullifiers);
120
144
  this.newLogs = this.newLogs.concat(nestedJournal.newLogs);
121
- // Merge Public State
122
- mergeCurrentValueMaps(this.currentStorageValue, nestedJournal.currentStorageValue);
123
- // Merge storage read and write journals
124
- mergeContractJournalMaps(this.storageReads, nestedJournal.storageReads);
125
- mergeContractJournalMaps(this.storageWrites, nestedJournal.storageWrites);
126
145
  }
127
146
  /**
128
- * Reject nested world state, merging in its journal, but not accepting its state modifications
129
- * - Utxo objects are concatenated
130
- * - Public state changes are dropped
131
- * - Public state journals (r/w logs) are maintained, with the accessing being appended in chronological order
147
+ * Reject nested world state, merging in its trace, but not accepting any state modifications
132
148
  */
133
- rejectNestedWorldState(nestedJournal) {
134
- // Merge storage read and write journals
135
- mergeContractJournalMaps(this.storageReads, nestedJournal.storageReads);
136
- mergeContractJournalMaps(this.storageWrites, nestedJournal.storageWrites);
149
+ rejectNestedCallState(nestedJournal) {
150
+ // Merge World State Access Trace
151
+ this.trace.acceptAndMerge(nestedJournal.trace);
137
152
  }
138
153
  /**
139
154
  * Access the current state of the journal
@@ -142,76 +157,17 @@ export class AvmWorldStateJournal {
142
157
  */
143
158
  flush() {
144
159
  return {
145
- newNoteHashes: this.newNoteHashes,
146
- newNullifiers: this.newNullifiers,
160
+ noteHashChecks: this.trace.noteHashChecks,
161
+ newNoteHashes: this.trace.newNoteHashes,
162
+ nullifierChecks: this.trace.nullifierChecks,
163
+ newNullifiers: this.trace.newNullifiers,
164
+ l1ToL2MessageChecks: this.trace.l1ToL2MessageChecks,
147
165
  newL1Messages: this.newL1Messages,
148
166
  newLogs: this.newLogs,
149
- currentStorageValue: this.currentStorageValue,
150
- storageReads: this.storageReads,
151
- storageWrites: this.storageWrites,
167
+ currentStorageValue: this.publicStorage.getCache().cachePerContract,
168
+ storageReads: this.trace.publicStorageReads,
169
+ storageWrites: this.trace.publicStorageWrites,
152
170
  };
153
171
  }
154
172
  }
155
- /**
156
- * Merges two contract current value together
157
- * Where childMap keys will take precedent over the hostMap
158
- * The assumption being that the child map is created at a later time
159
- * And thus contains more up to date information
160
- *
161
- * @param hostMap - The map to be merged into
162
- * @param childMap - The map to be merged from
163
- */
164
- function mergeCurrentValueMaps(hostMap, childMap) {
165
- for (const [key, value] of childMap) {
166
- const map1Value = hostMap.get(key);
167
- if (!map1Value) {
168
- hostMap.set(key, value);
169
- }
170
- else {
171
- mergeStorageCurrentValueMaps(map1Value, value);
172
- }
173
- }
174
- }
175
- /**
176
- * @param hostMap - The map to be merge into
177
- * @param childMap - The map to be merged from
178
- */
179
- function mergeStorageCurrentValueMaps(hostMap, childMap) {
180
- for (const [key, value] of childMap) {
181
- hostMap.set(key, value);
182
- }
183
- }
184
- /**
185
- * Merges two contract journalling maps together
186
- * For read maps, we just append the childMap arrays into the host map arrays, as the order is important
187
- *
188
- * @param hostMap - The map to be merged into
189
- * @param childMap - The map to be merged from
190
- */
191
- function mergeContractJournalMaps(hostMap, childMap) {
192
- for (const [key, value] of childMap) {
193
- const map1Value = hostMap.get(key);
194
- if (!map1Value) {
195
- hostMap.set(key, value);
196
- }
197
- else {
198
- mergeStorageJournalMaps(map1Value, value);
199
- }
200
- }
201
- }
202
- /**
203
- * @param hostMap - The map to be merge into
204
- * @param childMap - The map to be merged from
205
- */
206
- function mergeStorageJournalMaps(hostMap, childMap) {
207
- for (const [key, value] of childMap) {
208
- const readArr = hostMap.get(key);
209
- if (!readArr) {
210
- hostMap.set(key, value);
211
- }
212
- else {
213
- hostMap.set(key, readArr?.concat(...value));
214
- }
215
- }
216
- }
217
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiam91cm5hbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9hdm0vam91cm5hbC9qb3VybmFsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQXNCQTs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxPQUFPLG9CQUFvQjtJQXNCL0IsWUFBWSxXQUF3QixFQUFFLGFBQW9DO1FBbEIxRSxtREFBbUQ7UUFDbkQsc0VBQXNFO1FBQzlELGlCQUFZLEdBQW1DLElBQUksR0FBRyxFQUFFLENBQUM7UUFDekQsa0JBQWEsR0FBbUMsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUVsRSxvQkFBb0I7UUFDWixrQkFBYSxHQUFTLEVBQUUsQ0FBQztRQUN6QixrQkFBYSxHQUFTLEVBQUUsQ0FBQztRQUVqQyxlQUFlO1FBQ1Asa0JBQWEsR0FBVyxFQUFFLENBQUM7UUFDM0IsWUFBTyxHQUFXLEVBQUUsQ0FBQztRQUU3QixtQ0FBbUM7UUFDM0Isd0JBQW1CLEdBQWlDLElBQUksR0FBRyxFQUFFLENBQUM7UUFvRnRFLHFFQUFxRTtRQUM3RCxnQkFBVyxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDdkUsdUVBQXVFO1FBQy9ELGlCQUFZLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztRQWxGdkUsSUFBSSxDQUFDLFdBQVcsR0FBRyxXQUFXLENBQUM7UUFDL0IsSUFBSSxDQUFDLGFBQWEsR0FBRyxhQUFhLENBQUM7SUFDckMsQ0FBQztJQUVEOztPQUVHO0lBQ0ksSUFBSTtRQUNULE9BQU8sSUFBSSxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQzFELENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSSxZQUFZLENBQUMsZUFBbUIsRUFBRSxHQUFPLEVBQUUsS0FBUztR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
173
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiam91cm5hbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9hdm0vam91cm5hbC9qb3VybmFsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3hELE9BQU8sRUFBRSxZQUFZLEVBQUUsVUFBVSxFQUFFLGFBQWEsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQzdFLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUN0RCxPQUFPLEVBQUUsRUFBRSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFHOUMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNwRCxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxZQUFZLENBQUM7QUF5Qm5EOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxPQUFPLDBCQUEwQjtJQWlCckMsWUFBWSxXQUF3QixFQUFFLE1BQW1DO1FBSnpFLHdCQUF3QjtRQUNoQixrQkFBYSxHQUFvQixFQUFFLENBQUM7UUFDcEMsWUFBTyxHQUF1QixFQUFFLENBQUM7UUFHdkMsSUFBSSxDQUFDLFdBQVcsR0FBRyxXQUFXLENBQUM7UUFDL0IsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLGFBQWEsQ0FBQyxXQUFXLENBQUMsYUFBYSxFQUFFLE1BQU0sRUFBRSxhQUFhLENBQUMsQ0FBQztRQUN6RixJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksVUFBVSxDQUFDLFdBQVcsQ0FBQyxhQUFhLEVBQUUsTUFBTSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQ2hGLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxxQkFBcUIsQ0FBQyxNQUFNLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDeEQsQ0FBQztJQUVEOztPQUVHO0lBQ0ksSUFBSTtRQUNULE9BQU8s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
@@ -0,0 +1,85 @@
1
+ import { Fr } from '@aztec/foundation/fields';
2
+ import type { CommitmentsDB } from '../../index.js';
3
+ /**
4
+ * A class to manage new nullifier staging and existence checks during a contract call's AVM simulation.
5
+ * Maintains a nullifier cache, and ensures that existence checks fall back to the correct source.
6
+ * When a contract call completes, its cached nullifier set can be merged into its parent's.
7
+ */
8
+ export declare class Nullifiers {
9
+ /** Cached nullifiers. */
10
+ private cache;
11
+ /** Parent's nullifier cache. Checked on cache-miss. */
12
+ private readonly parentCache;
13
+ /** Reference to node storage. Checked on parent cache-miss. */
14
+ private readonly hostNullifiers;
15
+ constructor(hostNullifiers: CommitmentsDB, parent?: Nullifiers);
16
+ /**
17
+ * Get a nullifier's existence status.
18
+ * 1. Check cache.
19
+ * 2. Check parent's cache.
20
+ * 3. Fall back to the host state.
21
+ * 4. Not found! Nullifier does not exist.
22
+ *
23
+ * @param storageAddress - the address of the contract whose storage is being read from
24
+ * @param nullifier - the nullifier to check for
25
+ * @returns exists: whether the nullifier exists at all,
26
+ * isPending: whether the nullifier was found in a cache,
27
+ * leafIndex: the nullifier's leaf index if it exists and is not pending (comes from host state).
28
+ */
29
+ checkExists(storageAddress: Fr, nullifier: Fr): Promise<[/*exists=*/ boolean, /*isPending=*/ boolean, /*leafIndex=*/ Fr]>;
30
+ /**
31
+ * Stage a new nullifier (append it to the cache).
32
+ *
33
+ * @param storageAddress - the address of the contract that the nullifier is associated with
34
+ * @param nullifier - the nullifier to stage
35
+ */
36
+ append(storageAddress: Fr, nullifier: Fr): Promise<void>;
37
+ /**
38
+ * Merges another nullifier cache into this one.
39
+ *
40
+ * @param incomingNullifiers - the incoming cached nullifiers to merge into this instance's
41
+ */
42
+ acceptAndMerge(incomingNullifiers: Nullifiers): void;
43
+ }
44
+ /**
45
+ * A class to cache nullifiers created during a contract call's AVM simulation.
46
+ * "append" updates a map, "exists" checks that map.
47
+ * An instance of this class can merge another instance's cached nullifiers into its own.
48
+ */
49
+ export declare class NullifierCache {
50
+ /**
51
+ * Map for staging nullifiers.
52
+ * One inner-set per contract storage address,
53
+ * each entry being a nullifier.
54
+ */
55
+ private cachePerContract;
56
+ /**
57
+ * Check whether a nullifier exists in the cache.
58
+ *
59
+ * @param storageAddress - the address of the contract that the nullifier is associated with
60
+ * @param nullifier - the nullifier to check existence of
61
+ * @returns whether the nullifier is found in the cache
62
+ */
63
+ exists(storageAddress: Fr, nullifier: Fr): boolean;
64
+ /**
65
+ * Stage a new nullifier (append it to the cache).
66
+ *
67
+ * @param storageAddress - the address of the contract that the nullifier is associated with
68
+ * @param nullifier - the nullifier to stage
69
+ */
70
+ append(storageAddress: Fr, nullifier: Fr): void;
71
+ /**
72
+ * Merge another cache's nullifiers into this instance's.
73
+ *
74
+ * Cached nullifiers in "incoming" must not collide with any present in "this".
75
+ *
76
+ * In practice, "this" is a parent call's pending nullifiers, and "incoming" is a nested call's.
77
+ *
78
+ * @param incomingNullifiers - the incoming cached nullifiers to merge into this instance's
79
+ */
80
+ acceptAndMerge(incomingNullifiers: NullifierCache): void;
81
+ }
82
+ export declare class NullifierCollisionError extends Error {
83
+ constructor(message: string, ...rest: any[]);
84
+ }
85
+ //# sourceMappingURL=nullifiers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nullifiers.d.ts","sourceRoot":"","sources":["../../../src/avm/journal/nullifiers.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAE9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD;;;;GAIG;AACH,qBAAa,UAAU;IACrB,yBAAyB;IACzB,OAAO,CAAC,KAAK,CAAiB;IAC9B,uDAAuD;IACvD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;IACzD,+DAA+D;IAC/D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgB;gBAEnC,cAAc,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,UAAU;IAM9D;;;;;;;;;;;;OAYG;IACU,WAAW,CACtB,cAAc,EAAE,EAAE,EAClB,SAAS,EAAE,EAAE,GACZ,OAAO,CAAC,CAAC,WAAW,CAAC,OAAO,EAAE,cAAc,CAAC,OAAO,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC;IAmB5E;;;;;OAKG;IACU,MAAM,CAAC,cAAc,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE;IAUrD;;;;OAIG;IACI,cAAc,CAAC,kBAAkB,EAAE,UAAU;CAGrD;AAED;;;;GAIG;AACH,qBAAa,cAAc;IACzB;;;;OAIG;IACH,OAAO,CAAC,gBAAgB,CAAuC;IAE/D;;;;;;OAMG;IACI,MAAM,CAAC,cAAc,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,GAAG,OAAO;IAKzD;;;;;OAKG;IACI,MAAM,CAAC,cAAc,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE;IAe/C;;;;;;;;OAQG;IACI,cAAc,CAAC,kBAAkB,EAAE,cAAc;CAsBzD;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE;CAI5C"}
@@ -0,0 +1,147 @@
1
+ import { siloNullifier } from '@aztec/circuits.js/hash';
2
+ import { Fr } from '@aztec/foundation/fields';
3
+ /**
4
+ * A class to manage new nullifier staging and existence checks during a contract call's AVM simulation.
5
+ * Maintains a nullifier cache, and ensures that existence checks fall back to the correct source.
6
+ * When a contract call completes, its cached nullifier set can be merged into its parent's.
7
+ */
8
+ export class Nullifiers {
9
+ constructor(hostNullifiers, parent) {
10
+ this.hostNullifiers = hostNullifiers;
11
+ this.parentCache = parent?.cache;
12
+ this.cache = new NullifierCache();
13
+ }
14
+ /**
15
+ * Get a nullifier's existence status.
16
+ * 1. Check cache.
17
+ * 2. Check parent's cache.
18
+ * 3. Fall back to the host state.
19
+ * 4. Not found! Nullifier does not exist.
20
+ *
21
+ * @param storageAddress - the address of the contract whose storage is being read from
22
+ * @param nullifier - the nullifier to check for
23
+ * @returns exists: whether the nullifier exists at all,
24
+ * isPending: whether the nullifier was found in a cache,
25
+ * leafIndex: the nullifier's leaf index if it exists and is not pending (comes from host state).
26
+ */
27
+ async checkExists(storageAddress, nullifier) {
28
+ // First check this cache
29
+ let existsAsPending = this.cache.exists(storageAddress, nullifier);
30
+ // Then check parent's cache
31
+ if (!existsAsPending && this.parentCache) {
32
+ existsAsPending = this.parentCache?.exists(storageAddress, nullifier);
33
+ }
34
+ // Finally try the host's Aztec state (a trip to the database)
35
+ // If the value is found in the database, it will be associated with a leaf index!
36
+ let leafIndex = undefined;
37
+ if (!existsAsPending) {
38
+ // silo the nullifier before checking for its existence in the host
39
+ leafIndex = await this.hostNullifiers.getNullifierIndex(siloNullifier(storageAddress, nullifier));
40
+ }
41
+ const exists = existsAsPending || leafIndex !== undefined;
42
+ leafIndex = leafIndex === undefined ? BigInt(0) : leafIndex;
43
+ return Promise.resolve([exists, existsAsPending, new Fr(leafIndex)]);
44
+ }
45
+ /**
46
+ * Stage a new nullifier (append it to the cache).
47
+ *
48
+ * @param storageAddress - the address of the contract that the nullifier is associated with
49
+ * @param nullifier - the nullifier to stage
50
+ */
51
+ async append(storageAddress, nullifier) {
52
+ const [exists, ,] = await this.checkExists(storageAddress, nullifier);
53
+ if (exists) {
54
+ throw new NullifierCollisionError(`Nullifier ${nullifier} at contract ${storageAddress} already exists in parent cache or host.`);
55
+ }
56
+ this.cache.append(storageAddress, nullifier);
57
+ }
58
+ /**
59
+ * Merges another nullifier cache into this one.
60
+ *
61
+ * @param incomingNullifiers - the incoming cached nullifiers to merge into this instance's
62
+ */
63
+ acceptAndMerge(incomingNullifiers) {
64
+ this.cache.acceptAndMerge(incomingNullifiers.cache);
65
+ }
66
+ }
67
+ /**
68
+ * A class to cache nullifiers created during a contract call's AVM simulation.
69
+ * "append" updates a map, "exists" checks that map.
70
+ * An instance of this class can merge another instance's cached nullifiers into its own.
71
+ */
72
+ export class NullifierCache {
73
+ constructor() {
74
+ /**
75
+ * Map for staging nullifiers.
76
+ * One inner-set per contract storage address,
77
+ * each entry being a nullifier.
78
+ */
79
+ this.cachePerContract = new Map();
80
+ }
81
+ /**
82
+ * Check whether a nullifier exists in the cache.
83
+ *
84
+ * @param storageAddress - the address of the contract that the nullifier is associated with
85
+ * @param nullifier - the nullifier to check existence of
86
+ * @returns whether the nullifier is found in the cache
87
+ */
88
+ exists(storageAddress, nullifier) {
89
+ const exists = this.cachePerContract.get(storageAddress.toBigInt())?.has(nullifier.toBigInt());
90
+ return exists ? true : false;
91
+ }
92
+ /**
93
+ * Stage a new nullifier (append it to the cache).
94
+ *
95
+ * @param storageAddress - the address of the contract that the nullifier is associated with
96
+ * @param nullifier - the nullifier to stage
97
+ */
98
+ append(storageAddress, nullifier) {
99
+ let nullifiersForContract = this.cachePerContract.get(storageAddress.toBigInt());
100
+ // If this contract's nullifier set has no cached nullifiers, create a new Set to store them
101
+ if (!nullifiersForContract) {
102
+ nullifiersForContract = new Set();
103
+ this.cachePerContract.set(storageAddress.toBigInt(), nullifiersForContract);
104
+ }
105
+ if (nullifiersForContract.has(nullifier.toBigInt())) {
106
+ throw new NullifierCollisionError(`Nullifier ${nullifier} at contract ${storageAddress} already exists in cache.`);
107
+ }
108
+ nullifiersForContract.add(nullifier.toBigInt());
109
+ }
110
+ /**
111
+ * Merge another cache's nullifiers into this instance's.
112
+ *
113
+ * Cached nullifiers in "incoming" must not collide with any present in "this".
114
+ *
115
+ * In practice, "this" is a parent call's pending nullifiers, and "incoming" is a nested call's.
116
+ *
117
+ * @param incomingNullifiers - the incoming cached nullifiers to merge into this instance's
118
+ */
119
+ acceptAndMerge(incomingNullifiers) {
120
+ // Iterate over all contracts with staged writes in the child.
121
+ for (const [incomingAddress, incomingCacheAtContract] of incomingNullifiers.cachePerContract) {
122
+ const thisCacheAtContract = this.cachePerContract.get(incomingAddress);
123
+ if (!thisCacheAtContract) {
124
+ // This contract has no nullifiers cached here
125
+ // so just accept incoming cache as-is for this contract.
126
+ this.cachePerContract.set(incomingAddress, incomingCacheAtContract);
127
+ }
128
+ else {
129
+ // "Incoming" and "this" both have cached nullifiers for this contract.
130
+ // Merge in incoming nullifiers, erroring if there are any duplicates.
131
+ for (const nullifier of incomingCacheAtContract) {
132
+ if (thisCacheAtContract.has(nullifier)) {
133
+ throw new NullifierCollisionError(`Failed to accept child call's nullifiers. Nullifier ${nullifier} already exists at contract ${incomingAddress}.`);
134
+ }
135
+ thisCacheAtContract.add(nullifier);
136
+ }
137
+ }
138
+ }
139
+ }
140
+ }
141
+ export class NullifierCollisionError extends Error {
142
+ constructor(message, ...rest) {
143
+ super(message, ...rest);
144
+ this.name = 'NullifierCollisionError';
145
+ }
146
+ }
147
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnVsbGlmaWVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9hdm0vam91cm5hbC9udWxsaWZpZXJzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN4RCxPQUFPLEVBQUUsRUFBRSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFJOUM7Ozs7R0FJRztBQUNILE1BQU0sT0FBTyxVQUFVO0lBUXJCLFlBQVksY0FBNkIsRUFBRSxNQUFtQjtRQUM1RCxJQUFJLENBQUMsY0FBYyxHQUFHLGNBQWMsQ0FBQztRQUNyQyxJQUFJLENBQUMsV0FBVyxHQUFHLE1BQU0sRUFBRSxLQUFLLENBQUM7UUFDakMsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLGNBQWMsRUFBRSxDQUFDO0lBQ3BDLENBQUM7SUFFRDs7Ozs7Ozs7Ozs7O09BWUc7SUFDSSxLQUFLLENBQUMsV0FBVyxDQUN0QixjQUFrQixFQUNsQixTQUFhO1FBRWIseUJBQXlCO1FBQ3pCLElBQUksZUFBZSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLGNBQWMsRUFBRSxTQUFTLENBQUMsQ0FBQztRQUNuRSw0QkFBNEI7UUFDNUIsSUFBSSxDQUFDLGVBQWUsSUFBSSxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDekMsZUFBZSxHQUFHLElBQUksQ0FBQyxXQUFXLEVBQUUsTUFBTSxDQUFDLGNBQWMsRUFBRSxTQUFTLENBQUMsQ0FBQztRQUN4RSxDQUFDO1FBQ0QsOERBQThEO1FBQzlELGtGQUFrRjtRQUNsRixJQUFJLFNBQVMsR0FBdUIsU0FBUyxDQUFDO1FBQzlDLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUNyQixtRUFBbUU7WUFDbkUsU0FBUyxHQUFHLE1BQU0sSUFBSSxDQUFDLGNBQWMsQ0FBQyxpQkFBaUIsQ0FBQyxhQUFhLENBQUMsY0FBYyxFQUFFLFNBQVMsQ0FBQyxDQUFD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