Skip to main content

Overview

Validation ensures that your blockchain maintains its integrity by verifying cryptographic signatures, hash chains, and data consistency. Regular validation confirms that no tampering has occurred.

Basic Validation

Run the validate command to check blockchain integrity:
ubu-block --config config.toml validate
Expected output:
INFO ubu_block] Blockchain is valid!

What Gets Validated

The validation process performs comprehensive checks:

1. Genesis Block Verification

  • Confirms genesis block exists at height 0
  • Verifies genesis block structure
  • Checks initial creator public key

2. Chain Continuity

For each block in sequence:
Block N-1 (hash: abc123...) → Block N (prev_hash: abc123...)
  • Each block’s prev_hash matches the previous block’s hash
  • Block heights increment sequentially
  • No gaps in the chain

3. Cryptographic Signatures

Every block’s signature is verified:
// Verification process
1. Extract public key from block
2. Reconstruct block data to be signed
3. Verify signature using Ed25519
4. Confirm signature matches block contents

4. Merkle Tree Verification

Results are verified against the Merkle root:
  • Reconstruct Merkle tree from block results
  • Compare calculated root with stored merkle_root
  • Ensures results haven’t been tampered with

5. Data Integrity

Validate result data:
  • Station IDs exist in database
  • Candidate IDs exist in database
  • Vote counts are non-negative
  • Timestamps are valid

Detecting Tampering

Let’s demonstrate how validation detects tampering:
1

Check initial state

First, validate the blockchain:
ubu-block --config config.toml validate
Output: Blockchain is valid!
2

Attempt tampering

Open the database and modify a vote count:
sqlite3 data/blockchain.db
UPDATE "results" SET "votes" = 71 WHERE _rowid_ = 1;
3

Query shows tampered data

Query the blockchain - it will show the modified value:
ubu-block query -q "SELECT * FROM results WHERE _rowid_ = 1"
The tampered value (71) appears in the output.
4

Validation catches tampering

Run validation again:
ubu-block validate
Output:
thread 'main' panicked at 'Could not verify block, 
found 0e70cebe0ab3bd8c3606a08d26483d092534eea4ccdb7816fc2692aee5ed3109, 
block: Block { ... CandidateResult { station_id: 22113056303301, 
candidate_id: 1, votes: 71 }]......}', src/db.rs:189:17
The validation fails because:
  • The Merkle root no longer matches the results
  • The block hash doesn’t match the expected hash
This demonstrates Ubu-Block’s core principle: No “fungua servers” - data cannot be secretly modified without detection.

Validation Algorithm

The validation process follows this algorithm:
// Simplified validation logic
pub async fn is_valid(&self) -> Result<bool, ChainError> {
    let blocks = self.get_all_blocks().await?;
    
    // Verify genesis block
    let genesis = &blocks[0];
    verify_genesis(genesis)?;
    
    // Verify each subsequent block
    for i in 1..blocks.len() {
        let current = &blocks[i];
        let previous = &blocks[i-1];
        
        // Check chain continuity
        assert_eq!(current.prev_hash, previous.hash);
        assert_eq!(current.height, previous.height + 1);
        
        // Verify signature
        verify_signature(current)?;
        
        // Verify Merkle root
        verify_merkle_root(current)?;
    }
    
    Ok(true)
}

Validation Frequency

When to Validate

When your node receives blocks from peers, validate before accepting:
async fn handle_new_block(&mut self, block: Block) -> Result<(), ChainError> {
    // Add block
    self.add_block(&block).await?;
    
    // Validate immediately
    assert!(self.is_valid().await?);
    
    Ok(())
}
Run periodic validation to detect corruption:
# Cron job example (daily at 2 AM)
0 2 * * * /usr/local/bin/ubu-block --config /path/config.toml validate
Validate after any manual database operations or maintenance.
Validate before:
  • Generating reports
  • Syncing with new peers
  • Backup operations

Performance Considerations

Validation complexity:
  • Time Complexity: O(n) where n is the number of blocks
  • Space Complexity: O(1) - processes blocks sequentially
For large blockchains:
// Validate only recent blocks
pub async fn validate_recent(&self, block_count: usize) -> Result<bool, ChainError> {
    let height = self.get_height().await?;
    let start_height = height.saturating_sub(block_count as i64);
    
    // Validate from start_height to current height
    self.validate_range(start_height, height).await
}

Error Types

Invalid Signature

Error: Signature verification failed for block at height 42
Cause: Block signature doesn’t match the public key or content Resolution:
  • Block may be corrupted
  • Wrong public key used
  • Check if block was transmitted correctly

Broken Chain

Error: Hash mismatch at height 15
Expected: abc123...
Found: def456...
Cause: Previous hash doesn’t link correctly Resolution:
  • Database corruption
  • Missing blocks
  • Attempt to restore from backup or resync

Merkle Root Mismatch

Error: Merkle root verification failed
Calculated: 0e70cebe...
Stored: 1a8f3d9c...
Cause: Results don’t match the Merkle root in the block Resolution:
  • Results table was modified
  • Restore results from the correct source
  • Resync from trusted peer

Validation in P2P Networks

When running as a P2P node, validation occurs automatically:
impl BlockChain {
    async fn handle_new_block(&mut self, block: Block) -> Result<i64, ChainError> {
        log::info!("Processing new block: {}", block.hash);
        
        // Add block to chain
        self.add_block_to_chain(block).await?;
        
        // Implicit validation during add
        // Invalid blocks are rejected
        
        Ok(block.height)
    }
}
Invalid blocks are rejected before being added to your local blockchain. This prevents propagation of corrupted data.

Validation Reporting

For detailed validation reports, use direct database queries:
-- Check for hash chain continuity
SELECT 
    b1.height as block,
    b1.hash as hash,
    b2.prev_hash as next_prev_hash,
    CASE 
        WHEN b1.hash = b2.prev_hash THEN 'OK'
        ELSE 'BROKEN'
    END as status
FROM blocks b1
JOIN blocks b2 ON b2.height = b1.height + 1
ORDER BY b1.height;

Recovering from Validation Failures

Option 1: Restore from Backup

If you have a known-good backup:
cp backup/blockchain.db data/blockchain.db
ubu-block validate

Option 2: Resync from Network

Resync the blockchain from trusted peers:
# Remove corrupted data
rm data/blockchain.db

# Initialize fresh
ubu-block init --source setup.sql

# Connect to trusted peer
ubu-block connect --peer trusted-node.example.com:8333

Option 3: Manual Repair

For specific corruption, manual SQL repair may be possible (advanced users only).

Best Practices

  1. Regular Validation: Run validation at least daily
  2. Automated Monitoring: Set up alerts for validation failures
  3. Backup Strategy: Maintain verified backups
  4. Immutable Storage: Use read-only filesystems when possible
  5. Audit Logs: Keep logs of all validation runs

Next Steps

Build docs developers (and LLMs) love