fix: Properly format transaction data for PoA validators

Problem: Votes were being rejected by validators with 'Invalid data format'
error because the transaction data wasn't in the correct format.

Root cause: The validator's eth_sendTransaction endpoint expects the 'data'
field to be:
1. A hex string prefixed with '0x'
2. The hex-encoded JSON of a Transaction object containing:
   - voter_id
   - election_id
   - encrypted_vote
   - ballot_hash
   - timestamp

Solution:
- Update BlockchainClient.submit_vote() to properly encode transaction data
  as JSON, then hex-encode it with 0x prefix
- Add ballot_hash parameter to submit_vote() method
- Update both call sites in votes.py to pass ballot_hash
- Generate ballot_hash if not provided for safety

This ensures votes are now properly formatted and accepted by validators,
allowing them to be submitted to the blockchain instead of falling back to
local blockchain.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Alexis Bruneteau 2025-11-07 16:43:56 +01:00
parent 8582a2da62
commit 050f525b1b
2 changed files with 29 additions and 4 deletions

View File

@ -153,7 +153,8 @@ class BlockchainClient:
voter_id: str,
election_id: int,
encrypted_vote: str,
transaction_id: Optional[str] = None
transaction_id: Optional[str] = None,
ballot_hash: Optional[str] = None
) -> Dict[str, Any]:
"""
Submit a vote to the PoA blockchain network.
@ -161,8 +162,9 @@ class BlockchainClient:
Args:
voter_id: Voter identifier
election_id: Election ID
encrypted_vote: Encrypted vote (base64 or hex)
encrypted_vote: Encrypted vote data
transaction_id: Optional transaction ID (generated if not provided)
ballot_hash: Optional ballot hash for verification
Returns:
Transaction receipt with block hash and index
@ -179,6 +181,27 @@ class BlockchainClient:
import uuid
transaction_id = f"tx-{uuid.uuid4().hex[:12]}"
# Generate ballot hash if not provided
if not ballot_hash:
import hashlib
ballot_hash = hashlib.sha256(f"{voter_id}{election_id}{encrypted_vote}".encode()).hexdigest()
import time
# Create transaction data as JSON
tx_data = {
"voter_id": str(voter_id),
"election_id": int(election_id),
"encrypted_vote": str(encrypted_vote),
"ballot_hash": str(ballot_hash),
"timestamp": int(time.time())
}
# Encode transaction data as hex string with 0x prefix
import json
tx_json = json.dumps(tx_data)
data_hex = "0x" + tx_json.encode().hex()
# Prepare JSON-RPC request
rpc_request = {
"jsonrpc": "2.0",
@ -186,7 +209,7 @@ class BlockchainClient:
"params": [{
"from": voter_id,
"to": f"election-{election_id}",
"data": encrypted_vote,
"data": data_hex,
"gas": "0x5208"
}],
"id": transaction_id

View File

@ -130,7 +130,8 @@ async def submit_simple_vote(
submission_result = await poa_client.submit_vote(
voter_id=current_voter.id,
election_id=election_id,
encrypted_vote=ballot_hash, # Use ballot hash as data
encrypted_vote="", # Empty for MVP (not encrypted)
ballot_hash=ballot_hash,
transaction_id=transaction_id
)
blockchain_response = {
@ -272,6 +273,7 @@ async def submit_vote(
voter_id=current_voter.id,
election_id=vote_bulletin.election_id,
encrypted_vote=vote_bulletin.encrypted_vote,
ballot_hash=ballot_hash,
transaction_id=transaction_id
)