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:
parent
d7ec538ed2
commit
38369a7f88
@ -360,33 +360,52 @@ 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")
|
||||
if not self._client:
|
||||
raise Exception("AsyncClient not initialized")
|
||||
|
||||
# Query blockchain info endpoint on validator
|
||||
response = await self._client.get(
|
||||
f"{validator.rpc_url}/blockchain",
|
||||
params={"election_id": election_id},
|
||||
timeout=self.timeout
|
||||
)
|
||||
# Query all validators and get the one with longest chain
|
||||
best_state = None
|
||||
best_block_count = 0
|
||||
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
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},
|
||||
timeout=self.timeout
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to get blockchain state: {e}")
|
||||
return None
|
||||
response.raise_for_status()
|
||||
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 from {validator.node_id}: {e}")
|
||||
continue
|
||||
|
||||
return best_state if best_state else None
|
||||
|
||||
async def verify_blockchain_integrity(self, election_id: int) -> bool:
|
||||
"""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user