Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
e891f0c
pvm inteface
DrEverr Oct 13, 2025
56c9a0a
Merge branch 'main' into maso-ananas
DrEverr Oct 13, 2025
97dba6c
run ananas without setting registers and memory
DrEverr Oct 13, 2025
694cd02
setting registers
DrEverr Oct 13, 2025
6016207
Merge branch 'main' into maso-ananas
DrEverr Oct 13, 2025
e47732c
adding store and load
DrEverr Oct 14, 2025
b38deac
Merge branch 'main' into maso-ananas
DrEverr Oct 14, 2025
c9923ef
qa fix
DrEverr Oct 14, 2025
25370fb
invalid memory set
DrEverr Oct 14, 2025
75eeec5
added flat to start ananas interpreter
DrEverr Oct 14, 2025
19a81f5
reset ananas and print program code
DrEverr Oct 14, 2025
bd7df0f
Make sure it runs.
tomusdrw Oct 14, 2025
e44bc4c
sub and set gas
DrEverr Oct 14, 2025
f722af8
qa-fix
DrEverr Oct 14, 2025
8e14d7b
Merge branch 'main' into maso-ananas
DrEverr Oct 16, 2025
fefabe4
added ananasAPI, cleaned common methods between interpreters
DrEverr Oct 17, 2025
8538ff4
added interface without memory interface
DrEverr Oct 17, 2025
9a265aa
Merge branch 'main' into maso-ananas
DrEverr Oct 18, 2025
c7aa7e4
add memory interface; applied IMemory for build in interpreter
DrEverr Oct 20, 2025
6839ce7
using new gas in HCs
DrEverr Oct 20, 2025
faa4353
rename IMemory methods to set and get; implement them
DrEverr Oct 20, 2025
ec61330
merge
DrEverr Oct 20, 2025
22afec3
rename pvminterpreter default to buildin
DrEverr Oct 20, 2025
53af23e
Merge branch 'main' into maso-ananas
DrEverr Oct 20, 2025
dc9144c
added set all to IRegisters; using IHostCallRegisters in host calls
DrEverr Oct 21, 2025
1a1c1fe
Merge branch 'maso-ananas' of github.com:FluffyLabs/typeberry into ma…
DrEverr Oct 21, 2025
c8d57a1
Merge branch 'main' into maso-ananas
DrEverr Oct 21, 2025
0b0cc0c
changed interpreter option name to backend name (more general)
DrEverr Oct 21, 2025
d439138
explicitly declare what backend to run on accumulation
DrEverr Oct 21, 2025
cdff0aa
fix sub gas
DrEverr Oct 21, 2025
964e9c9
throws error on incorrect pvm flag
DrEverr Oct 21, 2025
6a9582a
Update packages/core/pvm-host-calls/host-call-memory.ts
DrEverr Oct 22, 2025
cdde06d
apply suggestions
DrEverr Oct 22, 2025
3548d12
merge
DrEverr Oct 22, 2025
40eebd1
changed HCRegisters to accept buffer
DrEverr Oct 23, 2025
8e3dab3
applied suggestions
DrEverr Oct 24, 2025
b04d8c9
added tests and async create instanca manager
DrEverr Oct 24, 2025
5532dea
added hc store load tests
DrEverr Oct 24, 2025
089c364
instanciate built in without async
DrEverr Oct 24, 2025
6ce4980
fixed gas in tb interpreter:
DrEverr Oct 24, 2025
c447ca2
disable both pvms accumulation
DrEverr Oct 25, 2025
9c07e2b
wraping memory address in hcMemory; simplify codec for pvmBacked
DrEverr Oct 25, 2025
f4f5b0f
implement newest ananas memory api
DrEverr Oct 25, 2025
f3ea303
added ananas to external dependency
DrEverr Oct 25, 2025
24d86eb
correctly display default pvm in help
DrEverr Oct 25, 2025
ffbf671
moved pvm backend to separate config file
DrEverr Oct 25, 2025
d874c6c
fixed log
DrEverr Oct 25, 2025
26ece95
fixed test names
DrEverr Oct 25, 2025
a5d4d25
self review
DrEverr Oct 26, 2025
7280a49
Remove API.
tomusdrw Oct 26, 2025
4f46cd2
Remove redundant interfaces.
tomusdrw Oct 26, 2025
c6d55ee
Remove dependency on pvm-interpreter.
tomusdrw Oct 26, 2025
045262f
Code review fix.
tomusdrw Oct 26, 2025
1a12752
Separate runners for w3f accumulate.
tomusdrw Oct 26, 2025
522ebcc
Update packages readme.
tomusdrw Oct 26, 2025
781f60c
Add warnings about WASM inlining.
tomusdrw Oct 26, 2025
b37c58b
Fix tests.
tomusdrw Oct 26, 2025
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
27 changes: 26 additions & 1 deletion bin/jam/args.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import assert from "node:assert";
import { describe, it } from "node:test";

import { PvmBackend, PvmBackendNames } from "@typeberry/config";
import { NODE_DEFAULTS } from "@typeberry/config-node";
import { tryAsU16 } from "@typeberry/numbers";
import { deepEqual } from "@typeberry/utils";
Expand All @@ -11,6 +11,7 @@ describe("CLI", () => {
const defaultOptions: SharedOptions = {
nodeName: NODE_DEFAULTS.name,
configPath: NODE_DEFAULTS.config,
pvm: NODE_DEFAULTS.pvm,
};

it("should start with default arguments", () => {
Expand Down Expand Up @@ -82,6 +83,30 @@ describe("CLI", () => {
});
});

it("should parse pvm option", () => {
const args = parse(["--pvm=ananas"]);

deepEqual(args, {
command: Command.Run,
args: {
...defaultOptions,
pvm: PvmBackend.Ananas,
},
});
});

it("should throw on invalid pvm option", () => {
const pvms = PvmBackendNames.join(", ");
assert.throws(
() => {
const _args = parse(["--pvm=unimplemented"]);
},
{
message: `Invalid value 'unimplemented' for option 'pvm': Error: Use one of ${pvms}`,
},
);
});

it("should throw on missing output path", () => {
assert.throws(
() => {
Expand Down
17 changes: 17 additions & 0 deletions bin/jam/args.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { type PvmBackend, PvmBackendNames } from "@typeberry/config";
import { DEFAULT_CONFIG, DEV_CONFIG, NODE_DEFAULTS } from "@typeberry/config-node";
import { isU16, type U16 } from "@typeberry/numbers";
import minimist from "minimist";
Expand All @@ -18,6 +19,8 @@ Options:
[default: ${NODE_DEFAULTS.name}]
--config Path to a config file or one of: ['${DEV_CONFIG}', '${DEFAULT_CONFIG}'].
[default: ${NODE_DEFAULTS.config}]
--pvm PVM Backend, one of: [${PvmBackendNames.join(", ")}].
[default: ${PvmBackendNames[NODE_DEFAULTS.pvm]}]
`;

/** Command to execute. */
Expand All @@ -37,6 +40,7 @@ export enum Command {
export type SharedOptions = {
nodeName: string;
configPath: string;
pvm: PvmBackend;
};

export type Arguments =
Expand Down Expand Up @@ -79,10 +83,23 @@ function parseSharedOptions(
(v) => (v === DEV_CONFIG || v === DEFAULT_CONFIG ? v : withRelPath(v)),
defaultConfig,
);
const { pvm } = parseStringOption(
args,
"pvm",
(v) => {
const pvm = PvmBackendNames.indexOf(v);
if (pvm >= 0) {
return pvm as PvmBackend;
}
throw Error(`Use one of ${PvmBackendNames.join(", ")}`);
},
NODE_DEFAULTS.pvm,
);

return {
nodeName: name,
configPath: config,
pvm,
};
}

Expand Down
8 changes: 5 additions & 3 deletions bin/jam/build-for-npm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ DIST_FOLDER=./dist/jam
mkdir $DIST_FOLDER || true
rm -rf $DIST_FOLDER/*


# TODO [ToDr] Temporary require anan-as before https://github.com/tomusdrw/anan-as/issues/99
# is resolved.
# Build the main binary
BUILD="npx @vercel/ncc build -a -s -e lmdb -e @matrixai/quic -e tsx/esm/api"
BUILD="npx @vercel/ncc build -a -s -e lmdb -e @matrixai/quic -e @fluffylabs/anan-as -e tsx/esm/api"
$BUILD ./bin/jam/index.ts -o $DIST_FOLDER

# Fix un-compiled worker files to point to the ones we will compile manually.
Expand Down Expand Up @@ -80,7 +81,8 @@ cat > ./package.json << EOF
},
"dependencies": {
"lmdb": "3.1.3",
"@matrixai/quic": "2.0.9"
"@matrixai/quic": "2.0.9",
"@fluffylabs/anan-as": "1.0.0-a9b8141"
},
"homepage": "https://typeberry.dev",
"author": "Fluffy Labs <hello@fluffylabs.dev>",
Expand Down
1 change: 1 addition & 0 deletions bin/jam/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ async function prepareConfigFile(args: Arguments, blake2b: Blake2b): Promise<Jam
isAuthoring: args.command === Command.Dev,
nodeName,
nodeConfig,
pvmBackend: args.args.pvm,
networkConfig: {
key: devNetworkingSeed(blake2b, nodeName),
host: "127.0.0.1",
Expand Down
49 changes: 34 additions & 15 deletions bin/pvm/index.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,48 @@
// biome-ignore-all lint/suspicious/noConsole: bin file

import { Interpreter, tryAsGas } from "@typeberry/pvm-interpreter";
import { Status } from "@typeberry/pvm-interpreter/status.js";

const pvm = new Interpreter();
import { Status, tryAsGas } from "@typeberry/pvm-interface";
import { Interpreter } from "@typeberry/pvm-interpreter";
import { AnanasInterpreter } from "@typeberry/pvm-interpreter-ananas";

const program = new Uint8Array([
0, 0, 35, 173, 101, 126, 173, 255, 239, 101, 101, 101, 101, 101, 194, 101, 101, 101, 174, 120, 44, 0, 0, 0, 0, 178,
230, 174, 73, 44, 0, 0, 0, 0, 178, 230, 174, 120, 73, 85, 65, 2, 4,
]);
pvm.reset(program, 0, tryAsGas(200n));
const instructions = pvm.printProgram();

const pvmTb = new Interpreter({ useSbrkGas: true });
const pvmAnanas = await AnanasInterpreter.new();

pvmTb.resetGeneric(program, 0, tryAsGas(200n));
pvmAnanas.resetGeneric(program, 0, tryAsGas(200n));

const instructions = pvmTb.printProgram();

let i = 0;
while (pvm.nextStep() === Status.OK) {
let ananas = pvmAnanas.nextStep();
let tb = Status.OK;

while (ananas || tb === Status.OK) {
console.info(`Instruction ${i}: ${instructions[i]}`);
console.info(`Registers: ${pvm.getRegisters().getAllU64()}`);
console.info(`Status: ${pvm.getStatus()}`);
console.info(`Gas: ${pvm.getGas()}`);
console.info(`Gas: ${pvm.getPC()}`);
console.info(`🫐 Registers: ${pvmTb.registers.getAllU64()}`);
console.info(`🍍 Registers: ${pvmAnanas.registers.getAllU64()}`);
console.info(`Status: 🫐 ${pvmTb.getStatus()} | 🍍 ${pvmAnanas.getStatus()}`);
console.info(`Gas: 🫐 ${pvmTb.gas.get()}| 🍍 ${pvmAnanas.gas.get()}`);
console.info(`PC: 🫐 ${pvmTb.getPC()} | 🍍 ${pvmAnanas.getPC()}`);
console.info();
i++;
if (tb === Status.OK) {
tb = pvmTb.nextStep();
}
if (ananas) {
ananas = pvmAnanas.nextStep();
}
}

console.info(`Instruction ${i}: ${instructions[i]}`);
console.info(`Registers: ${pvm.getRegisters().getAllU64()}`);
console.info(`Status: ${pvm.getStatus()}`);
console.info(`Gas: ${pvm.getGas()}`);
console.info(`Gas: ${pvm.getPC()}`);
console.info(`🫐 Registers: ${pvmTb.registers.getAllU64()}`);
console.info(`🍍 Registers: ${pvmAnanas.registers.getAllU64()}`);
console.info(`Status: 🫐 ${pvmTb.getStatus()} | 🍍 ${pvmAnanas.getStatus()}`);
// TODO [MaSo] Check why they not finished with same gas.
console.info(`Gas: 🫐 ${pvmTb.gas.get()}| 🍍 ${pvmAnanas.gas.get()}`);
console.info(`PC: 🫐 ${pvmTb.getPC()} | 🍍 ${pvmAnanas.getPC()}`);
console.info();
4 changes: 3 additions & 1 deletion bin/pvm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"description": "PVM program runner.",
"main": "index.ts",
"dependencies": {
"@typeberry/pvm-interpreter": "*"
"@typeberry/pvm-interface": "*",
"@typeberry/pvm-interpreter": "*",
"@typeberry/pvm-interpreter-ananas": "*"
},
"scripts": {
"start": "tsx ./index.ts",
Expand Down
2 changes: 1 addition & 1 deletion bin/rpc/test/e2e-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const withRelPath = workspacePathFix(`${import.meta.dirname}/../../..`);

async function main() {
const nodeConfig = loadConfig(`${import.meta.dirname}/e2e.config.json`);
const jamConfig = JamConfig.new({ nodeName: NODE_DEFAULTS.name, nodeConfig });
const jamConfig = JamConfig.new({ nodeName: NODE_DEFAULTS.name, nodeConfig, pvmBackend: NODE_DEFAULTS.pvm });
try {
const api = await node(jamConfig, withRelPath);
await importBlocks(api, blocksToImport);
Expand Down
1 change: 1 addition & 0 deletions bin/tci/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ describe("Typeberry Common Interface: Config", () => {
nodeName: NODE_DEFAULTS.name,
nodeConfig: loadConfig(NODE_DEFAULTS.config),
devConfig: DEFAULT_DEV_CONFIG,
pvmBackend: NODE_DEFAULTS.pvm,
});
const key = Bytes.fill(SEED_SIZE, 1).asOpaque<PublicKeySeed>();

Expand Down
7 changes: 6 additions & 1 deletion bin/tci/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,12 @@ export function createJamConfig(argv: CommonArguments): node.JamConfig {
};
}

return node.JamConfig.new({ nodeName: NODE_DEFAULTS.name, nodeConfig, devConfig });
return node.JamConfig.new({
nodeName: NODE_DEFAULTS.name,
nodeConfig,
devConfig,
pvmBackend: NODE_DEFAULTS.pvm,
});
}

if (import.meta.url === pathToFileURL(process.argv[1]).href) {
Expand Down
2 changes: 2 additions & 0 deletions bin/test-runner/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"@typeberry/codec": "*",
"@typeberry/collections": "*",
"@typeberry/config": "*",
"@typeberry/config-node": "*",
"@typeberry/crypto": "*",
"@typeberry/database": "*",
"@typeberry/disputes": "*",
Expand All @@ -18,6 +19,7 @@
"@typeberry/json-parser": "*",
"@typeberry/logger": "*",
"@typeberry/numbers": "*",
"@typeberry/pvm-interface": "*",
"@typeberry/pvm-interpreter": "*",
"@typeberry/safrole": "*",
"@typeberry/shuffling": "*",
Expand Down
27 changes: 17 additions & 10 deletions bin/test-runner/w3f/accumulate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type { WorkPackageHash } from "@typeberry/block/refine-context.js";
import type { WorkReport } from "@typeberry/block/work-report.js";
import { fromJson, workReportFromJson } from "@typeberry/block-json";
import { asKnownSize, HashSet } from "@typeberry/collections";
import type { ChainSpec } from "@typeberry/config";
import { type ChainSpec, PvmBackend, PvmBackendNames } from "@typeberry/config";
import { Blake2b } from "@typeberry/hash";
import { type FromJson, json } from "@typeberry/json-parser";
import type { InMemoryService } from "@typeberry/state";
Expand Down Expand Up @@ -142,8 +142,15 @@ export class AccumulateTest {
}

export async function runAccumulateTest(test: AccumulateTest, path: string) {
const chainSpec = getChainSpec(path);
await runAccumulateInternal(test, path, PvmBackend.BuiltIn);
}

export async function runAccumulateTestAnanas(test: AccumulateTest, path: string) {
await runAccumulateInternal(test, path, PvmBackend.Ananas);
}

async function runAccumulateInternal(test: AccumulateTest, path: string, pvm: PvmBackend) {
const chainSpec = getChainSpec(path);
/**
* entropy has to be moved to input because state is incompatibile -
* in test state we have: `entropy: EntropyHash;`
Expand All @@ -152,19 +159,19 @@ export async function runAccumulateTest(test: AccumulateTest, path: string) {
*/
const entropy = test.pre_state.entropy;

const state = TestState.toAccumulateState(test.pre_state as TestState, chainSpec);
const accumulate = new Accumulate(chainSpec, await Blake2b.createHasher(), state);
const post_state = TestState.toAccumulateState(test.post_state, chainSpec);

const state = TestState.toAccumulateState(test.pre_state, chainSpec);
const accumulate = new Accumulate(chainSpec, await Blake2b.createHasher(), state, pvm);
const accumulateOutput = new AccumulateOutput();
const result = await accumulate.transition({ ...test.input, entropy });

if (result.isError) {
assert.fail(`Expected successfull accumulation, got: ${result}`);
assert.fail(`Expected successfull accumulation for ${PvmBackendNames[pvm]}, got: ${result}`);
}
const accumulateRoot = await accumulateOutput.transition({ accumulationOutputLog: result.ok.accumulationOutputLog });
const accumulateRoot = await accumulateOutput.transition({
accumulationOutputLog: result.ok.accumulationOutputLog,
});
state.applyUpdate(result.ok.stateUpdate);

const post_state = TestState.toAccumulateState(test.post_state as TestState, chainSpec);

deepEqual(state, post_state);
deepEqual(accumulateRoot, test.output.ok);
}
5 changes: 3 additions & 2 deletions bin/test-runner/w3f/pvm-gas-cost.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import assert from "node:assert";
import { fromJson } from "@typeberry/block-json";
import { type FromJson, json } from "@typeberry/json-parser";
import { Interpreter, tryAsGas } from "@typeberry/pvm-interpreter";
import { tryAsGas } from "@typeberry/pvm-interface";
import { Interpreter } from "@typeberry/pvm-interpreter";

export class PvmGasCostTest {
static fromJson: FromJson<PvmGasCostTest> = {
Expand All @@ -15,7 +16,7 @@ export class PvmGasCostTest {

export async function runPvmGasCostTest(testContent: PvmGasCostTest) {
const pvm = new Interpreter();
pvm.reset(testContent.program, 0, tryAsGas(1000));
pvm.resetGeneric(testContent.program, 0, tryAsGas(1000));

const blockGasCosts = pvm.calculateBlockGasCost();

Expand Down
12 changes: 6 additions & 6 deletions bin/test-runner/w3f/pvm.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import assert from "node:assert";
import { fromJson } from "@typeberry/block-json";
import { type FromJson, json } from "@typeberry/json-parser";
import { Interpreter, tryAsGas } from "@typeberry/pvm-interpreter";
import { MAX_MEMORY_INDEX, Status, tryAsGas } from "@typeberry/pvm-interface";
import { Interpreter } from "@typeberry/pvm-interpreter";
import { MemoryBuilder } from "@typeberry/pvm-interpreter/memory/index.js";
import { MAX_MEMORY_INDEX, PAGE_SIZE } from "@typeberry/pvm-interpreter/memory/memory-consts.js";
import { PAGE_SIZE } from "@typeberry/pvm-interpreter/memory/memory-consts.js";
import { tryAsMemoryIndex, tryAsSbrkIndex } from "@typeberry/pvm-interpreter/memory/memory-index.js";
import { getPageNumber } from "@typeberry/pvm-interpreter/memory/memory-utils.js";
import { type PageNumber, tryAsPageNumber } from "@typeberry/pvm-interpreter/memory/pages/page-utils.js";
import { Registers } from "@typeberry/pvm-interpreter/registers.js";
import { Status } from "@typeberry/pvm-interpreter/status.js";
import { safeAllocUint8Array } from "@typeberry/utils";

class MemoryChunkItem {
Expand Down Expand Up @@ -113,12 +113,12 @@ export async function runPvmTest(testContent: PvmTest) {
return "halt";
};

pvm.reset(testContent.program, testContent["initial-pc"], tryAsGas(testContent["initial-gas"]), regs, memory);
pvm.resetGeneric(testContent.program, testContent["initial-pc"], tryAsGas(testContent["initial-gas"]), regs, memory);
Comment thread
DrEverr marked this conversation as resolved.
pvm.runProgram();

assert.strictEqual(pvm.getGas(), BigInt(testContent["expected-gas"]));
assert.strictEqual(pvm.gas.get(), BigInt(testContent["expected-gas"]));
assert.strictEqual(pvm.getPC(), testContent["expected-pc"]);
assert.deepStrictEqual(pvm.getRegisters().getAllU64(), testContent["expected-regs"]);
assert.deepStrictEqual(pvm.registers.getAllU64(), testContent["expected-regs"]);

const testStatus = mapPvmStatus(pvm.getStatus());
const exitParam = pvm.getExitParam();
Expand Down
3 changes: 2 additions & 1 deletion bin/test-runner/w3f/runners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
import { fullChainSpec, tinyChainSpec } from "@typeberry/config";
import { runner } from "../common.js";
import { runStateTransition, StateTransition } from "../state-transition/state-transition.js";
import { AccumulateTest, runAccumulateTest } from "./accumulate.js";
import { AccumulateTest, runAccumulateTest, runAccumulateTestAnanas } from "./accumulate.js";
import { AssurancesTestFull, AssurancesTestTiny, runAssurancesTestFull, runAssurancesTestTiny } from "./assurances.js";
import { AuthorizationsTest, runAuthorizationsTest } from "./authorizations.js";
import {
Expand Down Expand Up @@ -50,6 +50,7 @@ import { runTrieTest, trieTestSuiteFromJson } from "./trie.js";

export const runners = [
runner("accumulate", AccumulateTest.fromJson, runAccumulateTest),
runner("accumulate_ananas", AccumulateTest.fromJson, runAccumulateTestAnanas),
runner("assurances/tiny", AssurancesTestTiny.fromJson, runAssurancesTestTiny),
runner("assurances/full", AssurancesTestFull.fromJson, runAssurancesTestFull),
runner("authorizations", AuthorizationsTest.fromJson, runAuthorizationsTest),
Expand Down
Loading
Loading