Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -euo pipefail

echo "Running pre-push checks..."

echo "==> QA (biome ci)"
npm run qa

echo "==> Build"
npm run build

echo "==> Tests"
npm test

echo "All pre-push checks passed."
7 changes: 4 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ jobs:
repository: FluffyLabs/jamtestvectors
path: "./jamtestvectors"
ref: ba76542dbf7a0c72d414a87ad2e30ce4da380448 # New test vectors.
- run: npm run test:w3f ./jamtestvectors/pvm/programs/*.json
- name: Run W3F tests (WASM)
run: npm run test:w3f ./jamtestvectors/pvm/programs/*.json
- name: Run W3F tests (portable JS)
run: npm run test:w3f-portable ./jamtestvectors/pvm/programs/*.json

build-and-test:
runs-on: ubuntu-latest
Expand All @@ -42,5 +45,3 @@ jobs:
- run: npm run qa
- run: npm run build
- run: npm test --if-present


16 changes: 8 additions & 8 deletions assembly/api-debugger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Interpreter, Status } from "./interpreter";
import { MaybePageFault, MemoryBuilder } from "./memory";
import { Access, PAGE_SIZE } from "./memory-page";
import { deblob, extractCodeAndMetadata, liftBytes } from "./program";
import { NO_OF_REGISTERS, REG_SIZE_BYTES, Registers } from "./registers";
import { NO_OF_REGISTERS, newRegisters, REG_SIZE_BYTES, Registers } from "./registers";
import { decodeSpi } from "./spi";

let interpreter: Interpreter | null = null;
Expand All @@ -30,7 +30,7 @@ export function resetGeneric(program: u8[], flatRegisters: u8[], initialGas: Gas
const code = hasMetadata ? extractCodeAndMetadata(liftBytes(program)).code : liftBytes(program);

const p = deblob(code);
const registers: Registers = new StaticArray(NO_OF_REGISTERS);
const registers: Registers = newRegisters();
fillRegisters(registers, flatRegisters);
const int = new Interpreter(p, registers);
int.gas.set(initialGas);
Expand All @@ -53,7 +53,7 @@ export function resetGenericWithMemory(
const code = hasMetadata ? extractCodeAndMetadata(liftBytes(program)).code : liftBytes(program);

const p = deblob(code);
const registers: Registers = new StaticArray(NO_OF_REGISTERS);
const registers: Registers = newRegisters();
fillRegisters(registers, flatRegisters);

const builder = new MemoryBuilder();
Expand Down Expand Up @@ -115,7 +115,7 @@ export function getExitArg(): u32 {

export function getGasLeft(): i64 {
if (interpreter === null) {
return 0;
return i64(0);
}
const int = <Interpreter>interpreter;
return int.gas.get();
Expand All @@ -139,8 +139,8 @@ export function getRegisters(): Uint8Array {
let val = int.registers[i];
for (let j = 0; j < REG_SIZE_BYTES; j++) {
const index = i * REG_SIZE_BYTES + j;
flat[index] = <u8>(val & 0xff);
val = val >> 8;
flat[index] = <u8>(val & u64(0xff));
val = val >> u64(8);
}
}

Expand Down Expand Up @@ -249,10 +249,10 @@ function fillRegisters(registers: Registers, flat: u8[]): void {
}

for (let i = 0; i < registers.length; i++) {
let num: u64 = 0;
let num: u64 = u64(0);
for (let j: u8 = 0; j < <u8>REG_SIZE_BYTES; j++) {
const index = i * REG_SIZE_BYTES + j;
num |= (<u64>flat[index]) << (j * 8);
num |= (<u64>flat[index]) << u64(j * 8);
}
registers[i] = num;
}
Expand Down
10 changes: 6 additions & 4 deletions assembly/api-internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { INSTRUCTIONS, MISSING_INSTRUCTION } from "./instructions";
import { Interpreter, Status } from "./interpreter";
import { MaybePageFault, Memory, MemoryBuilder } from "./memory";
import { Access, PAGE_SIZE, RESERVED_MEMORY } from "./memory-page";
import { portable } from "./portable";
import { decodeArguments, Program, resolveArguments } from "./program";

export function getAssembly(p: Program): string {
Expand All @@ -25,7 +26,7 @@ export function getAssembly(p: Program): string {

v += "\n";
v += `${i}: `;
v += changetype<string>(iData.namePtr);
v += iData.name;
v += `(${instruction})`;

const skipBytes = p.mask.skipBytesToNextInstruction(i);
Expand Down Expand Up @@ -144,8 +145,8 @@ function readResult(int: Interpreter): u8[] {
}

// JAM return convention
const ptr_start = u32(int.registers[7] & 0xffff_ffff);
const ptr_end = u32(int.registers[8] & 0xffff_ffff);
const ptr_start = u32(int.registers[7] & u64(0xffff_ffff));
const ptr_end = u32(int.registers[8] & u64(0xffff_ffff));

// invalid output result
if (ptr_start >= ptr_end) {
Expand Down Expand Up @@ -176,7 +177,8 @@ function readResult(int: Interpreter): u8[] {

function getOutputChunks(memory: Memory): InitialChunk[] {
const chunks: InitialChunk[] = [];
const pages = memory.pages.keys();
// @ts-ignore: AS returns T[], JS returns iterator - asArray handles both
const pages: u32[] = portable.asArray<u32>(memory.pages.keys());
Comment thread
tomusdrw marked this conversation as resolved.
let currentChunk: InitialChunk | null = null;
for (let i = 0; i < pages.length; i++) {
const pageIdx = pages[i];
Expand Down
6 changes: 3 additions & 3 deletions assembly/api-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class VmRunOptions {

export class VmInput {
pc: u32 = 0;
gas: i64 = 0;
gas: i64 = i64(0);

constructor(
public readonly program: Program,
Expand All @@ -39,15 +39,15 @@ export class VmPause {
exitCode: u32 = 0;
pc: u32 = 0;
nextPc: u32 = 0;
gas: i64 = 0;
gas: i64 = i64(0);
registers: u64[] = [];
}

export class VmOutput {
status: Status = Status.OK;
exitCode: u32 = 0;
pc: u32 = 0;
gas: i64 = 0;
gas: i64 = i64(0);
result: u8[] = [];
registers: u64[] = [];
memory: InitialChunk[] = [];
Expand Down
12 changes: 8 additions & 4 deletions assembly/api-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { InitialChunk, InitialPage, VmInput, VmOutput, VmPause, VmRunOptions } f
import { BlockGasCost, computeGasCosts } from "./gas-costs";
import { Interpreter } from "./interpreter";
import { MaybePageFault, MemoryBuilder } from "./memory";
import { portable } from "./portable";
import { deblob, extractCodeAndMetadata, liftBytes } from "./program";
import { NO_OF_REGISTERS, Registers } from "./registers";
import { NO_OF_REGISTERS, newRegisters, Registers } from "./registers";
import { decodeSpi, StandardProgram } from "./spi";

export enum InputKind {
Expand All @@ -20,7 +21,8 @@ export enum HasMetadata {
export function getGasCosts(input: u8[], kind: InputKind, withMetadata: HasMetadata): BlockGasCost[] {
const program = prepareProgram(kind, withMetadata, input, [], [], [], [], 0);

return computeGasCosts(program.program).values();
// @ts-ignore: AS returns T[], JS returns iterator - asArray handles both
return portable.asArray<BlockGasCost>(computeGasCosts(program.program).values());
}

export function disassemble(input: u8[], kind: InputKind, withMetadata: HasMetadata): string {
Expand Down Expand Up @@ -59,7 +61,9 @@ export function prepareProgram(

if (hasMetadata === HasMetadata.Yes) {
const data = extractCodeAndMetadata(code);
// @ts-ignore: TS 5.9 Uint8Array generic parameter mismatch
code = data.code;
// @ts-ignore: TS 5.9 Uint8Array generic parameter mismatch
metadata = data.metadata;
}
Comment thread
tomusdrw marked this conversation as resolved.

Expand All @@ -69,7 +73,7 @@ export function prepareProgram(
const builder = new MemoryBuilder(preallocateMemoryPages);
const memory = buildMemory(builder, initialPageMap, initialMemory);

const registers: Registers = new StaticArray(NO_OF_REGISTERS);
const registers: Registers = newRegisters();
const safeLen = initialRegisters.length < NO_OF_REGISTERS ? initialRegisters.length : NO_OF_REGISTERS;
for (let r = 0; r < safeLen; r++) {
registers[r] = initialRegisters[r];
Expand Down Expand Up @@ -100,7 +104,7 @@ export function runProgram(
dumpMemory: boolean = false,
): VmOutput {
const vmInput = new VmInput(program.program, program.memory, program.registers);
vmInput.gas = initialGas;
vmInput.gas = i64(initialGas);
vmInput.pc = programCounter;

const vmOptions = new VmRunOptions();
Expand Down
7 changes: 4 additions & 3 deletions assembly/arguments.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { minI32 } from "./math";
import { portable } from "./portable";

export enum Arguments {
Zero = 0,
Expand Down Expand Up @@ -53,7 +54,7 @@ export class Args {
type ArgsDecoder = (args: Args, code: u8[], offset: u32, end: u32) => Args;

function twoImm(args: Args, code: u8[], offset: u32, end: u32): Args {
const low = lowNibble(unchecked(code[offset]));
const low = lowNibble(portable.arrayAt(code, offset));
const split = minI32(4, low) + 1;
const first = decodeI32(code, offset + 1, offset + split);
const second = decodeI32(code, offset + split, end);
Expand Down Expand Up @@ -155,7 +156,7 @@ function decodeI32(input: u8[], start: u32, end: u32): u32 {
for (let i: u32 = 0; i < len; i++) {
num |= u32(input[start + i]) << (i * 8);
}
const msb = unchecked(input[start + len - 1]) & 0x80;
const msb = portable.arrayAt(input, start + len - 1) & 0x80;
if (len < 4 && msb > 0) {
num |= 0xffff_ffff << (len * 8);
}
Expand All @@ -167,5 +168,5 @@ function decodeU32(data: u8[], offset: u32): u32 {
num |= u32(data[offset + 1]) << 8;
num |= u32(data[offset + 2]) << 16;
num |= u32(data[offset + 3]) << 24;
return num;
return portable.asU32(num);
}
13 changes: 7 additions & 6 deletions assembly/codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ export function decodeVarU32(data: Uint8Array): ValOffset<u32> {
}

export function encodeVarU32(v: u64): Uint8Array {
if (v === 0) {
v = u64(v);
if (v === u64(0)) {
return new Uint8Array(1);
}

Expand All @@ -134,27 +135,27 @@ export function encodeVarU32(v: u64): Uint8Array {
}

// let's look for the correct range
let minEncoded = maxEncoded >> 7;
let minEncoded = maxEncoded >> u64(7);
for (let l = 7; l >= 0; l -= 1) {
if (v >= minEncoded) {
const dest = new Uint8Array(l + 1);

// encode the first byte
const maxVal = 2 ** (8 * l);
const byte = 2 ** 8 - 2 ** (8 - l) + v / maxVal;
const maxVal = u64(2 ** (8 * l));
const byte = (u32(2 ** 8 - 2 ** (8 - l)) + u32(v / maxVal)) & 0xffff_ffff;
dest[0] = u8(byte);

// now encode the rest of bytes of len `l`
let rest = v % maxVal;
for (let i = 1; i < 1 + l; i += 1) {
dest[i] = u8(rest);
rest >>= 8;
rest >>= u64(8);
}
return dest;
}
// move one power down
maxEncoded = minEncoded;
minEncoded >>= 7;
minEncoded >>= u64(7);
}

throw new Error(`Unhandled number encoding: ${v}`);
Expand Down
5 changes: 3 additions & 2 deletions assembly/gas-costs.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { INSTRUCTIONS, MISSING_INSTRUCTION } from "./instructions";
import { portable } from "./portable";
import { Program } from "./program";

export class BlockGasCost {
pc: u32 = 0;
gas: u64 = 0;
gas: u64 = u64(0);
}

export function computeGasCosts(p: Program): Map<u32, BlockGasCost> {
Expand All @@ -29,7 +30,7 @@ export function computeGasCosts(p: Program): Map<u32, BlockGasCost> {

if (currentBlock !== null) {
// add gas for current instruction
currentBlock.gas += iData.gas;
currentBlock.gas = portable.u64_add(currentBlock.gas, iData.gas);
}

// move forward
Expand Down
8 changes: 4 additions & 4 deletions assembly/gas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@ class GasCounterU64 implements GasCounter {
constructor(private gas: Gas) {}

set(g: Gas): void {
this.gas = <i64>g;
this.gas = i64(g);
}

get(): Gas {
return this.gas;
}

sub(g: Gas): boolean {
this.gas = this.gas - g;
if (this.gas < 0) {
this.gas = 0;
this.gas = this.gas - i64(g);
if (this.gas < i64(0)) {
this.gas = i64(0);
return true;
}
return false;
Expand Down
4 changes: 4 additions & 0 deletions assembly/index-shared.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from "./api-debugger";
export { getAssembly } from "./api-internal";
export * from "./api-utils";
export { wrapAsProgram } from "./program-build";
5 changes: 1 addition & 4 deletions assembly/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
export * from "./api-debugger";
export * from "./api-internal";
export * from "./api-utils";
export * from "./program-build";
export * from "./index-shared";
9 changes: 4 additions & 5 deletions assembly/instructions.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import { Arguments } from "./arguments";
import { Gas } from "./gas";

@unmanaged
export class Instruction {
namePtr: usize = 0;
name: string = "";
kind: Arguments = Arguments.Zero;
gas: Gas = 0;
gas: Gas = i64(0);
isTerminating: boolean = false;
}

function instruction(name: string, kind: Arguments, gas: Gas, isTerminating: boolean = false): Instruction {
const i = new Instruction();
i.namePtr = changetype<usize>(name);
i.name = name;
i.kind = kind;
i.gas = gas;
i.gas = i64(gas);
i.isTerminating = isTerminating;
return i;
}
Expand Down
Loading