import { BufReader, BufWriter, Serializable, ImportInstruction, ImportArgsSerializer, LoadInstruction, LoadArgsSerializer, LoadByOriginInstruction, LoadByOriginArgsSerializer, NewInstruction, NewArgsSerializer, CallInstruction, CallArgsSerializer, ExecInstruction, ExecArgsSerializer, FundInstruction, FundArgsSerializer, LockInstruction, LockArgsSerializer, DeployInstruction, DeployArgsSerializer, SignInstruction, SignArgsSerializer, SignToInstruction, SignToArgsSerializer, UnknownInstruction } from './internal.js' /** * All OpCode bytes. */ export enum OpCode { // Loading IMPORT = 0xA1, LOAD = 0xA2, LOADBYORIGIN = 0xA3, // Calling NEW = 0xB1, CALL = 0xB2, EXEC = 0xB3, // Output FUND = 0xC1, LOCK = 0xC2, // Code DEPLOY = 0xD1, // Cryptography SIGN = 0xE1, SIGNTO = 0xE2, } /** * Instruction base class. * * An Instruction is Aldea's smallest contiguous unit of execution. A * transaction consists of a `OpCode` byte and a number of arguments, depending * on the `OpCode`. */ export class Instruction { opcode: OpCode; constructor(opcode: OpCode) { this.opcode = opcode } static fromBytes(bytes: Uint8Array): Instruction { const buf = new BufReader(bytes) return buf.read(InstructionSerializer) } toBytes(): Uint8Array { const buf = new BufWriter() buf.write(InstructionSerializer, this) return buf.data } } /** * InstructionRef class - just a wrapper around number */ export class InstructionRef { idx: number; constructor(idx: number) { if (!Number.isInteger(idx)) throw new Error('invalid ref. must be an integer.') this.idx = idx } get [Symbol.toStringTag](): string { return `InstructionRef` } toString(): string { return `${this[Symbol.toStringTag]}<${this.idx}>` } } /** * Wrap a number with InstructionRef */ export function ref(idx: number): InstructionRef { return new InstructionRef(idx) } /** * Instruction Serializer object - implements the Serializable interface. */ export const InstructionSerializer: Serializable = { read(buf: BufReader): Instruction { const opcode = buf.readU8() const argsBuf = buf.readBytes() const args = new BufReader(argsBuf) switch(opcode) { case OpCode.IMPORT: return args.read(ImportArgsSerializer) case OpCode.LOAD: return args.read(LoadArgsSerializer) case OpCode.LOADBYORIGIN: return args.read(LoadByOriginArgsSerializer) case OpCode.NEW: return args.read(NewArgsSerializer) case OpCode.CALL: return args.read(CallArgsSerializer) case OpCode.EXEC: return args.read(ExecArgsSerializer) case OpCode.FUND: return args.read(FundArgsSerializer) case OpCode.LOCK: return args.read(LockArgsSerializer) case OpCode.DEPLOY: return args.read(DeployArgsSerializer) case OpCode.SIGN: return args.read(SignArgsSerializer) case OpCode.SIGNTO: return args.read(SignToArgsSerializer) default: return new UnknownInstruction(opcode, argsBuf) } }, write(buf: BufWriter, inst: Instruction): BufWriter { const args = new BufWriter() switch (inst.opcode) { case OpCode.IMPORT: args.write(ImportArgsSerializer, inst as ImportInstruction) break case OpCode.LOAD: args.write(LoadArgsSerializer, inst as LoadInstruction) break case OpCode.LOADBYORIGIN: args.write(LoadByOriginArgsSerializer, inst as LoadByOriginInstruction) break case OpCode.NEW: args.write(NewArgsSerializer, inst as NewInstruction) break case OpCode.CALL: args.write(CallArgsSerializer, inst as CallInstruction) break case OpCode.EXEC: args.write(ExecArgsSerializer, inst as ExecInstruction) break case OpCode.FUND: args.write(FundArgsSerializer, inst as FundInstruction) break case OpCode.LOCK: args.write(LockArgsSerializer, inst as LockInstruction) break case OpCode.DEPLOY: args.write(DeployArgsSerializer, inst as DeployInstruction) break case OpCode.SIGN: args.write(SignArgsSerializer, inst as SignInstruction) break case OpCode.SIGNTO: args.write(SignToArgsSerializer, inst as SignToInstruction) break default: args.writeFixedBytes((inst).argsBuf) } const argsBuf = args.data buf.writeU8(inst.opcode) buf.writeBytes(argsBuf) return buf } }