D60_monero: Monero Blockchain Service Examples
This folder provides three Seed-Emulator examples for the Monero blockchain service:
- ver1 (detailed configuration): Shows the full API surface with fine-grained options.
- ver2 (default configuration): Minimal configuration to spin up a ready-to-use blockchain.
- ver3 (custom binaries): Demonstrates how to run with your own Monero executables.
ver1: Detailed configuration (monero_ver1_detailed_config.py)
- Create the blockchain with
MoneroService.createBlockchain("base-monero", net_type=...) - Configure blockchain-level options:
setSeedConnectionMode(): seed connectivity policy (e.g., EXCLUSIVE)setFixedDifficulty(): fixed mining difficulty (reduce for demos/teaching)setDefaultWalletTemplate(): default wallet template
- Define nodes and roles:
createNode()withsetSeedRole()/setClientRole()- Control mining, threads, and triggers (e.g., AFTER_SEED_REACHABLE)
- Enable Wallet RPC for light/full nodes as needed
Topology layout:
- AS150-154: two hosts per AS;
host_0is seed,host_1is client (only AS150 client mines) - AS160-161: one client per AS
- AS162-163: one light wallet per AS
- AS164: one pruned node
Run:
python3 monero_ver1_detailed_config.py [amd|arm]
cd output && docker compose build && docker compose up
ver2: Default configuration (monero_ver2_default_config.py)
- Create a blockchain with minimal configuration:
MoneroService.createBlockchain("base-monero") - Use convenience node APIs:
createSeedNode()/createClientNode()/createLightWallet()/createPrunedNode()
- Demonstrate a mining trigger that starts only after seeds are reachable
Run:
python3 monero_ver2_default_config.py [amd|arm]
cd output && docker compose build && docker compose up
ver3: Custom binaries (monero_ver3_custom_binary.py)
When you modify Monero (research/experiments), place your binaries under custom/:
- Required files:
custom/monerodcustom/monero-wallet-clicustom/monero-wallet-rpc
- The script validates these files before proceeding
- Configure each node to use custom binaries:
server.options.binary_source = MoneroBinarySource.CUSTOM server.options.custom_binary_imports = { "/usr/local/bin/monerod": "<path>/custom/monerod", "/usr/local/bin/monero-wallet-cli": "<path>/custom/monero-wallet-cli", "/usr/local/bin/monero-wallet-rpc": "<path>/custom/monero-wallet-rpc", }
Run:
python3 monero_ver3_custom_binary.py [amd|arm]
cd output && docker compose build && docker compose up
Interacting and verifying
- Seed and full nodes expose P2P/RPC/ZMQ ports (determined by blockchain defaults and auto assignment)
- Light wallet nodes enable Wallet RPC by default; check
enableWalletRpc()in scripts for exposure settings
Enter a container:
docker ps | grep monero
docker exec -it <container_id_or_name> bash
FAQ
- Port conflicts: Ports are auto-assigned across nodes; if you override ports manually, ensure no conflicts (P2P/RPC/ZMQ/Wallet-RPC).
- Slow mining: Reduce difficulty for demos (e.g.,
setFixedDifficulty(2000)). - Missing custom binaries: Ensure all three files under
custom/exist and are executable.
Testing
The following commands help you validate the deployment. By default:
- Wallet RPC (digest auth) listens on 18088 inside containers (username/password are typically
seed:seedin examples). - Daemon RPC (no auth) listens on 28081 inside containers.
Replace <container> with an actual container name (e.g., as150h-Monero-Client-150-10.150.0.72).
Wallet RPC (port 18088, digest auth)
# Get wallet height
docker exec <container> curl -s --digest -u <user>:<pass> \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":"height","method":"get_height"}' \
http://127.0.0.1:18088/json_rpc
# Get wallet balance for account 0
docker exec <container> curl -s --digest -u <user>:<pass> \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":"balance","method":"get_balance","params":{"account_index":0}}' \
http://127.0.0.1:18088/json_rpc
# Get primary address (account 0)
docker exec <container> curl -s --digest -u <user>:<pass> \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":"addr","method":"get_address","params":{"account_index":0}}' \
http://127.0.0.1:18088/json_rpc
# Refresh wallet (rescan)
docker exec <container> curl -s --digest -u <user>:<pass> \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":"refresh","method":"refresh"}' \
http://127.0.0.1:18088/json_rpc
# List transfers (in/out/pending/failed)
docker exec <container> curl -s --digest -u <user>:<pass> \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":"txs","method":"get_transfers","params":{"in":true,"out":true,"pending":true,"failed":true}}' \
http://127.0.0.1:18088/json_rpc
Example transfer request (may return “not enough unlocked money” until coinbase rewards unlock; retry after sufficient blocks):
docker exec <container> curl -s --digest -u <user>:<pass> \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":"tx","method":"transfer","params":{"destinations":[{"address":"<recipient-address>","amount":1000000000000}],"account_index":0,"ring_size":12,"priority":0,"get_tx_key":true,"do_not_relay":false}}' \
http://127.0.0.1:18088/json_rpc
Daemon RPC (port 28081, no auth)
# Get block count
docker exec <container> curl -s \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":"count","method":"get_block_count"}' \
http://127.0.0.1:28081/json_rpc
# Get node info
docker exec <container> curl -s \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":"info","method":"get_info"}' \
http://127.0.0.1:28081/json_rpc
# Get peer connections
docker exec <container> curl -s \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":"conn","method":"get_connections"}' \
http://127.0.0.1:28081/json_rpc
# Get block hash at height 123
docker exec <container> curl -s \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":"hash","method":"get_block_hash","params":[123]}' \
http://127.0.0.1:28081/json_rpc
Logs and troubleshooting
# Recent logs of a container
docker logs <container_name> | tail -n 120
# Check daemon logs for ERROR/WARNING
docker exec <container_name> grep -i "error" /var/log/monero/<log_dir>/monerod.log | tail
docker exec <container_name> grep -i "warning" /var/log/monero/<log_dir>/monerod.log | tail
# Inspect wallet CLI / RPC logs
docker exec <container_name> tail -n 40 /var/log/monero/<log_dir>/wallet-cli.log
docker exec <container_name> tail -n 40 /var/log/monero/<log_dir>/wallet-rpc.log
# Ensure wallet-rpc process exists (light/RPC nodes)
docker exec <container_name> ps aux | grep monero-wallet-rpc
Notes on ports
- Full/pruned nodes expose P2P/RPC/ZMQ on incrementing testnet-style ports (P2P ≈ 28080+N, RPC ≈ 28081+N, ZMQ ≈ 28082+N).
- Wallet RPC defaults to
0.0.0.0:18088inside containers with digest auth (examples useseed:seed). - Light nodes run only
monero-wallet-rpc(port 18088); they do not startmonerod.
Source: SEED Emulator · D60 README