Elections are now immutably recorded to blockchain with:
- SHA-256 hash chain for integrity (prevents tampering)
- RSA-PSS signatures for authentication
- Candidate verification via SHA-256 hash
- Tamper detection on every verification
- Complete audit trail
Changes:
- backend/blockchain_elections.py: Core blockchain implementation (ElectionBlock, ElectionsBlockchain)
- backend/init_blockchain.py: Startup initialization to sync existing elections
- backend/services.py: ElectionService.create_election() with automatic blockchain recording
- backend/main.py: Added blockchain initialization on startup
- backend/routes/elections.py: Already had /api/elections/blockchain and /{id}/blockchain-verify endpoints
- test_blockchain_election.py: Comprehensive test suite for blockchain integration
- BLOCKCHAIN_ELECTION_INTEGRATION.md: Full technical documentation
- BLOCKCHAIN_QUICK_START.md: Quick reference guide
- BLOCKCHAIN_IMPLEMENTATION_SUMMARY.md: Implementation summary
API Endpoints:
- GET /api/elections/blockchain - Returns complete blockchain
- GET /api/elections/{id}/blockchain-verify - Verifies election integrity
Test:
python3 test_blockchain_election.py
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
77 lines
2.7 KiB
Python
77 lines
2.7 KiB
Python
"""
|
|
Initialize blockchain with existing elections from database.
|
|
|
|
This module ensures that when the backend starts, all elections in the database
|
|
are recorded to the blockchain if they aren't already.
|
|
"""
|
|
|
|
from sqlalchemy.orm import Session
|
|
from . import models
|
|
from .blockchain_elections import elections_blockchain, record_election_to_blockchain
|
|
from datetime import datetime
|
|
import json
|
|
|
|
|
|
def initialize_elections_blockchain(db: Session) -> None:
|
|
"""
|
|
Initialize the elections blockchain with all elections from database.
|
|
|
|
Called on backend startup to ensure all elections are immutably recorded.
|
|
Uses the elections_blockchain.blocks to check if an election is already recorded.
|
|
|
|
Args:
|
|
db: Database session
|
|
"""
|
|
# Get all elections from database
|
|
elections = db.query(models.Election).all()
|
|
|
|
if not elections:
|
|
print("No elections to record to blockchain")
|
|
return
|
|
|
|
# Check which elections are already on blockchain
|
|
existing_election_ids = {block.election_id for block in elections_blockchain.blocks}
|
|
|
|
# Record each election that isn't already on blockchain
|
|
for election in elections:
|
|
if election.id in existing_election_ids:
|
|
print(f"Election {election.id} already on blockchain, skipping")
|
|
continue
|
|
|
|
try:
|
|
# Get candidates for this election
|
|
candidates = db.query(models.Candidate).filter(
|
|
models.Candidate.election_id == election.id
|
|
).all()
|
|
|
|
candidates_data = [
|
|
{
|
|
"id": c.id,
|
|
"name": c.name,
|
|
"description": c.description or "",
|
|
"order": c.order or 0
|
|
}
|
|
for c in candidates
|
|
]
|
|
|
|
# Record to blockchain
|
|
record_election_to_blockchain(
|
|
election_id=election.id,
|
|
election_name=election.name,
|
|
election_description=election.description or "",
|
|
candidates=candidates_data,
|
|
start_date=election.start_date.isoformat(),
|
|
end_date=election.end_date.isoformat(),
|
|
is_active=election.is_active,
|
|
creator_id=0 # Database creation, no specific admin
|
|
)
|
|
print(f"✓ Recorded election {election.id} ({election.name}) to blockchain")
|
|
except Exception as e:
|
|
print(f"✗ Failed to record election {election.id} to blockchain: {e}")
|
|
|
|
# Verify blockchain integrity
|
|
if elections_blockchain.verify_chain_integrity():
|
|
print(f"✓ Blockchain integrity verified - {len(elections_blockchain.blocks)} blocks")
|
|
else:
|
|
print("✗ Blockchain integrity check failed!")
|