Skip to main content
This guide walks you through setting up Ubu-Block, initializing your first blockchain, submitting election results, and validating the chain. You’ll see firsthand how the immutable ledger prevents tampering.

Prerequisites

Before you begin, make sure you have:
  • Rust and Cargo installed (version 1.70 or later)
  • Git for cloning the repository
  • Basic familiarity with command-line tools
New to Rust? Install it from rustup.rs. It takes about 5 minutes.

Set up your environment

1

Clone the repository

Clone the Ubu-Block repository and navigate into it:
git clone https://github.com/koleshjr/ubu-block
cd ubu-block
2

Create the data directory

Set up the directory structure for your blockchain databases:
mkdir data
This creates a data/ folder where your blockchain and private key databases will be stored.
3

Copy database files

Initialize the SQLite database files from the empty templates:
cp crates/database/sql/empty.db data/blockchain.db
cp crates/database/sql/empty.db data/private.db
These two databases serve different purposes:
  • blockchain.db stores the public blockchain data
  • private.db stores your node’s cryptographic keys

Initialize your blockchain

Now you’ll create the genesis block and set up the regional data structure:
cargo run --bin ubu-block-cli -- -c config.toml init --source apps/cli/init.sql
You should see:
INFO ubu_block] Blockchain was successfully initialized!
The init.sql file contains sample constituency, ward, and station data. You can customize this for your region.

Submit your first election results

Add blocks to the blockchain with sample election data:
cargo run --bin ubu-block-cli -- -c config.toml submit http://localhost:8080 022113056303301 1 66
cargo run --bin ubu-block-cli -- -c config.toml submit http://localhost:8080 022113056303301 2 21
These commands submit to a local node. Make sure you have a submission node running on port 8080, or the commands will fail.
Each successful submission returns:
Block submitted successfully
The command format is:
cargo run --bin ubu-block-cli -- submit <node-address> <station-id> <candidate-id> <votes>

Validate the blockchain

Verify that your blockchain is cryptographically valid:
cargo run --bin ubu-block-cli -- -c config.toml validate
You should see:
INFO ubu_block] Blockchain is valid!
This command verifies:
  • All block hashes are correctly computed
  • The chain of hashes links properly
  • All signatures are valid
  • Merkle roots match the transaction data

Test tamper detection

Let’s verify that the blockchain actually prevents tampering:
1

Modify a vote count

Open data/blockchain.db with any SQLite editor and run:
UPDATE "results" SET "votes" = 71 WHERE _rowid_ = 1
This changes one candidate’s vote count from 21 to 71.
2

Attempt validation

Try validating the blockchain again:
cargo run --bin ubu-block-cli -- -c config.toml validate
The validation will fail with a panic showing the hash mismatch:
thread 'main' panicked at 'Could not verify block, found 0e70cebe0ab3bd8c3606a08d26483d092534eea4ccdb7816fc2692aee5ed3109, block: Block {...
3

Restore the database

The blockchain detected the tampering! Restore your database:
cp crates/database/sql/empty.db data/blockchain.db
cp crates/database/sql/empty.db data/private.db
This demonstrates Ubu-Block’s core promise: no “fungua server” shenanigans. Any tampering is immediately detectable.

Query election results

Run SQL queries directly on the blockchain:
cargo run --bin ubu-block-cli -- -c config.toml query -q "SELECT 
  c.name as candidate,
  SUM(votes) as votes,
  ward_name as ward,
  constituency_name as constituency,
  county_name as county,
  parties.title as party
FROM results
  INNER JOIN stations ON stations.id = results.station_id
  INNER JOIN candidates c ON c.id = results.candidate_id
  INNER JOIN wards on stations.ward_code = wards.ward_code
  INNER JOIN parties ON parties.id = c.party_id
  INNER JOIN constituencies ON wards.constituency_code = constituencies.constituency_code
  INNER JOIN counties ON constituencies.county_code = counties.county_code
WHERE position_type = 'Mp' and constituency = 'Juja' 
GROUP BY candidate;"
You’ll see formatted results:
+--------+--------------+----------+-----------+-------+-------+
| county | constituency |   ward   | candidate | party | votes |
+--------+--------------+----------+-----------+-------+-------+
| Kiambu |     Juja     | Kalimoni |   Omosh   |  ODM  |  21   |
| Kiambu |     Juja     | Kalimoni |   Mwas    |  PNU  |  66   |
+--------+--------------+----------+-----------+-------+-------+

Next steps

Node types

Learn about Submission, Observer, and Verification nodes

Submit results

Learn how to submit results to a live network

Run a node

Set up your own Observer or Submission node

API reference

Explore the REST API for programmatic access

Build docs developers (and LLMs) love