feat: Add transaction broadcasting between PoA validators
Problem: Votes were being submitted to one validator but not shared with
other validators, preventing them from being included in blocks.
Root cause: When a validator received a transaction via eth_sendTransaction,
it added it to its pending_transactions pool but did NOT broadcast it to
peer validators. Only blocks were being broadcast.
This meant:
- validator-1 receives vote → adds to pending_transactions
- validator-2 (responsible for next block) never receives the vote
- validator-2 can't include vote in block because it doesn't know about it
- Result: votes sit in pending queue forever
Solution:
- Add broadcast_transaction() method following same pattern as broadcast_block()
- Broadcast transaction to all known peers via /p2p/new_transaction endpoint
- Call broadcast on receipt of each transaction
- Peer validators receive and add to their pending_transactions pool
- All validators now have same pending transactions
- Any validator can create blocks with all pending transactions
The /p2p/new_transaction endpoint already existed, so validators can now
receive and process transactions from peers.
This fixes the issue where votes were submitted successfully but never
appeared on the blockchain.
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
8be804f7c6
commit
6cd555a552
@ -411,6 +411,38 @@ class PoAValidator:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error creating block: {e}")
|
logger.error(f"Error creating block: {e}")
|
||||||
|
|
||||||
|
async def broadcast_transaction(self, transaction: Transaction) -> None:
|
||||||
|
"""Broadcast transaction to all peers"""
|
||||||
|
if not self.peer_connections:
|
||||||
|
logger.debug("No peers to broadcast transaction to")
|
||||||
|
return
|
||||||
|
|
||||||
|
payload = json.dumps({
|
||||||
|
"type": "new_transaction",
|
||||||
|
"transaction": {
|
||||||
|
"voter_id": transaction.voter_id,
|
||||||
|
"election_id": transaction.election_id,
|
||||||
|
"encrypted_vote": transaction.encrypted_vote,
|
||||||
|
"ballot_hash": transaction.ballot_hash,
|
||||||
|
"proof": transaction.proof,
|
||||||
|
"timestamp": transaction.timestamp
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
for node_id, peer_url in self.peer_connections.items():
|
||||||
|
try:
|
||||||
|
async with session.post(
|
||||||
|
f"{peer_url}/p2p/new_transaction",
|
||||||
|
data=payload,
|
||||||
|
headers={"Content-Type": "application/json"},
|
||||||
|
timeout=aiohttp.ClientTimeout(total=5)
|
||||||
|
) as resp:
|
||||||
|
if resp.status == 200:
|
||||||
|
logger.debug(f"Transaction broadcast to {node_id}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Failed to broadcast transaction to {node_id}: {e}")
|
||||||
|
|
||||||
async def broadcast_block(self, block: Block) -> None:
|
async def broadcast_block(self, block: Block) -> None:
|
||||||
"""Broadcast block to all peers"""
|
"""Broadcast block to all peers"""
|
||||||
if not self.peer_connections:
|
if not self.peer_connections:
|
||||||
@ -586,6 +618,9 @@ async def handle_json_rpc(request: dict):
|
|||||||
transaction = Transaction(**tx_dict)
|
transaction = Transaction(**tx_dict)
|
||||||
tx_id = validator.add_transaction(transaction)
|
tx_id = validator.add_transaction(transaction)
|
||||||
|
|
||||||
|
# Broadcast transaction to other validators
|
||||||
|
asyncio.create_task(validator.broadcast_transaction(transaction))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"result": tx_id,
|
"result": tx_id,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user