Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

SDK API

Calling Convention

Your service WASM module must export one of:

  • refine(ptr: u32, len: u32) -> u64 and accumulate(ptr: u32, len: u32) -> u64 for a regular service
  • is_authorized(ptr: u32, len: u32) -> u64 for an authorizer service

Arguments are passed as a pointer + length into linear memory. The return value is a packed u64 where len = result >> 32 and ptr = result & 0xffffffff. Use .toPtrAndLen() on a BytesBlob to produce this value.

Service Helpers

The SDK provides helpers for parsing arguments and encoding results:

  • ctx.parseArgs(ptr, len) — Parse raw refine/accumulate arguments. Panics on invalid host-provided entry-point data.
  • ctx.yieldHash(hash) — Encode an optional accumulate result hash and return the packed u64.
  • readFromMemory(ptr, len) — Read raw bytes from WASM linear memory.
  • ptrAndLen(data) — Pack a raw Uint8Array into a u64 return value.

To return a result, call .toPtrAndLen() on a BytesBlob (or use ptrAndLen() for a raw Uint8Array).

Entry Point Pattern

// assembly/index.ts
export { refine, accumulate } from "./service";
// assembly/service.ts
import { AccumulateContext, Logger, RefineContext } from "@fluffylabs/as-lan";
import { CodeHash } from "@fluffylabs/as-lan";

const logger = Logger.create("my-service");

export function accumulate(ptr: u32, len: u32): u64 {
  const ctx = AccumulateContext.create();
  const args = ctx.parseArgs(ptr, len);
  logger.info(`accumulate called for service ${args.serviceId}`);
  return ctx.yieldHash(null);
}

export function refine(ptr: u32, len: u32): u64 {
  const ctx = RefineContext.create();
  const args = ctx.parseArgs(ptr, len);
  logger.info(`refine called for service ${args.serviceId}`);
  return args.payload.toPtrAndLen();
}

Parsed Argument Types

RefineArgs (fields available after successful parse):

  • coreIndex: CoreIndex (u16)
  • itemIndex: u32
  • serviceId: ServiceId (u32)
  • payload: BytesBlob
  • workPackageHash: WorkPackageHash (Bytes32)

AccumulateArgs (fields available after successful parse):

  • slot: Slot (u32)
  • serviceId: ServiceId (u32)
  • argsLength: u32

Types

All types are imported from "@fluffylabs/as-lan".

TypeDescription
SlotBlock slot number (u32)
ServiceIdService identifier (u32)
CoreIndexCore index (u16)
CodeHash32-byte blake2b hash
PayloadHash32-byte blake2b payload hash
WorkPackageHash32-byte work package hash
HeaderHash32-byte blake2b header hash
StateRootHash32-byte blake2b state root hash
MmrPeakHash32-byte keccak256 MMR peak hash
BytesBlobVariable-length byte array with .toPtrAndLen()
WorkOutputAlias for BytesBlob
WorkPayloadAlias for BytesBlob
AuthOutputAlias for BytesBlob
Optional<T>Option type with .isSome and .val (nullable T)
OptionalN<T>Option type for non-nullable T
Result<Ok, Err>Result type with .isOkay, .okay, .isError, .error
ResultN<Ok, Err>Result type for non-nullable Ok
Bytes32Fixed-size 32-byte wrapper with hex parsing

Utilities

Logger

JIP-1 structured logger. Methods: fatal, warn, info, debug, trace.

debug and trace are compiled out at optimization level 3 (release builds).

import { Logger } from "@fluffylabs/as-lan";

const logger = Logger.create("my-service");
logger.info("processing work item");
logger.debug(`payload length: ${payload.length}`);

Binary size note: Logger accepts string messages, so using template literals (`value: ${n}`) pulls in AssemblyScript’s string concatenation, UTF-8 encoding, and number-to-string machinery. This can add ~1.3 KiB to the WASM output. If binary size is a concern, use LogMsg instead (see below).

LogMsg (lightweight logger)

A buffer-based logger that writes directly to a fixed-size byte buffer, bypassing AssemblyScript’s String machinery entirely. It uses a builder pattern to append text and numbers, then sends the raw bytes to the host.

Using LogMsg instead of Logger can reduce WASM output by 5KB and PVM output by 8KB for a typical service. Note that for large services the trade-off between code size and readability & debuggability might not be worth it.

import { LogMsg } from "@fluffylabs/as-lan";

const logger = LogMsg.create("my-service");
logger.str("processing item ").u32(itemId).info();
logger.str("result: ").u64(value).str(" bytes").debug();

Builder methods (all return LogMsg for chaining):

  • .str(s) — append an ASCII string
  • .u32(v) — append an unsigned 32-bit number as decimal
  • .u64(v) — append an unsigned 64-bit number as decimal
  • .i32(v) — append a signed 32-bit number as decimal
  • .blob(data) — append a BytesBlob as 0x-prefixed hex (no String allocation)

Terminal methods (send the message and reset the buffer):

  • .fatal(), .warn(), .info(), .debug(), .trace()

debug and trace are compiled out at optimization level 3, same as Logger.

ByteBuf (byte-buffer builder)

A lightweight Uint8Array builder that avoids String allocations. Used internally by LogMsg and useful for constructing binary output (e.g. auth traces) from string fragments and raw byte slices.

import { ByteBuf, ptrAndLen } from "@fluffylabs/as-lan";

const result = ByteBuf.create(64)
  .str("Auth=<")
  .bytes(token.raw)
  .str(">")
  .finish();           // → Uint8Array
return ptrAndLen(result);

Builder methods (all return ByteBuf for chaining):

  • .str(s) — append an ASCII string
  • .bytes(data) — append raw Uint8Array
  • .hex(data) — append Uint8Array as 0x-prefixed hex
  • .u32(v), .u64(v), .i32(v) — append numbers as decimal ASCII

Terminal methods:

  • .finish() — copy buffer into a new Uint8Array and reset
  • .reset() — discard contents without producing output

The buffer is heap-allocated at a fixed capacity; writes beyond the capacity are silently truncated.

Decoder

Binary protocol decoder for reading host-provided data.

import { Decoder } from "@fluffylabs/as-lan";

const decoder = Decoder.fromBlob(data);
const value = decoder.varU64();
const hash = decoder.bytes32();
const blob = decoder.bytesVarLen();

Key methods: u8, u16, u32, u64, varU64, bytes32, bytesFixLen, bytesVarLen, object, optional, sequenceFixLen, sequenceVarLen, skip, isFinished, isError.

Byte Types

  • Bytes32 — Fixed-size 32-byte array with hex string parsing
  • BytesBlob — Variable-length byte array wrapper with .toPtrAndLen() for returning results

Host Calls (ecalli)

Declared host functions available to services. Import from "@fluffylabs/as-lan" or from a specific group ("@fluffylabs/as-lan/ecalli/general", .../refine, .../accumulate).

General (available in all contexts):

IDFunctionDescription
0gas()Returns remaining gas
1fetch(dest_ptr, offset, length, kind, param1, param2)Fetch context data
2lookup(service, hash_ptr, out_ptr, offset, length)Look up preimage by hash
3read(service, key_ptr, key_len, out_ptr, offset, length)Read from storage
4write(key_ptr, key_len, value_ptr, value_len)Write to storage
5info(service, out_ptr, offset, length)Get service account info
100log(level, target_ptr, target_len, msg_ptr, msg_len)JIP-1 debug log (prefer Logger)

Refine (available during refinement):

IDFunctionDescription
6historical_lookup(service, hash_ptr, out_ptr, offset, length)Historical preimage lookup
7export_(segment_ptr, segment_len)Export a data segment
8machine(code_ptr, code_len, entrypoint)Create inner PVM machine
9peek(machine_id, dest_ptr, source, length)Read inner machine memory
10poke(machine_id, source_ptr, dest, length)Write inner machine memory
11pages(machine_id, start_page, page_count, access_type)Set inner machine page access
12invoke(machine_id, io_ptr, out_r8)Run inner machine (r7=exit reason, r8 written to out_r8)
13expunge(machine_id)Destroy inner machine

Accumulate (available during accumulation):

IDFunctionDescription
14bless(manager, auth_queue_ptr, delegator, registrar, auto_accum_ptr, count)Set privileged config
15assign(core, auth_queue_ptr, assigners)Assign core
16designate(validators_ptr)Set next epoch validators
17checkpoint()Commit state, return remaining gas
18new_service(code_hash_ptr, code_len, gas, allowance, gratis_storage, id)Create service
19upgrade(code_hash_ptr, gas, allowance)Upgrade service code
20transfer(dest, amount, gas_fee, memo_ptr)Transfer funds
21eject(service, prev_code_hash_ptr)Remove service
22query(hash_ptr, length, out_r8)Query preimage status (r8 written to out_r8)
23solicit(hash_ptr, length)Request preimage availability
24forget(hash_ptr, length)Cancel preimage solicitation
25yield_result(hash_ptr)Provide accumulation result hash
26provide(service, preimage_ptr, preimage_len)Supply solicited preimage

All functions return i64. Error sentinels are defined in EcalliResult: NONE (-1), WHAT (-2), OOB (-3), WHO (-4), FULL (-5), CORE (-6), CASH (-7), LOW (-8), HUH (-9).

Test Utilities

The SDK exports test helpers for writing AssemblyScript tests:

import { test, Assert } from "@fluffylabs/as-lan/test";

const allTests = [
  test("my test", (): Assert => {
    const a = Assert.create();
    a.isEqual(1 + 1, 2, "basic math");
    return a;
  }),
];

See the Testing guide for the full test framework, including configurable ecalli mocks (TestGas, TestFetch, TestLookup, TestStorage).