@aztec/simulator 0.23.0 → 0.24.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.
Files changed (123) hide show
  1. package/dest/acvm/oracle/oracle.d.ts +2 -2
  2. package/dest/acvm/oracle/oracle.d.ts.map +1 -1
  3. package/dest/acvm/oracle/oracle.js +5 -5
  4. package/dest/acvm/oracle/typed_oracle.d.ts +2 -2
  5. package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
  6. package/dest/acvm/oracle/typed_oracle.js +3 -3
  7. package/dest/avm/avm_execution_environment.d.ts +3 -2
  8. package/dest/avm/avm_execution_environment.d.ts.map +1 -1
  9. package/dest/avm/avm_execution_environment.js +6 -5
  10. package/dest/avm/avm_memory_types.d.ts +119 -38
  11. package/dest/avm/avm_memory_types.d.ts.map +1 -1
  12. package/dest/avm/avm_memory_types.js +91 -109
  13. package/dest/avm/avm_simulator.d.ts.map +1 -1
  14. package/dest/avm/avm_simulator.js +2 -3
  15. package/dest/avm/errors.d.ts +3 -1
  16. package/dest/avm/errors.d.ts.map +1 -1
  17. package/dest/avm/errors.js +9 -3
  18. package/dest/avm/fixtures/index.d.ts +4 -0
  19. package/dest/avm/fixtures/index.d.ts.map +1 -1
  20. package/dest/avm/fixtures/index.js +10 -2
  21. package/dest/avm/journal/host_storage.d.ts +1 -1
  22. package/dest/avm/journal/host_storage.d.ts.map +1 -1
  23. package/dest/avm/opcodes/addressing_mode.d.ts +24 -0
  24. package/dest/avm/opcodes/addressing_mode.d.ts.map +1 -0
  25. package/dest/avm/opcodes/addressing_mode.js +62 -0
  26. package/dest/avm/opcodes/comparators.d.ts.map +1 -1
  27. package/dest/avm/opcodes/comparators.js +8 -5
  28. package/dest/avm/opcodes/instruction.d.ts +4 -4
  29. package/dest/avm/opcodes/instruction.d.ts.map +1 -1
  30. package/dest/avm/opcodes/instruction.js +1 -1
  31. package/dest/avm/opcodes/memory.d.ts.map +1 -1
  32. package/dest/avm/opcodes/memory.js +5 -3
  33. package/dest/avm/serialization/bytecode_serialization.d.ts.map +1 -1
  34. package/dest/avm/serialization/bytecode_serialization.js +24 -22
  35. package/dest/avm/serialization/instruction_serialization.d.ts +17 -15
  36. package/dest/avm/serialization/instruction_serialization.d.ts.map +1 -1
  37. package/dest/avm/serialization/instruction_serialization.js +18 -16
  38. package/dest/avm/temporary_executor_migration.d.ts +25 -0
  39. package/dest/avm/temporary_executor_migration.d.ts.map +1 -0
  40. package/dest/avm/temporary_executor_migration.js +71 -0
  41. package/dest/client/client_execution_context.d.ts +4 -2
  42. package/dest/client/client_execution_context.d.ts.map +1 -1
  43. package/dest/client/client_execution_context.js +7 -4
  44. package/dest/client/execution_result.d.ts +2 -0
  45. package/dest/client/execution_result.d.ts.map +1 -1
  46. package/dest/client/execution_result.js +1 -1
  47. package/dest/client/simulator.d.ts +10 -5
  48. package/dest/client/simulator.d.ts.map +1 -1
  49. package/dest/client/simulator.js +19 -11
  50. package/dest/client/unconstrained_execution.js +2 -2
  51. package/dest/public/execution.js +2 -2
  52. package/dest/public/executor.d.ts +7 -0
  53. package/dest/public/executor.d.ts.map +1 -1
  54. package/dest/public/executor.js +26 -1
  55. package/dest/public/public_execution_context.js +2 -2
  56. package/dest/public/state_actions.d.ts +1 -1
  57. package/dest/public/state_actions.d.ts.map +1 -1
  58. package/dest/public/state_actions.js +5 -6
  59. package/dest/utils.d.ts +5 -20
  60. package/dest/utils.d.ts.map +1 -1
  61. package/dest/utils.js +4 -20
  62. package/package.json +7 -5
  63. package/src/acvm/acvm.ts +156 -0
  64. package/src/acvm/acvm_types.ts +11 -0
  65. package/src/acvm/deserialize.ts +36 -0
  66. package/src/acvm/index.ts +5 -0
  67. package/src/acvm/oracle/debug.ts +109 -0
  68. package/src/acvm/oracle/index.ts +17 -0
  69. package/src/acvm/oracle/oracle.ts +332 -0
  70. package/src/acvm/oracle/typed_oracle.ts +217 -0
  71. package/src/acvm/serialize.ts +75 -0
  72. package/src/avm/avm_context.ts +63 -0
  73. package/src/avm/avm_execution_environment.ts +98 -0
  74. package/src/avm/avm_machine_state.ts +93 -0
  75. package/src/avm/avm_memory_types.ts +309 -0
  76. package/src/avm/avm_message_call_result.ts +29 -0
  77. package/src/avm/avm_simulator.ts +89 -0
  78. package/src/avm/errors.ts +57 -0
  79. package/src/avm/fixtures/index.ts +90 -0
  80. package/src/avm/journal/host_storage.ts +20 -0
  81. package/src/avm/journal/index.ts +2 -0
  82. package/src/avm/journal/journal.ts +266 -0
  83. package/src/avm/opcodes/.eslintrc.cjs +8 -0
  84. package/src/avm/opcodes/accrued_substate.ts +92 -0
  85. package/src/avm/opcodes/addressing_mode.ts +66 -0
  86. package/src/avm/opcodes/arithmetic.ts +79 -0
  87. package/src/avm/opcodes/bitwise.ts +129 -0
  88. package/src/avm/opcodes/comparators.ts +72 -0
  89. package/src/avm/opcodes/control_flow.ts +129 -0
  90. package/src/avm/opcodes/environment_getters.ts +199 -0
  91. package/src/avm/opcodes/external_calls.ts +122 -0
  92. package/src/avm/opcodes/index.ts +10 -0
  93. package/src/avm/opcodes/instruction.ts +64 -0
  94. package/src/avm/opcodes/instruction_impl.ts +52 -0
  95. package/src/avm/opcodes/memory.ts +193 -0
  96. package/src/avm/opcodes/storage.ts +76 -0
  97. package/src/avm/serialization/buffer_cursor.ts +109 -0
  98. package/src/avm/serialization/bytecode_serialization.ts +172 -0
  99. package/src/avm/serialization/instruction_serialization.ts +167 -0
  100. package/src/avm/temporary_executor_migration.ts +108 -0
  101. package/src/client/client_execution_context.ts +472 -0
  102. package/src/client/db_oracle.ts +184 -0
  103. package/src/client/execution_note_cache.ts +90 -0
  104. package/src/client/execution_result.ts +89 -0
  105. package/src/client/index.ts +3 -0
  106. package/src/client/pick_notes.ts +125 -0
  107. package/src/client/private_execution.ts +78 -0
  108. package/src/client/simulator.ts +316 -0
  109. package/src/client/unconstrained_execution.ts +49 -0
  110. package/src/client/view_data_oracle.ts +243 -0
  111. package/src/common/errors.ts +61 -0
  112. package/src/common/index.ts +3 -0
  113. package/src/common/packed_args_cache.ts +55 -0
  114. package/src/common/side_effect_counter.ts +12 -0
  115. package/src/index.ts +3 -0
  116. package/src/public/db.ts +85 -0
  117. package/src/public/execution.ts +137 -0
  118. package/src/public/executor.ts +158 -0
  119. package/src/public/index.ts +9 -0
  120. package/src/public/public_execution_context.ts +217 -0
  121. package/src/public/state_actions.ts +100 -0
  122. package/src/test/utils.ts +38 -0
  123. package/src/utils.ts +18 -0
@@ -0,0 +1,64 @@
1
+ import { strict as assert } from 'assert';
2
+
3
+ import type { AvmContext } from '../avm_context.js';
4
+ import { BufferCursor } from '../serialization/buffer_cursor.js';
5
+ import { OperandType, deserialize, serialize } from '../serialization/instruction_serialization.js';
6
+
7
+ type InstructionConstructor = {
8
+ new (...args: any[]): Instruction;
9
+ wireFormat?: OperandType[];
10
+ };
11
+
12
+ /**
13
+ * Parent class for all AVM instructions.
14
+ * It's most important aspects are execute and (de)serialize.
15
+ */
16
+ export abstract class Instruction {
17
+ /**
18
+ * Execute the instruction.
19
+ * Instruction sub-classes must implement this.
20
+ * As an AvmContext executes its contract code, it calls this function for
21
+ * each instruction until the machine state signals "halted".
22
+ * @param context - The AvmContext in which the instruction executes.
23
+ */
24
+ public abstract execute(context: AvmContext): Promise<void>;
25
+
26
+ /**
27
+ * Generate a string representation of the instruction including
28
+ * the instruction sub-class name all of its flags and operands.
29
+ * @returns Thee string representation.
30
+ */
31
+ public toString(): string {
32
+ let instructionStr = this.constructor.name + ': ';
33
+ // assumes that all properties are flags or operands
34
+ for (const prop of Object.getOwnPropertyNames(this) as (keyof Instruction)[]) {
35
+ instructionStr += `${prop}:${this[prop].toString()}, `;
36
+ }
37
+ return instructionStr;
38
+ }
39
+
40
+ /**
41
+ * Serialize the instruction to a Buffer according to its wire format specified in its subclass.
42
+ * If you want to use this, your subclass should specify a {@code static wireFormat: OperandType[]}.
43
+ * @param this - The instruction to serialize.
44
+ * @returns The serialized instruction.
45
+ */
46
+ public serialize(this: any): Buffer {
47
+ assert(!!this.constructor.wireFormat, 'wireFormat must be defined on the class');
48
+ return serialize(this.constructor.wireFormat, this);
49
+ }
50
+
51
+ /**
52
+ * Deserializes a subclass of Instruction from a Buffer.
53
+ * If you want to use this, your subclass should specify a {@code static wireFormat: OperandType[]}.
54
+ * @param this Class object to deserialize to.
55
+ * @param buf Buffer to read from.
56
+ * @returns Constructed instance of Class.
57
+ */
58
+ public static deserialize(this: InstructionConstructor, buf: BufferCursor | Buffer): Instruction {
59
+ assert(!!this.wireFormat, 'wireFormat must be defined on the instruction class');
60
+ const res = deserialize(buf, this.wireFormat);
61
+ const args = res.slice(1); // Remove opcode.
62
+ return new this(...args);
63
+ }
64
+ }
@@ -0,0 +1,52 @@
1
+ import { OperandType } from '../serialization/instruction_serialization.js';
2
+ import { Instruction } from './instruction.js';
3
+
4
+ /**
5
+ * Covers (de)serialization for an instruction with:
6
+ * indirect, inTag, and two UINT32s.
7
+ */
8
+ export abstract class TwoOperandInstruction extends Instruction {
9
+ // Informs (de)serialization. See Instruction.deserialize.
10
+ static readonly wireFormat: OperandType[] = [
11
+ OperandType.UINT8,
12
+ OperandType.UINT8,
13
+ OperandType.UINT8,
14
+ OperandType.UINT32,
15
+ OperandType.UINT32,
16
+ ];
17
+
18
+ constructor(
19
+ protected indirect: number,
20
+ protected inTag: number,
21
+ protected aOffset: number,
22
+ protected dstOffset: number,
23
+ ) {
24
+ super();
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Covers (de)serialization for an instruction with:
30
+ * indirect, inTag, and three UINT32s.
31
+ */
32
+ export abstract class ThreeOperandInstruction extends Instruction {
33
+ // Informs (de)serialization. See Instruction.deserialize.
34
+ static readonly wireFormat: OperandType[] = [
35
+ OperandType.UINT8,
36
+ OperandType.UINT8,
37
+ OperandType.UINT8,
38
+ OperandType.UINT32,
39
+ OperandType.UINT32,
40
+ OperandType.UINT32,
41
+ ];
42
+
43
+ constructor(
44
+ protected indirect: number,
45
+ protected inTag: number,
46
+ protected aOffset: number,
47
+ protected bOffset: number,
48
+ protected dstOffset: number,
49
+ ) {
50
+ super();
51
+ }
52
+ }
@@ -0,0 +1,193 @@
1
+ import type { AvmContext } from '../avm_context.js';
2
+ import { Field, TaggedMemory, TypeTag } from '../avm_memory_types.js';
3
+ import { InstructionExecutionError } from '../errors.js';
4
+ import { BufferCursor } from '../serialization/buffer_cursor.js';
5
+ import { Opcode, OperandType, deserialize, serialize } from '../serialization/instruction_serialization.js';
6
+ import { Addressing } from './addressing_mode.js';
7
+ import { Instruction } from './instruction.js';
8
+ import { TwoOperandInstruction } from './instruction_impl.js';
9
+
10
+ const TAG_TO_OPERAND_TYPE = new Map<TypeTag, OperandType>([
11
+ [TypeTag.UINT8, OperandType.UINT8],
12
+ [TypeTag.UINT16, OperandType.UINT16],
13
+ [TypeTag.UINT32, OperandType.UINT32],
14
+ [TypeTag.UINT64, OperandType.UINT64],
15
+ [TypeTag.UINT128, OperandType.UINT128],
16
+ ]);
17
+
18
+ function getOperandTypeFromInTag(inTag: number | bigint): OperandType {
19
+ inTag = inTag as number;
20
+ const tagOperandType = TAG_TO_OPERAND_TYPE.get(inTag);
21
+ if (tagOperandType === undefined) {
22
+ throw new Error(`Invalid tag ${inTag} for SET.`);
23
+ }
24
+ return tagOperandType;
25
+ }
26
+
27
+ export class Set extends Instruction {
28
+ static readonly type: string = 'SET';
29
+ static readonly opcode: Opcode = Opcode.SET;
30
+
31
+ private static readonly wireFormatBeforeConst: OperandType[] = [
32
+ OperandType.UINT8,
33
+ OperandType.UINT8,
34
+ OperandType.UINT8,
35
+ ];
36
+ private static readonly wireFormatAfterConst: OperandType[] = [OperandType.UINT32];
37
+
38
+ constructor(
39
+ private indirect: number,
40
+ private inTag: number,
41
+ private value: bigint | number,
42
+ private dstOffset: number,
43
+ ) {
44
+ super();
45
+ }
46
+
47
+ /** We need to use a custom serialize function because of the variable length of the value. */
48
+ public serialize(): Buffer {
49
+ const format: OperandType[] = [
50
+ ...Set.wireFormatBeforeConst,
51
+ getOperandTypeFromInTag(this.inTag),
52
+ ...Set.wireFormatAfterConst,
53
+ ];
54
+ return serialize(format, this);
55
+ }
56
+
57
+ /** We need to use a custom deserialize function because of the variable length of the value. */
58
+ public static deserialize(this: typeof Set, buf: BufferCursor | Buffer): Set {
59
+ if (buf instanceof Buffer) {
60
+ buf = new BufferCursor(buf);
61
+ }
62
+ const beforeConst = deserialize(buf, Set.wireFormatBeforeConst);
63
+ const tag = beforeConst[beforeConst.length - 1];
64
+ const val = deserialize(buf, [getOperandTypeFromInTag(tag)]);
65
+ const afterConst = deserialize(buf, Set.wireFormatAfterConst);
66
+ const res = [...beforeConst, ...val, ...afterConst];
67
+ const args = res.slice(1) as ConstructorParameters<typeof Set>; // Remove opcode.
68
+ return new this(...args);
69
+ }
70
+
71
+ async execute(context: AvmContext): Promise<void> {
72
+ // Per the YP, the tag cannot be a field.
73
+ if ([TypeTag.FIELD, TypeTag.UNINITIALIZED, TypeTag.INVALID].includes(this.inTag)) {
74
+ throw new InstructionExecutionError(`Invalid tag ${TypeTag[this.inTag]} for SET.`);
75
+ }
76
+
77
+ const res = TaggedMemory.integralFromTag(this.value, this.inTag);
78
+ context.machineState.memory.set(this.dstOffset, res);
79
+
80
+ context.machineState.incrementPc();
81
+ }
82
+ }
83
+
84
+ export class CMov extends Instruction {
85
+ static readonly type: string = 'CMOV';
86
+ static readonly opcode: Opcode = Opcode.CMOV;
87
+ // Informs (de)serialization. See Instruction.deserialize.
88
+ static readonly wireFormat: OperandType[] = [
89
+ OperandType.UINT8,
90
+ OperandType.UINT8,
91
+ OperandType.UINT32,
92
+ OperandType.UINT32,
93
+ OperandType.UINT32,
94
+ OperandType.UINT32,
95
+ ];
96
+
97
+ constructor(
98
+ private indirect: number,
99
+ private aOffset: number,
100
+ private bOffset: number,
101
+ private condOffset: number,
102
+ private dstOffset: number,
103
+ ) {
104
+ super();
105
+ }
106
+
107
+ async execute(context: AvmContext): Promise<void> {
108
+ const a = context.machineState.memory.get(this.aOffset);
109
+ const b = context.machineState.memory.get(this.bOffset);
110
+ const cond = context.machineState.memory.get(this.condOffset);
111
+
112
+ // TODO: reconsider toBigInt() here
113
+ context.machineState.memory.set(this.dstOffset, cond.toBigInt() > 0 ? a : b);
114
+
115
+ context.machineState.incrementPc();
116
+ }
117
+ }
118
+
119
+ export class Cast extends TwoOperandInstruction {
120
+ static readonly type: string = 'CAST';
121
+ static readonly opcode = Opcode.CAST;
122
+
123
+ constructor(indirect: number, dstTag: number, aOffset: number, dstOffset: number) {
124
+ super(indirect, dstTag, aOffset, dstOffset);
125
+ }
126
+
127
+ async execute(context: AvmContext): Promise<void> {
128
+ const a = context.machineState.memory.get(this.aOffset);
129
+
130
+ // TODO: consider not using toBigInt()
131
+ const casted =
132
+ this.inTag == TypeTag.FIELD ? new Field(a.toBigInt()) : TaggedMemory.integralFromTag(a.toBigInt(), this.inTag);
133
+
134
+ context.machineState.memory.set(this.dstOffset, casted);
135
+
136
+ context.machineState.incrementPc();
137
+ }
138
+ }
139
+
140
+ export class Mov extends Instruction {
141
+ static readonly type: string = 'MOV';
142
+ static readonly opcode: Opcode = Opcode.MOV;
143
+ // Informs (de)serialization. See Instruction.deserialize.
144
+ static readonly wireFormat: OperandType[] = [
145
+ OperandType.UINT8,
146
+ OperandType.UINT8,
147
+ OperandType.UINT32,
148
+ OperandType.UINT32,
149
+ ];
150
+
151
+ constructor(private indirect: number, private srcOffset: number, private dstOffset: number) {
152
+ super();
153
+ }
154
+
155
+ async execute(context: AvmContext): Promise<void> {
156
+ const [srcOffset, dstOffset] = Addressing.fromWire(this.indirect).resolve(
157
+ [this.srcOffset, this.dstOffset],
158
+ context.machineState.memory,
159
+ );
160
+
161
+ const a = context.machineState.memory.get(srcOffset);
162
+
163
+ context.machineState.memory.set(dstOffset, a);
164
+
165
+ context.machineState.incrementPc();
166
+ }
167
+ }
168
+
169
+ export class CalldataCopy extends Instruction {
170
+ static readonly type: string = 'CALLDATACOPY';
171
+ static readonly opcode: Opcode = Opcode.CALLDATACOPY;
172
+ // Informs (de)serialization. See Instruction.deserialize.
173
+ static readonly wireFormat: OperandType[] = [
174
+ OperandType.UINT8,
175
+ OperandType.UINT8,
176
+ OperandType.UINT32,
177
+ OperandType.UINT32,
178
+ OperandType.UINT32,
179
+ ];
180
+
181
+ constructor(private indirect: number, private cdOffset: number, private copySize: number, private dstOffset: number) {
182
+ super();
183
+ }
184
+
185
+ async execute(context: AvmContext): Promise<void> {
186
+ const transformedData = context.environment.calldata
187
+ .slice(this.cdOffset, this.cdOffset + this.copySize)
188
+ .map(f => new Field(f));
189
+ context.machineState.memory.setSlice(this.dstOffset, transformedData);
190
+
191
+ context.machineState.incrementPc();
192
+ }
193
+ }
@@ -0,0 +1,76 @@
1
+ import { Fr } from '@aztec/foundation/fields';
2
+
3
+ import type { AvmContext } from '../avm_context.js';
4
+ import { Field } from '../avm_memory_types.js';
5
+ import { InstructionExecutionError } from '../errors.js';
6
+ import { Opcode, OperandType } from '../serialization/instruction_serialization.js';
7
+ import { Instruction } from './instruction.js';
8
+
9
+ abstract class BaseStorageInstruction extends Instruction {
10
+ // Informs (de)serialization. See Instruction.deserialize.
11
+ public static readonly wireFormat: OperandType[] = [
12
+ OperandType.UINT8,
13
+ OperandType.UINT8,
14
+ OperandType.UINT32,
15
+ OperandType.UINT32,
16
+ ];
17
+
18
+ constructor(protected indirect: number, protected aOffset: number, protected bOffset: number) {
19
+ super();
20
+ }
21
+ }
22
+
23
+ export class SStore extends BaseStorageInstruction {
24
+ static readonly type: string = 'SSTORE';
25
+ static readonly opcode = Opcode.SSTORE;
26
+
27
+ constructor(indirect: number, srcOffset: number, slotOffset: number) {
28
+ super(indirect, srcOffset, slotOffset);
29
+ }
30
+
31
+ async execute(context: AvmContext): Promise<void> {
32
+ if (context.environment.isStaticCall) {
33
+ throw new StaticCallStorageAlterError();
34
+ }
35
+
36
+ const slot = context.machineState.memory.get(this.aOffset);
37
+ const data = context.machineState.memory.get(this.bOffset);
38
+
39
+ context.worldState.writeStorage(
40
+ context.environment.storageAddress,
41
+ new Fr(slot.toBigInt()),
42
+ new Fr(data.toBigInt()),
43
+ );
44
+
45
+ context.machineState.incrementPc();
46
+ }
47
+ }
48
+
49
+ export class SLoad extends BaseStorageInstruction {
50
+ static readonly type: string = 'SLOAD';
51
+ static readonly opcode = Opcode.SLOAD;
52
+
53
+ constructor(indirect: number, slotOffset: number, dstOffset: number) {
54
+ super(indirect, slotOffset, dstOffset);
55
+ }
56
+
57
+ async execute(context: AvmContext): Promise<void> {
58
+ const slot = context.machineState.memory.get(this.aOffset);
59
+
60
+ const data: Fr = await context.worldState.readStorage(context.environment.storageAddress, new Fr(slot.toBigInt()));
61
+
62
+ context.machineState.memory.set(this.bOffset, new Field(data));
63
+
64
+ context.machineState.incrementPc();
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Error is thrown when a static call attempts to alter storage
70
+ */
71
+ export class StaticCallStorageAlterError extends InstructionExecutionError {
72
+ constructor() {
73
+ super('Static calls cannot alter storage');
74
+ this.name = 'StaticCallStorageAlterError';
75
+ }
76
+ }
@@ -0,0 +1,109 @@
1
+ import { strict as assert } from 'assert';
2
+
3
+ /*
4
+ * A Buffer-like class that automatically advances the position.
5
+ */
6
+ export class BufferCursor {
7
+ constructor(private _buffer: Buffer, private _position: number = 0) {}
8
+
9
+ public position(): number {
10
+ return this._position;
11
+ }
12
+
13
+ public eof(): boolean {
14
+ return this._position === this._buffer.length;
15
+ }
16
+
17
+ public bufferAtPosition(): Buffer {
18
+ return this._buffer.subarray(this._position);
19
+ }
20
+
21
+ public advance(n: number): void {
22
+ this._position += n;
23
+ assert(n < this._buffer.length);
24
+ }
25
+
26
+ public readUint8(): number {
27
+ const ret = this._buffer.readUint8(this._position);
28
+ this._position += 1;
29
+ return ret;
30
+ }
31
+
32
+ public readUint16LE(): number {
33
+ const ret = this._buffer.readUint16LE(this._position);
34
+ this._position += 2;
35
+ return ret;
36
+ }
37
+
38
+ public readUint16BE(): number {
39
+ const ret = this._buffer.readUint16BE(this._position);
40
+ this._position += 2;
41
+ return ret;
42
+ }
43
+
44
+ public readUint32LE(): number {
45
+ const ret = this._buffer.readUint32LE(this._position);
46
+ this._position += 4;
47
+ return ret;
48
+ }
49
+
50
+ public readUint32BE(): number {
51
+ const ret = this._buffer.readUint32BE(this._position);
52
+ this._position += 4;
53
+ return ret;
54
+ }
55
+
56
+ public readBigInt64LE(): bigint {
57
+ const ret = this._buffer.readBigInt64LE(this._position);
58
+ this._position += 8;
59
+ return ret;
60
+ }
61
+
62
+ public readBigInt64BE(): bigint {
63
+ const ret = this._buffer.readBigInt64BE(this._position);
64
+ this._position += 8;
65
+ return ret;
66
+ }
67
+
68
+ public writeUint8(v: number) {
69
+ const ret = this._buffer.writeUint8(v, this._position);
70
+ this._position += 1;
71
+ return ret;
72
+ }
73
+
74
+ public writeUint16LE(v: number) {
75
+ const ret = this._buffer.writeUint16LE(v, this._position);
76
+ this._position += 2;
77
+ return ret;
78
+ }
79
+
80
+ public writeUint16BE(v: number) {
81
+ const ret = this._buffer.writeUint16BE(v, this._position);
82
+ this._position += 2;
83
+ return ret;
84
+ }
85
+
86
+ public writeUint32LE(v: number) {
87
+ const ret = this._buffer.writeUint32LE(v, this._position);
88
+ this._position += 4;
89
+ return ret;
90
+ }
91
+
92
+ public writeUint32BE(v: number) {
93
+ const ret = this._buffer.writeUint32BE(v, this._position);
94
+ this._position += 4;
95
+ return ret;
96
+ }
97
+
98
+ public writeBigInt64LE(v: bigint) {
99
+ const ret = this._buffer.writeBigInt64LE(v, this._position);
100
+ this._position += 8;
101
+ return ret;
102
+ }
103
+
104
+ public writeBigInt64BE(v: bigint) {
105
+ const ret = this._buffer.writeBigInt64BE(v, this._position);
106
+ this._position += 8;
107
+ return ret;
108
+ }
109
+ }
@@ -0,0 +1,172 @@
1
+ import {
2
+ Add,
3
+ Address,
4
+ And,
5
+ BlockNumber,
6
+ CMov,
7
+ Call,
8
+ CalldataCopy,
9
+ Cast,
10
+ ChainId,
11
+ Div,
12
+ EmitNoteHash,
13
+ EmitNullifier,
14
+ EmitUnencryptedLog,
15
+ Eq,
16
+ FeePerDAGas,
17
+ FeePerL1Gas,
18
+ FeePerL2Gas,
19
+ InternalCall,
20
+ InternalReturn,
21
+ Jump,
22
+ JumpI,
23
+ Lt,
24
+ Lte,
25
+ Mov,
26
+ Mul,
27
+ Not,
28
+ Or,
29
+ Origin,
30
+ Portal,
31
+ Return,
32
+ Revert,
33
+ SLoad,
34
+ SStore,
35
+ SendL2ToL1Message,
36
+ Sender,
37
+ Set,
38
+ Shl,
39
+ Shr,
40
+ StaticCall,
41
+ StorageAddress,
42
+ Sub,
43
+ Timestamp,
44
+ Version,
45
+ Xor,
46
+ } from '../opcodes/index.js';
47
+ import type { Instruction } from '../opcodes/index.js';
48
+ import { BufferCursor } from './buffer_cursor.js';
49
+ import { Opcode } from './instruction_serialization.js';
50
+
51
+ interface DeserializableInstruction {
52
+ deserialize(buf: BufferCursor | Buffer): Instruction;
53
+ opcode: Opcode;
54
+ }
55
+
56
+ export type InstructionSet = Map<Opcode, DeserializableInstruction>;
57
+ // TODO(4359): This is a function so that Call and StaticCall can be lazily resolved.
58
+ // This is a temporary solution until we solve the dependency cycle.
59
+ const INSTRUCTION_SET = () =>
60
+ new Map<Opcode, DeserializableInstruction>([
61
+ [Add.opcode, Add],
62
+ [Sub.opcode, Sub],
63
+ [Mul.opcode, Mul],
64
+ [Div.opcode, Div],
65
+ [Eq.opcode, Eq],
66
+ [Lt.opcode, Lt],
67
+ [Lte.opcode, Lte],
68
+ [And.opcode, And],
69
+ [Or.opcode, Or],
70
+ [Xor.opcode, Xor],
71
+ [Not.opcode, Not],
72
+ [Shl.opcode, Shl],
73
+ [Shr.opcode, Shr],
74
+ [Cast.opcode, Cast],
75
+ [Address.opcode, Address],
76
+ [StorageAddress.opcode, StorageAddress],
77
+ [Origin.opcode, Origin],
78
+ [Sender.opcode, Sender],
79
+ [Portal.opcode, Portal],
80
+ [FeePerL1Gas.opcode, FeePerL1Gas],
81
+ [FeePerL2Gas.opcode, FeePerL2Gas],
82
+ [FeePerDAGas.opcode, FeePerDAGas],
83
+ //[Contractcalldepth.opcode, Contractcalldepth],
84
+ // Execution Environment - Globals
85
+ [ChainId.opcode, ChainId],
86
+ [Version.opcode, Version],
87
+ [BlockNumber.opcode, BlockNumber],
88
+ [Timestamp.opcode, Timestamp],
89
+ //[Coinbase.opcode, Coinbase],
90
+ //[Blockl1gaslimit.opcode, Blockl1gaslimit],
91
+ //[Blockl2gaslimit.opcode, Blockl2gaslimit],
92
+ //[Blockdagaslimit.opcode, Blockdagaslimit],
93
+ // Execution Environment - Calldata
94
+ [CalldataCopy.opcode, CalldataCopy],
95
+
96
+ // Machine State
97
+ // Machine State - Gas
98
+ //[L1gasleft.opcode, L1gasleft],
99
+ //[L2gasleft.opcode, L2gasleft],
100
+ //[Dagasleft.opcode, Dagasleft],
101
+ // Machine State - Internal Control Flow
102
+ [Jump.opcode, Jump],
103
+ [JumpI.opcode, JumpI],
104
+ [InternalCall.opcode, InternalCall],
105
+ [InternalReturn.opcode, InternalReturn],
106
+ [Set.opcode, Set],
107
+ [Mov.opcode, Mov],
108
+ [CMov.opcode, CMov],
109
+
110
+ // World State
111
+ [SLoad.opcode, SLoad], // Public Storage
112
+ [SStore.opcode, SStore], // Public Storage
113
+ //[NoteHashExists.opcode, NoteHashExists], // Notes & Nullifiers
114
+ [EmitNoteHash.opcode, EmitNoteHash], // Notes & Nullifiers
115
+ //[NullifierExists.opcode, NullifierExists], // Notes & Nullifiers
116
+ [EmitNullifier.opcode, EmitNullifier], // Notes & Nullifiers
117
+ //[Readl1tol2msg.opcode, Readl1tol2msg], // Messages
118
+ //[HeaderMember.opcode, HeaderMember], // Header
119
+
120
+ // Accrued Substate
121
+ [EmitUnencryptedLog.opcode, EmitUnencryptedLog],
122
+ [SendL2ToL1Message.opcode, SendL2ToL1Message],
123
+
124
+ // Control Flow - Contract Calls
125
+ [Call.opcode, Call],
126
+ [StaticCall.opcode, StaticCall],
127
+ [Return.opcode, Return],
128
+ [Revert.opcode, Revert],
129
+
130
+ // Gadgets
131
+ //[Keccak.opcode, Keccak],
132
+ //[Poseidon.opcode, Poseidon],
133
+ ]);
134
+
135
+ interface Serializable {
136
+ serialize(): Buffer;
137
+ }
138
+
139
+ /**
140
+ * Serializes an array of instructions to bytecode.
141
+ */
142
+ export function encodeToBytecode(instructions: Serializable[]): Buffer {
143
+ return Buffer.concat(instructions.map(i => i.serialize()));
144
+ }
145
+
146
+ /**
147
+ * Convert a buffer of bytecode into an array of instructions.
148
+ * @param bytecode Buffer of bytecode.
149
+ * @param instructionSet Optional {@code InstructionSet} to be used for deserialization.
150
+ * @returns Bytecode decoded into an ordered array of Instructions
151
+ */
152
+ export function decodeFromBytecode(
153
+ bytecode: Buffer,
154
+ instructionSet: InstructionSet = INSTRUCTION_SET(),
155
+ ): Instruction[] {
156
+ const instructions: Instruction[] = [];
157
+ const cursor = new BufferCursor(bytecode);
158
+
159
+ while (!cursor.eof()) {
160
+ const opcode: Opcode = cursor.bufferAtPosition().readUint8(); // peek.
161
+ const instructionDeserializerOrUndef = instructionSet.get(opcode);
162
+ if (instructionDeserializerOrUndef === undefined) {
163
+ throw new Error(`Opcode ${Opcode[opcode]} (0x${opcode.toString(16)}) not implemented`);
164
+ }
165
+
166
+ const instructionDeserializer: DeserializableInstruction = instructionDeserializerOrUndef;
167
+ const i: Instruction = instructionDeserializer.deserialize(cursor);
168
+ instructions.push(i);
169
+ }
170
+
171
+ return instructions;
172
+ }