@aztec/simulator 0.59.0 → 0.61.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.
- package/dest/acvm/acvm.d.ts +1 -0
- package/dest/acvm/acvm.d.ts.map +1 -1
- package/dest/acvm/oracle/oracle.d.ts +5 -3
- package/dest/acvm/oracle/oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/oracle.js +15 -7
- package/dest/acvm/oracle/typed_oracle.d.ts +7 -4
- package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/typed_oracle.js +10 -4
- package/dest/acvm/serialize.d.ts +1 -0
- package/dest/acvm/serialize.d.ts.map +1 -1
- package/dest/avm/avm_context.d.ts +1 -1
- package/dest/avm/avm_context.js +1 -1
- package/dest/avm/avm_execution_environment.d.ts +2 -5
- package/dest/avm/avm_execution_environment.d.ts.map +1 -1
- package/dest/avm/avm_execution_environment.js +7 -15
- package/dest/avm/avm_gas.d.ts.map +1 -1
- package/dest/avm/avm_gas.js +6 -10
- package/dest/avm/avm_machine_state.d.ts +2 -0
- package/dest/avm/avm_machine_state.d.ts.map +1 -1
- package/dest/avm/avm_machine_state.js +3 -1
- package/dest/avm/avm_memory_types.d.ts +1 -0
- package/dest/avm/avm_memory_types.d.ts.map +1 -1
- package/dest/avm/avm_simulator.d.ts +16 -0
- package/dest/avm/avm_simulator.d.ts.map +1 -1
- package/dest/avm/avm_simulator.js +45 -4
- package/dest/avm/bytecode_utils.d.ts +1 -0
- package/dest/avm/bytecode_utils.d.ts.map +1 -1
- package/dest/avm/fixtures/index.d.ts +3 -0
- package/dest/avm/fixtures/index.d.ts.map +1 -1
- package/dest/avm/fixtures/index.js +8 -2
- package/dest/avm/journal/journal.d.ts +19 -19
- package/dest/avm/journal/journal.d.ts.map +1 -1
- package/dest/avm/journal/journal.js +73 -48
- package/dest/avm/journal/nullifiers.d.ts +9 -9
- package/dest/avm/journal/nullifiers.d.ts.map +1 -1
- package/dest/avm/journal/nullifiers.js +24 -24
- package/dest/avm/journal/public_storage.d.ts +10 -10
- package/dest/avm/journal/public_storage.d.ts.map +1 -1
- package/dest/avm/journal/public_storage.js +21 -21
- package/dest/avm/opcodes/accrued_substate.d.ts.map +1 -1
- package/dest/avm/opcodes/accrued_substate.js +5 -5
- package/dest/avm/opcodes/contract.d.ts +8 -1
- package/dest/avm/opcodes/contract.d.ts.map +1 -1
- package/dest/avm/opcodes/contract.js +41 -21
- package/dest/avm/opcodes/conversion.d.ts +1 -1
- package/dest/avm/opcodes/conversion.d.ts.map +1 -1
- package/dest/avm/opcodes/conversion.js +12 -9
- package/dest/avm/opcodes/environment_getters.d.ts +13 -14
- package/dest/avm/opcodes/environment_getters.d.ts.map +1 -1
- package/dest/avm/opcodes/environment_getters.js +17 -16
- package/dest/avm/opcodes/external_calls.d.ts +3 -6
- package/dest/avm/opcodes/external_calls.d.ts.map +1 -1
- package/dest/avm/opcodes/external_calls.js +23 -43
- package/dest/avm/opcodes/hashing.d.ts +2 -26
- package/dest/avm/opcodes/hashing.d.ts.map +1 -1
- package/dest/avm/opcodes/hashing.js +11 -95
- package/dest/avm/opcodes/index.d.ts +0 -1
- package/dest/avm/opcodes/index.d.ts.map +1 -1
- package/dest/avm/opcodes/index.js +1 -2
- package/dest/avm/opcodes/instruction.d.ts +1 -0
- package/dest/avm/opcodes/instruction.d.ts.map +1 -1
- package/dest/avm/opcodes/memory.d.ts +20 -0
- package/dest/avm/opcodes/memory.d.ts.map +1 -1
- package/dest/avm/opcodes/memory.js +59 -3
- package/dest/avm/opcodes/storage.js +3 -3
- package/dest/avm/serialization/buffer_cursor.d.ts +1 -0
- package/dest/avm/serialization/buffer_cursor.d.ts.map +1 -1
- package/dest/avm/serialization/bytecode_serialization.d.ts +1 -0
- package/dest/avm/serialization/bytecode_serialization.d.ts.map +1 -1
- package/dest/avm/serialization/bytecode_serialization.js +5 -7
- package/dest/avm/serialization/instruction_serialization.d.ts +34 -35
- package/dest/avm/serialization/instruction_serialization.d.ts.map +1 -1
- package/dest/avm/serialization/instruction_serialization.js +34 -36
- package/dest/avm/test_utils.d.ts +3 -1
- package/dest/avm/test_utils.d.ts.map +1 -1
- package/dest/avm/test_utils.js +4 -1
- package/dest/client/client_execution_context.d.ts +9 -18
- package/dest/client/client_execution_context.d.ts.map +1 -1
- package/dest/client/client_execution_context.js +30 -50
- package/dest/client/db_oracle.d.ts +17 -1
- package/dest/client/db_oracle.d.ts.map +1 -1
- package/dest/client/db_oracle.js +1 -1
- package/dest/client/private_execution.d.ts.map +1 -1
- package/dest/client/private_execution.js +3 -4
- package/dest/client/simulator.d.ts.map +1 -1
- package/dest/client/simulator.js +3 -3
- package/dest/client/view_data_oracle.d.ts +17 -1
- package/dest/client/view_data_oracle.d.ts.map +1 -1
- package/dest/client/view_data_oracle.js +21 -1
- package/dest/common/index.d.ts +0 -1
- package/dest/common/index.d.ts.map +1 -1
- package/dest/common/index.js +1 -2
- package/dest/mocks/fixtures.js +2 -2
- package/dest/providers/acvm_native.d.ts +1 -0
- package/dest/providers/acvm_native.d.ts.map +1 -1
- package/dest/public/db_interfaces.d.ts +1 -0
- package/dest/public/db_interfaces.d.ts.map +1 -1
- package/dest/public/dual_side_effect_trace.d.ts +10 -11
- package/dest/public/dual_side_effect_trace.d.ts.map +1 -1
- package/dest/public/dual_side_effect_trace.js +26 -22
- package/dest/public/enqueued_call_side_effect_trace.d.ts +11 -12
- package/dest/public/enqueued_call_side_effect_trace.d.ts.map +1 -1
- package/dest/public/enqueued_call_side_effect_trace.js +33 -23
- package/dest/public/enqueued_call_simulator.d.ts +3 -3
- package/dest/public/enqueued_call_simulator.d.ts.map +1 -1
- package/dest/public/enqueued_call_simulator.js +30 -39
- package/dest/public/enqueued_calls_processor.d.ts +2 -3
- package/dest/public/enqueued_calls_processor.d.ts.map +1 -1
- package/dest/public/enqueued_calls_processor.js +19 -26
- package/dest/public/execution.d.ts +1 -0
- package/dest/public/execution.d.ts.map +1 -1
- package/dest/public/execution.js +2 -2
- package/dest/public/executor.d.ts.map +1 -1
- package/dest/public/executor.js +6 -5
- package/dest/public/public_db_sources.d.ts +1 -0
- package/dest/public/public_db_sources.d.ts.map +1 -1
- package/dest/public/public_kernel.d.ts +0 -1
- package/dest/public/public_kernel.d.ts.map +1 -1
- package/dest/public/public_kernel.js +5 -8
- package/dest/public/public_kernel_tail_simulator.d.ts +1 -5
- package/dest/public/public_kernel_tail_simulator.d.ts.map +1 -1
- package/dest/public/public_kernel_tail_simulator.js +6 -12
- package/dest/public/public_processor.js +4 -4
- package/dest/public/side_effect_trace.d.ts +11 -9
- package/dest/public/side_effect_trace.d.ts.map +1 -1
- package/dest/public/side_effect_trace.js +40 -30
- package/dest/public/side_effect_trace_interface.d.ts +10 -9
- package/dest/public/side_effect_trace_interface.d.ts.map +1 -1
- package/package.json +9 -9
- package/src/acvm/oracle/oracle.ts +13 -6
- package/src/acvm/oracle/typed_oracle.ts +9 -3
- package/src/avm/avm_context.ts +1 -1
- package/src/avm/avm_execution_environment.ts +0 -15
- package/src/avm/avm_gas.ts +5 -9
- package/src/avm/avm_machine_state.ts +2 -0
- package/src/avm/avm_simulator.ts +69 -6
- package/src/avm/fixtures/index.ts +7 -2
- package/src/avm/journal/journal.ts +93 -50
- package/src/avm/journal/nullifiers.ts +23 -23
- package/src/avm/journal/public_storage.ts +20 -20
- package/src/avm/opcodes/accrued_substate.ts +4 -8
- package/src/avm/opcodes/contract.ts +45 -21
- package/src/avm/opcodes/conversion.ts +9 -6
- package/src/avm/opcodes/environment_getters.ts +7 -5
- package/src/avm/opcodes/external_calls.ts +21 -45
- package/src/avm/opcodes/hashing.ts +9 -122
- package/src/avm/opcodes/index.ts +0 -1
- package/src/avm/opcodes/memory.ts +69 -2
- package/src/avm/opcodes/storage.ts +2 -2
- package/src/avm/serialization/bytecode_serialization.ts +6 -9
- package/src/avm/serialization/instruction_serialization.ts +3 -5
- package/src/avm/test_utils.ts +5 -1
- package/src/client/client_execution_context.ts +21 -71
- package/src/client/db_oracle.ts +26 -0
- package/src/client/private_execution.ts +1 -9
- package/src/client/simulator.ts +0 -2
- package/src/client/view_data_oracle.ts +31 -1
- package/src/common/index.ts +0 -1
- package/src/mocks/fixtures.ts +1 -1
- package/src/public/dual_side_effect_trace.ts +38 -24
- package/src/public/enqueued_call_side_effect_trace.ts +60 -28
- package/src/public/enqueued_call_simulator.ts +52 -49
- package/src/public/enqueued_calls_processor.ts +27 -41
- package/src/public/execution.ts +1 -1
- package/src/public/executor.ts +11 -5
- package/src/public/public_kernel.ts +9 -12
- package/src/public/public_kernel_tail_simulator.ts +6 -15
- package/src/public/public_processor.ts +3 -3
- package/src/public/side_effect_trace.ts +73 -29
- package/src/public/side_effect_trace_interface.ts +15 -10
- package/dest/avm/opcodes/commitment.d.ts +0 -16
- package/dest/avm/opcodes/commitment.d.ts.map +0 -1
- package/dest/avm/opcodes/commitment.js +0 -51
- package/dest/client/test_utils.d.ts +0 -9
- package/dest/client/test_utils.d.ts.map +0 -1
- package/dest/client/test_utils.js +0 -27
- package/dest/common/side_effect_counter.d.ts +0 -10
- package/dest/common/side_effect_counter.d.ts.map +0 -1
- package/dest/common/side_effect_counter.js +0 -18
- package/dest/rollup/index.d.ts +0 -2
- package/dest/rollup/index.d.ts.map +0 -1
- package/dest/rollup/index.js +0 -2
- package/dest/rollup/rollup.d.ts +0 -101
- package/dest/rollup/rollup.d.ts.map +0 -1
- package/dest/rollup/rollup.js +0 -100
- package/src/avm/opcodes/commitment.ts +0 -65
- package/src/client/test_utils.ts +0 -57
- package/src/common/side_effect_counter.ts +0 -17
- package/src/rollup/index.ts +0 -1
- package/src/rollup/rollup.ts +0 -228
package/src/avm/avm_simulator.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { strict as assert } from 'assert';
|
|
|
6
6
|
import { SideEffectLimitReachedError } from '../public/side_effect_errors.js';
|
|
7
7
|
import type { AvmContext } from './avm_context.js';
|
|
8
8
|
import { AvmContractCallResult } from './avm_contract_call_result.js';
|
|
9
|
+
import { type Gas } from './avm_gas.js';
|
|
9
10
|
import { isAvmBytecode } from './bytecode_utils.js';
|
|
10
11
|
import {
|
|
11
12
|
AvmExecutionError,
|
|
@@ -17,9 +18,21 @@ import {
|
|
|
17
18
|
import type { Instruction } from './opcodes/index.js';
|
|
18
19
|
import { decodeFromBytecode } from './serialization/bytecode_serialization.js';
|
|
19
20
|
|
|
21
|
+
type OpcodeTally = {
|
|
22
|
+
count: number;
|
|
23
|
+
gas: Gas;
|
|
24
|
+
};
|
|
25
|
+
type PcTally = {
|
|
26
|
+
opcode: string;
|
|
27
|
+
count: number;
|
|
28
|
+
gas: Gas;
|
|
29
|
+
};
|
|
30
|
+
|
|
20
31
|
export class AvmSimulator {
|
|
21
32
|
private log: DebugLogger;
|
|
22
33
|
private bytecode: Buffer | undefined;
|
|
34
|
+
public opcodeTallies: Map<string, OpcodeTally> = new Map();
|
|
35
|
+
public pcTallies: Map<number, PcTally> = new Map();
|
|
23
36
|
|
|
24
37
|
constructor(private context: AvmContext) {
|
|
25
38
|
assert(
|
|
@@ -33,10 +46,7 @@ export class AvmSimulator {
|
|
|
33
46
|
* Fetch the bytecode and execute it in the current context.
|
|
34
47
|
*/
|
|
35
48
|
public async execute(): Promise<AvmContractCallResult> {
|
|
36
|
-
const bytecode = await this.context.persistableState.getBytecode(
|
|
37
|
-
this.context.environment.address,
|
|
38
|
-
this.context.environment.functionSelector,
|
|
39
|
-
);
|
|
49
|
+
const bytecode = await this.context.persistableState.getBytecode(this.context.environment.address);
|
|
40
50
|
|
|
41
51
|
// This assumes that we will not be able to send messages to accounts without code
|
|
42
52
|
// Pending classes and instances impl details
|
|
@@ -75,6 +85,7 @@ export class AvmSimulator {
|
|
|
75
85
|
try {
|
|
76
86
|
// Execute instruction pointed to by the current program counter
|
|
77
87
|
// continuing until the machine state signifies a halt
|
|
88
|
+
let instrCounter = 0;
|
|
78
89
|
while (!machineState.getHalted()) {
|
|
79
90
|
const instruction = instructions[machineState.pc];
|
|
80
91
|
assert(
|
|
@@ -82,13 +93,26 @@ export class AvmSimulator {
|
|
|
82
93
|
'AVM attempted to execute non-existent instruction. This should never happen (invalid bytecode or AVM simulator bug)!',
|
|
83
94
|
);
|
|
84
95
|
|
|
85
|
-
const
|
|
86
|
-
|
|
96
|
+
const instrStartGas = machineState.gasLeft; // Save gas before executing instruction (for profiling)
|
|
97
|
+
const instrPc = machineState.pc; // Save PC before executing instruction (for profiling)
|
|
98
|
+
|
|
99
|
+
this.log.debug(
|
|
100
|
+
`[PC:${machineState.pc}] [IC:${instrCounter++}] ${instruction.toString()} (gasLeft l2=${
|
|
101
|
+
machineState.l2GasLeft
|
|
102
|
+
} da=${machineState.daGasLeft})`,
|
|
103
|
+
);
|
|
87
104
|
// Execute the instruction.
|
|
88
105
|
// Normal returns and reverts will return normally here.
|
|
89
106
|
// "Exceptional halts" will throw.
|
|
90
107
|
await instruction.execute(this.context);
|
|
91
108
|
|
|
109
|
+
// gas used by this instruction - used for profiling/tallying
|
|
110
|
+
const gasUsed: Gas = {
|
|
111
|
+
l2Gas: instrStartGas.l2Gas - machineState.l2GasLeft,
|
|
112
|
+
daGas: instrStartGas.daGas - machineState.daGasLeft,
|
|
113
|
+
};
|
|
114
|
+
this.tallyInstruction(instrPc, instruction.constructor.name, gasUsed);
|
|
115
|
+
|
|
92
116
|
if (machineState.pc >= instructions.length) {
|
|
93
117
|
this.log.warn('Passed end of program');
|
|
94
118
|
throw new InvalidProgramCounterError(machineState.pc, /*max=*/ instructions.length);
|
|
@@ -100,6 +124,8 @@ export class AvmSimulator {
|
|
|
100
124
|
const revertReason = reverted ? revertReasonFromExplicitRevert(output, this.context) : undefined;
|
|
101
125
|
const results = new AvmContractCallResult(reverted, output, revertReason);
|
|
102
126
|
this.log.debug(`Context execution results: ${results.toString()}`);
|
|
127
|
+
|
|
128
|
+
this.printOpcodeTallies();
|
|
103
129
|
// Return results for processing by calling context
|
|
104
130
|
return results;
|
|
105
131
|
} catch (err: any) {
|
|
@@ -113,8 +139,45 @@ export class AvmSimulator {
|
|
|
113
139
|
// Note: "exceptional halts" cannot return data, hence []
|
|
114
140
|
const results = new AvmContractCallResult(/*reverted=*/ true, /*output=*/ [], revertReason);
|
|
115
141
|
this.log.debug(`Context execution results: ${results.toString()}`);
|
|
142
|
+
|
|
143
|
+
this.printOpcodeTallies();
|
|
116
144
|
// Return results for processing by calling context
|
|
117
145
|
return results;
|
|
118
146
|
}
|
|
119
147
|
}
|
|
148
|
+
|
|
149
|
+
private tallyInstruction(pc: number, opcode: string, gasUsed: Gas) {
|
|
150
|
+
const opcodeTally = this.opcodeTallies.get(opcode) || ({ count: 0, gas: { l2Gas: 0, daGas: 0 } } as OpcodeTally);
|
|
151
|
+
opcodeTally.count++;
|
|
152
|
+
opcodeTally.gas.l2Gas += gasUsed.l2Gas;
|
|
153
|
+
opcodeTally.gas.daGas += gasUsed.daGas;
|
|
154
|
+
this.opcodeTallies.set(opcode, opcodeTally);
|
|
155
|
+
|
|
156
|
+
const pcTally = this.pcTallies.get(pc) || ({ opcode: opcode, count: 0, gas: { l2Gas: 0, daGas: 0 } } as PcTally);
|
|
157
|
+
pcTally.count++;
|
|
158
|
+
pcTally.gas.l2Gas += gasUsed.l2Gas;
|
|
159
|
+
pcTally.gas.daGas += gasUsed.daGas;
|
|
160
|
+
this.pcTallies.set(pc, pcTally);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
private printOpcodeTallies() {
|
|
164
|
+
this.log.debug(`Printing tallies per opcode sorted by gas...`);
|
|
165
|
+
// sort descending by L2 gas consumed
|
|
166
|
+
const sortedOpcodes = Array.from(this.opcodeTallies.entries()).sort((a, b) => b[1].gas.l2Gas - a[1].gas.l2Gas);
|
|
167
|
+
for (const [opcode, tally] of sortedOpcodes) {
|
|
168
|
+
// NOTE: don't care to clutter the logs with DA gas for now
|
|
169
|
+
this.log.debug(`${opcode} executed ${tally.count} times consuming a total of ${tally.gas.l2Gas} L2 gas`);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
this.log.debug(`Printing tallies per PC sorted by #times each PC was executed...`);
|
|
173
|
+
const sortedPcs = Array.from(this.pcTallies.entries())
|
|
174
|
+
.sort((a, b) => b[1].count - a[1].count)
|
|
175
|
+
.filter((_, i) => i < 20);
|
|
176
|
+
for (const [pc, tally] of sortedPcs) {
|
|
177
|
+
// NOTE: don't care to clutter the logs with DA gas for now
|
|
178
|
+
this.log.debug(
|
|
179
|
+
`PC:${pc} containing opcode ${tally.opcode} executed ${tally.count} times consuming a total of ${tally.gas.l2Gas} L2 gas`,
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
120
183
|
}
|
|
@@ -58,14 +58,12 @@ export function initPersistableStateManager(overrides?: {
|
|
|
58
58
|
export function initExecutionEnvironment(overrides?: Partial<AvmExecutionEnvironment>): AvmExecutionEnvironment {
|
|
59
59
|
return new AvmExecutionEnvironment(
|
|
60
60
|
overrides?.address ?? AztecAddress.zero(),
|
|
61
|
-
overrides?.storageAddress ?? AztecAddress.zero(),
|
|
62
61
|
overrides?.sender ?? AztecAddress.zero(),
|
|
63
62
|
overrides?.functionSelector ?? FunctionSelector.empty(),
|
|
64
63
|
overrides?.contractCallDepth ?? Fr.zero(),
|
|
65
64
|
overrides?.transactionFee ?? Fr.zero(),
|
|
66
65
|
overrides?.globals ?? GlobalVariables.empty(),
|
|
67
66
|
overrides?.isStaticCall ?? false,
|
|
68
|
-
overrides?.isDelegateCall ?? false,
|
|
69
67
|
overrides?.calldata ?? [],
|
|
70
68
|
);
|
|
71
69
|
}
|
|
@@ -119,6 +117,13 @@ export function randomMemoryFields(length: number): Field[] {
|
|
|
119
117
|
return [...Array(length)].map(_ => new Field(Fr.random()));
|
|
120
118
|
}
|
|
121
119
|
|
|
120
|
+
export function getAvmTestContractFunctionSelector(functionName: string): FunctionSelector {
|
|
121
|
+
const artifact = AvmTestContractArtifact.functions.find(f => f.name === functionName)!;
|
|
122
|
+
assert(!!artifact, `Function ${functionName} not found in AvmTestContractArtifact`);
|
|
123
|
+
const params = artifact.parameters;
|
|
124
|
+
return FunctionSelector.fromNameAndParameters(artifact.name, params);
|
|
125
|
+
}
|
|
126
|
+
|
|
122
127
|
export function getAvmTestContractBytecode(functionName: string): Buffer {
|
|
123
128
|
const artifact = AvmTestContractArtifact.functions.find(f => f.name === functionName)!;
|
|
124
129
|
assert(
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
AztecAddress,
|
|
3
|
+
type Gas,
|
|
4
|
+
SerializableContractInstance,
|
|
5
|
+
computePublicBytecodeCommitment,
|
|
6
|
+
} from '@aztec/circuits.js';
|
|
2
7
|
import { Fr } from '@aztec/foundation/fields';
|
|
3
8
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
4
9
|
|
|
10
|
+
import assert from 'assert';
|
|
11
|
+
|
|
5
12
|
import { getPublicFunctionDebugName } from '../../common/debug_fn_name.js';
|
|
6
13
|
import { type WorldStateDB } from '../../public/public_db_sources.js';
|
|
7
|
-
import { type TracedContractInstance } from '../../public/side_effect_trace.js';
|
|
8
14
|
import { type PublicSideEffectTraceInterface } from '../../public/side_effect_trace_interface.js';
|
|
9
15
|
import { type AvmContractCallResult } from '../avm_contract_call_result.js';
|
|
10
16
|
import { type AvmExecutionEnvironment } from '../avm_execution_environment.js';
|
|
@@ -67,44 +73,44 @@ export class AvmPersistableStateManager {
|
|
|
67
73
|
/**
|
|
68
74
|
* Write to public storage, journal/trace the write.
|
|
69
75
|
*
|
|
70
|
-
* @param
|
|
76
|
+
* @param contractAddress - the address of the contract whose storage is being written to
|
|
71
77
|
* @param slot - the slot in the contract's storage being written to
|
|
72
78
|
* @param value - the value being written to the slot
|
|
73
79
|
*/
|
|
74
|
-
public writeStorage(
|
|
75
|
-
this.log.debug(`Storage write (address=${
|
|
80
|
+
public writeStorage(contractAddress: Fr, slot: Fr, value: Fr) {
|
|
81
|
+
this.log.debug(`Storage write (address=${contractAddress}, slot=${slot}): value=${value}`);
|
|
76
82
|
// Cache storage writes for later reference/reads
|
|
77
|
-
this.publicStorage.write(
|
|
78
|
-
this.trace.tracePublicStorageWrite(
|
|
83
|
+
this.publicStorage.write(contractAddress, slot, value);
|
|
84
|
+
this.trace.tracePublicStorageWrite(contractAddress, slot, value);
|
|
79
85
|
}
|
|
80
86
|
|
|
81
87
|
/**
|
|
82
88
|
* Read from public storage, trace the read.
|
|
83
89
|
*
|
|
84
|
-
* @param
|
|
90
|
+
* @param contractAddress - the address of the contract whose storage is being read from
|
|
85
91
|
* @param slot - the slot in the contract's storage being read from
|
|
86
92
|
* @returns the latest value written to slot, or 0 if never written to before
|
|
87
93
|
*/
|
|
88
|
-
public async readStorage(
|
|
89
|
-
const { value, exists, cached } = await this.publicStorage.read(
|
|
94
|
+
public async readStorage(contractAddress: Fr, slot: Fr): Promise<Fr> {
|
|
95
|
+
const { value, exists, cached } = await this.publicStorage.read(contractAddress, slot);
|
|
90
96
|
this.log.debug(
|
|
91
|
-
`Storage read (address=${
|
|
97
|
+
`Storage read (address=${contractAddress}, slot=${slot}): value=${value}, exists=${exists}, cached=${cached}`,
|
|
92
98
|
);
|
|
93
|
-
this.trace.tracePublicStorageRead(
|
|
99
|
+
this.trace.tracePublicStorageRead(contractAddress, slot, value, exists, cached);
|
|
94
100
|
return Promise.resolve(value);
|
|
95
101
|
}
|
|
96
102
|
|
|
97
103
|
/**
|
|
98
104
|
* Read from public storage, don't trace the read.
|
|
99
105
|
*
|
|
100
|
-
* @param
|
|
106
|
+
* @param contractAddress - the address of the contract whose storage is being read from
|
|
101
107
|
* @param slot - the slot in the contract's storage being read from
|
|
102
108
|
* @returns the latest value written to slot, or 0 if never written to before
|
|
103
109
|
*/
|
|
104
|
-
public async peekStorage(
|
|
105
|
-
const { value, exists, cached } = await this.publicStorage.read(
|
|
110
|
+
public async peekStorage(contractAddress: Fr, slot: Fr): Promise<Fr> {
|
|
111
|
+
const { value, exists, cached } = await this.publicStorage.read(contractAddress, slot);
|
|
106
112
|
this.log.debug(
|
|
107
|
-
`Storage peek (address=${
|
|
113
|
+
`Storage peek (address=${contractAddress}, slot=${slot}): value=${value}, exists=${exists}, cached=${cached}`,
|
|
108
114
|
);
|
|
109
115
|
return Promise.resolve(value);
|
|
110
116
|
}
|
|
@@ -113,20 +119,20 @@ export class AvmPersistableStateManager {
|
|
|
113
119
|
/**
|
|
114
120
|
* Check if a note hash exists at the given leaf index, trace the check.
|
|
115
121
|
*
|
|
116
|
-
* @param
|
|
122
|
+
* @param contractAddress - the address of the contract whose storage is being read from
|
|
117
123
|
* @param noteHash - the unsiloed note hash being checked
|
|
118
124
|
* @param leafIndex - the leaf index being checked
|
|
119
125
|
* @returns true if the note hash exists at the given leaf index, false otherwise
|
|
120
126
|
*/
|
|
121
|
-
public async checkNoteHashExists(
|
|
127
|
+
public async checkNoteHashExists(contractAddress: Fr, noteHash: Fr, leafIndex: Fr): Promise<boolean> {
|
|
122
128
|
const gotLeafValue = (await this.worldStateDB.getCommitmentValue(leafIndex.toBigInt())) ?? Fr.ZERO;
|
|
123
129
|
const exists = gotLeafValue.equals(noteHash);
|
|
124
130
|
this.log.debug(
|
|
125
|
-
`noteHashes(${
|
|
131
|
+
`noteHashes(${contractAddress})@${noteHash} ?? leafIndex: ${leafIndex} | gotLeafValue: ${gotLeafValue}, exists: ${exists}.`,
|
|
126
132
|
);
|
|
127
133
|
// TODO(8287): We still return exists here, but we need to transmit both the requested noteHash and the gotLeafValue
|
|
128
134
|
// such that the VM can constrain the equality and decide on exists based on that.
|
|
129
|
-
this.trace.traceNoteHashCheck(
|
|
135
|
+
this.trace.traceNoteHashCheck(contractAddress, gotLeafValue, leafIndex, exists);
|
|
130
136
|
return Promise.resolve(exists);
|
|
131
137
|
}
|
|
132
138
|
|
|
@@ -134,37 +140,37 @@ export class AvmPersistableStateManager {
|
|
|
134
140
|
* Write a note hash, trace the write.
|
|
135
141
|
* @param noteHash - the unsiloed note hash to write
|
|
136
142
|
*/
|
|
137
|
-
public writeNoteHash(
|
|
138
|
-
this.log.debug(`noteHashes(${
|
|
139
|
-
this.trace.traceNewNoteHash(
|
|
143
|
+
public writeNoteHash(contractAddress: Fr, noteHash: Fr) {
|
|
144
|
+
this.log.debug(`noteHashes(${contractAddress}) += @${noteHash}.`);
|
|
145
|
+
this.trace.traceNewNoteHash(contractAddress, noteHash);
|
|
140
146
|
}
|
|
141
147
|
|
|
142
148
|
/**
|
|
143
149
|
* Check if a nullifier exists, trace the check.
|
|
144
|
-
* @param
|
|
150
|
+
* @param contractAddress - address of the contract that the nullifier is associated with
|
|
145
151
|
* @param nullifier - the unsiloed nullifier to check
|
|
146
152
|
* @returns exists - whether the nullifier exists in the nullifier set
|
|
147
153
|
*/
|
|
148
|
-
public async checkNullifierExists(
|
|
149
|
-
const [exists, isPending, leafIndex] = await this.nullifiers.checkExists(
|
|
154
|
+
public async checkNullifierExists(contractAddress: Fr, nullifier: Fr): Promise<boolean> {
|
|
155
|
+
const [exists, isPending, leafIndex] = await this.nullifiers.checkExists(contractAddress, nullifier);
|
|
150
156
|
this.log.debug(
|
|
151
|
-
`nullifiers(${
|
|
157
|
+
`nullifiers(${contractAddress})@${nullifier} ?? leafIndex: ${leafIndex}, exists: ${exists}, pending: ${isPending}.`,
|
|
152
158
|
);
|
|
153
|
-
this.trace.traceNullifierCheck(
|
|
159
|
+
this.trace.traceNullifierCheck(contractAddress, nullifier, leafIndex, exists, isPending);
|
|
154
160
|
return Promise.resolve(exists);
|
|
155
161
|
}
|
|
156
162
|
|
|
157
163
|
/**
|
|
158
164
|
* Write a nullifier to the nullifier set, trace the write.
|
|
159
|
-
* @param
|
|
165
|
+
* @param contractAddress - address of the contract that the nullifier is associated with
|
|
160
166
|
* @param nullifier - the unsiloed nullifier to write
|
|
161
167
|
*/
|
|
162
|
-
public async writeNullifier(
|
|
163
|
-
this.log.debug(`nullifiers(${
|
|
168
|
+
public async writeNullifier(contractAddress: Fr, nullifier: Fr) {
|
|
169
|
+
this.log.debug(`nullifiers(${contractAddress}) += ${nullifier}.`);
|
|
164
170
|
// Cache pending nullifiers for later access
|
|
165
|
-
await this.nullifiers.append(
|
|
171
|
+
await this.nullifiers.append(contractAddress, nullifier);
|
|
166
172
|
// Trace all nullifier creations (even reverted ones)
|
|
167
|
-
this.trace.traceNewNullifier(
|
|
173
|
+
this.trace.traceNewNullifier(contractAddress, nullifier);
|
|
168
174
|
}
|
|
169
175
|
|
|
170
176
|
/**
|
|
@@ -210,22 +216,26 @@ export class AvmPersistableStateManager {
|
|
|
210
216
|
/**
|
|
211
217
|
* Get a contract instance.
|
|
212
218
|
* @param contractAddress - address of the contract instance to retrieve.
|
|
213
|
-
* @returns the contract instance
|
|
219
|
+
* @returns the contract instance or undefined if it does not exist.
|
|
214
220
|
*/
|
|
215
|
-
public async getContractInstance(contractAddress: Fr): Promise<
|
|
216
|
-
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
221
|
+
public async getContractInstance(contractAddress: Fr): Promise<SerializableContractInstance | undefined> {
|
|
222
|
+
this.log.debug(`Getting contract instance for address ${contractAddress}`);
|
|
223
|
+
const instanceWithAddress = await this.worldStateDB.getContractInstance(AztecAddress.fromField(contractAddress));
|
|
224
|
+
const exists = instanceWithAddress !== undefined;
|
|
225
|
+
|
|
226
|
+
if (exists) {
|
|
227
|
+
const instance = new SerializableContractInstance(instanceWithAddress);
|
|
228
|
+
this.log.debug(
|
|
229
|
+
`Got contract instance (address=${contractAddress}): exists=${exists}, instance=${JSON.stringify(instance)}`,
|
|
230
|
+
);
|
|
231
|
+
this.trace.traceGetContractInstance(contractAddress, exists, instance);
|
|
232
|
+
|
|
233
|
+
return Promise.resolve(instance);
|
|
234
|
+
} else {
|
|
235
|
+
this.log.debug(`Contract instance NOT FOUND (address=${contractAddress})`);
|
|
236
|
+
this.trace.traceGetContractInstance(contractAddress, exists);
|
|
237
|
+
return Promise.resolve(undefined);
|
|
222
238
|
}
|
|
223
|
-
this.log.debug(
|
|
224
|
-
`Get Contract instance (address=${contractAddress}): exists=${exists}, instance=${JSON.stringify(instance)}`,
|
|
225
|
-
);
|
|
226
|
-
const tracedInstance = { ...instance, exists };
|
|
227
|
-
this.trace.traceGetContractInstance(tracedInstance);
|
|
228
|
-
return Promise.resolve(tracedInstance);
|
|
229
239
|
}
|
|
230
240
|
|
|
231
241
|
/**
|
|
@@ -237,10 +247,43 @@ export class AvmPersistableStateManager {
|
|
|
237
247
|
}
|
|
238
248
|
|
|
239
249
|
/**
|
|
240
|
-
* Get a contract's bytecode from the contracts DB
|
|
250
|
+
* Get a contract's bytecode from the contracts DB, also trace the contract class and instance
|
|
241
251
|
*/
|
|
242
|
-
public async getBytecode(contractAddress: AztecAddress
|
|
243
|
-
|
|
252
|
+
public async getBytecode(contractAddress: AztecAddress): Promise<Buffer | undefined> {
|
|
253
|
+
this.log.debug(`Getting bytecode for contract address ${contractAddress}`);
|
|
254
|
+
const instanceWithAddress = await this.worldStateDB.getContractInstance(contractAddress);
|
|
255
|
+
const exists = instanceWithAddress !== undefined;
|
|
256
|
+
|
|
257
|
+
if (exists) {
|
|
258
|
+
const instance = new SerializableContractInstance(instanceWithAddress);
|
|
259
|
+
|
|
260
|
+
const contractClass = await this.worldStateDB.getContractClass(instance.contractClassId);
|
|
261
|
+
assert(
|
|
262
|
+
contractClass,
|
|
263
|
+
`Contract class not found in DB, but a contract instance was found with this class ID (${instance.contractClassId}). This should not happen!`,
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
const contractClassPreimage = {
|
|
267
|
+
artifactHash: contractClass.artifactHash,
|
|
268
|
+
privateFunctionsRoot: contractClass.privateFunctionsRoot,
|
|
269
|
+
publicBytecodeCommitment: computePublicBytecodeCommitment(contractClass.packedBytecode),
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
this.trace.traceGetBytecode(
|
|
273
|
+
contractAddress,
|
|
274
|
+
exists,
|
|
275
|
+
contractClass.packedBytecode,
|
|
276
|
+
instance,
|
|
277
|
+
contractClassPreimage,
|
|
278
|
+
);
|
|
279
|
+
return contractClass.packedBytecode;
|
|
280
|
+
} else {
|
|
281
|
+
// If the contract instance is not found, we assume it has not been deployed.
|
|
282
|
+
// It doesnt matter what the values of the contract instance are in this case, as long as we tag it with exists=false.
|
|
283
|
+
// This will hint to the avm circuit to just perform the non-membership check on the address and disregard the bytecode hash
|
|
284
|
+
this.trace.traceGetBytecode(contractAddress, exists); // bytecode, instance, class undefined
|
|
285
|
+
return undefined;
|
|
286
|
+
}
|
|
244
287
|
}
|
|
245
288
|
|
|
246
289
|
/**
|
|
@@ -37,17 +37,17 @@ export class NullifierManager {
|
|
|
37
37
|
/**
|
|
38
38
|
* Get a nullifier's existence in this' cache or parent's (recursively).
|
|
39
39
|
* DOES NOT CHECK HOST STORAGE!
|
|
40
|
-
* @param
|
|
40
|
+
* @param contractAddress - the address of the contract whose storage is being read from
|
|
41
41
|
* @param nullifier - the nullifier to check for
|
|
42
42
|
* @returns exists: whether the nullifier exists in cache here or in parent's
|
|
43
43
|
*/
|
|
44
|
-
private checkExistsHereOrParent(
|
|
44
|
+
private checkExistsHereOrParent(contractAddress: Fr, nullifier: Fr): boolean {
|
|
45
45
|
// First check this cache
|
|
46
|
-
let existsAsPending = this.cache.exists(
|
|
46
|
+
let existsAsPending = this.cache.exists(contractAddress, nullifier);
|
|
47
47
|
// Then try parent's nullifier cache
|
|
48
48
|
if (!existsAsPending && this.parent) {
|
|
49
49
|
// Note: this will recurse to grandparent/etc until a cache-hit is encountered.
|
|
50
|
-
existsAsPending = this.parent.checkExistsHereOrParent(
|
|
50
|
+
existsAsPending = this.parent.checkExistsHereOrParent(contractAddress, nullifier);
|
|
51
51
|
}
|
|
52
52
|
return existsAsPending;
|
|
53
53
|
}
|
|
@@ -59,24 +59,24 @@ export class NullifierManager {
|
|
|
59
59
|
* 3. Fall back to the host state.
|
|
60
60
|
* 4. Not found! Nullifier does not exist.
|
|
61
61
|
*
|
|
62
|
-
* @param
|
|
62
|
+
* @param contractAddress - the address of the contract whose storage is being read from
|
|
63
63
|
* @param nullifier - the nullifier to check for
|
|
64
64
|
* @returns exists: whether the nullifier exists at all,
|
|
65
65
|
* isPending: whether the nullifier was found in a cache,
|
|
66
66
|
* leafIndex: the nullifier's leaf index if it exists and is not pending (comes from host state).
|
|
67
67
|
*/
|
|
68
68
|
public async checkExists(
|
|
69
|
-
|
|
69
|
+
contractAddress: Fr,
|
|
70
70
|
nullifier: Fr,
|
|
71
71
|
): Promise<[/*exists=*/ boolean, /*isPending=*/ boolean, /*leafIndex=*/ Fr]> {
|
|
72
72
|
// Check this cache and parent's (recursively)
|
|
73
|
-
const existsAsPending = this.checkExistsHereOrParent(
|
|
73
|
+
const existsAsPending = this.checkExistsHereOrParent(contractAddress, nullifier);
|
|
74
74
|
// Finally try the host's Aztec state (a trip to the database)
|
|
75
75
|
// If the value is found in the database, it will be associated with a leaf index!
|
|
76
76
|
let leafIndex: bigint | undefined = undefined;
|
|
77
77
|
if (!existsAsPending) {
|
|
78
78
|
// silo the nullifier before checking for its existence in the host
|
|
79
|
-
leafIndex = await this.hostNullifiers.getNullifierIndex(siloNullifier(
|
|
79
|
+
leafIndex = await this.hostNullifiers.getNullifierIndex(siloNullifier(contractAddress, nullifier));
|
|
80
80
|
}
|
|
81
81
|
const exists = existsAsPending || leafIndex !== undefined;
|
|
82
82
|
leafIndex = leafIndex === undefined ? BigInt(0) : leafIndex;
|
|
@@ -86,17 +86,17 @@ export class NullifierManager {
|
|
|
86
86
|
/**
|
|
87
87
|
* Stage a new nullifier (append it to the cache).
|
|
88
88
|
*
|
|
89
|
-
* @param
|
|
89
|
+
* @param contractAddress - the address of the contract that the nullifier is associated with
|
|
90
90
|
* @param nullifier - the nullifier to stage
|
|
91
91
|
*/
|
|
92
|
-
public async append(
|
|
93
|
-
const [exists, ,] = await this.checkExists(
|
|
92
|
+
public async append(contractAddress: Fr, nullifier: Fr) {
|
|
93
|
+
const [exists, ,] = await this.checkExists(contractAddress, nullifier);
|
|
94
94
|
if (exists) {
|
|
95
95
|
throw new NullifierCollisionError(
|
|
96
|
-
`Nullifier ${nullifier} at contract ${
|
|
96
|
+
`Nullifier ${nullifier} at contract ${contractAddress} already exists in parent cache or host.`,
|
|
97
97
|
);
|
|
98
98
|
}
|
|
99
|
-
this.cache.append(
|
|
99
|
+
this.cache.append(contractAddress, nullifier);
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
/**
|
|
@@ -135,35 +135,35 @@ export class NullifierCache {
|
|
|
135
135
|
/**
|
|
136
136
|
* Check whether a nullifier exists in the cache.
|
|
137
137
|
*
|
|
138
|
-
* @param
|
|
138
|
+
* @param contractAddress - the address of the contract that the nullifier is associated with
|
|
139
139
|
* @param nullifier - the nullifier to check existence of
|
|
140
140
|
* @returns whether the nullifier is found in the cache
|
|
141
141
|
*/
|
|
142
|
-
public exists(
|
|
142
|
+
public exists(contractAddress: Fr, nullifier: Fr): boolean {
|
|
143
143
|
const exists =
|
|
144
|
-
this.cachePerContract.get(
|
|
145
|
-
this.siloedNullifiers.has(siloNullifier(AztecAddress.fromField(
|
|
144
|
+
this.cachePerContract.get(contractAddress.toBigInt())?.has(nullifier.toBigInt()) ||
|
|
145
|
+
this.siloedNullifiers.has(siloNullifier(AztecAddress.fromField(contractAddress), nullifier).toBigInt());
|
|
146
146
|
return !!exists;
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
/**
|
|
150
150
|
* Stage a new nullifier (append it to the cache).
|
|
151
151
|
*
|
|
152
|
-
* @param
|
|
152
|
+
* @param contractAddress - the address of the contract that the nullifier is associated with
|
|
153
153
|
* @param nullifier - the nullifier to stage
|
|
154
154
|
*/
|
|
155
|
-
public append(
|
|
156
|
-
if (this.exists(
|
|
155
|
+
public append(contractAddress: Fr, nullifier: Fr) {
|
|
156
|
+
if (this.exists(contractAddress, nullifier)) {
|
|
157
157
|
throw new NullifierCollisionError(
|
|
158
|
-
`Nullifier ${nullifier} at contract ${
|
|
158
|
+
`Nullifier ${nullifier} at contract ${contractAddress} already exists in cache.`,
|
|
159
159
|
);
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
let nullifiersForContract = this.cachePerContract.get(
|
|
162
|
+
let nullifiersForContract = this.cachePerContract.get(contractAddress.toBigInt());
|
|
163
163
|
// If this contract's nullifier set has no cached nullifiers, create a new Set to store them
|
|
164
164
|
if (!nullifiersForContract) {
|
|
165
165
|
nullifiersForContract = new Set();
|
|
166
|
-
this.cachePerContract.set(
|
|
166
|
+
this.cachePerContract.set(contractAddress.toBigInt(), nullifiersForContract);
|
|
167
167
|
}
|
|
168
168
|
nullifiersForContract.add(nullifier.toBigInt());
|
|
169
169
|
}
|
|
@@ -45,17 +45,17 @@ export class PublicStorage {
|
|
|
45
45
|
* Read a storage value from this' cache or parent's (recursively).
|
|
46
46
|
* DOES NOT CHECK HOST STORAGE!
|
|
47
47
|
*
|
|
48
|
-
* @param
|
|
48
|
+
* @param contractAddress - the address of the contract whose storage is being read from
|
|
49
49
|
* @param slot - the slot in the contract's storage being read from
|
|
50
50
|
* @returns value: the latest value written according to this cache or the parent's. undefined on cache miss.
|
|
51
51
|
*/
|
|
52
|
-
public readHereOrParent(
|
|
52
|
+
public readHereOrParent(contractAddress: Fr, slot: Fr): Fr | undefined {
|
|
53
53
|
// First try check this storage cache
|
|
54
|
-
let value = this.cache.read(
|
|
54
|
+
let value = this.cache.read(contractAddress, slot);
|
|
55
55
|
// Then try parent's storage cache
|
|
56
56
|
if (!value && this.parent) {
|
|
57
57
|
// Note: this will recurse to grandparent/etc until a cache-hit is encountered.
|
|
58
|
-
value = this.parent.readHereOrParent(
|
|
58
|
+
value = this.parent.readHereOrParent(contractAddress, slot);
|
|
59
59
|
}
|
|
60
60
|
return value;
|
|
61
61
|
}
|
|
@@ -67,17 +67,17 @@ export class PublicStorage {
|
|
|
67
67
|
* 3. Fall back to the host state.
|
|
68
68
|
* 4. Not found! Value has never been written to before. Flag it as non-existent and return value zero.
|
|
69
69
|
*
|
|
70
|
-
* @param
|
|
70
|
+
* @param contractAddress - the address of the contract whose storage is being read from
|
|
71
71
|
* @param slot - the slot in the contract's storage being read from
|
|
72
72
|
* @returns exists: whether the slot has EVER been written to before, value: the latest value written to slot, or 0 if never written to before
|
|
73
73
|
*/
|
|
74
|
-
public async read(
|
|
74
|
+
public async read(contractAddress: Fr, slot: Fr): Promise<PublicStorageReadResult> {
|
|
75
75
|
let cached = false;
|
|
76
76
|
// Check this cache and parent's (recursively)
|
|
77
|
-
let value = this.readHereOrParent(
|
|
77
|
+
let value = this.readHereOrParent(contractAddress, slot);
|
|
78
78
|
// Finally try the host's Aztec state (a trip to the database)
|
|
79
79
|
if (!value) {
|
|
80
|
-
value = await this.hostPublicStorage.storageRead(
|
|
80
|
+
value = await this.hostPublicStorage.storageRead(contractAddress, slot);
|
|
81
81
|
// TODO(dbanks12): if value retrieved from host storage, we can cache it here
|
|
82
82
|
// any future reads to the same slot can read from cache instead of more expensive
|
|
83
83
|
// DB access
|
|
@@ -93,12 +93,12 @@ export class PublicStorage {
|
|
|
93
93
|
/**
|
|
94
94
|
* Stage a storage write.
|
|
95
95
|
*
|
|
96
|
-
* @param
|
|
96
|
+
* @param contractAddress - the address of the contract whose storage is being written to
|
|
97
97
|
* @param slot - the slot in the contract's storage being written to
|
|
98
98
|
* @param value - the value being written to the slot
|
|
99
99
|
*/
|
|
100
|
-
public write(
|
|
101
|
-
this.cache.write(
|
|
100
|
+
public write(contractAddress: Fr, slot: Fr, value: Fr) {
|
|
101
|
+
this.cache.write(contractAddress, slot, value);
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
/**
|
|
@@ -114,9 +114,9 @@ export class PublicStorage {
|
|
|
114
114
|
* Commits ALL staged writes to the host's state.
|
|
115
115
|
*/
|
|
116
116
|
public async commitToDB() {
|
|
117
|
-
for (const [
|
|
117
|
+
for (const [contractAddress, cacheAtContract] of this.cache.cachePerContract) {
|
|
118
118
|
for (const [slot, value] of cacheAtContract) {
|
|
119
|
-
await this.hostPublicStorage.storageWrite(AztecAddress.fromBigInt(
|
|
119
|
+
await this.hostPublicStorage.storageWrite(AztecAddress.fromBigInt(contractAddress), new Fr(slot), value);
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
}
|
|
@@ -139,27 +139,27 @@ class PublicStorageCache {
|
|
|
139
139
|
/**
|
|
140
140
|
* Read a staged value from storage, if it has been previously written to.
|
|
141
141
|
*
|
|
142
|
-
* @param
|
|
142
|
+
* @param contractAddress - the address of the contract whose storage is being read from
|
|
143
143
|
* @param slot - the slot in the contract's storage being read from
|
|
144
144
|
* @returns the latest value written to slot, or undefined if no value has been written
|
|
145
145
|
*/
|
|
146
|
-
public read(
|
|
147
|
-
return this.cachePerContract.get(
|
|
146
|
+
public read(contractAddress: Fr, slot: Fr): Fr | undefined {
|
|
147
|
+
return this.cachePerContract.get(contractAddress.toBigInt())?.get(slot.toBigInt());
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
/**
|
|
151
151
|
* Stage a storage write.
|
|
152
152
|
*
|
|
153
|
-
* @param
|
|
153
|
+
* @param contractAddress - the address of the contract whose storage is being written to
|
|
154
154
|
* @param slot - the slot in the contract's storage being written to
|
|
155
155
|
* @param value - the value being written to the slot
|
|
156
156
|
*/
|
|
157
|
-
public write(
|
|
158
|
-
let cacheAtContract = this.cachePerContract.get(
|
|
157
|
+
public write(contractAddress: Fr, slot: Fr, value: Fr) {
|
|
158
|
+
let cacheAtContract = this.cachePerContract.get(contractAddress.toBigInt());
|
|
159
159
|
if (!cacheAtContract) {
|
|
160
160
|
// If this contract's storage has no staged modifications, create a new inner map to store them
|
|
161
161
|
cacheAtContract = new Map();
|
|
162
|
-
this.cachePerContract.set(
|
|
162
|
+
this.cachePerContract.set(contractAddress.toBigInt(), cacheAtContract);
|
|
163
163
|
}
|
|
164
164
|
cacheAtContract.set(slot.toBigInt(), value);
|
|
165
165
|
}
|