Runners#

Runners specify execution environments for GenVM contracts.

Runner Architecture#

Identification and Packaging#

Each runner is identified by <human-readable-id>:<hash>. human-readable-id is provided for convenience. hash is a sha3-256 hash of its contents

Hash Format#

Hash is SHA3 256-bit hash, converted to a string with following algorithm:

def digest_to_hash_id(got_hash: bytes) -> str:
    chars = '0123456789abcdfghijklmnpqrsvwxyz'

    bytes_count = len(got_hash)
    base32_len = (bytes_count * 8 - 1) // 5 + 1

    my_hash_arr = []
    for n in range(base32_len - 1, -1, -1):
        b = n * 5
        i = b // 8
        j = b % 8
        c = (got_hash[i] >> j) | (0 if i >= bytes_count - 1 else got_hash[i + 1] << (8 - j))
        my_hash_arr.append(chars[c & 0x1F])

    return ''.join(my_hash_arr)

This ensures that it contains no fs-illegal characters and is case insensitive.

Runner Layout#

For any of the layouts a file list is constructed. Each file in this name has:

  • a name

    1. it must not start with /

    2. path separator must be /

    3. it must not contain . or .. path components

  • contents (raw bytes slice)

1. ZIP Archive#

Used if runner bytes represent a ZIP archive

  • If successful, extracts the archive contents and processes it as a structured runner package

  • This format supports complex runners with multiple files, dependencies, and configuration

  • Only allowed compression is stored (no compression)

2. Raw WASM#

Used if runner bytes represent a wasm file (magic matches)

Creates a minimal runner configuration

version = v0.1.0
runner.json = { "StartWasm": "file" }
file = # source bytes

3. Text-based#

Used if neither of previous worked. Must be a valid utf-8 encoded string

Comment Header Format#

The contract source code must begin with comment lines using one of the supported comment syntaxes:

  • // (C-style comments)

  • # (Shell/Python-style comments)

  • -- (SQL/Lua/Haskell-style comments)

The comment header consists of:

  1. Version Line (first comment line): Must start with v followed by version information

  2. :term:`Runner` Configuration (subsequent comment lines): JSON configuration for the runner

Resulting structure#

version = # first line if started with version, else default
runner.json = # consequent comment lines with removed comment prefix. All whitespaces are kept as-is
file = # source bytes

Example#

# v1.0.0
# {
#   "Depends": "python:latest",
#   "StartWasm": "python.wasm"
# }

exit(30)

version file#

This file must contain a single line with the version of genvm in v<major>.<minor>.<patch> format.

If this file is not present, the default version is used.

runner.json File#

The runner.json file defines a recursive structure of initialization actions that configure the execution environment for a contract.

Schema is available in runner.json JSON Schema.

It must be a valid JSON object with described below structure

AddEnv#

Adds an environment variable to the GenVM environment with variable interpolation support using ${} syntax.

Example#

{
    "AddEnv": {
        "name": "DEBUG",
        "val": "true"
    }
}

MapFile#

Maps files or directories from an archive to specific paths in the GenVM filesystem.

Properties#

  • file (string): Path within the archive. If ending with /, recursively maps all files in the directory

  • to (string): Absolute destination path in the GenVM filesystem

Example#

{
    "MapFile": {
        "file": "config/",
        "to": "/etc/myapp/"
    }
}

Creating a single file mapping implies RAM Consumption of

  1. gvm-def-consts-value-memory-limiter-consts-file-mapping.

  2. file name length in octets

SetArgs#

Sets process arguments for the GenVM environment.

Type: Array of strings

Example#

{
    "SetArgs": ["exe-name", "--verbose", "--config", "/path/to/config"]
}

LinkWasm#

Links a WebAssembly file to make it available in GenVM.

Type: String (path to WebAssembly file)

{
    "LinkWasm": "path/in/arch/to/module.wasm"
}

If function _initialize is present, it will be called immediately after linking.

StartWasm#

Starts a specific WebAssembly file in GenVM.

Type: String (path to WebAssembly file)

Example#

{
    "StartWasm": "path/in/arch/to/module.wasm"
}

This is a terminal action in the runner configuration. It results in linking the module and calling _start function.

Depends#

Specifies a dependency on another runner by its ID and hash.

Example#

{
    "Depends": "cpython:123"
}

Dependencies are processed only once, for the first request

Seq#

Executes a sequence of initialization actions.

{
    "Seq": [
        { "SetArgs": ["exe-name", "--verbose", "--config", "/path/to/config"] },
        { "StartWasm": "path/in/arch/to/module.wasm" }
    ]
}

When#

Conditionally executes an action based on WebAssembly execution mode.

Properties#

  • cond: WebAssembly mode, either det (deterministic) or nondet (non-deterministic)

  • action: Action to execute when condition is met

Example#

{
    "When": {
        "cond": "det",
        "action": { "AddEnv": {"name": "MODE", "val": "deterministic"} }
    }
}

With#

Sets a runner as current without executing its action, useful for reusing files or creating runner locks.

Example#

{
    "With": {
        "runner": "base-environment",
        "action": { "MapFile": {"file": "patched.foo", "to": "foo" } }
    }
}

Startup#

Runner actions are executed left-recursively, until StartWasm is reached. If it was not reached, it will result in a VMError with error_inval code.

Loading a runner implies RAM Consumption of its size in octets. Each loading in a single contract, but different sub-VM instances, leads to additional RAM consumption. Deterministic Mode and Non-Deterministic Mode have separate RAM limits.