logos-execution-zone-module/doctests/logos-execution-zone-runtime.test.yaml
Iuri Matias 06acc51055 ci fix
2026-06-15 11:13:40 -04:00

280 lines
13 KiB
YAML

name: "Running This Execution-Zone Module Against logoscore"
output: logos-execution-zone-runtime.md
release: ""
intro: |
`logos-execution-zone` is a Logos `core` module that wraps the
[Logos execution-zone wallet library](https://github.com/logos-blockchain/lssa)
(`wallet_ffi`) to provide wallet lifecycle, account management, balance and
block queries, transfers, pinata claiming, and account-id encoding. This
doc-test exercises **this** execution-zone-module commit end-to-end through the
headless `logoscore` runtime:
1. Build the `logoscore` CLI and the `lgpm` local package manager from their
published flakes. `logoscore` is the headless frontend for `logos-liblogos`,
so building it brings in the whole module-runtime stack (`logos_host`,
`liblogos_core`, the IPC layer).
2. Build **this** execution-zone module as an installable `.lgx` package
straight from its own flake's `#lgx` output, **pinned to the commit under
test** — so the module you run is built from exactly what is checked out
here, not the latest published release.
3. Install the `.lgx` into a `./modules` directory with `lgpm`.
4. Start `logoscore` in daemon mode (`-D`), load `logos_execution_zone`,
introspect it with `module-info`, and call its wallet-free methods —
verifying the module actually runs and round-trips real values through
`wallet_ffi`.
The methods exercised here — `name`/`version` and the base58 account-id codec
(`account_id_to_base58` / `account_id_from_base58`) — are the module's
deterministic, **offline** surface: they need neither an open wallet nor a live
sequencer, so a green run is reproducible in CI. The stateful operations
(creating accounts, transfers, sync, pinata claims) require a running
sequencer and network, and are covered by the module's unit tests (mocked
`wallet_ffi`) and integration tests (real `wallet_ffi`) instead.
Because the module is built from the commit under test and then loaded and
called through a real `logoscore` daemon, a green run is real evidence that
this change keeps the execution-zone module loadable and callable.
what_you_build: "This `logos_execution_zone` module, packaged as `.lgx`, installed with `lgpm`, and called through a `logoscore` daemon."
what_you_learn:
- How to build the `logoscore` runtime and the `lgpm` package manager from their flakes
- How a module's flake exposes a ready-to-install `.lgx` via its `#lgx` output
- How to install an `.lgx` into a modules directory with `lgpm`
- How to start the `logoscore` daemon, load a module, introspect it, and call its methods
- How to shut the daemon down and confirm it has exited
prerequisites:
- |
**Nix** with flakes enabled. Install from [nixos.org](https://nixos.org/download.html), then enable flakes:
```bash
mkdir -p ~/.config/nix
echo 'experimental-features = nix-command flakes' >> ~/.config/nix/nix.conf
```
Verify: `nix flake --help >/dev/null 2>&1 && echo "Flakes enabled"`
- "**A Linux or macOS machine.**"
sections:
- title: "Build logoscore"
step: true
text: |
Build the `logoscore` CLI from its published flake. The result is symlinked to
`./logos/`. `logoscore` is the headless frontend for `logos-liblogos`, so this
one build brings in the whole module-runtime stack the daemon needs.
steps:
- title: "Build the CLI"
run: "nix build 'github:logos-co/logos-logoscore-cli' --out-link ./logos"
code_block: |
nix build 'github:logos-co/logos-logoscore-cli' --out-link ./logos
check_file: "logos/bin/logoscore"
post_text: |
The build produces `logos/bin/logoscore` plus bundled runtime libraries
and a `logos/modules/` directory containing the built-in
`capability_module` (required for the auth handshake when loading
modules).
- title: "Build the lgpm package manager"
step: true
text: |
`lgpm` installs `.lgx` packages into a modules directory and scans what is
installed. Build it from the `logos-package-manager` flake and link it as
`./lgpm`.
steps:
- title: "Build lgpm"
run: "nix build 'github:logos-co/logos-package-manager#cli' -o lgpm"
check_file: "lgpm/bin/lgpm"
post_text: "The executable is at `./lgpm/bin/lgpm`."
- title: "Build and install this execution-zone module"
step: true
text: |
Build **this** execution-zone module's `.lgx` straight from its flake's
`#lgx` output and install it into a local `./modules` directory with `lgpm`.
Every module built with
[`logos-module-builder`](https://github.com/logos-co/logos-module-builder)
exposes a ready-to-install `#lgx`.
> The `{release}` in the URL is what pins the build to a specific commit: the
> doc-test runner expands it to a concrete ref. Locally that is this
> checkout's `HEAD` (see `run.sh`); in CI it is the commit being tested. With
> no pin it falls back to the latest `master`.
steps:
- title: "Build the module's .lgx"
text: |
Build the `#lgx` output and link it as `./lez-lgx`. (This compiles the
module and the `wallet_ffi` library it depends on through Nix, so the
first build is slow.)
run: "nix build 'github:logos-blockchain/logos-execution-zone-module{release}#lgx' -o lez-lgx"
code_block: |
# From inside the clone this is simply: nix build '.#lgx'
nix build 'github:logos-blockchain/logos-execution-zone-module{release}#lgx' -o lez-lgx
post_text: "The `.lgx` package is now under `./lez-lgx/`:"
extra_run:
run: "ls lez-lgx/*.lgx"
- title: "Seed the modules directory with the bundled capability module"
text: |
`logos_execution_zone` is loaded through the host's capability layer, so
the modules directory also needs the `capability_module` that ships with
`logoscore`. Copy it across first.
run: |
mkdir -p modules
cp -RL ./logos/modules/. ./modules/
check_file: "modules/capability_module/manifest.json"
- title: "Install the .lgx with lgpm"
text: |
Install the freshly-built package into `./modules`. `logos_execution_zone`
is a `core` module, so it goes to `--modules-dir`. The package is unsigned
(a local dev build), so we pass `--allow-unsigned`.
run: "./lgpm/bin/lgpm --modules-dir ./modules --allow-unsigned install --file lez-lgx/*.lgx"
expect_contains:
- "Installed to:"
- title: "Confirm the install"
text: "Scan the directory and confirm the module landed:"
run: "./lgpm/bin/lgpm --modules-dir ./modules list"
expect_contains:
- "logos_execution_zone"
check_file: "modules/logos_execution_zone/manifest.json"
- title: "Run the daemon and call the module"
step: true
text: |
Start `logoscore` in daemon mode pointed at `./modules`, then use the client
subcommands to load `logos_execution_zone`, introspect it, and call several
of its methods. Daemon output is captured in `logs.txt`.
steps:
- title: "Start the daemon"
text: |
Start logoscore in daemon mode in the background, capturing output to
`logs.txt`:
run: "sh -c './logos/bin/logoscore -D -m ./modules > logs.txt 2>&1 &'"
code_block: "logoscore -D -m ./modules > logs.txt &"
post_text: |
The `-D` flag starts the daemon. The client subcommands below connect to
this running process via the config written under `~/.logoscore/`.
- run: "sleep 3"
- title: "Inspect the startup log"
text: "Review the daemon's startup output:"
run: "cat logs.txt"
- title: "Check daemon status"
text: "Verify the daemon is running:"
run: "./logos/bin/logoscore status"
code_block: "logoscore status"
- title: "List discovered modules"
text: "`logos_execution_zone` should be visible in the scan directory:"
run: "./logos/bin/logoscore list-modules"
code_block: "logoscore list-modules"
expect_contains:
- "logos_execution_zone"
- title: "Load the module"
text: "Load `logos_execution_zone` into the running daemon:"
run: "./logos/bin/logoscore load-module logos_execution_zone"
code_block: "logoscore load-module logos_execution_zone"
expect_contains:
- "logos_execution_zone"
- title: "Confirm the module is loaded"
text: |
Re-run `status`; the module that was `not_loaded` before now reports
`loaded`:
run: "./logos/bin/logoscore status"
code_block: "logoscore status"
expect_contains:
- "logos_execution_zone"
- '"status":"loaded"'
- title: "Introspect the module with module-info"
text: |
`module-info` lists the methods the module exposes — the same methods you
can `call`:
run: "./logos/bin/logoscore module-info logos_execution_zone"
code_block: "logoscore module-info logos_execution_zone"
expect_contains:
- "logos_execution_zone"
- "account_id_to_base58"
- "account_id_from_base58"
- title: "Read the module name"
text: |
`name` returns the module's own identifier — the simplest possible
round-trip through the loaded plugin over liblogos' IPC:
run: "./logos/bin/logoscore call logos_execution_zone name"
code_block: "logoscore call logos_execution_zone name"
expect_contains:
- '"result":"logos_execution_zone"'
- title: "Read the module version"
text: |
`version` returns the module's semantic version (`1.0.0`), matching
`metadata.json`:
run: "./logos/bin/logoscore call logos_execution_zone version"
code_block: "logoscore call logos_execution_zone version"
expect_contains:
- '"result":"1.0.0"'
- title: "Encode an account id to base58"
text: |
`account_id_to_base58` takes a 32-byte account id as 64 hex characters
and returns its base58 form. This is a pure encoding helper in
`wallet_ffi` — no open wallet and no network required, so it runs
entirely offline:
run: "./logos/bin/logoscore call logos_execution_zone account_id_to_base58 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
code_block: "logoscore call logos_execution_zone account_id_to_base58 aaaaaaaa...aaaa # 64 hex chars"
expect_contains:
- '"result"'
- title: "Round-trip it back to hex"
text: |
`account_id_from_base58` is the inverse: feed it the base58 string we just
produced and it returns the original 64-hex account id. Encoding then
decoding the same id and recovering the input is a deterministic,
end-to-end proof that the codec — and the IPC path to this module — work:
run: |
ENC=$(./logos/bin/logoscore call logos_execution_zone account_id_to_base58 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)
B58=$(printf '%s' "$ENC" | sed -n 's/.*"result":"\([^"]*\)".*/\1/p')
echo "encoded: $B58"
./logos/bin/logoscore call logos_execution_zone account_id_from_base58 "$B58"
code_block: |
# Encode, then decode the result back — the round-trip returns the input.
B58=$(logoscore call logos_execution_zone account_id_to_base58 aaaa...aaaa)
logoscore call logos_execution_zone account_id_from_base58 "$B58"
expect_contains:
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- title: "Reject malformed base58"
text: |
Decoding obvious garbage fails cleanly: `account_id_from_base58` returns
an empty result rather than crashing the module or the daemon:
run: "./logos/bin/logoscore call logos_execution_zone account_id_from_base58 '!!!not-base58!!!'"
code_block: "logoscore call logos_execution_zone account_id_from_base58 '!!!not-base58!!!'"
expect_contains:
- '"result":""'
- title: "Stop the daemon"
text: "Shut the daemon down cleanly:"
run: "./logos/bin/logoscore stop"
code_block: "logoscore stop"
post_text: |
The daemon removes its state file and exits.
- run: "sleep 2"
- title: "Confirm the daemon has stopped"
text: |
With no daemon running, the client reports `not_running` and exits
non-zero, so we add `|| true` to let the doc-test assert on the output:
run: "./logos/bin/logoscore status || true"
code_block: "logoscore status"
expect_contains:
- '"status":"not_running"'