Skip to main content

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

1

Ensure configuration is ready

You should have a valid config.toml file:
config.toml
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"
2

Initialize the blockchain

If this is a new node, initialize the blockchain:
cargo run -- init --source setup_constituencies.sql
3

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

Run from the source directory:
RUST_LOG=info cargo run --release -p submission -- --config config.toml

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

1

Create data directory

mkdir -p data
2

Identify a peer submission node

You need the address of a running submission node to connect to.For testing: 127.0.0.1:9090For production: Use a public submission node address

Starting the Node

Observer nodes are lightweight and connect to existing submission nodes:
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).

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

1

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
2

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
3

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

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:
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:
Press Ctrl+C in the terminal running the node.
Always perform a graceful shutdown to ensure database integrity. Avoid SIGKILL unless absolutely necessary.

Troubleshooting

Check the configuration file:
cat config.toml
Verify database files exist:
ls -lh data/
Check logs for specific errors:
RUST_LOG=debug cargo run --release -p submission -- --config config.toml
Find what’s using the port:
sudo lsof -i :9090
Either stop the conflicting process or change the port in config.toml.
Verify network connectivity:
telnet peer-address 9090
Check firewall rules:
sudo ufw status
Ensure peer address is correct in configuration.

Next Steps

Monitoring

Monitor node health and performance

Maintenance

Perform routine maintenance tasks

Build docs developers (and LLMs) love