@aztec/simulator 0.37.0 → 0.39.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 -1
- package/dest/acvm/acvm.d.ts.map +1 -1
- package/dest/acvm/acvm.js +2 -2
- package/dest/acvm/oracle/oracle.d.ts +6 -5
- package/dest/acvm/oracle/oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/oracle.js +26 -30
- package/dest/acvm/oracle/typed_oracle.d.ts +5 -5
- package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/typed_oracle.js +9 -9
- package/dest/avm/avm_execution_environment.d.ts +4 -3
- package/dest/avm/avm_execution_environment.d.ts.map +1 -1
- package/dest/avm/avm_execution_environment.js +17 -11
- package/dest/avm/avm_gas.d.ts.map +1 -1
- package/dest/avm/avm_gas.js +4 -1
- package/dest/avm/avm_machine_state.d.ts +5 -8
- package/dest/avm/avm_machine_state.d.ts.map +1 -1
- package/dest/avm/avm_machine_state.js +10 -22
- package/dest/avm/avm_memory_types.d.ts +1 -1
- package/dest/avm/avm_memory_types.d.ts.map +1 -1
- package/dest/avm/avm_message_call_result.d.ts +5 -8
- package/dest/avm/avm_message_call_result.d.ts.map +1 -1
- package/dest/avm/avm_message_call_result.js +1 -4
- package/dest/avm/avm_simulator.d.ts.map +1 -1
- package/dest/avm/avm_simulator.js +19 -13
- package/dest/avm/errors.d.ts +43 -2
- package/dest/avm/errors.d.ts.map +1 -1
- package/dest/avm/errors.js +86 -4
- package/dest/avm/journal/journal.d.ts +20 -1
- package/dest/avm/journal/journal.d.ts.map +1 -1
- package/dest/avm/journal/journal.js +70 -9
- package/dest/avm/journal/nullifiers.d.ts +3 -1
- package/dest/avm/journal/nullifiers.d.ts.map +1 -1
- package/dest/avm/journal/nullifiers.js +14 -6
- package/dest/avm/journal/public_storage.d.ts +10 -1
- package/dest/avm/journal/public_storage.d.ts.map +1 -1
- package/dest/avm/journal/public_storage.js +17 -2
- package/dest/avm/journal/trace.d.ts +1 -4
- package/dest/avm/journal/trace.d.ts.map +1 -1
- package/dest/avm/journal/trace.js +4 -5
- package/dest/avm/journal/trace_types.d.ts +1 -0
- package/dest/avm/journal/trace_types.d.ts.map +1 -1
- package/dest/avm/journal/trace_types.js +1 -1
- package/dest/avm/opcodes/bitwise.d.ts +4 -1
- package/dest/avm/opcodes/bitwise.d.ts.map +1 -1
- package/dest/avm/opcodes/bitwise.js +14 -2
- package/dest/avm/opcodes/conversion.d.ts +16 -0
- package/dest/avm/opcodes/conversion.d.ts.map +1 -0
- package/dest/avm/opcodes/conversion.js +48 -0
- package/dest/avm/opcodes/environment_getters.d.ts +16 -12
- package/dest/avm/opcodes/environment_getters.d.ts.map +1 -1
- package/dest/avm/opcodes/environment_getters.js +19 -48
- package/dest/avm/opcodes/external_calls.d.ts.map +1 -1
- package/dest/avm/opcodes/external_calls.js +24 -13
- package/dest/avm/serialization/bytecode_serialization.d.ts.map +1 -1
- package/dest/avm/serialization/bytecode_serialization.js +6 -2
- package/dest/avm/serialization/instruction_serialization.d.ts +40 -38
- package/dest/avm/serialization/instruction_serialization.d.ts.map +1 -1
- package/dest/avm/serialization/instruction_serialization.js +42 -39
- package/dest/client/client_execution_context.d.ts +59 -19
- package/dest/client/client_execution_context.d.ts.map +1 -1
- package/dest/client/client_execution_context.js +97 -45
- package/dest/client/db_oracle.d.ts +4 -11
- package/dest/client/db_oracle.d.ts.map +1 -1
- package/dest/client/execution_result.d.ts +22 -15
- package/dest/client/execution_result.d.ts.map +1 -1
- package/dest/client/execution_result.js +59 -13
- package/dest/client/logs_cache.d.ts +33 -0
- package/dest/client/logs_cache.d.ts.map +1 -0
- package/dest/client/logs_cache.js +59 -0
- package/dest/client/private_execution.d.ts +2 -2
- package/dest/client/private_execution.d.ts.map +1 -1
- package/dest/client/private_execution.js +5 -7
- package/dest/client/simulator.d.ts +4 -34
- package/dest/client/simulator.d.ts.map +1 -1
- package/dest/client/simulator.js +5 -43
- package/dest/client/unconstrained_execution.d.ts +2 -2
- package/dest/client/unconstrained_execution.d.ts.map +1 -1
- package/dest/client/unconstrained_execution.js +1 -1
- package/dest/client/view_data_oracle.d.ts +0 -7
- package/dest/client/view_data_oracle.d.ts.map +1 -1
- package/dest/client/view_data_oracle.js +1 -10
- package/dest/common/errors.d.ts +5 -0
- package/dest/common/errors.d.ts.map +1 -1
- package/dest/common/errors.js +6 -1
- package/dest/index.d.ts +1 -0
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +2 -1
- package/dest/mocks/fixtures.d.ts.map +1 -1
- package/dest/mocks/fixtures.js +3 -1
- package/dest/public/abstract_phase_manager.d.ts +10 -4
- package/dest/public/abstract_phase_manager.d.ts.map +1 -1
- package/dest/public/abstract_phase_manager.js +50 -19
- package/dest/public/app_logic_phase_manager.d.ts +1 -0
- package/dest/public/app_logic_phase_manager.d.ts.map +1 -1
- package/dest/public/app_logic_phase_manager.js +3 -3
- package/dest/public/execution.d.ts +9 -0
- package/dest/public/execution.d.ts.map +1 -1
- package/dest/public/execution.js +1 -1
- package/dest/public/executor.d.ts +2 -2
- package/dest/public/executor.d.ts.map +1 -1
- package/dest/public/executor.js +34 -17
- package/dest/public/hints_builder.d.ts +3 -3
- package/dest/public/hints_builder.d.ts.map +1 -1
- package/dest/public/hints_builder.js +3 -3
- package/dest/public/public_execution_context.d.ts +10 -4
- package/dest/public/public_execution_context.d.ts.map +1 -1
- package/dest/public/public_execution_context.js +19 -6
- package/dest/public/public_processor.d.ts.map +1 -1
- package/dest/public/public_processor.js +5 -3
- package/dest/public/setup_phase_manager.d.ts +1 -0
- package/dest/public/setup_phase_manager.d.ts.map +1 -1
- package/dest/public/setup_phase_manager.js +3 -2
- package/dest/public/tail_phase_manager.d.ts +1 -1
- package/dest/public/tail_phase_manager.d.ts.map +1 -1
- package/dest/public/tail_phase_manager.js +4 -26
- package/dest/public/teardown_phase_manager.d.ts +1 -0
- package/dest/public/teardown_phase_manager.d.ts.map +1 -1
- package/dest/public/teardown_phase_manager.js +3 -2
- package/dest/public/transitional_adaptors.d.ts +4 -17
- package/dest/public/transitional_adaptors.d.ts.map +1 -1
- package/dest/public/transitional_adaptors.js +27 -119
- package/dest/rollup/index.d.ts +2 -0
- package/dest/rollup/index.d.ts.map +1 -0
- package/dest/rollup/index.js +2 -0
- package/dest/rollup/rollup.d.ts +77 -0
- package/dest/rollup/rollup.d.ts.map +1 -0
- package/dest/rollup/rollup.js +78 -0
- package/dest/stats/index.d.ts +2 -0
- package/dest/stats/index.d.ts.map +1 -0
- package/dest/stats/index.js +2 -0
- package/dest/stats/stats.d.ts +4 -0
- package/dest/stats/stats.d.ts.map +1 -0
- package/dest/stats/stats.js +11 -0
- package/package.json +8 -8
- package/src/acvm/acvm.ts +2 -2
- package/src/acvm/oracle/oracle.ts +62 -36
- package/src/acvm/oracle/typed_oracle.ts +19 -11
- package/src/avm/avm_execution_environment.ts +34 -42
- package/src/avm/avm_gas.ts +3 -0
- package/src/avm/avm_machine_state.ts +14 -25
- package/src/avm/avm_memory_types.ts +1 -1
- package/src/avm/avm_message_call_result.ts +3 -14
- package/src/avm/avm_simulator.ts +24 -12
- package/src/avm/errors.ts +94 -4
- package/src/avm/journal/journal.ts +134 -9
- package/src/avm/journal/nullifiers.ts +19 -8
- package/src/avm/journal/public_storage.ts +23 -2
- package/src/avm/journal/trace.ts +3 -4
- package/src/avm/journal/trace_types.ts +1 -0
- package/src/avm/opcodes/bitwise.ts +18 -7
- package/src/avm/opcodes/conversion.ts +59 -0
- package/src/avm/opcodes/environment_getters.ts +21 -65
- package/src/avm/opcodes/external_calls.ts +32 -16
- package/src/avm/serialization/bytecode_serialization.ts +5 -0
- package/src/avm/serialization/instruction_serialization.ts +3 -0
- package/src/client/client_execution_context.ts +142 -46
- package/src/client/db_oracle.ts +4 -18
- package/src/client/execution_result.ts +75 -25
- package/src/client/logs_cache.ts +65 -0
- package/src/client/private_execution.ts +6 -10
- package/src/client/simulator.ts +8 -84
- package/src/client/unconstrained_execution.ts +2 -2
- package/src/client/view_data_oracle.ts +0 -10
- package/src/common/errors.ts +5 -0
- package/src/index.ts +1 -0
- package/src/mocks/fixtures.ts +2 -0
- package/src/public/abstract_phase_manager.ts +59 -23
- package/src/public/app_logic_phase_manager.ts +2 -1
- package/src/public/execution.ts +9 -0
- package/src/public/executor.ts +47 -14
- package/src/public/hints_builder.ts +5 -5
- package/src/public/public_execution_context.ts +18 -4
- package/src/public/public_processor.ts +8 -2
- package/src/public/setup_phase_manager.ts +16 -8
- package/src/public/tail_phase_manager.ts +8 -35
- package/src/public/teardown_phase_manager.ts +16 -8
- package/src/public/transitional_adaptors.ts +39 -177
- package/src/rollup/index.ts +1 -0
- package/src/rollup/rollup.ts +160 -0
- package/src/stats/index.ts +1 -0
- package/src/stats/stats.ts +20 -0
package/src/avm/errors.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type FailingFunction, type NoirCallStack } from '@aztec/circuit-types';
|
|
2
|
+
import { type AztecAddress, type Fr } from '@aztec/circuits.js';
|
|
3
|
+
|
|
4
|
+
import { ExecutionError } from '../common/errors.js';
|
|
5
|
+
import { type AvmContext } from './avm_context.js';
|
|
2
6
|
|
|
3
7
|
/**
|
|
4
8
|
* Avm-specific errors should derive from this
|
|
5
9
|
*/
|
|
6
10
|
export abstract class AvmExecutionError extends Error {
|
|
7
|
-
constructor(message: string
|
|
8
|
-
super(message
|
|
9
|
-
this.name = '
|
|
11
|
+
constructor(message: string) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = 'AvmExecutionError';
|
|
10
14
|
}
|
|
11
15
|
}
|
|
12
16
|
|
|
@@ -63,3 +67,89 @@ export class OutOfGasError extends AvmExecutionError {
|
|
|
63
67
|
this.name = 'OutOfGasError';
|
|
64
68
|
}
|
|
65
69
|
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Error thrown to propagate a nested call's revert.
|
|
73
|
+
* @param message - the error's message
|
|
74
|
+
* @param nestedError - the revert reason of the nested call
|
|
75
|
+
*/
|
|
76
|
+
export class RethrownError extends AvmExecutionError {
|
|
77
|
+
constructor(message: string, public nestedError: AvmRevertReason) {
|
|
78
|
+
super(message);
|
|
79
|
+
this.name = 'RethrownError';
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Meaningfully named alias for ExecutionError when used in the context of the AVM.
|
|
85
|
+
* Maintains a recursive structure reflecting the AVM's external callstack/errorstack, where
|
|
86
|
+
* options.cause is the error that caused this error (if this is not the root-cause itself).
|
|
87
|
+
*/
|
|
88
|
+
export class AvmRevertReason extends ExecutionError {
|
|
89
|
+
constructor(message: string, failingFunction: FailingFunction, noirCallStack: NoirCallStack, options?: ErrorOptions) {
|
|
90
|
+
super(message, failingFunction, noirCallStack, options);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Helper to create a "revert reason" error optionally with a nested error cause.
|
|
96
|
+
*
|
|
97
|
+
* @param message - the error message
|
|
98
|
+
* @param context - the context of the AVM execution used to extract the failingFunction and noirCallStack
|
|
99
|
+
* @param nestedError - the error that caused this one (if this is not the root-cause itself)
|
|
100
|
+
*/
|
|
101
|
+
function createRevertReason(message: string, context: AvmContext, nestedError?: AvmRevertReason): AvmRevertReason {
|
|
102
|
+
return new AvmRevertReason(
|
|
103
|
+
message,
|
|
104
|
+
/*failingFunction=*/ {
|
|
105
|
+
contractAddress: context.environment.address,
|
|
106
|
+
functionSelector: context.environment.temporaryFunctionSelector,
|
|
107
|
+
},
|
|
108
|
+
/*noirCallStack=*/ [...context.machineState.internalCallStack, context.machineState.pc].map(pc => `0.${pc}`),
|
|
109
|
+
/*options=*/ { cause: nestedError },
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Create a "revert reason" error for an exceptional halt,
|
|
115
|
+
* creating the recursive structure if the halt was a RethrownError.
|
|
116
|
+
*
|
|
117
|
+
* @param haltingError - the lower-level error causing the exceptional halt
|
|
118
|
+
* @param context - the context of the AVM execution used to extract the failingFunction and noirCallStack
|
|
119
|
+
*/
|
|
120
|
+
export function revertReasonFromExceptionalHalt(haltingError: AvmExecutionError, context: AvmContext): AvmRevertReason {
|
|
121
|
+
// A RethrownError has a nested/child AvmRevertReason
|
|
122
|
+
const nestedError = haltingError instanceof RethrownError ? haltingError.nestedError : undefined;
|
|
123
|
+
return createRevertReason(haltingError.message, context, nestedError);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Create a "revert reason" error for an explicit revert (a root cause).
|
|
128
|
+
*
|
|
129
|
+
* @param revertData - output data of the explicit REVERT instruction
|
|
130
|
+
* @param context - the context of the AVM execution used to extract the failingFunction and noirCallStack
|
|
131
|
+
*/
|
|
132
|
+
export function revertReasonFromExplicitRevert(revertData: Fr[], context: AvmContext): AvmRevertReason {
|
|
133
|
+
const revertMessage = decodeRevertDataAsMessage(revertData);
|
|
134
|
+
return createRevertReason(revertMessage, context);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Interpret revert data as a message string.
|
|
139
|
+
*
|
|
140
|
+
* @param revertData - output data of an explicit REVERT instruction
|
|
141
|
+
*/
|
|
142
|
+
export function decodeRevertDataAsMessage(revertData: Fr[]): string {
|
|
143
|
+
if (revertData.length === 0) {
|
|
144
|
+
return 'Assertion failed.';
|
|
145
|
+
} else {
|
|
146
|
+
try {
|
|
147
|
+
// We remove the first element which is the 'error selector'.
|
|
148
|
+
const revertOutput = revertData.slice(1);
|
|
149
|
+
// Try to interpret the output as a text string.
|
|
150
|
+
return 'Assertion failed: ' + String.fromCharCode(...revertOutput.map(fr => fr.toNumber()));
|
|
151
|
+
} catch (e) {
|
|
152
|
+
return 'Assertion failed: <cannot interpret as string>';
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -1,9 +1,21 @@
|
|
|
1
|
+
// TODO(5818): Rename file and all uses of "journal"
|
|
1
2
|
import { UnencryptedL2Log } from '@aztec/circuit-types';
|
|
2
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
AztecAddress,
|
|
5
|
+
ContractStorageRead,
|
|
6
|
+
ContractStorageUpdateRequest,
|
|
7
|
+
EthAddress,
|
|
8
|
+
L2ToL1Message,
|
|
9
|
+
NoteHash,
|
|
10
|
+
Nullifier,
|
|
11
|
+
ReadRequest,
|
|
12
|
+
SideEffect,
|
|
13
|
+
} from '@aztec/circuits.js';
|
|
3
14
|
import { EventSelector } from '@aztec/foundation/abi';
|
|
4
15
|
import { Fr } from '@aztec/foundation/fields';
|
|
5
16
|
import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log';
|
|
6
17
|
|
|
18
|
+
import { type PublicExecutionResult } from '../../index.js';
|
|
7
19
|
import { type HostStorage } from './host_storage.js';
|
|
8
20
|
import { Nullifiers } from './nullifiers.js';
|
|
9
21
|
import { PublicStorage } from './public_storage.js';
|
|
@@ -19,6 +31,7 @@ import {
|
|
|
19
31
|
type TracedUnencryptedL2Log,
|
|
20
32
|
} from './trace_types.js';
|
|
21
33
|
|
|
34
|
+
// TODO:(5818): do we need this type anymore?
|
|
22
35
|
/**
|
|
23
36
|
* Data held within the journal
|
|
24
37
|
*/
|
|
@@ -37,6 +50,25 @@ export type JournalData = {
|
|
|
37
50
|
newLogsHashes: TracedUnencryptedL2Log[];
|
|
38
51
|
/** contract address -\> key -\> value */
|
|
39
52
|
currentStorageValue: Map<bigint, Map<bigint, Fr>>;
|
|
53
|
+
|
|
54
|
+
sideEffectCounter: number;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
|
|
58
|
+
type PartialPublicExecutionResult = {
|
|
59
|
+
nullifierReadRequests: ReadRequest[];
|
|
60
|
+
nullifierNonExistentReadRequests: ReadRequest[];
|
|
61
|
+
newNoteHashes: NoteHash[];
|
|
62
|
+
newL2ToL1Messages: L2ToL1Message[];
|
|
63
|
+
startSideEffectCounter: number;
|
|
64
|
+
newNullifiers: Nullifier[];
|
|
65
|
+
contractStorageReads: ContractStorageRead[];
|
|
66
|
+
contractStorageUpdateRequests: ContractStorageUpdateRequest[];
|
|
67
|
+
unencryptedLogsHashes: SideEffect[];
|
|
68
|
+
unencryptedLogs: UnencryptedL2Log[];
|
|
69
|
+
unencryptedLogPreimagesLength: Fr;
|
|
70
|
+
allUnencryptedLogs: UnencryptedL2Log[];
|
|
71
|
+
nestedExecutions: PublicExecutionResult[];
|
|
40
72
|
};
|
|
41
73
|
|
|
42
74
|
/**
|
|
@@ -53,7 +85,7 @@ export class AvmPersistableStateManager {
|
|
|
53
85
|
/** Reference to node storage */
|
|
54
86
|
public readonly hostStorage: HostStorage;
|
|
55
87
|
|
|
56
|
-
// TODO: make members private once this is not used in transitional_adaptors.ts.
|
|
88
|
+
// TODO(5818): make members private once this is not used in transitional_adaptors.ts.
|
|
57
89
|
/** World State */
|
|
58
90
|
/** Public storage, including cached writes */
|
|
59
91
|
public publicStorage: PublicStorage;
|
|
@@ -67,11 +99,31 @@ export class AvmPersistableStateManager {
|
|
|
67
99
|
public newL1Messages: L2ToL1Message[] = [];
|
|
68
100
|
public newLogs: UnencryptedL2Log[] = [];
|
|
69
101
|
|
|
102
|
+
// TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
|
|
103
|
+
public transitionalExecutionResult: PartialPublicExecutionResult;
|
|
104
|
+
|
|
70
105
|
constructor(hostStorage: HostStorage, parent?: AvmPersistableStateManager) {
|
|
71
106
|
this.hostStorage = hostStorage;
|
|
72
107
|
this.publicStorage = new PublicStorage(hostStorage.publicStateDb, parent?.publicStorage);
|
|
73
108
|
this.nullifiers = new Nullifiers(hostStorage.commitmentsDb, parent?.nullifiers);
|
|
74
109
|
this.trace = new WorldStateAccessTrace(parent?.trace);
|
|
110
|
+
|
|
111
|
+
this.transitionalExecutionResult = {
|
|
112
|
+
nullifierReadRequests: [],
|
|
113
|
+
nullifierNonExistentReadRequests: [],
|
|
114
|
+
newNoteHashes: [],
|
|
115
|
+
newL2ToL1Messages: [],
|
|
116
|
+
startSideEffectCounter: this.trace.accessCounter,
|
|
117
|
+
newNullifiers: [],
|
|
118
|
+
contractStorageReads: [],
|
|
119
|
+
contractStorageUpdateRequests: [],
|
|
120
|
+
unencryptedLogsHashes: [],
|
|
121
|
+
unencryptedLogs: [],
|
|
122
|
+
// The length starts at 4 because it will always include the size.
|
|
123
|
+
unencryptedLogPreimagesLength: new Fr(4),
|
|
124
|
+
allUnencryptedLogs: [],
|
|
125
|
+
nestedExecutions: [],
|
|
126
|
+
};
|
|
75
127
|
}
|
|
76
128
|
|
|
77
129
|
/**
|
|
@@ -92,6 +144,21 @@ export class AvmPersistableStateManager {
|
|
|
92
144
|
this.log.debug(`storage(${storageAddress})@${slot} <- ${value}`);
|
|
93
145
|
// Cache storage writes for later reference/reads
|
|
94
146
|
this.publicStorage.write(storageAddress, slot, value);
|
|
147
|
+
|
|
148
|
+
// TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
|
|
149
|
+
// The current info to the kernel clears any previous read or write request.
|
|
150
|
+
this.transitionalExecutionResult.contractStorageReads =
|
|
151
|
+
this.transitionalExecutionResult.contractStorageReads.filter(
|
|
152
|
+
read => !read.storageSlot.equals(slot) || !read.contractAddress!.equals(storageAddress),
|
|
153
|
+
);
|
|
154
|
+
this.transitionalExecutionResult.contractStorageUpdateRequests =
|
|
155
|
+
this.transitionalExecutionResult.contractStorageUpdateRequests.filter(
|
|
156
|
+
update => !update.storageSlot.equals(slot) || !update.contractAddress!.equals(storageAddress),
|
|
157
|
+
);
|
|
158
|
+
this.transitionalExecutionResult.contractStorageUpdateRequests.push(
|
|
159
|
+
new ContractStorageUpdateRequest(slot, value, this.trace.accessCounter, storageAddress),
|
|
160
|
+
);
|
|
161
|
+
|
|
95
162
|
// Trace all storage writes (even reverted ones)
|
|
96
163
|
this.trace.tracePublicStorageWrite(storageAddress, slot, value);
|
|
97
164
|
}
|
|
@@ -104,10 +171,24 @@ export class AvmPersistableStateManager {
|
|
|
104
171
|
* @returns the latest value written to slot, or 0 if never written to before
|
|
105
172
|
*/
|
|
106
173
|
public async readStorage(storageAddress: Fr, slot: Fr): Promise<Fr> {
|
|
107
|
-
const
|
|
108
|
-
this.log.debug(`storage(${storageAddress})@${slot} ?? value: ${value}, exists: ${exists}.`);
|
|
174
|
+
const { value, exists, cached } = await this.publicStorage.read(storageAddress, slot);
|
|
175
|
+
this.log.debug(`storage(${storageAddress})@${slot} ?? value: ${value}, exists: ${exists}, cached: ${cached}.`);
|
|
176
|
+
|
|
177
|
+
// TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
|
|
178
|
+
// The current info to the kernel kernel does not consider cached reads.
|
|
179
|
+
if (!cached) {
|
|
180
|
+
// The current info to the kernel removes any previous reads to the same slot.
|
|
181
|
+
this.transitionalExecutionResult.contractStorageReads =
|
|
182
|
+
this.transitionalExecutionResult.contractStorageReads.filter(
|
|
183
|
+
read => !read.storageSlot.equals(slot) || !read.contractAddress!.equals(storageAddress),
|
|
184
|
+
);
|
|
185
|
+
this.transitionalExecutionResult.contractStorageReads.push(
|
|
186
|
+
new ContractStorageRead(slot, value, this.trace.accessCounter, storageAddress),
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
109
190
|
// We want to keep track of all performed reads (even reverted ones)
|
|
110
|
-
this.trace.tracePublicStorageRead(storageAddress, slot, value, exists);
|
|
191
|
+
this.trace.tracePublicStorageRead(storageAddress, slot, value, exists, cached);
|
|
111
192
|
return Promise.resolve(value);
|
|
112
193
|
}
|
|
113
194
|
|
|
@@ -133,6 +214,9 @@ export class AvmPersistableStateManager {
|
|
|
133
214
|
* @param noteHash - the unsiloed note hash to write
|
|
134
215
|
*/
|
|
135
216
|
public writeNoteHash(storageAddress: Fr, noteHash: Fr) {
|
|
217
|
+
// TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
|
|
218
|
+
this.transitionalExecutionResult.newNoteHashes.push(new NoteHash(noteHash, this.trace.accessCounter));
|
|
219
|
+
|
|
136
220
|
this.log.debug(`noteHashes(${storageAddress}) += @${noteHash}.`);
|
|
137
221
|
this.trace.traceNewNoteHash(storageAddress, noteHash);
|
|
138
222
|
}
|
|
@@ -148,6 +232,16 @@ export class AvmPersistableStateManager {
|
|
|
148
232
|
this.log.debug(
|
|
149
233
|
`nullifiers(${storageAddress})@${nullifier} ?? leafIndex: ${leafIndex}, pending: ${isPending}, exists: ${exists}.`,
|
|
150
234
|
);
|
|
235
|
+
|
|
236
|
+
// TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
|
|
237
|
+
if (exists) {
|
|
238
|
+
this.transitionalExecutionResult.nullifierReadRequests.push(new ReadRequest(nullifier, this.trace.accessCounter));
|
|
239
|
+
} else {
|
|
240
|
+
this.transitionalExecutionResult.nullifierNonExistentReadRequests.push(
|
|
241
|
+
new ReadRequest(nullifier, this.trace.accessCounter),
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
151
245
|
this.trace.traceNullifierCheck(storageAddress, nullifier, exists, isPending, leafIndex);
|
|
152
246
|
return Promise.resolve(exists);
|
|
153
247
|
}
|
|
@@ -158,6 +252,9 @@ export class AvmPersistableStateManager {
|
|
|
158
252
|
* @param nullifier - the unsiloed nullifier to write
|
|
159
253
|
*/
|
|
160
254
|
public async writeNullifier(storageAddress: Fr, nullifier: Fr) {
|
|
255
|
+
// TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
|
|
256
|
+
this.transitionalExecutionResult.newNullifiers.push(new Nullifier(nullifier, this.trace.accessCounter, Fr.ZERO));
|
|
257
|
+
|
|
161
258
|
this.log.debug(`nullifiers(${storageAddress}) += ${nullifier}.`);
|
|
162
259
|
// Cache pending nullifiers for later access
|
|
163
260
|
await this.nullifiers.append(storageAddress, nullifier);
|
|
@@ -189,18 +286,39 @@ export class AvmPersistableStateManager {
|
|
|
189
286
|
public writeL1Message(recipient: EthAddress | Fr, content: Fr) {
|
|
190
287
|
this.log.debug(`L1Messages(${recipient}) += ${content}.`);
|
|
191
288
|
const recipientAddress = recipient instanceof EthAddress ? recipient : EthAddress.fromField(recipient);
|
|
192
|
-
|
|
289
|
+
const message = new L2ToL1Message(recipientAddress, content, 0);
|
|
290
|
+
this.newL1Messages.push(message);
|
|
291
|
+
|
|
292
|
+
// TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
|
|
293
|
+
this.transitionalExecutionResult.newL2ToL1Messages.push(message);
|
|
193
294
|
}
|
|
194
295
|
|
|
195
296
|
public writeLog(contractAddress: Fr, event: Fr, log: Fr[]) {
|
|
196
297
|
this.log.debug(`UnencryptedL2Log(${contractAddress}) += event ${event} with ${log.length} fields.`);
|
|
197
|
-
const
|
|
298
|
+
const ulog = new UnencryptedL2Log(
|
|
198
299
|
AztecAddress.fromField(contractAddress),
|
|
199
300
|
EventSelector.fromField(event),
|
|
200
301
|
Buffer.concat(log.map(f => f.toBuffer())),
|
|
201
302
|
);
|
|
202
|
-
|
|
203
|
-
|
|
303
|
+
const logHash = Fr.fromBuffer(ulog.hash());
|
|
304
|
+
|
|
305
|
+
// TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
|
|
306
|
+
this.transitionalExecutionResult.unencryptedLogs.push(ulog);
|
|
307
|
+
this.transitionalExecutionResult.allUnencryptedLogs.push(ulog);
|
|
308
|
+
// this duplicates exactly what happens in the trace just for the purpose of transitional integration with the kernel
|
|
309
|
+
this.transitionalExecutionResult.unencryptedLogsHashes.push(
|
|
310
|
+
new SideEffect(logHash, new Fr(this.trace.accessCounter)),
|
|
311
|
+
);
|
|
312
|
+
// Duplicates computation performed in public_context.nr::emit_unencrypted_log
|
|
313
|
+
// 44 = addr (32) + selector (4) + raw log len (4) + processed log len (4).
|
|
314
|
+
this.transitionalExecutionResult.unencryptedLogPreimagesLength = new Fr(
|
|
315
|
+
this.transitionalExecutionResult.unencryptedLogPreimagesLength.toNumber() + 44 + log.length * Fr.SIZE_IN_BYTES,
|
|
316
|
+
);
|
|
317
|
+
// TODO(6206): likely need to track this here and not just in the transitional logic.
|
|
318
|
+
|
|
319
|
+
// TODO(6205): why are logs pushed here but logs hashes are traced?
|
|
320
|
+
this.newLogs.push(ulog);
|
|
321
|
+
this.trace.traceNewLog(logHash);
|
|
204
322
|
}
|
|
205
323
|
|
|
206
324
|
/**
|
|
@@ -216,6 +334,11 @@ export class AvmPersistableStateManager {
|
|
|
216
334
|
// Accrued Substate
|
|
217
335
|
this.newL1Messages = this.newL1Messages.concat(nestedJournal.newL1Messages);
|
|
218
336
|
this.newLogs = this.newLogs.concat(nestedJournal.newLogs);
|
|
337
|
+
|
|
338
|
+
// TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
|
|
339
|
+
this.transitionalExecutionResult.allUnencryptedLogs.concat(
|
|
340
|
+
nestedJournal.transitionalExecutionResult.allUnencryptedLogs,
|
|
341
|
+
);
|
|
219
342
|
}
|
|
220
343
|
|
|
221
344
|
/**
|
|
@@ -226,6 +349,7 @@ export class AvmPersistableStateManager {
|
|
|
226
349
|
this.trace.acceptAndMerge(nestedJournal.trace);
|
|
227
350
|
}
|
|
228
351
|
|
|
352
|
+
// TODO:(5818): do we need this type anymore?
|
|
229
353
|
/**
|
|
230
354
|
* Access the current state of the journal
|
|
231
355
|
*
|
|
@@ -244,6 +368,7 @@ export class AvmPersistableStateManager {
|
|
|
244
368
|
currentStorageValue: this.publicStorage.getCache().cachePerContract,
|
|
245
369
|
storageReads: this.trace.publicStorageReads,
|
|
246
370
|
storageWrites: this.trace.publicStorageWrites,
|
|
371
|
+
sideEffectCounter: this.trace.accessCounter,
|
|
247
372
|
};
|
|
248
373
|
}
|
|
249
374
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AztecAddress } from '@aztec/circuits.js';
|
|
1
2
|
import { siloNullifier } from '@aztec/circuits.js/hash';
|
|
2
3
|
import { Fr } from '@aztec/foundation/fields';
|
|
3
4
|
|
|
@@ -10,7 +11,7 @@ import type { CommitmentsDB } from '../../index.js';
|
|
|
10
11
|
*/
|
|
11
12
|
export class Nullifiers {
|
|
12
13
|
/** Cached nullifiers. */
|
|
13
|
-
|
|
14
|
+
public cache: NullifierCache;
|
|
14
15
|
/** Parent's nullifier cache. Checked on cache-miss. */
|
|
15
16
|
private readonly parentCache: NullifierCache | undefined;
|
|
16
17
|
/** Reference to node storage. Checked on parent cache-miss. */
|
|
@@ -95,6 +96,7 @@ export class NullifierCache {
|
|
|
95
96
|
* each entry being a nullifier.
|
|
96
97
|
*/
|
|
97
98
|
private cachePerContract: Map<bigint, Set<bigint>> = new Map();
|
|
99
|
+
private siloedNullifiers: Set<bigint> = new Set();
|
|
98
100
|
|
|
99
101
|
/**
|
|
100
102
|
* Check whether a nullifier exists in the cache.
|
|
@@ -104,8 +106,10 @@ export class NullifierCache {
|
|
|
104
106
|
* @returns whether the nullifier is found in the cache
|
|
105
107
|
*/
|
|
106
108
|
public exists(storageAddress: Fr, nullifier: Fr): boolean {
|
|
107
|
-
const exists =
|
|
108
|
-
|
|
109
|
+
const exists =
|
|
110
|
+
this.cachePerContract.get(storageAddress.toBigInt())?.has(nullifier.toBigInt()) ||
|
|
111
|
+
this.siloedNullifiers.has(siloNullifier(AztecAddress.fromField(storageAddress), nullifier).toBigInt());
|
|
112
|
+
return !!exists;
|
|
109
113
|
}
|
|
110
114
|
|
|
111
115
|
/**
|
|
@@ -115,20 +119,25 @@ export class NullifierCache {
|
|
|
115
119
|
* @param nullifier - the nullifier to stage
|
|
116
120
|
*/
|
|
117
121
|
public append(storageAddress: Fr, nullifier: Fr) {
|
|
122
|
+
if (this.exists(storageAddress, nullifier)) {
|
|
123
|
+
throw new NullifierCollisionError(
|
|
124
|
+
`Nullifier ${nullifier} at contract ${storageAddress} already exists in cache.`,
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
118
128
|
let nullifiersForContract = this.cachePerContract.get(storageAddress.toBigInt());
|
|
119
129
|
// If this contract's nullifier set has no cached nullifiers, create a new Set to store them
|
|
120
130
|
if (!nullifiersForContract) {
|
|
121
131
|
nullifiersForContract = new Set();
|
|
122
132
|
this.cachePerContract.set(storageAddress.toBigInt(), nullifiersForContract);
|
|
123
133
|
}
|
|
124
|
-
if (nullifiersForContract.has(nullifier.toBigInt())) {
|
|
125
|
-
throw new NullifierCollisionError(
|
|
126
|
-
`Nullifier ${nullifier} at contract ${storageAddress} already exists in cache.`,
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
134
|
nullifiersForContract.add(nullifier.toBigInt());
|
|
130
135
|
}
|
|
131
136
|
|
|
137
|
+
public appendSiloed(siloedNullifier: Fr) {
|
|
138
|
+
this.siloedNullifiers.add(siloedNullifier.toBigInt());
|
|
139
|
+
}
|
|
140
|
+
|
|
132
141
|
/**
|
|
133
142
|
* Merge another cache's nullifiers into this instance's.
|
|
134
143
|
*
|
|
@@ -139,6 +148,8 @@ export class NullifierCache {
|
|
|
139
148
|
* @param incomingNullifiers - the incoming cached nullifiers to merge into this instance's
|
|
140
149
|
*/
|
|
141
150
|
public acceptAndMerge(incomingNullifiers: NullifierCache) {
|
|
151
|
+
// Merge siloed nullifiers.
|
|
152
|
+
this.siloedNullifiers = new Set([...this.siloedNullifiers, ...incomingNullifiers.siloedNullifiers]);
|
|
142
153
|
// Iterate over all contracts with staged writes in the child.
|
|
143
154
|
for (const [incomingAddress, incomingCacheAtContract] of incomingNullifiers.cachePerContract) {
|
|
144
155
|
const thisCacheAtContract = this.cachePerContract.get(incomingAddress);
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
+
import { AztecAddress } from '@aztec/circuits.js';
|
|
1
2
|
import { Fr } from '@aztec/foundation/fields';
|
|
2
3
|
|
|
3
4
|
import type { PublicStateDB } from '../../index.js';
|
|
4
5
|
|
|
6
|
+
type PublicStorageReadResult = {
|
|
7
|
+
value: Fr;
|
|
8
|
+
exists: boolean;
|
|
9
|
+
cached: boolean;
|
|
10
|
+
};
|
|
11
|
+
|
|
5
12
|
/**
|
|
6
13
|
* A class to manage public storage reads and writes during a contract call's AVM simulation.
|
|
7
14
|
* Maintains a storage write cache, and ensures that reads fall back to the correct source.
|
|
@@ -39,7 +46,8 @@ export class PublicStorage {
|
|
|
39
46
|
* @param slot - the slot in the contract's storage being read from
|
|
40
47
|
* @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
|
|
41
48
|
*/
|
|
42
|
-
public async read(storageAddress: Fr, slot: Fr): Promise<
|
|
49
|
+
public async read(storageAddress: Fr, slot: Fr): Promise<PublicStorageReadResult> {
|
|
50
|
+
let cached = false;
|
|
43
51
|
// First try check this storage cache
|
|
44
52
|
let value = this.cache.read(storageAddress, slot);
|
|
45
53
|
// Then try parent's storage cache (if it exists / written to earlier in this TX)
|
|
@@ -49,11 +57,13 @@ export class PublicStorage {
|
|
|
49
57
|
// Finally try the host's Aztec state (a trip to the database)
|
|
50
58
|
if (!value) {
|
|
51
59
|
value = await this.hostPublicStorage.storageRead(storageAddress, slot);
|
|
60
|
+
} else {
|
|
61
|
+
cached = true;
|
|
52
62
|
}
|
|
53
63
|
// if value is undefined, that means this slot has never been written to!
|
|
54
64
|
const exists = value !== undefined;
|
|
55
65
|
const valueOrZero = exists ? value : Fr.ZERO;
|
|
56
|
-
return Promise.resolve(
|
|
66
|
+
return Promise.resolve({ value: valueOrZero, exists, cached });
|
|
57
67
|
}
|
|
58
68
|
|
|
59
69
|
/**
|
|
@@ -75,6 +85,17 @@ export class PublicStorage {
|
|
|
75
85
|
public acceptAndMerge(incomingPublicStorage: PublicStorage) {
|
|
76
86
|
this.cache.acceptAndMerge(incomingPublicStorage.cache);
|
|
77
87
|
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Commits ALL staged writes to the host's state.
|
|
91
|
+
*/
|
|
92
|
+
public async commitToDB() {
|
|
93
|
+
for (const [storageAddress, cacheAtContract] of this.cache.cachePerContract) {
|
|
94
|
+
for (const [slot, value] of cacheAtContract) {
|
|
95
|
+
await this.hostPublicStorage.storageWrite(AztecAddress.fromBigInt(storageAddress), new Fr(slot), value);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
78
99
|
}
|
|
79
100
|
|
|
80
101
|
/**
|
package/src/avm/journal/trace.ts
CHANGED
|
@@ -29,13 +29,14 @@ export class WorldStateAccessTrace {
|
|
|
29
29
|
|
|
30
30
|
constructor(parentTrace?: WorldStateAccessTrace) {
|
|
31
31
|
this.accessCounter = parentTrace ? parentTrace.accessCounter : 0;
|
|
32
|
+
// TODO(4805): consider tracking the parent's trace vector lengths so we can enforce limits
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
public getAccessCounter() {
|
|
35
36
|
return this.accessCounter;
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
public tracePublicStorageRead(storageAddress: Fr, slot: Fr, value: Fr, exists: boolean) {
|
|
39
|
+
public tracePublicStorageRead(storageAddress: Fr, slot: Fr, value: Fr, exists: boolean, cached: boolean) {
|
|
39
40
|
// TODO(4805): check if some threshold is reached for max storage reads
|
|
40
41
|
// (need access to parent length, or trace needs to be initialized with parent's contents)
|
|
41
42
|
const traced: TracedPublicStorageRead = {
|
|
@@ -44,6 +45,7 @@ export class WorldStateAccessTrace {
|
|
|
44
45
|
slot,
|
|
45
46
|
value,
|
|
46
47
|
exists,
|
|
48
|
+
cached,
|
|
47
49
|
counter: new Fr(this.accessCounter),
|
|
48
50
|
// endLifetime: Fr.ZERO,
|
|
49
51
|
};
|
|
@@ -151,9 +153,6 @@ export class WorldStateAccessTrace {
|
|
|
151
153
|
/**
|
|
152
154
|
* Merges another trace into this one
|
|
153
155
|
*
|
|
154
|
-
* - Public state journals (r/w logs), with the accessing being appended in chronological order
|
|
155
|
-
* - Utxo objects are concatenated
|
|
156
|
-
*
|
|
157
156
|
* @param incomingTrace - the incoming trace to merge into this instance
|
|
158
157
|
*/
|
|
159
158
|
public acceptAndMerge(incomingTrace: WorldStateAccessTrace) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AvmContext } from '../avm_context.js';
|
|
2
|
-
import { type IntegralValue } from '../avm_memory_types.js';
|
|
2
|
+
import { type IntegralValue, type TaggedMemoryInterface, TypeTag } from '../avm_memory_types.js';
|
|
3
3
|
import { Opcode } from '../serialization/instruction_serialization.js';
|
|
4
4
|
import { ThreeOperandInstruction, TwoOperandInstruction } from './instruction_impl.js';
|
|
5
5
|
|
|
@@ -9,7 +9,7 @@ abstract class ThreeOperandBitwiseInstruction extends ThreeOperandInstruction {
|
|
|
9
9
|
const memory = context.machineState.memory.track(this.type);
|
|
10
10
|
context.machineState.consumeGas(this.gasCost(memoryOperations));
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
this.checkTags(memory, this.inTag, this.aOffset, this.bOffset);
|
|
13
13
|
|
|
14
14
|
const a = memory.getAs<IntegralValue>(this.aOffset);
|
|
15
15
|
const b = memory.getAs<IntegralValue>(this.bOffset);
|
|
@@ -22,13 +22,16 @@ abstract class ThreeOperandBitwiseInstruction extends ThreeOperandInstruction {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
protected abstract compute(a: IntegralValue, b: IntegralValue): IntegralValue;
|
|
25
|
+
protected checkTags(memory: TaggedMemoryInterface, inTag: number, aOffset: number, bOffset: number) {
|
|
26
|
+
memory.checkTags(inTag, aOffset, bOffset);
|
|
27
|
+
}
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
export class And extends ThreeOperandBitwiseInstruction {
|
|
28
31
|
static readonly type: string = 'AND';
|
|
29
32
|
static readonly opcode = Opcode.AND;
|
|
30
33
|
|
|
31
|
-
protected compute(a: IntegralValue, b: IntegralValue): IntegralValue {
|
|
34
|
+
protected override compute(a: IntegralValue, b: IntegralValue): IntegralValue {
|
|
32
35
|
return a.and(b);
|
|
33
36
|
}
|
|
34
37
|
}
|
|
@@ -37,7 +40,7 @@ export class Or extends ThreeOperandBitwiseInstruction {
|
|
|
37
40
|
static readonly type: string = 'OR';
|
|
38
41
|
static readonly opcode = Opcode.OR;
|
|
39
42
|
|
|
40
|
-
protected compute(a: IntegralValue, b: IntegralValue): IntegralValue {
|
|
43
|
+
protected override compute(a: IntegralValue, b: IntegralValue): IntegralValue {
|
|
41
44
|
return a.or(b);
|
|
42
45
|
}
|
|
43
46
|
}
|
|
@@ -46,7 +49,7 @@ export class Xor extends ThreeOperandBitwiseInstruction {
|
|
|
46
49
|
static readonly type: string = 'XOR';
|
|
47
50
|
static readonly opcode = Opcode.XOR;
|
|
48
51
|
|
|
49
|
-
protected compute(a: IntegralValue, b: IntegralValue): IntegralValue {
|
|
52
|
+
protected override compute(a: IntegralValue, b: IntegralValue): IntegralValue {
|
|
50
53
|
return a.xor(b);
|
|
51
54
|
}
|
|
52
55
|
}
|
|
@@ -55,18 +58,26 @@ export class Shl extends ThreeOperandBitwiseInstruction {
|
|
|
55
58
|
static readonly type: string = 'SHL';
|
|
56
59
|
static readonly opcode = Opcode.SHL;
|
|
57
60
|
|
|
58
|
-
protected compute(a: IntegralValue, b: IntegralValue): IntegralValue {
|
|
61
|
+
protected override compute(a: IntegralValue, b: IntegralValue): IntegralValue {
|
|
59
62
|
return a.shl(b);
|
|
60
63
|
}
|
|
64
|
+
protected override checkTags(memory: TaggedMemoryInterface, inTag: number, aOffset: number, bOffset: number) {
|
|
65
|
+
memory.checkTag(inTag, aOffset);
|
|
66
|
+
memory.checkTag(TypeTag.UINT8, bOffset);
|
|
67
|
+
}
|
|
61
68
|
}
|
|
62
69
|
|
|
63
70
|
export class Shr extends ThreeOperandBitwiseInstruction {
|
|
64
71
|
static readonly type: string = 'SHR';
|
|
65
72
|
static readonly opcode = Opcode.SHR;
|
|
66
73
|
|
|
67
|
-
protected compute(a: IntegralValue, b: IntegralValue): IntegralValue {
|
|
74
|
+
protected override compute(a: IntegralValue, b: IntegralValue): IntegralValue {
|
|
68
75
|
return a.shr(b);
|
|
69
76
|
}
|
|
77
|
+
protected override checkTags(memory: TaggedMemoryInterface, inTag: number, aOffset: number, bOffset: number) {
|
|
78
|
+
memory.checkTag(inTag, aOffset);
|
|
79
|
+
memory.checkTag(TypeTag.UINT8, bOffset);
|
|
80
|
+
}
|
|
70
81
|
}
|
|
71
82
|
|
|
72
83
|
export class Not extends TwoOperandInstruction {
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { strict as assert } from 'assert';
|
|
2
|
+
|
|
3
|
+
import { type AvmContext } from '../avm_context.js';
|
|
4
|
+
import { TypeTag, Uint8 } from '../avm_memory_types.js';
|
|
5
|
+
import { Opcode, OperandType } from '../serialization/instruction_serialization.js';
|
|
6
|
+
import { Addressing } from './addressing_mode.js';
|
|
7
|
+
import { Instruction } from './instruction.js';
|
|
8
|
+
|
|
9
|
+
export class ToRadixLE extends Instruction {
|
|
10
|
+
static type: string = 'TORADIXLE';
|
|
11
|
+
static readonly opcode: Opcode = Opcode.TORADIXLE;
|
|
12
|
+
|
|
13
|
+
// Informs (de)serialization. See Instruction.deserialize.
|
|
14
|
+
static readonly wireFormat: OperandType[] = [
|
|
15
|
+
OperandType.UINT8, // Opcode
|
|
16
|
+
OperandType.UINT8, // Indirect
|
|
17
|
+
OperandType.UINT32, // src memory address
|
|
18
|
+
OperandType.UINT32, // dst memory address
|
|
19
|
+
OperandType.UINT32, // radix (immediate)
|
|
20
|
+
OperandType.UINT32, // number of limbs (Immediate)
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
constructor(
|
|
24
|
+
private indirect: number,
|
|
25
|
+
private srcOffset: number,
|
|
26
|
+
private dstOffset: number,
|
|
27
|
+
private radix: number,
|
|
28
|
+
private numLimbs: number,
|
|
29
|
+
) {
|
|
30
|
+
assert(radix <= 256, 'Radix cannot be greater than 256');
|
|
31
|
+
super();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public async execute(context: AvmContext): Promise<void> {
|
|
35
|
+
const memory = context.machineState.memory.track(this.type);
|
|
36
|
+
const [srcOffset, dstOffset] = Addressing.fromWire(this.indirect).resolve([this.srcOffset, this.dstOffset], memory);
|
|
37
|
+
const memoryOperations = { reads: 1, writes: this.numLimbs, indirect: this.indirect };
|
|
38
|
+
context.machineState.consumeGas(this.gasCost(memoryOperations));
|
|
39
|
+
|
|
40
|
+
// The radix gadget only takes in a Field
|
|
41
|
+
memory.checkTag(TypeTag.FIELD, srcOffset);
|
|
42
|
+
|
|
43
|
+
let value: bigint = memory.get(srcOffset).toBigInt();
|
|
44
|
+
const radixBN: bigint = BigInt(this.radix);
|
|
45
|
+
const limbArray = [];
|
|
46
|
+
|
|
47
|
+
for (let i = 0; i < this.numLimbs; i++) {
|
|
48
|
+
const limb = value % radixBN;
|
|
49
|
+
limbArray.push(limb);
|
|
50
|
+
value /= radixBN;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const res = [...limbArray].map(byte => new Uint8(byte));
|
|
54
|
+
memory.setSlice(dstOffset, res);
|
|
55
|
+
|
|
56
|
+
memory.assert(memoryOperations);
|
|
57
|
+
context.machineState.incrementPc();
|
|
58
|
+
}
|
|
59
|
+
}
|