How to Set Up an Amadeus Protocol Node: Complete Installation Guide
Set up an Amadeus Protocol node by building a Docker image with Erlang/OTP and RocksDB, compiling the release with ./build.sh, and launching with TESTNET=true for local development or configuring systemd with AUTOUPDATE=true for production.
This guide walks you through deploying an Amadeus Protocol node, an Elixir/Erlang OTP application that powers a high-performance, UDP-based blockchain engine. The node manages networking, persistent storage, and JSON-RPC handling through supervised GenServer processes, with support for WebAssembly contracts written in AssemblyScript or Rust.
Prerequisites for Amadeus Protocol Node Setup
Before building the node, ensure your system meets these requirements:
| Requirement | Purpose | Installation |
|---|---|---|
| Docker or Podman | Containerized build environment | sudo apt install podman or sudo apt install docker.io |
| Erlang OTP 26+ / Elixir 1.16+ | BEAM VM runtime for the node | Included in Docker image; optional local install for development |
| Rust toolchain (optional) | Compile Rust contracts to WebAssembly | curl https://sh.rustup.rs -sSf | sh |
| Node.js 20+ (optional) | Build AssemblyScript contracts | sudo apt install nodejs |
| High file descriptor limits | Support many UDP sockets and open files | Apply sysctl and limits.conf settings (see Production Deployment section) |
The node runs as a single OS process inside the BEAM virtual machine, using message-passing between components for fault tolerance and low latency.
Architecture Overview
Understanding the core components helps troubleshoot issues and optimize performance:
| Component | File Path | Function |
|---|---|---|
| OTP Supervision Tree | ex/lib/node/node_gen.ex |
Creates the main supervision hierarchy managing socket, reassembly, net-guard, and RPC processes |
| UDP Socket Layer | ex/lib/node/node_gen_socket_gen.ex, ex/lib/node/node_gen_netguard.ex |
Handles raw UDP packets, NAT traversal, and packet size enforcement |
| RocksDB Storage | ex/lib/misc/rocksdb.ex |
Persistent key/value store for blocks, state, and contract data |
| STUN/NAT Helper | ex/lib/misc/stun.ex |
Discovers public IP/port for peer-to-peer communication |
| RPC API | ex/lib/api/rpc_api.ex |
Exposes JSON-RPC endpoint for browsers, wallets, and CLI tools |
| Contract Loader | ex/lib/ex_bakeware.ex |
Loads WebAssembly contracts and routes RPC calls to them |
All components are supervised, meaning failures in one process trigger automatic restarts without stopping the entire node.
Building the Amadeus Protocol Node
Step 1: Build the Docker Image
The build.Dockerfile provides a reproducible environment with Erlang/Elixir, RocksDB native libraries, and optional Rust tooling:
# Build the Erlang/Elixir base image with RocksDB
podman build --tag erlang_builder -f build.Dockerfile
# Compile the production release
./build.sh
The build.sh script produces a BEAM release at _build/prod/rel/amadeusd and copies the executable amadeusd to your repository root.
Step 2: Verify the Build
Check that the binary exists and is executable:
ls -la ./amadeusd
file ./amadeusd
Running a Local Testnet Node
The fastest way to set up an Amadeus Protocol node is testnet mode, which starts a single-node network with an in-process RPC server:
# Start testnet with HTTP RPC on localhost port 80
TESTNET=true WORKFOLDER=/tmp/testnet HTTP_IPV4=127.0.0.1 HTTP_PORT=80 ./amadeusd
Environment variables control the node behavior:
| Variable | Description | Example |
|---|---|---|
TESTNET=true |
Enable single-node testnet mode | Required for local development |
WORKFOLDER |
Data directory for blocks and state | /tmp/testnet |
HTTP_IPV4 |
IP address to bind RPC server | 127.0.0.1 |
HTTP_PORT |
Port for JSON-RPC endpoint | 80 |
Interacting with the Running Node
Once started, connect via the Elixir REPL (iex) or direct HTTP calls:
Using the REPL:
iex -S mix
# Load trainer keys (pre-funded in testnet)
iex> pk = Application.fetch_env!(:ama, :trainer_pk)
iex> sk = Application.fetch_env!(:ama, :trainer_sk)
# Transfer AMA tokens
iex> Testnet.call(sk, "Coin", "transfer", [pk, "5", "AMA"])
# Deploy a WebAssembly contract
iex> Testnet.deploy "/path/to/node/contract_samples/assemblyscript/counter.wasm"
# Call contract methods
iex> Testnet.call(sk, pk, "get", [])
iex> Testnet.call(sk, pk, "increment", ["2"])
Using curl (external clients):
curl -X POST http://127.0.0.1:80/rpc \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"call","params":["<sk>","Coin","balance",["<pk>"]],"id":1}'
Deploying Custom WebAssembly Contracts
The Amadeus Protocol node executes contracts compiled to WebAssembly. Two toolchains are supported:
AssemblyScript Contracts
cd contract_samples/assemblyscript
# Compile and validate
./build_and_validate.sh my_contract.ts
# Output: my_contract.wasm ready for deployment
Upload via Testnet.deploy in the REPL or through the RPC API.
Rust Contracts
Follow contract_samples/rust/README.md for project setup, then:
cargo build --release --target wasm32-unknown-unknown
Critical: Use wasm32-unknown-unknown target only. Other targets produce invalid WASM for the node runtime.
Production Deployment with Systemd
For persistent, auto-updating nodes, configure systemd with optimized kernel parameters.
System Limits Configuration
Apply UDP buffer sizes and security settings (referenced in README.md lines 49–62):
cat <<'EOF' | sudo tee /etc/sysctl.d/99-amadeusd.conf
net.core.wmem_max = 268435456
net.core.rmem_max = 268435456
net.ipv4.udp_mem = 3060432 4080578 6120864
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
EOF
sudo sysctl --system
Set file descriptor and process limits (README.md lines 65–78):
cat <<'EOF' | sudo tee /etc/security/limits.d/99-amadeusd.conf
* hard nofile 1048576
* soft nofile 1048576
* hard nproc unlimited
* soft nproc unlimited
* hard memlock unlimited
* soft memlock unlimited
EOF
Systemd Service File
Create the service unit (adapted from README.md lines 98–115):
cat <<'EOF' | sudo tee /etc/systemd/system/amadeusd.service
[Unit]
Description=AmadeusD Node
After=network-online.target
Wants=network-online.target
[Service]
Type=forking
LimitNOFILE=1048576
KillMode=control-group
Restart=always
RestartSec=3
User=root
WorkingDirectory=/root
Environment="AUTOUPDATE=true"
ExecStart=/usr/bin/screen -UdmS amadeusd bash -c './amadeusd'
[Install]
WantedBy=multi-user.target
EOF
Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable amadeusd
sudo systemctl start amadeusd
For non-root deployment, modify User and WorkingDirectory as shown in README.md lines 124–128.
Troubleshooting Common Issues
| Symptom | Root Cause | Solution |
|---|---|---|
EADDRINUSE on port 80/443 |
Privileged port restrictions | Run sudo sysctl -w net.ipv4.ip_unprivileged_port_start=80 (README line 27) |
| Browser CORS errors | Cross-origin security policy | Launch Chrome with --ignore-certificate-errors --disable-web-security (README line 23) |
| Node crashes under load | Insufficient nofile/memlock limits |
Apply limits.conf settings from production section |
| "Invalid wasm" on contract upload | Wrong compilation target | Verify wasm32-unknown-unknown for Rust, or use provided AssemblyScript build script |
| STUN/NAT traversal failures | Firewall blocking UDP | Open UDP ports used by node_gen_socket_gen.ex and verify stun.ex can reach public STUN servers |
Summary
- Build process: Use
build.Dockerfileand./build.shto compile theamadeusdbinary with all native dependencies - Local development: Launch with
TESTNET=truefor immediate RPC access via REPL or HTTP - Contract support: Compile AssemblyScript with
build_and_validate.shor Rust withwasm32-unknown-unknowntarget - Production readiness: Configure systemd with
AUTOUPDATE=true, apply kernel tuning for UDP buffers, and set high file descriptor limits - Core files: Reference
ex/lib/node/node_gen.exfor supervision tree,ex/lib/api/rpc_api.exfor RPC handling, andex/lib/misc/rocksdb.exfor storage implementation
Frequently Asked Questions
What hardware is required to run an Amadeus Protocol node?
A node runs on modest hardware: 2+ CPU cores, 4GB RAM, and SSD storage for RocksDB. The critical requirement is network capacity—the UDP-heavy architecture in node_gen_socket_gen.ex benefits from low-latency connections and sufficient kernel buffer sizes (rmem_max/wmem_max).
How does the node handle software updates?
Set AUTOUPDATE=true in the environment to enable the built-in updater. The node checks for releases and applies them automatically while maintaining state in the WORKFOLDER directory. For manual control, run without this flag and replace the amadeusd binary directly.
Can I run multiple nodes on the same machine?
Yes. Specify distinct WORKFOLDER, HTTP_PORT, and UDP port ranges for each instance. The node_gen.ex supervision tree isolates processes within each BEAM VM, though you must ensure sufficient file descriptors (nofile limits) for the combined socket count.
Is there a difference between testnet and mainnet binaries?
No. The same amadeusd binary serves both modes. Testnet behavior is activated solely by the TESTNET=true environment variable, which modifies the genesis block and consensus rules in node_gen.ex without requiring a separate build.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →