@aztec/simulator 0.60.0 → 0.62.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/oracle/oracle.d.ts +3 -0
- package/dest/acvm/oracle/oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/oracle.js +12 -1
- package/dest/acvm/oracle/typed_oracle.d.ts +4 -1
- package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/typed_oracle.js +10 -1
- package/dest/avm/avm_gas.d.ts.map +1 -1
- package/dest/avm/avm_gas.js +8 -5
- 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_simulator.d.ts +15 -0
- package/dest/avm/avm_simulator.d.ts.map +1 -1
- package/dest/avm/avm_simulator.js +45 -4
- package/dest/avm/fixtures/index.d.ts +1 -1
- package/dest/avm/fixtures/index.d.ts.map +1 -1
- package/dest/avm/fixtures/index.js +7 -7
- package/dest/avm/journal/journal.d.ts +5 -6
- package/dest/avm/journal/journal.d.ts.map +1 -1
- package/dest/avm/journal/journal.js +42 -17
- 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/control_flow.js +5 -5
- 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 +1 -1
- package/dest/avm/opcodes/environment_getters.d.ts.map +1 -1
- package/dest/avm/opcodes/environment_getters.js +5 -1
- 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/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/serialization/bytecode_serialization.d.ts.map +1 -1
- package/dest/avm/serialization/bytecode_serialization.js +5 -3
- package/dest/avm/serialization/instruction_serialization.d.ts +36 -34
- package/dest/avm/serialization/instruction_serialization.d.ts.map +1 -1
- package/dest/avm/serialization/instruction_serialization.js +37 -35
- package/dest/avm/test_utils.d.ts +2 -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 +1 -8
- package/dest/client/client_execution_context.d.ts.map +1 -1
- package/dest/client/client_execution_context.js +4 -18
- package/dest/client/db_oracle.d.ts +24 -1
- package/dest/client/db_oracle.d.ts.map +1 -1
- package/dest/client/db_oracle.js +1 -1
- 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/public/dual_side_effect_trace.d.ts +3 -5
- package/dest/public/dual_side_effect_trace.d.ts.map +1 -1
- package/dest/public/dual_side_effect_trace.js +8 -4
- package/dest/public/enqueued_call_side_effect_trace.d.ts +4 -6
- package/dest/public/enqueued_call_side_effect_trace.d.ts.map +1 -1
- package/dest/public/enqueued_call_side_effect_trace.js +19 -7
- package/dest/public/enqueued_call_simulator.d.ts +2 -2
- package/dest/public/enqueued_call_simulator.d.ts.map +1 -1
- package/dest/public/enqueued_call_simulator.js +21 -29
- 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 +18 -25
- package/dest/public/public_db_sources.d.ts.map +1 -1
- package/dest/public/public_db_sources.js +10 -15
- 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 +4 -3
- package/dest/public/side_effect_trace.d.ts.map +1 -1
- package/dest/public/side_effect_trace.js +27 -16
- package/dest/public/side_effect_trace_interface.d.ts +3 -3
- package/dest/public/side_effect_trace_interface.d.ts.map +1 -1
- package/dest/test/utils.d.ts +2 -2
- package/dest/test/utils.d.ts.map +1 -1
- package/dest/test/utils.js +4 -4
- package/package.json +9 -9
- package/src/acvm/oracle/oracle.ts +20 -0
- package/src/acvm/oracle/typed_oracle.ts +13 -0
- package/src/avm/avm_gas.ts +7 -4
- package/src/avm/avm_machine_state.ts +2 -0
- package/src/avm/avm_simulator.ts +69 -6
- package/src/avm/fixtures/index.ts +7 -7
- package/src/avm/journal/journal.ts +62 -19
- package/src/avm/opcodes/contract.ts +45 -21
- package/src/avm/opcodes/control_flow.ts +5 -5
- package/src/avm/opcodes/conversion.ts +9 -6
- package/src/avm/opcodes/environment_getters.ts +7 -2
- package/src/avm/opcodes/external_calls.ts +21 -45
- package/src/avm/opcodes/memory.ts +69 -2
- package/src/avm/serialization/bytecode_serialization.ts +6 -2
- package/src/avm/serialization/instruction_serialization.ts +5 -3
- package/src/avm/test_utils.ts +5 -1
- package/src/client/client_execution_context.ts +4 -27
- package/src/client/db_oracle.ts +38 -0
- package/src/client/view_data_oracle.ts +31 -1
- package/src/common/index.ts +0 -1
- package/src/public/dual_side_effect_trace.ts +20 -6
- package/src/public/enqueued_call_side_effect_trace.ts +46 -8
- package/src/public/enqueued_call_simulator.ts +42 -26
- package/src/public/enqueued_calls_processor.ts +26 -38
- package/src/public/public_db_sources.ts +10 -15
- 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 +54 -15
- package/src/public/side_effect_trace_interface.ts +9 -4
- package/src/test/utils.ts +9 -2
- 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/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/dest/test/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/test/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,aAAa,EAAW,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAE,KAAK,YAAY,EAAc,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/test/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,aAAa,EAAW,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAE,KAAK,YAAY,EAAc,EAAE,EAAE,MAAM,oBAAoB,CAAC;AAIvE;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,aACnB,MAAM,mBACC,EAAE,EAAE,kBACL,YAAY,UACpB,EAAE,YACA,EAAE,GAAG,MAAM,kBAetB,CAAC"}
|
package/dest/test/utils.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { L1Actor, L1ToL2Message, L2Actor } from '@aztec/circuit-types';
|
|
2
|
-
import { EthAddress } from '@aztec/circuits.js';
|
|
2
|
+
import { EthAddress, Fr } from '@aztec/circuits.js';
|
|
3
3
|
import { computeSecretHash } from '@aztec/circuits.js/hash';
|
|
4
4
|
import { sha256ToField } from '@aztec/foundation/crypto';
|
|
5
5
|
/**
|
|
@@ -10,11 +10,11 @@ import { sha256ToField } from '@aztec/foundation/crypto';
|
|
|
10
10
|
* @param secret - The secret to unlock the message.
|
|
11
11
|
* @returns The L1 to L2 message.
|
|
12
12
|
*/
|
|
13
|
-
export const buildL1ToL2Message = (selector, contentPreimage, targetContract, secret) => {
|
|
13
|
+
export const buildL1ToL2Message = (selector, contentPreimage, targetContract, secret, msgIndex) => {
|
|
14
14
|
// Write the selector into a buffer.
|
|
15
15
|
const selectorBuf = Buffer.from(selector, 'hex');
|
|
16
16
|
const content = sha256ToField([selectorBuf, ...contentPreimage]);
|
|
17
17
|
const secretHash = computeSecretHash(secret);
|
|
18
|
-
return new L1ToL2Message(new L1Actor(EthAddress.random(), 1), new L2Actor(targetContract, 1), content, secretHash);
|
|
18
|
+
return new L1ToL2Message(new L1Actor(EthAddress.random(), 1), new L2Actor(targetContract, 1), content, secretHash, new Fr(msgIndex));
|
|
19
19
|
};
|
|
20
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
20
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdGVzdC91dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsT0FBTyxFQUFFLGFBQWEsRUFBRSxPQUFPLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUN2RSxPQUFPLEVBQXFCLFVBQVUsRUFBRSxFQUFFLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUN2RSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUM1RCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFFekQ7Ozs7Ozs7R0FPRztBQUNILE1BQU0sQ0FBQyxNQUFNLGtCQUFrQixHQUFHLENBQ2hDLFFBQWdCLEVBQ2hCLGVBQXFCLEVBQ3JCLGNBQTRCLEVBQzVCLE1BQVUsRUFDVixRQUFxQixFQUNyQixFQUFFO0lBQ0Ysb0NBQW9DO0lBQ3BDLE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBRWpELE1BQU0sT0FBTyxHQUFHLGFBQWEsQ0FBQyxDQUFDLFdBQVcsRUFBRSxHQUFHLGVBQWUsQ0FBQyxDQUFDLENBQUM7SUFDakUsTUFBTSxVQUFVLEdBQUcsaUJBQWlCLENBQUMsTUFBTSxDQUFDLENBQUM7SUFFN0MsT0FBTyxJQUFJLGFBQWEsQ0FDdEIsSUFBSSxPQUFPLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUNuQyxJQUFJLE9BQU8sQ0FBQyxjQUFjLEVBQUUsQ0FBQyxDQUFDLEVBQzlCLE9BQU8sRUFDUCxVQUFVLEVBQ1YsSUFBSSxFQUFFLENBQUMsUUFBUSxDQUFDLENBQ2pCLENBQUM7QUFDSixDQUFDLENBQUMifQ==
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/simulator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.62.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dest/index.js",
|
|
@@ -59,14 +59,14 @@
|
|
|
59
59
|
]
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@aztec/circuit-types": "0.
|
|
63
|
-
"@aztec/circuits.js": "0.
|
|
64
|
-
"@aztec/foundation": "0.
|
|
65
|
-
"@aztec/noir-protocol-circuits-types": "0.
|
|
66
|
-
"@aztec/protocol-contracts": "0.
|
|
67
|
-
"@aztec/telemetry-client": "0.
|
|
68
|
-
"@aztec/types": "0.
|
|
69
|
-
"@aztec/world-state": "0.
|
|
62
|
+
"@aztec/circuit-types": "0.62.0",
|
|
63
|
+
"@aztec/circuits.js": "0.62.0",
|
|
64
|
+
"@aztec/foundation": "0.62.0",
|
|
65
|
+
"@aztec/noir-protocol-circuits-types": "0.62.0",
|
|
66
|
+
"@aztec/protocol-contracts": "0.62.0",
|
|
67
|
+
"@aztec/telemetry-client": "0.62.0",
|
|
68
|
+
"@aztec/types": "0.62.0",
|
|
69
|
+
"@aztec/world-state": "0.62.0",
|
|
70
70
|
"@noir-lang/acvm_js": "portal:../../noir/packages/acvm_js",
|
|
71
71
|
"@noir-lang/types": "portal:../../noir/packages/types",
|
|
72
72
|
"levelup": "^5.1.1",
|
|
@@ -408,4 +408,24 @@ export class Oracle {
|
|
|
408
408
|
notifySetMinRevertibleSideEffectCounter([minRevertibleSideEffectCounter]: ACVMField[]) {
|
|
409
409
|
this.typedOracle.notifySetMinRevertibleSideEffectCounter(frToNumber(fromACVMField(minRevertibleSideEffectCounter)));
|
|
410
410
|
}
|
|
411
|
+
|
|
412
|
+
async getAppTaggingSecret([sender]: ACVMField[], [recipient]: ACVMField[]): Promise<ACVMField[]> {
|
|
413
|
+
const taggingSecret = await this.typedOracle.getAppTaggingSecret(
|
|
414
|
+
AztecAddress.fromString(sender),
|
|
415
|
+
AztecAddress.fromString(recipient),
|
|
416
|
+
);
|
|
417
|
+
return taggingSecret.toFields().map(toACVMField);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
async incrementAppTaggingSecret([sender]: ACVMField[], [recipient]: ACVMField[]) {
|
|
421
|
+
await this.typedOracle.incrementAppTaggingSecret(
|
|
422
|
+
AztecAddress.fromString(sender),
|
|
423
|
+
AztecAddress.fromString(recipient),
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
async getAppTaggingSecretsForSenders([recipient]: ACVMField[]): Promise<ACVMField[]> {
|
|
428
|
+
const taggingSecrets = await this.typedOracle.getAppTaggingSecretsForSenders(AztecAddress.fromString(recipient));
|
|
429
|
+
return taggingSecrets.flatMap(taggingSecret => taggingSecret.toFields().map(toACVMField));
|
|
430
|
+
}
|
|
411
431
|
}
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
import {
|
|
12
12
|
type ContractInstance,
|
|
13
13
|
type Header,
|
|
14
|
+
type IndexedTaggingSecret,
|
|
14
15
|
type KeyValidationRequest,
|
|
15
16
|
type L1_TO_L2_MSG_TREE_HEIGHT,
|
|
16
17
|
} from '@aztec/circuits.js';
|
|
@@ -252,4 +253,16 @@ export abstract class TypedOracle {
|
|
|
252
253
|
debugLog(_message: string, _fields: Fr[]): void {
|
|
253
254
|
throw new OracleMethodNotAvailableError('debugLog');
|
|
254
255
|
}
|
|
256
|
+
|
|
257
|
+
getAppTaggingSecret(_sender: AztecAddress, _recipient: AztecAddress): Promise<IndexedTaggingSecret> {
|
|
258
|
+
throw new OracleMethodNotAvailableError('getAppTaggingSecret');
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
incrementAppTaggingSecret(_sender: AztecAddress, _recipient: AztecAddress): Promise<void> {
|
|
262
|
+
throw new OracleMethodNotAvailableError('incrementAppTaggingSecret');
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
getAppTaggingSecretsForSenders(_recipient: AztecAddress): Promise<IndexedTaggingSecret[]> {
|
|
266
|
+
throw new OracleMethodNotAvailableError('getAppTaggingSecretsForSenders');
|
|
267
|
+
}
|
|
255
268
|
}
|
package/src/avm/avm_gas.ts
CHANGED
|
@@ -89,8 +89,10 @@ const BASE_GAS_COSTS: Record<Opcode, Gas> = {
|
|
|
89
89
|
[Opcode.CAST_16]: makeCost(c.AVM_CAST_BASE_L2_GAS, 0),
|
|
90
90
|
[Opcode.GETENVVAR_16]: makeCost(c.AVM_GETENVVAR_BASE_L2_GAS, 0),
|
|
91
91
|
[Opcode.CALLDATACOPY]: makeCost(c.AVM_CALLDATACOPY_BASE_L2_GAS, 0),
|
|
92
|
-
[Opcode.
|
|
93
|
-
[Opcode.
|
|
92
|
+
[Opcode.RETURNDATASIZE]: makeCost(c.AVM_RETURNDATASIZE_BASE_L2_GAS, 0),
|
|
93
|
+
[Opcode.RETURNDATACOPY]: makeCost(c.AVM_RETURNDATACOPY_BASE_L2_GAS, 0),
|
|
94
|
+
[Opcode.JUMP_32]: makeCost(c.AVM_JUMP_BASE_L2_GAS, 0),
|
|
95
|
+
[Opcode.JUMPI_32]: makeCost(c.AVM_JUMPI_BASE_L2_GAS, 0),
|
|
94
96
|
[Opcode.INTERNALCALL]: makeCost(c.AVM_INTERNALCALL_BASE_L2_GAS, 0),
|
|
95
97
|
[Opcode.INTERNALRETURN]: makeCost(c.AVM_INTERNALRETURN_BASE_L2_GAS, 0),
|
|
96
98
|
[Opcode.SET_8]: makeCost(c.AVM_SET_BASE_L2_GAS, 0),
|
|
@@ -122,11 +124,12 @@ const BASE_GAS_COSTS: Record<Opcode, Gas> = {
|
|
|
122
124
|
[Opcode.KECCAKF1600]: makeCost(c.AVM_KECCAKF1600_BASE_L2_GAS, 0),
|
|
123
125
|
[Opcode.ECADD]: makeCost(c.AVM_ECADD_BASE_L2_GAS, 0),
|
|
124
126
|
[Opcode.MSM]: makeCost(c.AVM_MSM_BASE_L2_GAS, 0),
|
|
125
|
-
[Opcode.
|
|
127
|
+
[Opcode.TORADIXBE]: makeCost(c.AVM_TORADIXBE_BASE_L2_GAS, 0),
|
|
126
128
|
};
|
|
127
129
|
|
|
128
130
|
const DYNAMIC_GAS_COSTS = new Map<Opcode, Gas>([
|
|
129
131
|
[Opcode.CALLDATACOPY, makeCost(c.AVM_CALLDATACOPY_DYN_L2_GAS, 0)],
|
|
132
|
+
[Opcode.RETURNDATACOPY, makeCost(c.AVM_RETURNDATACOPY_DYN_L2_GAS, 0)],
|
|
130
133
|
[Opcode.EMITUNENCRYPTEDLOG, makeCost(c.AVM_EMITUNENCRYPTEDLOG_DYN_L2_GAS, c.AVM_EMITUNENCRYPTEDLOG_DYN_DA_GAS)],
|
|
131
134
|
[Opcode.CALL, makeCost(c.AVM_CALL_DYN_L2_GAS, 0)],
|
|
132
135
|
[Opcode.STATICCALL, makeCost(c.AVM_STATICCALL_DYN_L2_GAS, 0)],
|
|
@@ -134,7 +137,7 @@ const DYNAMIC_GAS_COSTS = new Map<Opcode, Gas>([
|
|
|
134
137
|
[Opcode.REVERT_8, makeCost(c.AVM_REVERT_DYN_L2_GAS, 0)],
|
|
135
138
|
[Opcode.REVERT_16, makeCost(c.AVM_REVERT_DYN_L2_GAS, 0)],
|
|
136
139
|
[Opcode.MSM, makeCost(c.AVM_MSM_DYN_L2_GAS, 0)],
|
|
137
|
-
[Opcode.
|
|
140
|
+
[Opcode.TORADIXBE, makeCost(c.AVM_TORADIXBE_DYN_L2_GAS, 0)],
|
|
138
141
|
]);
|
|
139
142
|
|
|
140
143
|
/** Returns the fixed base gas cost for a given opcode. */
|
|
@@ -21,6 +21,8 @@ export class AvmMachineState {
|
|
|
21
21
|
public daGasLeft: number;
|
|
22
22
|
/** program counter */
|
|
23
23
|
public pc: number = 0;
|
|
24
|
+
/** return/revertdata of the last nested call. */
|
|
25
|
+
public nestedReturndata: Fr[] = [];
|
|
24
26
|
|
|
25
27
|
/**
|
|
26
28
|
* On INTERNALCALL, internal call stack is pushed to with the current pc + 1
|
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
|
}
|
|
@@ -117,6 +117,13 @@ export function randomMemoryFields(length: number): Field[] {
|
|
|
117
117
|
return [...Array(length)].map(_ => new Field(Fr.random()));
|
|
118
118
|
}
|
|
119
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
|
+
|
|
120
127
|
export function getAvmTestContractBytecode(functionName: string): Buffer {
|
|
121
128
|
const artifact = AvmTestContractArtifact.functions.find(f => f.name === functionName)!;
|
|
122
129
|
assert(
|
|
@@ -147,10 +154,3 @@ export function resolveAvmTestContractAssertionMessage(
|
|
|
147
154
|
|
|
148
155
|
return resolveAssertionMessage(revertReason.noirCallStack, debugMetadata);
|
|
149
156
|
}
|
|
150
|
-
|
|
151
|
-
export function getAvmTestContractFunctionSelector(functionName: string): FunctionSelector {
|
|
152
|
-
const artifact = AvmTestContractArtifact.functions.find(f => f.name === functionName)!;
|
|
153
|
-
assert(!!artifact, `Function ${functionName} not found in AvmTestContractArtifact`);
|
|
154
|
-
const params = artifact.parameters;
|
|
155
|
-
return FunctionSelector.fromNameAndParameters(artifact.name, params);
|
|
156
|
-
}
|
|
@@ -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';
|
|
@@ -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
|
/**
|
|
@@ -1,23 +1,36 @@
|
|
|
1
|
-
import { Fr } from '@aztec/circuits.js';
|
|
2
|
-
|
|
3
1
|
import type { AvmContext } from '../avm_context.js';
|
|
4
|
-
import { Field, TypeTag } from '../avm_memory_types.js';
|
|
2
|
+
import { Field, TypeTag, Uint1 } from '../avm_memory_types.js';
|
|
3
|
+
import { InstructionExecutionError } from '../errors.js';
|
|
5
4
|
import { Opcode, OperandType } from '../serialization/instruction_serialization.js';
|
|
6
5
|
import { Addressing } from './addressing_mode.js';
|
|
7
6
|
import { Instruction } from './instruction.js';
|
|
8
7
|
|
|
8
|
+
export enum ContractInstanceMember {
|
|
9
|
+
DEPLOYER,
|
|
10
|
+
CLASS_ID,
|
|
11
|
+
INIT_HASH,
|
|
12
|
+
}
|
|
13
|
+
|
|
9
14
|
export class GetContractInstance extends Instruction {
|
|
10
15
|
static readonly type: string = 'GETCONTRACTINSTANCE';
|
|
11
16
|
static readonly opcode: Opcode = Opcode.GETCONTRACTINSTANCE;
|
|
12
17
|
// Informs (de)serialization. See Instruction.deserialize.
|
|
13
18
|
static readonly wireFormat: OperandType[] = [
|
|
14
|
-
OperandType.UINT8,
|
|
15
|
-
OperandType.UINT8,
|
|
16
|
-
OperandType.
|
|
17
|
-
OperandType.
|
|
19
|
+
OperandType.UINT8, // opcode
|
|
20
|
+
OperandType.UINT8, // indirect bits
|
|
21
|
+
OperandType.UINT8, // member enum (immediate)
|
|
22
|
+
OperandType.UINT16, // addressOffset
|
|
23
|
+
OperandType.UINT16, // dstOffset
|
|
24
|
+
OperandType.UINT16, // existsOfsset
|
|
18
25
|
];
|
|
19
26
|
|
|
20
|
-
constructor(
|
|
27
|
+
constructor(
|
|
28
|
+
private indirect: number,
|
|
29
|
+
private memberEnum: number,
|
|
30
|
+
private addressOffset: number,
|
|
31
|
+
private dstOffset: number,
|
|
32
|
+
private existsOffset: number,
|
|
33
|
+
) {
|
|
21
34
|
super();
|
|
22
35
|
}
|
|
23
36
|
|
|
@@ -25,27 +38,38 @@ export class GetContractInstance extends Instruction {
|
|
|
25
38
|
const memory = context.machineState.memory.track(this.type);
|
|
26
39
|
context.machineState.consumeGas(this.gasCost());
|
|
27
40
|
|
|
28
|
-
|
|
41
|
+
if (!(this.memberEnum in ContractInstanceMember)) {
|
|
42
|
+
throw new InstructionExecutionError(`Invalid GETCONSTRACTINSTANCE member enum ${this.memberEnum}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const operands = [this.addressOffset, this.dstOffset, this.existsOffset];
|
|
29
46
|
const addressing = Addressing.fromWire(this.indirect, operands.length);
|
|
30
|
-
const [addressOffset, dstOffset] = addressing.resolve(operands, memory);
|
|
47
|
+
const [addressOffset, dstOffset, existsOffset] = addressing.resolve(operands, memory);
|
|
31
48
|
memory.checkTag(TypeTag.FIELD, addressOffset);
|
|
32
49
|
|
|
33
50
|
const address = memory.get(addressOffset).toFr();
|
|
34
51
|
const instance = await context.persistableState.getContractInstance(address);
|
|
52
|
+
const exists = instance !== undefined;
|
|
35
53
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
54
|
+
let memberValue = new Field(0);
|
|
55
|
+
if (exists) {
|
|
56
|
+
switch (this.memberEnum as ContractInstanceMember) {
|
|
57
|
+
case ContractInstanceMember.DEPLOYER:
|
|
58
|
+
memberValue = new Field(instance.deployer.toField());
|
|
59
|
+
break;
|
|
60
|
+
case ContractInstanceMember.CLASS_ID:
|
|
61
|
+
memberValue = new Field(instance.contractClassId.toField());
|
|
62
|
+
break;
|
|
63
|
+
case ContractInstanceMember.INIT_HASH:
|
|
64
|
+
memberValue = new Field(instance.initializationHash);
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
45
68
|
|
|
46
|
-
memory.
|
|
69
|
+
memory.set(existsOffset, new Uint1(exists ? 1 : 0));
|
|
70
|
+
memory.set(dstOffset, memberValue);
|
|
47
71
|
|
|
48
|
-
memory.assert({ reads: 1, writes:
|
|
72
|
+
memory.assert({ reads: 1, writes: 2, addressing });
|
|
49
73
|
context.machineState.incrementPc();
|
|
50
74
|
}
|
|
51
75
|
}
|
|
@@ -7,9 +7,9 @@ import { Instruction } from './instruction.js';
|
|
|
7
7
|
|
|
8
8
|
export class Jump extends Instruction {
|
|
9
9
|
static type: string = 'JUMP';
|
|
10
|
-
static readonly opcode: Opcode = Opcode.
|
|
10
|
+
static readonly opcode: Opcode = Opcode.JUMP_32;
|
|
11
11
|
// Informs (de)serialization. See Instruction.deserialize.
|
|
12
|
-
static readonly wireFormat: OperandType[] = [OperandType.UINT8, OperandType.
|
|
12
|
+
static readonly wireFormat: OperandType[] = [OperandType.UINT8, OperandType.UINT32];
|
|
13
13
|
|
|
14
14
|
constructor(private jumpOffset: number) {
|
|
15
15
|
super();
|
|
@@ -26,13 +26,13 @@ export class Jump extends Instruction {
|
|
|
26
26
|
|
|
27
27
|
export class JumpI extends Instruction {
|
|
28
28
|
static type: string = 'JUMPI';
|
|
29
|
-
static readonly opcode: Opcode = Opcode.
|
|
29
|
+
static readonly opcode: Opcode = Opcode.JUMPI_32;
|
|
30
30
|
|
|
31
31
|
// Instruction wire format with opcode.
|
|
32
32
|
static readonly wireFormat: OperandType[] = [
|
|
33
33
|
OperandType.UINT8,
|
|
34
34
|
OperandType.UINT8,
|
|
35
|
-
OperandType.
|
|
35
|
+
OperandType.UINT32,
|
|
36
36
|
OperandType.UINT16,
|
|
37
37
|
];
|
|
38
38
|
|
|
@@ -63,7 +63,7 @@ export class InternalCall extends Instruction {
|
|
|
63
63
|
static readonly type: string = 'INTERNALCALL';
|
|
64
64
|
static readonly opcode: Opcode = Opcode.INTERNALCALL;
|
|
65
65
|
// Informs (de)serialization. See Instruction.deserialize.
|
|
66
|
-
static readonly wireFormat: OperandType[] = [OperandType.UINT8, OperandType.
|
|
66
|
+
static readonly wireFormat: OperandType[] = [OperandType.UINT8, OperandType.UINT32];
|
|
67
67
|
|
|
68
68
|
constructor(private loc: number) {
|
|
69
69
|
super();
|
|
@@ -5,9 +5,9 @@ import { Opcode, OperandType } from '../serialization/instruction_serialization.
|
|
|
5
5
|
import { Addressing } from './addressing_mode.js';
|
|
6
6
|
import { Instruction } from './instruction.js';
|
|
7
7
|
|
|
8
|
-
export class
|
|
8
|
+
export class ToRadixBE extends Instruction {
|
|
9
9
|
static type: string = 'TORADIXLE';
|
|
10
|
-
static readonly opcode: Opcode = Opcode.
|
|
10
|
+
static readonly opcode: Opcode = Opcode.TORADIXBE;
|
|
11
11
|
|
|
12
12
|
// Informs (de)serialization. See Instruction.deserialize.
|
|
13
13
|
static readonly wireFormat: OperandType[] = [
|
|
@@ -44,15 +44,18 @@ export class ToRadixLE extends Instruction {
|
|
|
44
44
|
|
|
45
45
|
let value: bigint = memory.get(srcOffset).toBigInt();
|
|
46
46
|
const radix: bigint = memory.get(radixOffset).toBigInt();
|
|
47
|
+
if (this.numLimbs < 1) {
|
|
48
|
+
throw new InstructionExecutionError(`ToRadixBE instruction's numLimbs should be > 0 (was ${this.numLimbs})`);
|
|
49
|
+
}
|
|
47
50
|
if (radix > 256) {
|
|
48
|
-
throw new InstructionExecutionError(`
|
|
51
|
+
throw new InstructionExecutionError(`ToRadixBE instruction's radix should be <= 256 (was ${radix})`);
|
|
49
52
|
}
|
|
50
53
|
const radixBN: bigint = BigInt(radix);
|
|
51
|
-
const limbArray =
|
|
54
|
+
const limbArray = new Array(this.numLimbs);
|
|
52
55
|
|
|
53
|
-
for (let i =
|
|
56
|
+
for (let i = this.numLimbs - 1; i >= 0; i--) {
|
|
54
57
|
const limb = value % radixBN;
|
|
55
|
-
limbArray
|
|
58
|
+
limbArray[i] = limb;
|
|
56
59
|
value /= radixBN;
|
|
57
60
|
}
|
|
58
61
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AvmContext } from '../avm_context.js';
|
|
2
2
|
import { Field, Uint32, Uint64 } from '../avm_memory_types.js';
|
|
3
|
+
import { InstructionExecutionError } from '../errors.js';
|
|
3
4
|
import { Opcode, OperandType } from '../serialization/instruction_serialization.js';
|
|
4
5
|
import { Addressing } from './addressing_mode.js';
|
|
5
6
|
import { Instruction } from './instruction.js';
|
|
@@ -63,7 +64,7 @@ export class GetEnvVar extends Instruction {
|
|
|
63
64
|
OperandType.UINT16, // dstOffset
|
|
64
65
|
];
|
|
65
66
|
|
|
66
|
-
constructor(private indirect: number, private varEnum:
|
|
67
|
+
constructor(private indirect: number, private varEnum: number, private dstOffset: number) {
|
|
67
68
|
super();
|
|
68
69
|
}
|
|
69
70
|
|
|
@@ -71,11 +72,15 @@ export class GetEnvVar extends Instruction {
|
|
|
71
72
|
const memory = context.machineState.memory.track(this.type);
|
|
72
73
|
context.machineState.consumeGas(this.gasCost());
|
|
73
74
|
|
|
75
|
+
if (!(this.varEnum in EnvironmentVariable)) {
|
|
76
|
+
throw new InstructionExecutionError(`Invalid GETENVVAR var enum ${this.varEnum}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
74
79
|
const operands = [this.dstOffset];
|
|
75
80
|
const addressing = Addressing.fromWire(this.indirect, operands.length);
|
|
76
81
|
const [dstOffset] = addressing.resolve(operands, memory);
|
|
77
82
|
|
|
78
|
-
memory.set(dstOffset, getValue(this.varEnum, context));
|
|
83
|
+
memory.set(dstOffset, getValue(this.varEnum as EnvironmentVariable, context));
|
|
79
84
|
|
|
80
85
|
memory.assert({ writes: 1, addressing });
|
|
81
86
|
context.machineState.incrementPc();
|