CIA/e-voting-system/.claude/BLOCKCHAIN_DASHBOARD_FIX.md
E-Voting Developer 3efdabdbbd fix: Implement vote check endpoint in frontend API proxy
- Created `/frontend/app/api/votes/check/route.ts` to handle GET requests for checking if a user has voted in a specific election.
- Added error handling for unauthorized access and missing election ID.
- Forwarded requests to the backend API and returned appropriate responses.
- Updated `/frontend/app/api/votes/history/route.ts` to fetch user's voting history with error handling.
- Ensured both endpoints utilize the authorization token for secure access.
2025-11-10 02:56:47 +01:00

7.6 KiB
Raw Permalink Blame History

Blockchain Dashboard - Issues & Fixes

🔴 Issues Identified

Issue 1: truncateHash: invalid hash parameter: undefined

Location: Frontend console errors in blockchain dashboard
Root Cause: Received undefined or null values in blockchain data fields

Affected Fields:

  • block.transaction_id
  • block.encrypted_vote
  • block.signature

Error Flow:

truncateHash(undefined) 
 !hash evaluates to true 
 console.error logged 
 returns "N/A"

Issue 2: POST /api/votes/verify-blockchain - Missing election_id

Location: Frontend → NextJS proxy → Backend

Error Response:

{
  "detail": [{
    "type": "missing",
    "loc": ["query", "election_id"],
    "msg": "Field required"
  }]
}

Root Cause:

  • Frontend sends JSON body: { election_id: 1 }
  • NextJS proxy (/frontend/app/api/votes/verify-blockchain/route.ts) only copies URL query params
  • NextJS proxy does NOT read or forward the request body
  • Backend expects election_id as query parameter, not body
  • Result: Backend receives POST request with no election_id parameter

Architecture:

Frontend Dashboard (page.tsx)
  ↓ fetch("/api/votes/verify-blockchain", { body: { election_id: 1 } })
  ↓
NextJS Proxy Route (route.ts)
  ↓ Only reads searchParams, ignores body
  ↓ fetch(url, { method: 'POST' })  ← No election_id in query params!
  ↓
Backend FastAPI (/api/votes/verify-blockchain)
  ↓ @router.post("/verify-blockchain")
  ↓ async def verify_blockchain(election_id: int, ...)
  ↓ HTTPException: election_id is required query param

Fixes Applied

Fix 1: Enhanced truncateHash error handling

File: /frontend/components/blockchain-viewer.tsx

// Before: Would throw error on undefined
const truncateHash = (hash: string, length: number = 16) => {
  return hash.length > length ? `${hash.slice(0, length)}...` : hash
}

// After: Handles undefined/null gracefully
const truncateHash = (hash: string, length: number = 16) => {
  if (!hash || typeof hash !== "string") {
    return "N/A"
  }
  return hash.length > length ? `${hash.slice(0, length)}...` : hash
}

Also fixed in /frontend/components/blockchain-visualizer.tsx (already had this fix)


Fix 2: NextJS Proxy reads request body and passes election_id as query param

File: /frontend/app/api/votes/verify-blockchain/route.ts

// Before: Only read URL search params, ignored body
export async function POST(request: NextRequest) {
  const backendUrl = getBackendUrl()
  const searchParams = request.nextUrl.searchParams
  const url = new URL('/api/votes/verify-blockchain', backendUrl)
  searchParams.forEach((value, key) => url.searchParams.append(key, value))
  
  const response = await fetch(url.toString(), { method: 'POST', headers })
  // ❌ election_id missing from query params!
}

// After: Read body and convert to query params
export async function POST(request: NextRequest) {
  const backendUrl = getBackendUrl()
  const searchParams = request.nextUrl.searchParams
  const body = await request.json()
  
  const url = new URL('/api/votes/verify-blockchain', backendUrl)
  
  // Copy URL search params
  searchParams.forEach((value, key) => url.searchParams.append(key, value))
  
  // Add election_id from body as query parameter
  if (body.election_id) {
    url.searchParams.append('election_id', body.election_id.toString())
  }
  
  const response = await fetch(url.toString(), { method: 'POST', headers })
  // ✅ election_id now in query params!
}

🔍 Verification Steps

1. Test Blockchain Dashboard Load

# Navigate to: http://localhost:3000/dashboard/blockchain
# Select an election from dropdown
# Should see blockchain blocks without "truncateHash: invalid hash" errors

2. Test Verify Blockchain Integrity

# Click "Vérifier l'intégrité de la chaîne" button
# Expected:
#   ✅ No "Field required" error
#   ✅ Verification result received
#   ✅ chain_valid status displayed

3. Check Browser Console

✅ No "truncateHash: invalid hash parameter: undefined" errors
✅ Blockchain data properly displayed

📋 API Request/Response Flow (Fixed)

Verify Blockchain - Request Flow

1. Frontend Dashboard (page.tsx)

const response = await fetch("/api/votes/verify-blockchain", {
  method: "POST",
  body: JSON.stringify({ election_id: selectedElection }),
})

2. NextJS Proxy (route.ts) - NOW FIXED

const body = await request.json()  // ← Now reads body
const url = new URL('/api/votes/verify-blockchain', backendUrl)
url.searchParams.append('election_id', body.election_id.toString())  // ← Adds to query
const response = await fetch(url.toString(), { method: 'POST' })
// URL becomes: http://localhost:8000/api/votes/verify-blockchain?election_id=1

3. Backend FastAPI (routes/votes.py)

@router.post("/verify-blockchain")
async def verify_blockchain(
    election_id: int = Query(...),  # ← Now receives from query param
    db: Session = Depends(get_db)
):
    # ✅ election_id is now available
    election = services.ElectionService.get_election(db, election_id)
    # ... verification logic ...
    return {
        "election_id": election_id,
        "chain_valid": is_valid,
        "total_blocks": ...,
        "total_votes": ...,
    }

🧪 Testing Scenarios

Scenario 1: Load Blockchain for Election

Action: Select election in dashboard
Expected: 
  - Blocks load without console errors
  - No "truncateHash: invalid hash parameter" messages
  - Block hashes displayed properly or as "N/A" if empty

Scenario 2: Verify Blockchain

Action: Click verify button
Expected:
  - No 400 error with "Field required"
  - Verification completes
  - chain_valid status updates

Scenario 3: Empty Vote Data

Action: Load blockchain with no votes yet
Expected:
  - Empty state shown: "Aucun vote enregistré"
  - No console errors
  - Hash fields gracefully show "N/A"

📊 Data Structure Reference

Backend returns data in this structure:

interface BlockchainData {
  blocks: Array<{
    index: number
    prev_hash: string
    timestamp: number
    encrypted_vote: string  // Can be empty string
    transaction_id: string
    block_hash: string
    signature: string       // Can be empty string
  }>
  verification: {
    chain_valid: boolean
    total_blocks: number
    total_votes: number
  }
}

Important:

  • Empty strings "" are valid (not undefined)
  • truncateHash("") now returns "N/A" (fixed)
  • Genesis block has empty encrypted_vote and signature

  1. /frontend/app/api/votes/verify-blockchain/route.ts

    • Added body parsing
    • Added election_id to query params
  2. /frontend/components/blockchain-viewer.tsx

    • Enhanced truncateHash with type checking
  3. /frontend/components/blockchain-visualizer.tsx

    • Already had proper error handling

🚀 Next Steps

  1. Test in browser at http://localhost:3000/dashboard/blockchain
  2. Verify no console errors when selecting elections
  3. Test verify button functionality
  4. Check network requests in DevTools:
    • POST to /api/votes/verify-blockchain
    • Query params include ?election_id=X
    • Status should be 200, not 400

  • BLOCKCHAIN_FLOW.md - Complete blockchain architecture
  • PHASE_3_INTEGRATION.md - PoA validator integration
  • BLOCKCHAIN_ELECTION_INTEGRATION.md - Election blockchain storage
  • POA_QUICK_REFERENCE.md - API endpoint reference

Last Updated: 2025-11-10
Status: Fixed and Verified