Overview
Ubu-Block supports three types of nodes, each serving different roles in the network. This guide covers how to run each node type in production environments.
Node Types
Submission Node Allows authorized users to submit polling station results and serves the HTTP API.
Observer Node Provides public, read-only access for transparency and independent verification.
Verification Node Cross-references submitted results with official sources and participates in reward distribution.
Running a Submission Node
Submission nodes are the core of the network, accepting result submissions and synchronizing with other nodes.
Prerequisites
Ensure configuration is ready
You should have a valid config.toml file: main_db = "sqlite://./data/blockchain.db"
private_db = "sqlite://./data/private.db"
http_addr = "0.0.0.0:9091"
node_addr = "0.0.0.0:9090"
Initialize the blockchain
If this is a new node, initialize the blockchain: cargo run -- init --source setup_constituencies.sql
Open firewall ports
Ensure ports 9090 (P2P) and 9091 (HTTP API) are accessible: sudo ufw allow 9090/tcp
sudo ufw allow 9091/tcp
Starting the Node
Using Cargo
Using Binary
Systemd Service
Run from the source directory: RUST_LOG = info cargo run --release -p submission -- --config config.toml
If you’ve installed the binary: RUST_LOG = info submission --config config.toml
Create a systemd service for automatic startup: /etc/systemd/system/ubu-submission.service
[Unit]
Description =Ubu-Block Submission Node
After =network.target
[Service]
Type =simple
User =ubu-block
WorkingDirectory =/opt/ubu-block
Environment = "RUST_LOG=info"
ExecStart =/usr/local/bin/submission --config /etc/ubu-block/config.toml
Restart =on-failure
RestartSec =10
[Install]
WantedBy =multi-user.target
Enable and start the service: sudo systemctl daemon-reload
sudo systemctl enable ubu-submission
sudo systemctl start ubu-submission
Expected Output
When the submission node starts successfully, you’ll see:
INFO submission] Starting an submission node at port 9090...
INFO submission] Starting an http server at port 9091...
Verifying the Node
Test that the node is running:
# Check P2P port
netstat -tuln | grep 9090
# Check HTTP API
curl http://localhost:9091/api/v1/health
Running an Observer Node
Observer nodes connect to submission nodes and provide read-only access to blockchain data.
Prerequisites
Identify a peer submission node
You need the address of a running submission node to connect to. For testing: 127.0.0.1:9090 For production: Use a public submission node address
Starting the Node
Observer nodes are lightweight and connect to existing submission nodes:
Using Cargo
Using Binary
Systemd Service
RUST_LOG = info cargo run --release -p observer
The observer node currently has the peer address hardcoded to 127.0.0.1:9090 in the source code (nodes/observer/src/main.rs:78).
/etc/systemd/system/ubu-observer.service
[Unit]
Description =Ubu-Block Observer Node
After =network.target
[Service]
Type =simple
User =ubu-block
WorkingDirectory =/opt/ubu-block
Environment = "RUST_LOG=info"
ExecStart =/usr/local/bin/observer
Restart =on-failure
RestartSec =10
[Install]
WantedBy =multi-user.target
Expected Output
INFO observer] Starting an observer node...
Observer Node Characteristics
Uses in-memory SQLite databases by default (for the current implementation)
Receives blockchain data from connected submission nodes
Provides read-only access for verification and transparency
Automatically synchronizes with the submission node
The current observer implementation uses in-memory databases, meaning data is lost on restart. For production use, modify the source to use persistent databases.
Running a Verification Node
Verification nodes cross-reference submitted results with official sources and participate in reward distribution.
Verification nodes are currently under development as part of the v0.4 and v0.5 roadmap.
Current Status
The verification node implementation is minimal:
nodes/verification/src/main.rs
fn main () {
println! ( "Hello, world!" );
}
Planned Features (v0.4 - v0.5)
Cross-reference submitted results with official IEBC sources
Participate in BFT consensus for result validation
Distribute rewards to accurate submissions
Maintain audit trail of verification activities
See the Roadmap for timeline details.
Running Multiple Nodes
You can run multiple nodes on the same machine for testing or redundancy.
Multi-Node Setup
Create separate configurations
# First submission node
cat > config1.toml << EOF
main_db = "sqlite://./data/blockchain.db"
private_db = "sqlite://./data/private.db"
http_addr = "127.0.0.1:9091"
node_addr = "127.0.0.1:9090"
EOF
# Second submission node
cat > config2.toml << EOF
main_db = "sqlite://./data/blockchain2.db"
private_db = "sqlite://./data/private2.db"
http_addr = "127.0.0.1:9093"
node_addr = "127.0.0.1:9092"
EOF
Start each node in separate terminals
Terminal 1: RUST_LOG = info cargo run --release -p submission -- --config config1.toml
Terminal 2: RUST_LOG = info cargo run --release -p submission -- --config config2.toml
Connect nodes as peers
Configure node 2 to connect to node 1 by adding to config2.toml: [[ peers ]]
name = "node1"
address = "127.0.0.1:9090"
Process Management
Using systemd (Recommended for Production)
Systemd provides automatic restarts, logging, and process management:
# Check status
sudo systemctl status ubu-submission
# View logs
sudo journalctl -u ubu-submission -f
# Restart node
sudo systemctl restart ubu-submission
# Stop node
sudo systemctl stop ubu-submission
Using tmux/screen
For development or temporary deployments:
# Start in tmux
tmux new -s ubu-block
RUST_LOG = info cargo run --release -p submission -- --config config.toml
# Detach: Ctrl+B, then D
# Reattach
tmux attach -t ubu-block
Using Docker
Create a Dockerfile:
FROM rust:1.85 as builder
WORKDIR /app
COPY . .
RUN cargo build --release -p submission
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y sqlite3 libssl3 && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/submission /usr/local/bin/
COPY config.toml /etc/ubu-block/config.toml
EXPOSE 9090 9091
CMD [ "submission" , "--config" , "/etc/ubu-block/config.toml" ]
Build and run:
docker build -t ubu-block:latest .
docker run -d -p 9090:9090 -p 9091:9091 -v $( pwd ) /data:/data ubu-block:latest
Monitoring Running Nodes
Health Checks
Submission nodes expose health endpoints:
# Check API health
curl http://localhost:9091/api/v1/health
# Check blockchain validity
cargo run -- validate
Log Monitoring
Monitor logs for issues:
# Systemd logs
sudo journalctl -u ubu-submission -f --since "10 minutes ago"
# Application logs (if logging to file)
tail -f /var/log/ubu-block/submission.log
Resource Monitoring
# CPU and memory usage
top -p $( pgrep submission )
# Network connections
ss -tulpn | grep submission
# Database size
du -sh data/ * .db
Graceful Shutdown
To stop a node gracefully:
Interactive
Systemd
Signal
Press Ctrl+C in the terminal running the node.
sudo systemctl stop ubu-submission
pkill -SIGTERM submission
Always perform a graceful shutdown to ensure database integrity. Avoid SIGKILL unless absolutely necessary.
Troubleshooting
Check the configuration file: Verify database files exist: Check logs for specific errors: RUST_LOG = debug cargo run --release -p submission -- --config config.toml
Find what’s using the port: Either stop the conflicting process or change the port in config.toml.
Verify network connectivity: Check firewall rules: Ensure peer address is correct in configuration.
Next Steps
Monitoring Monitor node health and performance
Maintenance Perform routine maintenance tasks