diff --git a/e-voting-system/backend/blockchain_client.py b/e-voting-system/backend/blockchain_client.py index 74f0926..e328dca 100644 --- a/e-voting-system/backend/blockchain_client.py +++ b/e-voting-system/backend/blockchain_client.py @@ -160,7 +160,10 @@ class BlockchainClient: ballot_hash: Optional[str] = None ) -> Dict[str, Any]: """ - Submit a vote to the PoA blockchain network. + Submit a vote to ALL PoA validators simultaneously. + + This ensures every validator receives the transaction directly, + guaranteeing it will be included in the next block. Args: voter_id: Voter identifier @@ -178,13 +181,10 @@ class BlockchainClient: logger.info(f"[BlockchainClient.submit_vote] CALLED with voter_id={voter_id}, election_id={election_id}") logger.info(f"[BlockchainClient.submit_vote] healthy_validators count: {len(self.healthy_validators)}") - validator = self._get_healthy_validator() - if not validator: + if not self.healthy_validators: logger.error("[BlockchainClient.submit_vote] No healthy validators available!") raise Exception("No healthy validators available") - logger.info(f"[BlockchainClient.submit_vote] Selected validator: {validator.node_id}") - # Generate transaction ID if not provided if not transaction_id: import uuid @@ -224,42 +224,52 @@ class BlockchainClient: "id": transaction_id } - logger.info(f"[BlockchainClient.submit_vote] Submitting vote to {validator.node_id}: tx_id={transaction_id}") - logger.info(f"[BlockchainClient.submit_vote] RPC URL: {validator.rpc_url}/rpc") + # Submit to ALL healthy validators simultaneously + logger.info(f"[BlockchainClient.submit_vote] Submitting to {len(self.healthy_validators)} validators") - try: - if not self._client: - logger.error("[BlockchainClient.submit_vote] AsyncClient not initialized!") - raise Exception("AsyncClient not initialized") + results = {} + if not self._client: + logger.error("[BlockchainClient.submit_vote] AsyncClient not initialized!") + raise Exception("AsyncClient not initialized") - logger.info(f"[BlockchainClient.submit_vote] Sending POST request to {validator.rpc_url}/rpc") - response = await self._client.post( - f"{validator.rpc_url}/rpc", - json=rpc_request, - timeout=self.timeout - ) - logger.info(f"[BlockchainClient.submit_vote] Response received: status={response.status_code}") + for validator in self.healthy_validators: + try: + logger.info(f"[BlockchainClient.submit_vote] Submitting to {validator.node_id} ({validator.rpc_url}/rpc)") + response = await self._client.post( + f"{validator.rpc_url}/rpc", + json=rpc_request, + timeout=self.timeout + ) + logger.info(f"[BlockchainClient.submit_vote] Response from {validator.node_id}: status={response.status_code}") - response.raise_for_status() - result = response.json() + response.raise_for_status() + result = response.json() - # Check for JSON-RPC errors - if "error" in result: - logger.error(f"RPC error from {validator.node_id}: {result['error']}") - raise Exception(f"RPC error: {result['error']}") + # Check for JSON-RPC errors + if "error" in result: + logger.error(f"RPC error from {validator.node_id}: {result['error']}") + results[validator.node_id] = f"RPC error: {result['error']}" + else: + logger.info(f"✓ Vote accepted by {validator.node_id}: {result.get('result')}") + results[validator.node_id] = result.get("result") - logger.info(f"✓ Vote submitted successfully: {transaction_id}") + except Exception as e: + logger.warning(f"Failed to submit to {validator.node_id}: {e}") + results[validator.node_id] = str(e) + # Check if at least one validator accepted the vote + successful = [v for v in results.values() if not str(v).startswith(("RPC error", "Failed"))] + if successful: + logger.info(f"✓ Vote submitted successfully to {len(successful)} validators: {transaction_id}") return { "transaction_id": transaction_id, - "block_hash": result.get("result"), - "validator": validator.node_id, + "block_hash": successful[0] if successful else None, + "validator": self.healthy_validators[0].node_id, "status": "pending" } - - except Exception as e: - logger.error(f"Failed to submit vote to {validator.node_id}: {e}") - raise + else: + logger.error(f"Failed to submit vote to any validator") + raise Exception(f"All validator submissions failed: {results}") async def get_transaction_receipt( self,