Blockchain applications D60

View on GitHub

Monero Blockchain

Overview

This example deploys a Monero blockchain across an emulated Internet using real Monero client software. Users can configure different types of nodes, including seed nodes, full nodes, pruned nodes, and light wallets, as well as customize mining behavior and peer connections. The example supports both simplified deployment and detailed configuration, allowing users to construct Monero networks for different experimental needs. By inspecting peer connections, block production, and wallet transactions, users can explore how Monero nodes communicate and maintain the blockchain. You can further extend the scenario by changing mining difficulty, adjusting node connectivity, or deploying modified Monero clients to study blockchain performance, peer-to-peer networking, and security vulnerabilities.

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() with setSeedRole()/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_0 is seed, host_1 is 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/monerod
    • custom/monero-wallet-cli
    • custom/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:seed in 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:18088 inside containers with digest auth (examples use seed:seed).
  • Light nodes run only monero-wallet-rpc (port 18088); they do not start monerod.

Source: SEED Emulator · D60 README

Explore more blockchain applications examples