fix: Query all validators for blockchain state, use longest chain

Problem: When querying blockchain state via get_blockchain_state(),
the backend only queried validator-1 (via _get_healthy_validator()).
If validator-1 was behind other validators in block synchronization,
the backend would return stale data without the latest blocks.

This caused: Users' votes would be submitted to all validators and
included in blocks, but when querying the blockchain, the backend
would return an old state without those blocks.

Root cause: No block synchronization between validators yet. When a
validator creates a block, it doesn't immediately get to all peers.
So different validators can have different chain lengths.

Solution: Query ALL healthy validators for their blockchain state
and return the state from the one with the longest chain. This ensures
the client always gets the most up-to-date blockchain state.

Implementation:
- Loop through all healthy_validators
- Query each one's blockchain endpoint
- Track the state with the highest block count
- Return that state

This is a best-effort approach while block synchronization is being
established between validators.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Alexis Bruneteau 2025-11-07 17:07:34 +01:00
parent d7ec538ed2
commit 38369a7f88

View File

@ -360,21 +360,28 @@ class BlockchainClient:
"""
Get the current state of the blockchain for an election.
Queries ALL healthy validators and returns the state from the validator
with the longest chain (to ensure latest blocks).
Args:
election_id: Election ID
Returns:
Blockchain state with block count and verification status
"""
validator = self._get_healthy_validator()
if not validator:
if not self.healthy_validators:
return None
try:
if not self._client:
raise Exception("AsyncClient not initialized")
# Query blockchain info endpoint on validator
# Query all validators and get the one with longest chain
best_state = None
best_block_count = 0
for validator in self.healthy_validators:
try:
logger.debug(f"Querying blockchain state from {validator.node_id}")
response = await self._client.get(
f"{validator.rpc_url}/blockchain",
params={"election_id": election_id},
@ -382,11 +389,23 @@ class BlockchainClient:
)
response.raise_for_status()
return response.json()
state = response.json()
# Get block count from this validator
block_count = len(state.get("blocks", []))
logger.debug(f"{validator.node_id} has {block_count} blocks")
# Keep the state with the most blocks (longest chain)
if block_count > best_block_count:
best_state = state
best_block_count = block_count
logger.info(f"Using state from {validator.node_id} ({block_count} blocks)")
except Exception as e:
logger.warning(f"Failed to get blockchain state: {e}")
return None
logger.warning(f"Failed to get blockchain state from {validator.node_id}: {e}")
continue
return best_state if best_state else None
async def verify_blockchain_integrity(self, election_id: int) -> bool:
"""