@aztec/simulator 3.0.0-nightly.20251003 → 3.0.0-nightly.20251004
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/public/avm/serialization/instruction_serialization.d.ts +8 -0
- package/dest/public/avm/serialization/instruction_serialization.d.ts.map +1 -1
- package/dest/public/avm/serialization/instruction_serialization.js +10 -0
- package/dest/public/fixtures/custom_bytecode_tester.d.ts +12 -0
- package/dest/public/fixtures/custom_bytecode_tester.d.ts.map +1 -0
- package/dest/public/fixtures/custom_bytecode_tester.js +29 -0
- package/dest/public/fixtures/custom_bytecode_tests.d.ts +9 -0
- package/dest/public/fixtures/custom_bytecode_tests.d.ts.map +1 -0
- package/dest/public/fixtures/custom_bytecode_tests.js +109 -0
- package/dest/public/fixtures/index.d.ts +2 -1
- package/dest/public/fixtures/index.d.ts.map +1 -1
- package/dest/public/fixtures/index.js +2 -1
- package/dest/public/fixtures/minimal_public_tx.d.ts +1 -1
- package/dest/public/fixtures/minimal_public_tx.d.ts.map +1 -1
- package/dest/public/fixtures/minimal_public_tx.js +4 -20
- package/dest/public/state_manager/state_manager.js +2 -2
- package/package.json +15 -15
- package/src/public/avm/serialization/instruction_serialization.ts +12 -0
- package/src/public/fixtures/custom_bytecode_tester.ts +49 -0
- package/src/public/fixtures/custom_bytecode_tests.ts +135 -0
- package/src/public/fixtures/index.ts +2 -1
- package/src/public/fixtures/minimal_public_tx.ts +4 -31
- package/src/public/state_manager/state_manager.ts +2 -2
|
@@ -84,6 +84,14 @@ export declare enum OperandType {
|
|
|
84
84
|
TAG = 6
|
|
85
85
|
}
|
|
86
86
|
type DeserializedValue = number | bigint;
|
|
87
|
+
/**
|
|
88
|
+
* Returns the size of an operand in bytes.
|
|
89
|
+
* Should not be called with unknown operand types.
|
|
90
|
+
* @param operandType
|
|
91
|
+
* @returns number size in bytes
|
|
92
|
+
* @throws AssertionError if the operand type is unknown
|
|
93
|
+
*/
|
|
94
|
+
export declare function getOperandSize(operandType: OperandType): number;
|
|
87
95
|
/**
|
|
88
96
|
* Reads an array of operands from a buffer.
|
|
89
97
|
* @param cursor Buffer to read from. Might be longer than needed.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instruction_serialization.d.ts","sourceRoot":"","sources":["../../../../src/public/avm/serialization/instruction_serialization.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD;;;GAGG;AACH,oBAAY,MAAM;IAEhB,KAAK,IAAA;IACL,MAAM,IAAA;IACN,KAAK,IAAA;IACL,MAAM,IAAA;IACN,KAAK,IAAA;IACL,MAAM,IAAA;IACN,KAAK,IAAA;IACL,MAAM,IAAA;IACN,MAAM,IAAA;IACN,OAAO,IAAA;IACP,IAAI,KAAA;IACJ,KAAK,KAAA;IACL,IAAI,KAAA;IACJ,KAAK,KAAA;IACL,KAAK,KAAA;IACL,MAAM,KAAA;IACN,KAAK,KAAA;IACL,MAAM,KAAA;IACN,IAAI,KAAA;IACJ,KAAK,KAAA;IACL,KAAK,KAAA;IACL,MAAM,KAAA;IACN,KAAK,KAAA;IACL,MAAM,KAAA;IACN,KAAK,KAAA;IACL,MAAM,KAAA;IACN,KAAK,KAAA;IACL,MAAM,KAAA;IACN,MAAM,KAAA;IACN,OAAO,KAAA;IAEP,YAAY,KAAA;IACZ,YAAY,KAAA;IACZ,WAAW,KAAA;IACX,cAAc,KAAA;IACd,cAAc,KAAA;IAEd,OAAO,KAAA;IACP,QAAQ,KAAA;IACR,YAAY,KAAA;IACZ,cAAc,KAAA;IAEd,KAAK,KAAA;IACL,MAAM,KAAA;IACN,MAAM,KAAA;IACN,MAAM,KAAA;IACN,OAAO,KAAA;IACP,MAAM,KAAA;IACN,KAAK,KAAA;IACL,MAAM,KAAA;IAEN,KAAK,KAAA;IACL,MAAM,KAAA;IACN,cAAc,KAAA;IACd,YAAY,KAAA;IACZ,eAAe,KAAA;IACf,aAAa,KAAA;IACb,eAAe,KAAA;IACf,mBAAmB,KAAA;IACnB,kBAAkB,KAAA;IAClB,aAAa,KAAA;IAEb,IAAI,KAAA;IACJ,UAAU,KAAA;IACV,MAAM,KAAA;IACN,QAAQ,KAAA;IACR,SAAS,KAAA;IAET,QAAQ,KAAA;IAER,SAAS,KAAA;IACT,iBAAiB,KAAA;IACjB,WAAW,KAAA;IACX,KAAK,KAAA;IAEL,SAAS,KAAA;CACV;AAED,eAAO,MAAM,gBAAgB,QAI5B,CAAC;AAIF,oBAAY,WAAW;IACrB,KAAK,IAAA;IACL,MAAM,IAAA;IACN,MAAM,IAAA;IACN,MAAM,IAAA;IACN,OAAO,IAAA;IACP,EAAE,IAAA;IACF,GAAG,IAAA;CACJ;AAGD,KAAK,iBAAiB,GAAG,MAAM,GAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"instruction_serialization.d.ts","sourceRoot":"","sources":["../../../../src/public/avm/serialization/instruction_serialization.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD;;;GAGG;AACH,oBAAY,MAAM;IAEhB,KAAK,IAAA;IACL,MAAM,IAAA;IACN,KAAK,IAAA;IACL,MAAM,IAAA;IACN,KAAK,IAAA;IACL,MAAM,IAAA;IACN,KAAK,IAAA;IACL,MAAM,IAAA;IACN,MAAM,IAAA;IACN,OAAO,IAAA;IACP,IAAI,KAAA;IACJ,KAAK,KAAA;IACL,IAAI,KAAA;IACJ,KAAK,KAAA;IACL,KAAK,KAAA;IACL,MAAM,KAAA;IACN,KAAK,KAAA;IACL,MAAM,KAAA;IACN,IAAI,KAAA;IACJ,KAAK,KAAA;IACL,KAAK,KAAA;IACL,MAAM,KAAA;IACN,KAAK,KAAA;IACL,MAAM,KAAA;IACN,KAAK,KAAA;IACL,MAAM,KAAA;IACN,KAAK,KAAA;IACL,MAAM,KAAA;IACN,MAAM,KAAA;IACN,OAAO,KAAA;IAEP,YAAY,KAAA;IACZ,YAAY,KAAA;IACZ,WAAW,KAAA;IACX,cAAc,KAAA;IACd,cAAc,KAAA;IAEd,OAAO,KAAA;IACP,QAAQ,KAAA;IACR,YAAY,KAAA;IACZ,cAAc,KAAA;IAEd,KAAK,KAAA;IACL,MAAM,KAAA;IACN,MAAM,KAAA;IACN,MAAM,KAAA;IACN,OAAO,KAAA;IACP,MAAM,KAAA;IACN,KAAK,KAAA;IACL,MAAM,KAAA;IAEN,KAAK,KAAA;IACL,MAAM,KAAA;IACN,cAAc,KAAA;IACd,YAAY,KAAA;IACZ,eAAe,KAAA;IACf,aAAa,KAAA;IACb,eAAe,KAAA;IACf,mBAAmB,KAAA;IACnB,kBAAkB,KAAA;IAClB,aAAa,KAAA;IAEb,IAAI,KAAA;IACJ,UAAU,KAAA;IACV,MAAM,KAAA;IACN,QAAQ,KAAA;IACR,SAAS,KAAA;IAET,QAAQ,KAAA;IAER,SAAS,KAAA;IACT,iBAAiB,KAAA;IACjB,WAAW,KAAA;IACX,KAAK,KAAA;IAEL,SAAS,KAAA;CACV;AAED,eAAO,MAAM,gBAAgB,QAI5B,CAAC;AAIF,oBAAY,WAAW;IACrB,KAAK,IAAA;IACL,MAAM,IAAA;IACN,MAAM,IAAA;IACN,MAAM,IAAA;IACN,OAAO,IAAA;IACP,EAAE,IAAA;IACF,GAAG,IAAA;CACJ;AAGD,KAAK,iBAAiB,GAAG,MAAM,GAAG,MAAM,CAAC;AAgBzC;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAG/D;AAkDD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,iBAAiB,EAAE,CAyBvG;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,MAAM,CAmBrF"}
|
|
@@ -157,6 +157,16 @@ const OPERAND_SPEC = new Map([
|
|
|
157
157
|
]
|
|
158
158
|
]
|
|
159
159
|
]);
|
|
160
|
+
/**
|
|
161
|
+
* Returns the size of an operand in bytes.
|
|
162
|
+
* Should not be called with unknown operand types.
|
|
163
|
+
* @param operandType
|
|
164
|
+
* @returns number size in bytes
|
|
165
|
+
* @throws AssertionError if the operand type is unknown
|
|
166
|
+
*/ export function getOperandSize(operandType) {
|
|
167
|
+
assert(OPERAND_SPEC.has(operandType), `Unknown operand type: ${operandType}`);
|
|
168
|
+
return OPERAND_SPEC.get(operandType)[0];
|
|
169
|
+
}
|
|
160
170
|
function readUintBE(buf, offset, totalBytes) {
|
|
161
171
|
let value = 0n;
|
|
162
172
|
for(let i = 0; i < totalBytes; ++i){
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { PublicTxResult } from '../public_tx_simulator/public_tx_simulator.js';
|
|
2
|
+
import { PublicTxSimulationTester } from './public_tx_simulation_tester.js';
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* Test custom bytecode (simulation or proving) with the provided bytecode.
|
|
6
|
+
* @param bytecode - The bytecode buffer to use
|
|
7
|
+
* @param tester - The tester to use (simulation or proving)
|
|
8
|
+
* @param txLabel - The label of the transaction
|
|
9
|
+
* @param contractName - The name of the contract (default: 'CustomBytecodeContract')
|
|
10
|
+
*/
|
|
11
|
+
export declare function testCustomBytecode(bytecode: Buffer, tester: PublicTxSimulationTester, txLabel: string, contractName?: string): Promise<PublicTxResult>;
|
|
12
|
+
//# sourceMappingURL=custom_bytecode_tester.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom_bytecode_tester.d.ts","sourceRoot":"","sources":["../../../src/public/fixtures/custom_bytecode_tester.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+CAA+C,CAAC;AACpF,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAE5E;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,wBAAwB,EAChC,OAAO,EAAE,MAAM,EACf,YAAY,GAAE,MAAiC,GAC9C,OAAO,CAAC,cAAc,CAAC,CA6BzB"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { FunctionType, emptyContractArtifact, emptyFunctionArtifact } from '@aztec/stdlib/abi';
|
|
2
|
+
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* Test custom bytecode (simulation or proving) with the provided bytecode.
|
|
6
|
+
* @param bytecode - The bytecode buffer to use
|
|
7
|
+
* @param tester - The tester to use (simulation or proving)
|
|
8
|
+
* @param txLabel - The label of the transaction
|
|
9
|
+
* @param contractName - The name of the contract (default: 'CustomBytecodeContract')
|
|
10
|
+
*/ export async function testCustomBytecode(bytecode, tester, txLabel, contractName = 'CustomBytecodeContract') {
|
|
11
|
+
const deployer = AztecAddress.fromNumber(42);
|
|
12
|
+
const contractArtifact = emptyContractArtifact();
|
|
13
|
+
contractArtifact.name = contractName;
|
|
14
|
+
contractArtifact.functions = [
|
|
15
|
+
emptyFunctionArtifact()
|
|
16
|
+
];
|
|
17
|
+
contractArtifact.functions[0].name = 'public_dispatch';
|
|
18
|
+
contractArtifact.functions[0].functionType = FunctionType.PUBLIC;
|
|
19
|
+
contractArtifact.functions[0].bytecode = bytecode;
|
|
20
|
+
const testContract = await tester.registerAndDeployContract(/*constructorArgs=*/ [], deployer, /*contractArtifact=*/ contractArtifact);
|
|
21
|
+
// EXECUTE! This means that if using AvmProvingTester subclass, it will PROVE the transaction!
|
|
22
|
+
return await tester.executeTxWithLabel(/*txLabel=*/ txLabel, /*sender=*/ deployer, /*setupCalls=*/ [], /*appCalls=*/ [
|
|
23
|
+
{
|
|
24
|
+
address: testContract.address,
|
|
25
|
+
fnName: 'public_dispatch',
|
|
26
|
+
args: []
|
|
27
|
+
}
|
|
28
|
+
]);
|
|
29
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { PublicTxSimulationTester } from './public_tx_simulation_tester.js';
|
|
2
|
+
export declare function addressingWithBaseTagIssueTest(isIndirect: boolean, tester: PublicTxSimulationTester): Promise<import("../index.js").PublicTxResult>;
|
|
3
|
+
export declare function pcOutOfRangeTest(tester: PublicTxSimulationTester): Promise<import("../index.js").PublicTxResult>;
|
|
4
|
+
export declare function invalidOpcodeTest(tester: PublicTxSimulationTester): Promise<import("../index.js").PublicTxResult>;
|
|
5
|
+
export declare function invalidByteTest(tester: PublicTxSimulationTester): Promise<import("../index.js").PublicTxResult>;
|
|
6
|
+
export declare function instructionTruncatedTest(tester: PublicTxSimulationTester): Promise<import("../index.js").PublicTxResult>;
|
|
7
|
+
export declare function invalidTagValueTest(tester: PublicTxSimulationTester): Promise<import("../index.js").PublicTxResult>;
|
|
8
|
+
export declare function invalidTagValueAndInstructionTruncatedTest(tester: PublicTxSimulationTester): Promise<import("../index.js").PublicTxResult>;
|
|
9
|
+
//# sourceMappingURL=custom_bytecode_tests.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom_bytecode_tests.d.ts","sourceRoot":"","sources":["../../../src/public/fixtures/custom_bytecode_tests.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAI5E,wBAAsB,8BAA8B,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,wBAAwB,iDAczG;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,wBAAwB,iDAQtE;AAED,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,wBAAwB,iDAiBvE;AAGD,wBAAsB,eAAe,CAAC,MAAM,EAAE,wBAAwB,iDAOrE;AAGD,wBAAsB,wBAAwB,CAAC,MAAM,EAAE,wBAAwB,iDAU9E;AAGD,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,wBAAwB,iDAYzE;AAGD,wBAAsB,0CAA0C,CAAC,MAAM,EAAE,wBAAwB,iDAchG"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { strict as assert } from 'assert';
|
|
2
|
+
import { TypeTag } from '../avm/avm_memory_types.js';
|
|
3
|
+
import { Addressing, AddressingMode } from '../avm/opcodes/addressing_mode.js';
|
|
4
|
+
import { CalldataCopy, Jump, Return, Set } from '../avm/opcodes/index.js';
|
|
5
|
+
import { encodeToBytecode } from '../avm/serialization/bytecode_serialization.js';
|
|
6
|
+
import { MAX_OPCODE_VALUE, Opcode, OperandType, getOperandSize } from '../avm/serialization/instruction_serialization.js';
|
|
7
|
+
import { testCustomBytecode } from './custom_bytecode_tester.js';
|
|
8
|
+
// First instruction resolved a base address (offset 0) which is uninitialized and therefore
|
|
9
|
+
// of invalid tag (FF). This will trigger an exceptional halt.
|
|
10
|
+
export async function addressingWithBaseTagIssueTest(isIndirect, tester) {
|
|
11
|
+
const addressingMode = Addressing.fromModes([
|
|
12
|
+
isIndirect ? AddressingMode.INDIRECT_RELATIVE : AddressingMode.RELATIVE,
|
|
13
|
+
AddressingMode.DIRECT,
|
|
14
|
+
AddressingMode.DIRECT
|
|
15
|
+
]);
|
|
16
|
+
const bytecode = encodeToBytecode([
|
|
17
|
+
new CalldataCopy(/*indirect=*/ addressingMode.toWire(), /*copySize=*/ 1, /*cdOffset=*/ 0, /*dstOffset=*/ 0),
|
|
18
|
+
new Return(/*indirect=*/ 0, /*copySizeOffset=*/ 0, /*returnOffset=*/ 0)
|
|
19
|
+
]);
|
|
20
|
+
const txLabel = isIndirect ? 'AddressingWithBaseTagInvalidIndirect' : 'AddressingWithBaseTagInvalidDirect';
|
|
21
|
+
return await testCustomBytecode(bytecode, tester, txLabel);
|
|
22
|
+
}
|
|
23
|
+
export async function pcOutOfRangeTest(tester) {
|
|
24
|
+
const bytecode = encodeToBytecode([
|
|
25
|
+
new Jump(/*jumpOffset=*/ 123),
|
|
26
|
+
new Return(/*indirect=*/ 0, /*copySizeOffset=*/ 0, /*returnOffset=*/ 0)
|
|
27
|
+
]);
|
|
28
|
+
const txLabel = 'PcOutOfRange';
|
|
29
|
+
return await testCustomBytecode(bytecode, tester, txLabel);
|
|
30
|
+
}
|
|
31
|
+
export async function invalidOpcodeTest(tester) {
|
|
32
|
+
let bytecode = encodeToBytecode([
|
|
33
|
+
new Set(/*indirect=*/ 0, /*dstOffset=*/ 0, TypeTag.UINT32, /*value=*/ 0).as(Opcode.SET_8, Set.wireFormat8)
|
|
34
|
+
]);
|
|
35
|
+
const offsetReturnOpcodeByte = bytecode.length;
|
|
36
|
+
bytecode = Buffer.concat([
|
|
37
|
+
bytecode,
|
|
38
|
+
encodeToBytecode([
|
|
39
|
+
new Return(/*indirect=*/ 0, /*copySizeOffset=*/ 0, /*returnOffset=*/ 0)
|
|
40
|
+
])
|
|
41
|
+
]);
|
|
42
|
+
// Manipulate the Return opcode to make the opcode invalid (out of range).
|
|
43
|
+
bytecode[offsetReturnOpcodeByte] = MAX_OPCODE_VALUE + 1; // opcode is invalid.
|
|
44
|
+
const txLabel = 'InvalidOpcode';
|
|
45
|
+
return await testCustomBytecode(bytecode, tester, txLabel);
|
|
46
|
+
}
|
|
47
|
+
// Single invalid byte in the bytecode.
|
|
48
|
+
export async function invalidByteTest(tester) {
|
|
49
|
+
const invalidOpcode = MAX_OPCODE_VALUE + 7;
|
|
50
|
+
assert(invalidOpcode < 256, 'Invalid opcode must fit in a single byte');
|
|
51
|
+
const bytecode = Buffer.from([
|
|
52
|
+
invalidOpcode
|
|
53
|
+
]);
|
|
54
|
+
const txLabel = 'InvalidByte';
|
|
55
|
+
return await testCustomBytecode(bytecode, tester, txLabel);
|
|
56
|
+
}
|
|
57
|
+
// Truncate the last instruction in the bytecode.
|
|
58
|
+
export async function instructionTruncatedTest(tester) {
|
|
59
|
+
let bytecode = encodeToBytecode([
|
|
60
|
+
new Set(/*indirect=*/ 0, /*dstOffset=*/ 0, TypeTag.UINT32, /*value=*/ 0).as(Opcode.SET_8, Set.wireFormat8)
|
|
61
|
+
]);
|
|
62
|
+
// Truncate the bytecode.
|
|
63
|
+
bytecode = bytecode.subarray(0, -1);
|
|
64
|
+
const txLabel = 'InstructionTruncated';
|
|
65
|
+
return await testCustomBytecode(bytecode, tester, txLabel);
|
|
66
|
+
}
|
|
67
|
+
// Invalid tag value byte in an instruction.
|
|
68
|
+
export async function invalidTagValueTest(tester) {
|
|
69
|
+
const bytecode = encodeToBytecode([
|
|
70
|
+
new Set(/*indirect=*/ 0, /*dstOffset=*/ 0, TypeTag.UINT32, /*value=*/ 0).as(Opcode.SET_8, Set.wireFormat8),
|
|
71
|
+
new Return(/*indirect=*/ 0, /*copySizeOffset=*/ 0, /*returnOffset=*/ 0)
|
|
72
|
+
]);
|
|
73
|
+
const tagOffset = getTagOffsetInInstruction(Set.wireFormat8);
|
|
74
|
+
assert(bytecode[tagOffset].valueOf() == TypeTag.UINT32.valueOf(), 'Set instruction tag should be UINT32 in test');
|
|
75
|
+
bytecode[tagOffset] = TypeTag.INVALID;
|
|
76
|
+
const txLabel = 'InvalidTagValue';
|
|
77
|
+
return await testCustomBytecode(bytecode, tester, txLabel);
|
|
78
|
+
}
|
|
79
|
+
// Combine an invalid tag in the last instruction that is truncated.
|
|
80
|
+
export async function invalidTagValueAndInstructionTruncatedTest(tester) {
|
|
81
|
+
let bytecode = encodeToBytecode([
|
|
82
|
+
// Important: value argument must be a bigint otherwise a type error will be thrown.
|
|
83
|
+
new Set(/*indirect=*/ 0, /*dstOffset=*/ 0, TypeTag.UINT128, /*value=*/ 0n).as(Opcode.SET_128, Set.wireFormat128)
|
|
84
|
+
]);
|
|
85
|
+
// Truncate the bytecode.
|
|
86
|
+
bytecode = bytecode.subarray(0, -5);
|
|
87
|
+
const tagOffset = getTagOffsetInInstruction(Set.wireFormat128);
|
|
88
|
+
assert(bytecode[tagOffset].valueOf() == TypeTag.UINT128.valueOf(), 'Set instruction tag should be UINT128 in test');
|
|
89
|
+
bytecode[tagOffset] = 0x6f; // Invalid tag value.
|
|
90
|
+
const txLabel = 'InvalidTagValueAndInstructionTruncated';
|
|
91
|
+
return await testCustomBytecode(bytecode, tester, txLabel);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Returns the offset of the tag in an instruction.
|
|
95
|
+
* @details Loops over the wire format operand type entries until it finds the tag.
|
|
96
|
+
* Returns the byte offset of the tag based on each operand size that is passed.
|
|
97
|
+
*
|
|
98
|
+
* @param wireFormat array of operand types
|
|
99
|
+
* @returns byte offset of the tag
|
|
100
|
+
*/ function getTagOffsetInInstruction(wireFormat) {
|
|
101
|
+
let offset = 0;
|
|
102
|
+
for (const operand of wireFormat){
|
|
103
|
+
if (operand === OperandType.TAG) {
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
offset += getOperandSize(operand);
|
|
107
|
+
}
|
|
108
|
+
return offset;
|
|
109
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export * from './public_tx_simulation_tester.js';
|
|
2
2
|
export * from './utils.js';
|
|
3
3
|
export * from './simple_contract_data_source.js';
|
|
4
|
-
export { readAvmMinimalPublicTxInputsFromFile,
|
|
4
|
+
export { readAvmMinimalPublicTxInputsFromFile, simAvmMinimalPublicTx } from './minimal_public_tx.js';
|
|
5
5
|
export { TestExecutorMetrics } from '../test_executor_metrics.js';
|
|
6
6
|
export { ammTest } from './amm_test.js';
|
|
7
7
|
export { bulkTest, megaBulkTest } from './bulk_test.js';
|
|
8
8
|
export { tokenTest } from './token_test.js';
|
|
9
|
+
export * from './custom_bytecode_tests.js';
|
|
9
10
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/public/fixtures/index.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAC;AACjD,cAAc,YAAY,CAAC;AAC3B,cAAc,kCAAkC,CAAC;AACjD,OAAO,EAAE,oCAAoC,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/public/fixtures/index.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAC;AACjD,cAAc,YAAY,CAAC;AAC3B,cAAc,kCAAkC,CAAC;AACjD,OAAO,EAAE,oCAAoC,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AACrG,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,cAAc,4BAA4B,CAAC"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export * from './public_tx_simulation_tester.js';
|
|
2
2
|
export * from './utils.js';
|
|
3
3
|
export * from './simple_contract_data_source.js';
|
|
4
|
-
export { readAvmMinimalPublicTxInputsFromFile,
|
|
4
|
+
export { readAvmMinimalPublicTxInputsFromFile, simAvmMinimalPublicTx } from './minimal_public_tx.js';
|
|
5
5
|
export { TestExecutorMetrics } from '../test_executor_metrics.js';
|
|
6
6
|
export { ammTest } from './amm_test.js';
|
|
7
7
|
export { bulkTest, megaBulkTest } from './bulk_test.js';
|
|
8
8
|
export { tokenTest } from './token_test.js';
|
|
9
|
+
export * from './custom_bytecode_tests.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AvmCircuitInputs } from '@aztec/stdlib/avm';
|
|
2
2
|
import type { PublicTxResult } from '../public_tx_simulator/public_tx_simulator.js';
|
|
3
|
-
export declare function
|
|
3
|
+
export declare function simAvmMinimalPublicTx(): Promise<PublicTxResult>;
|
|
4
4
|
/**
|
|
5
5
|
* Reads the AVM circuit inputs for the minimal public tx from a pre-generated JSON file.
|
|
6
6
|
* @returns The AvmCircuitInputs for the minimal public tx.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"minimal_public_tx.d.ts","sourceRoot":"","sources":["../../../src/public/fixtures/minimal_public_tx.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"minimal_public_tx.d.ts","sourceRoot":"","sources":["../../../src/public/fixtures/minimal_public_tx.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAkC,MAAM,mBAAmB,CAAC;AAQrF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+CAA+C,CAAC;AAIpF,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,cAAc,CAAC,CA2BrE;AAED;;;GAGG;AACH,wBAAgB,oCAAoC,IAAI,gBAAgB,CAEvE"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Fr } from '@aztec/foundation/fields';
|
|
2
|
-
import { FunctionType, emptyContractArtifact, emptyFunctionArtifact } from '@aztec/stdlib/abi';
|
|
3
2
|
import { AvmCircuitInputs, AvmProtocolContractAddressHint } from '@aztec/stdlib/avm';
|
|
4
3
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
5
4
|
import avmMinimalCircuitInputsJson from '../../../artifacts/avm_minimal_inputs.json' with {
|
|
@@ -9,32 +8,17 @@ import { TypeTag } from '../avm/avm_memory_types.js';
|
|
|
9
8
|
import { Add, Return, Set } from '../avm/opcodes/index.js';
|
|
10
9
|
import { encodeToBytecode } from '../avm/serialization/bytecode_serialization.js';
|
|
11
10
|
import { Opcode } from '../avm/serialization/instruction_serialization.js';
|
|
11
|
+
import { testCustomBytecode } from './custom_bytecode_tester.js';
|
|
12
12
|
import { PublicTxSimulationTester } from './public_tx_simulation_tester.js';
|
|
13
|
-
export async function
|
|
14
|
-
const deployer = AztecAddress.fromNumber(42);
|
|
15
|
-
const simTester = await PublicTxSimulationTester.create();
|
|
13
|
+
export async function simAvmMinimalPublicTx() {
|
|
16
14
|
const minimalBytecode = encodeToBytecode([
|
|
17
15
|
new Set(/*indirect*/ 0, /*dstOffset*/ 0, TypeTag.UINT32, /*value*/ 1).as(Opcode.SET_8, Set.wireFormat8),
|
|
18
16
|
new Set(/*indirect*/ 0, /*dstOffset*/ 1, TypeTag.UINT32, /*value*/ 2).as(Opcode.SET_8, Set.wireFormat8),
|
|
19
17
|
new Add(/*indirect=*/ 0, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2).as(Opcode.ADD_8, Add.wireFormat8),
|
|
20
18
|
new Return(/*indirect=*/ 0, /*copySizeOffset=*/ 0, /*returnOffset=*/ 2)
|
|
21
19
|
]);
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
minimalContractArtifact.functions = [
|
|
25
|
-
emptyFunctionArtifact()
|
|
26
|
-
];
|
|
27
|
-
minimalContractArtifact.functions[0].name = 'public_dispatch';
|
|
28
|
-
minimalContractArtifact.functions[0].functionType = FunctionType.PUBLIC;
|
|
29
|
-
minimalContractArtifact.functions[0].bytecode = minimalBytecode;
|
|
30
|
-
const minimalTestContract = await simTester.registerAndDeployContract(/*constructorArgs=*/ [], deployer, /*contractArtifact=*/ minimalContractArtifact);
|
|
31
|
-
const result = await simTester.simulateTx(/*sender=*/ deployer, /*setupCalls=*/ [], /*appCalls=*/ [
|
|
32
|
-
{
|
|
33
|
-
address: minimalTestContract.address,
|
|
34
|
-
fnName: 'public_dispatch',
|
|
35
|
-
args: []
|
|
36
|
-
}
|
|
37
|
-
], /*teardownCall=*/ undefined, /*feePayer=*/ deployer);
|
|
20
|
+
const tester = await PublicTxSimulationTester.create();
|
|
21
|
+
const result = await testCustomBytecode(minimalBytecode, tester, 'MinimalTx', 'AvmMinimalContract');
|
|
38
22
|
// Modify the protocolContractDerivedAddresses to be all zeros and modify the protocolContractTreeRoot
|
|
39
23
|
// to be a fixed value (the root of a tree of all 0 leaves). This ensures that the testdata is stable
|
|
40
24
|
result.avmProvingRequest.inputs.hints.protocolContractDerivedAddresses = result.avmProvingRequest.inputs.hints.protocolContractDerivedAddresses.map(()=>new AvmProtocolContractAddressHint(AztecAddress.ZERO, AztecAddress.ZERO));
|
|
@@ -270,7 +270,7 @@ import { PublicStorage } from './public_storage.js';
|
|
|
270
270
|
return undefined;
|
|
271
271
|
}
|
|
272
272
|
this.log.trace(`Got contract instance (address=${contractAddress}): instance=${jsonStringify(instance)}`);
|
|
273
|
-
// All that is left is
|
|
273
|
+
// All that is left is to check that the contract updatability information is correct.
|
|
274
274
|
// That is, that the current and original contract class ids are correct.
|
|
275
275
|
await this.checkContractUpdateInformation(instanceWithAddress);
|
|
276
276
|
return instance;
|
|
@@ -289,7 +289,7 @@ import { PublicStorage } from './public_storage.js';
|
|
|
289
289
|
//
|
|
290
290
|
// However, we will also be checking the hash of the delayed public mutable values.
|
|
291
291
|
// This is a bit of a leak of information, since the circuit will use it to prove
|
|
292
|
-
// one public read
|
|
292
|
+
// one public read instead of N of the delayed public mutable values.
|
|
293
293
|
const { delayedPublicMutableSlot, delayedPublicMutableHashSlot } = await DelayedPublicMutableValuesWithHash.getContractUpdateSlots(instance.address);
|
|
294
294
|
const readDeployerStorage = async (storageSlot)=>await this.readStorage(ProtocolContractAddress.ContractInstanceRegistry, storageSlot);
|
|
295
295
|
const hash = await readDeployerStorage(delayedPublicMutableHashSlot);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/simulator",
|
|
3
|
-
"version": "3.0.0-nightly.
|
|
3
|
+
"version": "3.0.0-nightly.20251004",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./server": "./dest/server.js",
|
|
@@ -63,25 +63,25 @@
|
|
|
63
63
|
]
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@aztec/constants": "3.0.0-nightly.
|
|
67
|
-
"@aztec/foundation": "3.0.0-nightly.
|
|
68
|
-
"@aztec/noir-acvm_js": "3.0.0-nightly.
|
|
69
|
-
"@aztec/noir-noirc_abi": "3.0.0-nightly.
|
|
70
|
-
"@aztec/noir-protocol-circuits-types": "3.0.0-nightly.
|
|
71
|
-
"@aztec/noir-types": "3.0.0-nightly.
|
|
72
|
-
"@aztec/protocol-contracts": "3.0.0-nightly.
|
|
73
|
-
"@aztec/stdlib": "3.0.0-nightly.
|
|
74
|
-
"@aztec/telemetry-client": "3.0.0-nightly.
|
|
75
|
-
"@aztec/world-state": "3.0.0-nightly.
|
|
66
|
+
"@aztec/constants": "3.0.0-nightly.20251004",
|
|
67
|
+
"@aztec/foundation": "3.0.0-nightly.20251004",
|
|
68
|
+
"@aztec/noir-acvm_js": "3.0.0-nightly.20251004",
|
|
69
|
+
"@aztec/noir-noirc_abi": "3.0.0-nightly.20251004",
|
|
70
|
+
"@aztec/noir-protocol-circuits-types": "3.0.0-nightly.20251004",
|
|
71
|
+
"@aztec/noir-types": "3.0.0-nightly.20251004",
|
|
72
|
+
"@aztec/protocol-contracts": "3.0.0-nightly.20251004",
|
|
73
|
+
"@aztec/stdlib": "3.0.0-nightly.20251004",
|
|
74
|
+
"@aztec/telemetry-client": "3.0.0-nightly.20251004",
|
|
75
|
+
"@aztec/world-state": "3.0.0-nightly.20251004",
|
|
76
76
|
"lodash.clonedeep": "^4.5.0",
|
|
77
77
|
"lodash.merge": "^4.6.2",
|
|
78
78
|
"tslib": "^2.4.0"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
|
-
"@aztec/kv-store": "3.0.0-nightly.
|
|
82
|
-
"@aztec/merkle-tree": "3.0.0-nightly.
|
|
83
|
-
"@aztec/noir-contracts.js": "3.0.0-nightly.
|
|
84
|
-
"@aztec/noir-test-contracts.js": "3.0.0-nightly.
|
|
81
|
+
"@aztec/kv-store": "3.0.0-nightly.20251004",
|
|
82
|
+
"@aztec/merkle-tree": "3.0.0-nightly.20251004",
|
|
83
|
+
"@aztec/noir-contracts.js": "3.0.0-nightly.20251004",
|
|
84
|
+
"@aztec/noir-test-contracts.js": "3.0.0-nightly.20251004",
|
|
85
85
|
"@jest/globals": "^30.0.0",
|
|
86
86
|
"@types/jest": "^30.0.0",
|
|
87
87
|
"@types/lodash.clonedeep": "^4.5.7",
|
|
@@ -124,6 +124,18 @@ const OPERAND_SPEC = new Map<OperandType, [number, (offset: number) => OperandNa
|
|
|
124
124
|
[OperandType.TAG, [1, Buffer.prototype.readUint8, Buffer.prototype.writeUint8]],
|
|
125
125
|
]);
|
|
126
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Returns the size of an operand in bytes.
|
|
129
|
+
* Should not be called with unknown operand types.
|
|
130
|
+
* @param operandType
|
|
131
|
+
* @returns number size in bytes
|
|
132
|
+
* @throws AssertionError if the operand type is unknown
|
|
133
|
+
*/
|
|
134
|
+
export function getOperandSize(operandType: OperandType): number {
|
|
135
|
+
assert(OPERAND_SPEC.has(operandType), `Unknown operand type: ${operandType}`);
|
|
136
|
+
return OPERAND_SPEC.get(operandType)![0];
|
|
137
|
+
}
|
|
138
|
+
|
|
127
139
|
function readUintBE(buf: Buffer, offset: number, totalBytes: number): bigint {
|
|
128
140
|
let value: bigint = 0n;
|
|
129
141
|
for (let i = 0; i < totalBytes; ++i) {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { FunctionType, emptyContractArtifact, emptyFunctionArtifact } from '@aztec/stdlib/abi';
|
|
2
|
+
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
3
|
+
|
|
4
|
+
import type { PublicTxResult } from '../public_tx_simulator/public_tx_simulator.js';
|
|
5
|
+
import { PublicTxSimulationTester } from './public_tx_simulation_tester.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
*
|
|
9
|
+
* Test custom bytecode (simulation or proving) with the provided bytecode.
|
|
10
|
+
* @param bytecode - The bytecode buffer to use
|
|
11
|
+
* @param tester - The tester to use (simulation or proving)
|
|
12
|
+
* @param txLabel - The label of the transaction
|
|
13
|
+
* @param contractName - The name of the contract (default: 'CustomBytecodeContract')
|
|
14
|
+
*/
|
|
15
|
+
export async function testCustomBytecode(
|
|
16
|
+
bytecode: Buffer,
|
|
17
|
+
tester: PublicTxSimulationTester,
|
|
18
|
+
txLabel: string,
|
|
19
|
+
contractName: string = 'CustomBytecodeContract',
|
|
20
|
+
): Promise<PublicTxResult> {
|
|
21
|
+
const deployer = AztecAddress.fromNumber(42);
|
|
22
|
+
|
|
23
|
+
const contractArtifact = emptyContractArtifact();
|
|
24
|
+
contractArtifact.name = contractName;
|
|
25
|
+
contractArtifact.functions = [emptyFunctionArtifact()];
|
|
26
|
+
contractArtifact.functions[0].name = 'public_dispatch';
|
|
27
|
+
contractArtifact.functions[0].functionType = FunctionType.PUBLIC;
|
|
28
|
+
contractArtifact.functions[0].bytecode = bytecode;
|
|
29
|
+
|
|
30
|
+
const testContract = await tester.registerAndDeployContract(
|
|
31
|
+
/*constructorArgs=*/ [],
|
|
32
|
+
deployer,
|
|
33
|
+
/*contractArtifact=*/ contractArtifact,
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
// EXECUTE! This means that if using AvmProvingTester subclass, it will PROVE the transaction!
|
|
37
|
+
return await tester.executeTxWithLabel(
|
|
38
|
+
/*txLabel=*/ txLabel,
|
|
39
|
+
/*sender=*/ deployer,
|
|
40
|
+
/*setupCalls=*/ [],
|
|
41
|
+
/*appCalls=*/ [
|
|
42
|
+
{
|
|
43
|
+
address: testContract.address,
|
|
44
|
+
fnName: 'public_dispatch',
|
|
45
|
+
args: [],
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
);
|
|
49
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { strict as assert } from 'assert';
|
|
2
|
+
|
|
3
|
+
import { TypeTag } from '../avm/avm_memory_types.js';
|
|
4
|
+
import { Addressing, AddressingMode } from '../avm/opcodes/addressing_mode.js';
|
|
5
|
+
import { CalldataCopy, Jump, Return, Set } from '../avm/opcodes/index.js';
|
|
6
|
+
import { encodeToBytecode } from '../avm/serialization/bytecode_serialization.js';
|
|
7
|
+
import {
|
|
8
|
+
MAX_OPCODE_VALUE,
|
|
9
|
+
Opcode,
|
|
10
|
+
OperandType,
|
|
11
|
+
getOperandSize,
|
|
12
|
+
} from '../avm/serialization/instruction_serialization.js';
|
|
13
|
+
import { testCustomBytecode } from './custom_bytecode_tester.js';
|
|
14
|
+
import { PublicTxSimulationTester } from './public_tx_simulation_tester.js';
|
|
15
|
+
|
|
16
|
+
// First instruction resolved a base address (offset 0) which is uninitialized and therefore
|
|
17
|
+
// of invalid tag (FF). This will trigger an exceptional halt.
|
|
18
|
+
export async function addressingWithBaseTagIssueTest(isIndirect: boolean, tester: PublicTxSimulationTester) {
|
|
19
|
+
const addressingMode = Addressing.fromModes([
|
|
20
|
+
isIndirect ? AddressingMode.INDIRECT_RELATIVE : AddressingMode.RELATIVE,
|
|
21
|
+
AddressingMode.DIRECT,
|
|
22
|
+
AddressingMode.DIRECT,
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
const bytecode = encodeToBytecode([
|
|
26
|
+
new CalldataCopy(/*indirect=*/ addressingMode.toWire(), /*copySize=*/ 1, /*cdOffset=*/ 0, /*dstOffset=*/ 0),
|
|
27
|
+
new Return(/*indirect=*/ 0, /*copySizeOffset=*/ 0, /*returnOffset=*/ 0),
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
const txLabel = isIndirect ? 'AddressingWithBaseTagInvalidIndirect' : 'AddressingWithBaseTagInvalidDirect';
|
|
31
|
+
return await testCustomBytecode(bytecode, tester, txLabel);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function pcOutOfRangeTest(tester: PublicTxSimulationTester) {
|
|
35
|
+
const bytecode = encodeToBytecode([
|
|
36
|
+
new Jump(/*jumpOffset=*/ 123), // Jump to out-of-range pc offset.
|
|
37
|
+
new Return(/*indirect=*/ 0, /*copySizeOffset=*/ 0, /*returnOffset=*/ 0),
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
const txLabel = 'PcOutOfRange';
|
|
41
|
+
return await testCustomBytecode(bytecode, tester, txLabel);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export async function invalidOpcodeTest(tester: PublicTxSimulationTester) {
|
|
45
|
+
let bytecode = encodeToBytecode([
|
|
46
|
+
new Set(/*indirect=*/ 0, /*dstOffset=*/ 0, TypeTag.UINT32, /*value=*/ 0).as(Opcode.SET_8, Set.wireFormat8),
|
|
47
|
+
]);
|
|
48
|
+
|
|
49
|
+
const offsetReturnOpcodeByte = bytecode.length;
|
|
50
|
+
|
|
51
|
+
bytecode = Buffer.concat([
|
|
52
|
+
bytecode,
|
|
53
|
+
encodeToBytecode([new Return(/*indirect=*/ 0, /*copySizeOffset=*/ 0, /*returnOffset=*/ 0)]),
|
|
54
|
+
]);
|
|
55
|
+
|
|
56
|
+
// Manipulate the Return opcode to make the opcode invalid (out of range).
|
|
57
|
+
bytecode[offsetReturnOpcodeByte] = MAX_OPCODE_VALUE + 1; // opcode is invalid.
|
|
58
|
+
|
|
59
|
+
const txLabel = 'InvalidOpcode';
|
|
60
|
+
return await testCustomBytecode(bytecode, tester, txLabel);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Single invalid byte in the bytecode.
|
|
64
|
+
export async function invalidByteTest(tester: PublicTxSimulationTester) {
|
|
65
|
+
const invalidOpcode = MAX_OPCODE_VALUE + 7;
|
|
66
|
+
assert(invalidOpcode < 256, 'Invalid opcode must fit in a single byte');
|
|
67
|
+
const bytecode = Buffer.from([invalidOpcode]);
|
|
68
|
+
|
|
69
|
+
const txLabel = 'InvalidByte';
|
|
70
|
+
return await testCustomBytecode(bytecode, tester, txLabel);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Truncate the last instruction in the bytecode.
|
|
74
|
+
export async function instructionTruncatedTest(tester: PublicTxSimulationTester) {
|
|
75
|
+
let bytecode = encodeToBytecode([
|
|
76
|
+
new Set(/*indirect=*/ 0, /*dstOffset=*/ 0, TypeTag.UINT32, /*value=*/ 0).as(Opcode.SET_8, Set.wireFormat8),
|
|
77
|
+
]);
|
|
78
|
+
|
|
79
|
+
// Truncate the bytecode.
|
|
80
|
+
bytecode = bytecode.subarray(0, -1);
|
|
81
|
+
|
|
82
|
+
const txLabel = 'InstructionTruncated';
|
|
83
|
+
return await testCustomBytecode(bytecode, tester, txLabel);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Invalid tag value byte in an instruction.
|
|
87
|
+
export async function invalidTagValueTest(tester: PublicTxSimulationTester) {
|
|
88
|
+
const bytecode = encodeToBytecode([
|
|
89
|
+
new Set(/*indirect=*/ 0, /*dstOffset=*/ 0, TypeTag.UINT32, /*value=*/ 0).as(Opcode.SET_8, Set.wireFormat8),
|
|
90
|
+
new Return(/*indirect=*/ 0, /*copySizeOffset=*/ 0, /*returnOffset=*/ 0),
|
|
91
|
+
]);
|
|
92
|
+
|
|
93
|
+
const tagOffset = getTagOffsetInInstruction(Set.wireFormat8);
|
|
94
|
+
assert(bytecode[tagOffset].valueOf() == TypeTag.UINT32.valueOf(), 'Set instruction tag should be UINT32 in test');
|
|
95
|
+
bytecode[tagOffset] = TypeTag.INVALID;
|
|
96
|
+
|
|
97
|
+
const txLabel = 'InvalidTagValue';
|
|
98
|
+
return await testCustomBytecode(bytecode, tester, txLabel);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Combine an invalid tag in the last instruction that is truncated.
|
|
102
|
+
export async function invalidTagValueAndInstructionTruncatedTest(tester: PublicTxSimulationTester) {
|
|
103
|
+
let bytecode = encodeToBytecode([
|
|
104
|
+
// Important: value argument must be a bigint otherwise a type error will be thrown.
|
|
105
|
+
new Set(/*indirect=*/ 0, /*dstOffset=*/ 0, TypeTag.UINT128, /*value=*/ 0n).as(Opcode.SET_128, Set.wireFormat128),
|
|
106
|
+
]);
|
|
107
|
+
|
|
108
|
+
// Truncate the bytecode.
|
|
109
|
+
bytecode = bytecode.subarray(0, -5);
|
|
110
|
+
const tagOffset = getTagOffsetInInstruction(Set.wireFormat128);
|
|
111
|
+
assert(bytecode[tagOffset].valueOf() == TypeTag.UINT128.valueOf(), 'Set instruction tag should be UINT128 in test');
|
|
112
|
+
bytecode[tagOffset] = 0x6f; // Invalid tag value.
|
|
113
|
+
|
|
114
|
+
const txLabel = 'InvalidTagValueAndInstructionTruncated';
|
|
115
|
+
return await testCustomBytecode(bytecode, tester, txLabel);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Returns the offset of the tag in an instruction.
|
|
120
|
+
* @details Loops over the wire format operand type entries until it finds the tag.
|
|
121
|
+
* Returns the byte offset of the tag based on each operand size that is passed.
|
|
122
|
+
*
|
|
123
|
+
* @param wireFormat array of operand types
|
|
124
|
+
* @returns byte offset of the tag
|
|
125
|
+
*/
|
|
126
|
+
function getTagOffsetInInstruction(wireFormat: OperandType[]): number {
|
|
127
|
+
let offset = 0;
|
|
128
|
+
for (const operand of wireFormat) {
|
|
129
|
+
if (operand === OperandType.TAG) {
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
offset += getOperandSize(operand);
|
|
133
|
+
}
|
|
134
|
+
return offset;
|
|
135
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export * from './public_tx_simulation_tester.js';
|
|
2
2
|
export * from './utils.js';
|
|
3
3
|
export * from './simple_contract_data_source.js';
|
|
4
|
-
export { readAvmMinimalPublicTxInputsFromFile,
|
|
4
|
+
export { readAvmMinimalPublicTxInputsFromFile, simAvmMinimalPublicTx } from './minimal_public_tx.js';
|
|
5
5
|
export { TestExecutorMetrics } from '../test_executor_metrics.js';
|
|
6
6
|
export { ammTest } from './amm_test.js';
|
|
7
7
|
export { bulkTest, megaBulkTest } from './bulk_test.js';
|
|
8
8
|
export { tokenTest } from './token_test.js';
|
|
9
|
+
export * from './custom_bytecode_tests.js';
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Fr } from '@aztec/foundation/fields';
|
|
2
|
-
import { FunctionType, emptyContractArtifact, emptyFunctionArtifact } from '@aztec/stdlib/abi';
|
|
3
2
|
import { AvmCircuitInputs, AvmProtocolContractAddressHint } from '@aztec/stdlib/avm';
|
|
4
3
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
5
4
|
|
|
@@ -9,13 +8,10 @@ import { Add, Return, Set } from '../avm/opcodes/index.js';
|
|
|
9
8
|
import { encodeToBytecode } from '../avm/serialization/bytecode_serialization.js';
|
|
10
9
|
import { Opcode } from '../avm/serialization/instruction_serialization.js';
|
|
11
10
|
import type { PublicTxResult } from '../public_tx_simulator/public_tx_simulator.js';
|
|
11
|
+
import { testCustomBytecode } from './custom_bytecode_tester.js';
|
|
12
12
|
import { PublicTxSimulationTester } from './public_tx_simulation_tester.js';
|
|
13
13
|
|
|
14
|
-
export async function
|
|
15
|
-
const deployer = AztecAddress.fromNumber(42);
|
|
16
|
-
|
|
17
|
-
const simTester = await PublicTxSimulationTester.create();
|
|
18
|
-
|
|
14
|
+
export async function simAvmMinimalPublicTx(): Promise<PublicTxResult> {
|
|
19
15
|
const minimalBytecode = encodeToBytecode([
|
|
20
16
|
new Set(/*indirect*/ 0, /*dstOffset*/ 0, TypeTag.UINT32, /*value*/ 1).as(Opcode.SET_8, Set.wireFormat8),
|
|
21
17
|
new Set(/*indirect*/ 0, /*dstOffset*/ 1, TypeTag.UINT32, /*value*/ 2).as(Opcode.SET_8, Set.wireFormat8),
|
|
@@ -23,32 +19,9 @@ export async function createAvmMinimalPublicTx(): Promise<PublicTxResult> {
|
|
|
23
19
|
new Return(/*indirect=*/ 0, /*copySizeOffset=*/ 0, /*returnOffset=*/ 2),
|
|
24
20
|
]);
|
|
25
21
|
|
|
26
|
-
const
|
|
27
|
-
minimalContractArtifact.name = 'MinimalContract';
|
|
28
|
-
minimalContractArtifact.functions = [emptyFunctionArtifact()];
|
|
29
|
-
minimalContractArtifact.functions[0].name = 'public_dispatch';
|
|
30
|
-
minimalContractArtifact.functions[0].functionType = FunctionType.PUBLIC;
|
|
31
|
-
minimalContractArtifact.functions[0].bytecode = minimalBytecode;
|
|
22
|
+
const tester = await PublicTxSimulationTester.create();
|
|
32
23
|
|
|
33
|
-
const
|
|
34
|
-
/*constructorArgs=*/ [],
|
|
35
|
-
deployer,
|
|
36
|
-
/*contractArtifact=*/ minimalContractArtifact,
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
const result = await simTester.simulateTx(
|
|
40
|
-
/*sender=*/ deployer,
|
|
41
|
-
/*setupCalls=*/ [],
|
|
42
|
-
/*appCalls=*/ [
|
|
43
|
-
{
|
|
44
|
-
address: minimalTestContract.address,
|
|
45
|
-
fnName: 'public_dispatch',
|
|
46
|
-
args: [],
|
|
47
|
-
},
|
|
48
|
-
],
|
|
49
|
-
/*teardownCall=*/ undefined,
|
|
50
|
-
/*feePayer=*/ deployer,
|
|
51
|
-
);
|
|
24
|
+
const result = await testCustomBytecode(minimalBytecode, tester, 'MinimalTx', 'AvmMinimalContract');
|
|
52
25
|
|
|
53
26
|
// Modify the protocolContractDerivedAddresses to be all zeros and modify the protocolContractTreeRoot
|
|
54
27
|
// to be a fixed value (the root of a tree of all 0 leaves). This ensures that the testdata is stable
|
|
@@ -386,7 +386,7 @@ export class PublicPersistableStateManager {
|
|
|
386
386
|
|
|
387
387
|
this.log.trace(`Got contract instance (address=${contractAddress}): instance=${jsonStringify(instance!)}`);
|
|
388
388
|
|
|
389
|
-
// All that is left is
|
|
389
|
+
// All that is left is to check that the contract updatability information is correct.
|
|
390
390
|
// That is, that the current and original contract class ids are correct.
|
|
391
391
|
await this.checkContractUpdateInformation(instanceWithAddress);
|
|
392
392
|
|
|
@@ -407,7 +407,7 @@ export class PublicPersistableStateManager {
|
|
|
407
407
|
//
|
|
408
408
|
// However, we will also be checking the hash of the delayed public mutable values.
|
|
409
409
|
// This is a bit of a leak of information, since the circuit will use it to prove
|
|
410
|
-
// one public read
|
|
410
|
+
// one public read instead of N of the delayed public mutable values.
|
|
411
411
|
const { delayedPublicMutableSlot, delayedPublicMutableHashSlot } =
|
|
412
412
|
await DelayedPublicMutableValuesWithHash.getContractUpdateSlots(instance.address);
|
|
413
413
|
const readDeployerStorage = async (storageSlot: Fr) =>
|