Release set v0.2.1

The following package versions are pinned for release set v0.2.1.

Note: The release-set version identifies the testnet version. Individual package versions are pinned independently and do not need to match the release-set version.

Node operator guide

PackageVersion
logos-blockchain-module0.2.4
logos-storage-module2.1.2
logos-delivery-module0.2.1
logosctl0.2.3-rc.1

Other release packages

PackageVersion
lez-explorer-ui1.1.1
lez-indexer-module1.1.1
logos-execution-zone-module1.1.0
logos-execution-zone-wallet-ui1.1.0
logos-blockchain-ui0.2.1
logos-chat-module0.2.1
logos-chat-ui0.2.1
logos-storage-ui2.1.0
logos-basecamp0.2.3

Overview

Run one Logos node through one logosctl session. logosctl starts and controls the node and manages its modules within that session.

This guide starts these modules:

ModulePackagePublic ports
Blockchainblockchain_module3000/udp, configured Blend UDP port
Storagestorage_module8090/udp, 8091/tcp
Deliverydelivery_module9000/udp, 30303/tcp

Commands assume a Linux host and these default paths:

/usr/local/bin/logosctl
/var/lib/logos-node/.logosctl
/var/lib/logos-node

Replace <public-ip> with the public IPv4 address of the node. Run the module commands as the same OS user that owns /var/lib/logos-node.

Install logosctl

Install curl, jq, tar, and FUSE support for AppImage binaries.

apt-get update
apt-get install -y curl jq tar fuse3

Download the published x86_64 Linux release archive:

curl -fL \
  -o logosctl-x86_64-linux.tar.gz \
  https://github.com/logos-co/logos-logoscore-cli/releases/download/0.2.3-rc.1/logosctl-x86_64-linux.tar.gz

Verify and extract the archive:

sha256sum --check <<'EOF'
baa6e24522833c6b6e33146a9d44f7428660e465158be2d723575f62409ad851  logosctl-x86_64-linux.tar.gz
EOF
tar -xzf logosctl-x86_64-linux.tar.gz

Verify the extracted AppImage:

sha256sum --check <<'EOF'
3ee96869d6a873cddd19c05eaa86d258e156a69635b10811b77cda149899dd1e  logosctl-x86_64.AppImage
EOF

Install it as logosctl:

install -m755 logosctl-x86_64.AppImage /usr/local/bin/logosctl

Verify:

logosctl --version

Prepare The Host

Create the Logos node user, logosctl session directory, and module data directories:

useradd --system --home /var/lib/logos-node --create-home --shell /usr/sbin/nologin logos
mkdir -p /var/lib/logos-node/.logosctl
mkdir -p /var/lib/logos-node/blockchain-module-testnet
mkdir -p /var/lib/logos-node/storage-module
mkdir -p /var/lib/logos-node/delivery-module
chown -R logos:logos /var/lib/logos-node
chmod 700 /var/lib/logos-node/.logosctl

Open these ports on the host firewall:

3000/udp
<YOUR_BLEND_PORT>/udp
8090/udp
8091/tcp
9000/udp
30303/tcp

<YOUR_BLEND_PORT>/udp is required when joining Blend. Obtain it from blend.core.backend.listening_address in the generated blockchain configuration.

Install Modules

As root, open a shell as the logos user. Setting HOME selects the default /var/lib/logos-node/.logosctl session:

runuser -u logos -- env HOME=/var/lib/logos-node bash

Initialize the session with the default daemon configuration:

printf '{}\n' | logosctl daemon config set -

Temporarily start the Logos node in detached mode so its bundled package-management modules are available:

logosctl daemon start --detach
logosctl daemon status

Refresh the official module catalog:

logosctl catalog refresh

Install the pinned module packages. Each root hash selects the exact published package identity for its pinned version:

logosctl package install blockchain_module \
  --version 0.2.4 \
  --root-hash 2e57268c4ec1fdcf07e4b6bf1b33b5ac99705c071f879e6ca1c41b4e543cc674 \
  --yes
logosctl package install storage_module \
  --version 2.1.2 \
  --root-hash 19b11b153748c30665608c5527776ba2be74f7764481a11d33f687098764b740 \
  --yes
logosctl package install delivery_module \
  --version 0.2.1 \
  --root-hash 0bccd85b4702c01a2c227df8aa55b3f5159a9fe009d57ae8bb8b3a7c20dfcbbe \
  --yes

Installing a package does not load it into the running Logos node. Check the installed core packages:

logosctl package ls --type core

The output must list:

blockchain_module 0.2.4
delivery_module 0.2.1
storage_module 2.1.2

Stop the Logos node after installation. The next section starts it for normal operation:

logosctl daemon stop

Start The Logos Node

Continue in the logos user shell from the previous section. If it was closed, reopen it:

runuser -u logos -- env HOME=/var/lib/logos-node bash

Set the Logos node working directory:

cd /var/lib/logos-node

Run the node controls, module configuration, module calls, and health checks from this shell. This keeps the Logos node and logosctl client on the same /var/lib/logos-node/.logosctl session and ensures generated files belong to logos.

For a manual foreground run, start the Logos node with:

logosctl daemon start

Keep that terminal open. Use another logos user shell for module commands.

For a temporary detached run, use:

logosctl daemon start --detach

The detached command returns after the Logos node is ready to accept commands. For unattended operation, prefer a systemd service over a manually started daemon.

Check:

logosctl daemon status

Blockchain

Note: Blockchain module 0.2.4 starts a new blockchain with a new genesis. The Logos node testnet release remains v0.2.1, and the other module versions are unchanged. Existing nodes must start with an empty blockchain state directory. Existing 0.2.3 blockchain configuration and wallet keys can be retained. Existing wallet keys can be retained, but balances and Blend declarations from the previous blockchain do not carry over.

Create the blockchain peer file:

cd /var/lib/logos-node/blockchain-module-testnet
cat > peers.json <<EOF
{
  "initial_peers": [
    "/ip4/65.109.51.37/udp/3000/quic-v1/p2p/12D3KooWFrouXfmrR4nsLMtE7wu15DoMJ6VtoUtHinREZCvbWHar",
    "/ip4/65.109.51.37/udp/3001/quic-v1/p2p/12D3KooWJRGau8M1rjT7R5e4YYsgdFhsMX35nRDtMwCDjxQkXAHz",
    "/ip4/65.109.51.37/udp/3002/quic-v1/p2p/12D3KooWQXJavMDTRscjauFSgVAB1VLB6Rzpy2uY5SU9Tk7927tb",
    "/ip4/65.109.51.37/udp/50001/quic-v1/p2p/12D3KooWSQc7CcGtvWDPF1yCbBthFnQjprfCVHmfmNDUrSmqQsU1"
  ]
}
EOF

The blockchain-module-testnet directory is a setup workspace for the peer file and related blockchain commands. If an existing node was created with the older blockchain-module-devnet directory name, do not rename a running node just to match this guide. Keep the existing path or update all local scripts and services consistently during a planned reprovision.

Load the module and generate user_config.yaml:

logosctl module load blockchain_module
cd /var/lib/logos-node/blockchain-module-testnet
logosctl call blockchain_module generate_user_config @peers.json
chmod 600 /var/lib/logos-node/user_config.yaml /var/lib/logos-node/keystore.yaml

generate_user_config writes user_config.yaml in the Logos node working directory. With the service layout in this guide, that path is /var/lib/logos-node/user_config.yaml.

The generated user_config.yaml contains node-local wallet and key-management configuration. Keep it private, restrict file permissions, and do not publish it. Generate a fresh file for each node.

Start the module. The second argument is intentionally an empty string; the blockchain module no longer requires a downloaded deployment.yaml file:

logosctl call blockchain_module start /var/lib/logos-node/user_config.yaml ""

Check:

logosctl call blockchain_module get_cryptarchia_info | jq -r .result.value | jq .

Blockchain Config

Operator-facing fields in user_config.yaml:

FieldPurposeGuidance
network.initial_peersBootstrap peersUse the current network document
network.portPublic UDP P2P portKeep aligned with firewall/NAT, normally 3000
api.listen_addressLocal API bindKeep private, normally 127.0.0.1:8080
state.base_folderState directoryUse a persistent local path
logger filtersLog verbosityUse INFO for unattended operation

Fund the node for consensus

After the node reaches Online, request testnet funds to participate in consensus. Find the public keys associated with your node:

cd /var/lib/logos-node
grep -A6 known_keys user_config.yaml

Choose a public key from known_keys and request funds for it from the faucet. Alternatively, request funds directly, replacing <your-chosen-key> with that public key:

curl -fsS -X POST 'https://testnet.blockchain.logos.co/web/faucet-backend/<your-chosen-key>'

The faucet allows one request per key per block. Check the balance, replacing <your-chosen-key> with the public key you funded:

curl -fsS 'http://127.0.0.1:8080/wallet/<your-chosen-key>/balance' | jq .

Funds received in epoch N count for block production from epoch N+2.

Joining Blend Network

Request funds to both the BlendZk and SdpFunding keys from your keystore.yaml from the faucet

The public keys and note IDs below are examples. Use the corresponding values from your own keystore.yaml and wallet responses when running these commands.

# keystore.yaml
public_keys:
  ...
  BlendZk: 13cccf99f90fd78c2134891ce3c1afce0605753a7694b9d56678d63a8d471820
  ...
  SdpFunding: 91d381a87e05d46fc9bc95246273b6930290506f0589ad039444decd3c24940e
  ...
secret_keys:
  ...

Wait until you receive funds to both addresses. You can check the balance of your accounts with the following commands:

# check BlendZk key has received funds
logosctl call blockchain_module wallet_get_notes 13cccf99f90fd78c2134891ce3c1afce0605753a7694b9d56678d63a8d471820 "" \
  | jq -r .result.value | jq .notes
# > [
# >   {
# >     "id": "de5f5b6d2baac23bf562d89676ebd304e8d6e6f67afc22f378b5dabf164d142d",
# >     "value": "1000"
# >   }
# > ]
 
 
# check SdpFunding key has received funds
logosctl call blockchain_module wallet_get_notes 91d381a87e05d46fc9bc95246273b6930290506f0589ad039444decd3c24940e "" \
  | jq -r .result.value | jq .notes
# > [
# >   {
# >     "id": "47831c89a3609a7bd38755b2d2da7e2dfb63bef8515a8b8ad82c8a61b7b9a006",
# >     "value": "1000"
# >   }
# > ]

Join the blend network by locking one of the notes held by your BlendZk key.

  • <YOUR_IP>: must be your external ip address
  • <YOUR_BLEND_PORT>: Retrieve your configured blend port from the user_config.yaml (blend.core.backend.listening_address), note that if you do port-mapping, the external mapped port must be used.
  • <BLEND_ZK_NOTE_ID>: the note id of one of the notes held by your BlendZk key, as queried above.

Before joining:

  • open <YOUR_BLEND_PORT>/udp on the public host firewall;
  • if the node is behind NAT, forward that external UDP port to the port in blend.core.backend.listening_address;

The submitted locator must use the external address and port that other nodes can dial. The Blend core listener starts only after the node’s declaration becomes active. Configure the firewall and NAT forwarding before joining. Verify the local listener and public reachability after activation.

logosctl call blockchain_module blend_join_as_core_node \
  "/ip4/<YOUR_IP>/udp/<YOUR_BLEND_PORT>/quic-v1" \
  "<BLEND_ZK_NOTE_ID>"
 
# successful call will return the declaration id:
# > {"method":"blend_join_as_core_node","module":"blockchain_module","result":{"error":null,"success":true,"value":"2691821bd61394cc18939626de4e9231c699e8ddefd1ebf9e6c35b32229bdc65"},"status":"ok"}

Verify the declaration was accepted on chain by polling /mantle/sdp/declarations, looking for your declaration

curl http://127.0.0.1:8080/mantle/sdp/declarations | jq . 
# > [
# >   {
# >     "service_type": "BN",
# >     "provider_id": "35d60d973560b8344f83dc266a3fe89e35a3dcf9959c492d0a7a0b7a85c5d2ce",
# >     "locked_note_id": "<BLEND_ZK_NOTE_ID>",
# >     "locators": [
# >       "/ip4/<YOUR_IP>/udp/<YOUR_BLEND_PORT>/quic-v1"
# >     ],
# >     "zk_id": "13cccf99f90fd78c2134891ce3c1afce0605753a7694b9d56678d63a8d471820",
# >     "created": 1,
# >     "active": 3,
# >     "withdraw_at": null,
# >     "nonce": 0
# >   }
# > ]

service_type: BN identifies it as a Blend node declaration, zk_id is your BlendZk public key, and provider_id is your BlendSigning key.

When in a block, the active epoch should be two epochs in the future (active == created + 2), as that’s when it will become active

Storage

Create the storage config:

cd /var/lib/logos-node/storage-module
mkdir -p storage-data
cat > config.json <<EOF
{
  "data-dir": "./storage-data",
  "log-level": "INFO",
  "listen-ip": "0.0.0.0",
  "listen-port": 8091,
  "disc-port": 8090,
  "network": "logos.test"
}
EOF

Fields:

FieldPurpose
data-dirStorage repository path
log-levelLog verbosity
listen-ipLocal TCP bind address
listen-portPublic TCP libp2p port
disc-portPublic UDP discovery port
networkStorage network preset

The logos.test network preset provides the storage bootstrap settings.

Use fixed listen-port and disc-port. Do not leave public nodes on random ports.

Start storage without mix:

cd /var/lib/logos-node/storage-module
logosctl module load storage_module
logosctl call storage_module init @config.json
logosctl call storage_module start

Check:

logosctl call storage_module space

Optional: Mix Support And Private Queries

To run storage with mix support, generate the storage config from the current published mix bootstrap data. This replaces the basic config.json above. The script accepts an optional storage data directory as its first argument. Without one, it uses logos-storage-data under the current directory.

cd /var/lib/logos-node/storage-module
cat > make-mix-storage-config.sh <<'EOF'
#!/usr/bin/env bash
set -e
 
data_dir=${1:-"${PWD}/logos-storage-data"}
udp_spr_json=$(curl -s https://logos-storage-network.fra1.digitaloceanspaces.com/v0.2/udp-sprs.json)
tcp_spr_json=$(curl -s https://logos-storage-network.fra1.digitaloceanspaces.com/v0.2/tcp-sprs.json)
mp_json=$(curl -s https://logos-storage-network.fra1.digitaloceanspaces.com/v0.2/mix-pool.json | jq -c 'tostring')
 
cat <<JSON | jq .
{
  "log-level": "INFO;trace:libp2p,mix",
  "mix-enabled": true,
  "listen-port": 8091,
  "disc-port": 8090,
  "bootstrap-node": $udp_spr_json,
  "dht-mix-proxy": $tcp_spr_json,
  "data-dir": "${data_dir}",
  "mix-pool-json": ${mp_json}
}
JSON
 
EOF
 
chmod 755 make-mix-storage-config.sh
./make-mix-storage-config.sh > config.json

Start storage with that config:

cd /var/lib/logos-node/storage-module
logosctl module load storage_module
logosctl call storage_module init @config.json
logosctl call storage_module start
logosctl call storage_module togglePrivateQueries true

After startup, allow the node time to populate routing state. If the first private query fails with a manifest lookup error, retry once after a short warm-up period.

Privately query a known test object:

logosctl call storage_module downloadToUrl zDvZRwzkzrrYB6sS1rRpRLt4gBhc1pWoyTSjkfszfmj1seaYYLCZ /var/lib/logos-node/storage-module/farewell-to-westphalia.pdf false 65536

Delivery

Create the kernel-only delivery config for a node operator:

Replace <public-ip> before running this command.

cd /var/lib/logos-node/delivery-module
cat > config.json <<EOF
{
  "entryLayer": "kernel",
  "kernelConf": {
    "preset": "logos.test",
    "relay": true,
    "logLevel": "INFO",
    "tcpPort": 30303,
    "discv5UdpPort": 9000,
    "discv5Discovery": true,
    "nat": "extip:<public-ip>"
  }
}
EOF

Fields:

FieldPurpose
entryLayerDelivery stack layer; use kernel for a node-operator service
kernelConfKernel node configuration
kernelConf.presetNetwork preset
kernelConf.relayEnable the Relay protocol
kernelConf.logLevelLog verbosity
kernelConf.tcpPortPublic TCP P2P port
kernelConf.discv5UdpPortPublic UDP discovery port
kernelConf.discv5DiscoveryEnable discv5 discovery
kernelConf.natPublic IP advertisement mode

The kernel-only entry layer intentionally omits the messaging client and reliable channel manager. Calls to send, subscribe, and channel* are unavailable, while getNodeInfo, storeQuery, and metrics remain available.

The logos.test preset provides the delivery network bootstrap settings. extMultiaddrs is usually not needed when nat advertises the public address.

Use fixed tcpPort and discv5UdpPort. Do not leave public nodes on random ports.

Start:

cd /var/lib/logos-node/delivery-module
logosctl module load delivery_module
logosctl call delivery_module createNode @config.json
logosctl call delivery_module start

Check:

logosctl call delivery_module getAvailableNodeInfoIDs
logosctl call delivery_module getNodeInfo Version
logosctl call delivery_module getNodeInfo MyMultiaddresses

Health Checks

Check the Logos node and loaded modules:

logosctl daemon status --json | jq .
logosctl module ls --loaded

Expected modules:

blockchain_module
capability_module
delivery_module
package_downloader
package_manager
storage_module

Check listeners:

ss -lntup | egrep '(:3000|:8090|:8091|:9000|:30303|:8080)'

Expected:

0.0.0.0:3000/udp
0.0.0.0:8090/udp
0.0.0.0:8091/tcp
0.0.0.0:9000/udp
0.0.0.0:30303/tcp
127.0.0.1:8080/tcp

Check blockchain:

logosctl call blockchain_module get_cryptarchia_info | jq -r .result.value | jq .

Check storage:

logosctl call storage_module space

Check delivery:

logosctl call delivery_module getNodeInfo MyMultiaddresses

Check the configured Blend UDP listener:

ss -lun

Confirm that the local UDP port from blend.core.backend.listening_address is present. If the public Blend port differs, also confirm that NAT forwards <YOUR_BLEND_PORT>/udp to this local port.

Optional: Systemd

For unattended operation, use systemd.

Recommended pattern:

  • one service for the Logos node process started and controlled by logosctl;
  • one separate bootstrap service or script for module startup;
  • journald output with retention limits.

Do not start modules from ExecStartPost in logos-node.service. If module startup is slow or returns an error, systemd may kill the daemon.

Create /etc/systemd/system/logos-node.service:

[Unit]
Description=Logos node managed by logosctl
After=network-online.target
Wants=network-online.target
 
[Service]
User=logos
Group=logos
WorkingDirectory=/var/lib/logos-node
Environment=HOME=/var/lib/logos-node
Environment=LOGOSCTL_CONFIG_DIR=/var/lib/logos-node/.logosctl
ExecStart=/usr/local/bin/logosctl daemon start
ExecStop=/usr/local/bin/logosctl daemon stop
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
 
[Install]
WantedBy=multi-user.target

The separate bootstrap script should:

  1. wait for logosctl daemon status;
  2. load and start blockchain;
  3. load and start storage;
  4. load and start delivery;
  5. tolerate already-loaded modules and slow module starts.

Cap journal usage:

[Journal]
SystemMaxUse=200M
SystemKeepFree=1G
MaxRetentionSec=7day
MaxFileSec=1day

Prefer INFO logs for unattended operation. Use DEBUG only for short troubleshooting windows.