@@ -1749,8 +1749,11 @@ impl SimplifiedP2P {
17491749
17501750 // REMOVED: start_kademlia_peer_discovery was a stub, now using Kademlia fields directly in PeerInfo
17511751
1752- /// Broadcast block data
1752+ /// Broadcast block data with parallel sending but synchronous completion
17531753 pub fn broadcast_block ( & self , height : u64 , block_data : Vec < u8 > ) -> Result < ( ) , String > {
1754+ use std:: sync:: Arc ;
1755+ use std:: thread;
1756+
17541757 // CRITICAL FIX: Use CACHED validated active peers for broadcast performance
17551758 // This ensures we broadcast to all REAL peers, with 30s cache for performance
17561759 let validated_peers = self . get_validated_active_peers ( ) ;
@@ -1769,7 +1772,11 @@ impl SimplifiedP2P {
17691772 println ! ( "[P2P] 📡 Broadcasting block #{} to {} validated peers" , height, validated_peers. len( ) ) ;
17701773 }
17711774
1772- // In production: Actually send block data to peers
1775+ // CRITICAL FIX: Parallel broadcast with synchronous completion
1776+ // Like Solana: send to all peers in parallel but wait for completion
1777+ let block_data = Arc :: new ( block_data) ;
1778+ let mut handles = Vec :: new ( ) ;
1779+
17731780 for peer in validated_peers. iter ( ) {
17741781 // Filter by node type for efficiency
17751782 let should_send = match ( & self . node_type , & peer. node_type ) {
@@ -1779,22 +1786,79 @@ impl SimplifiedP2P {
17791786 } ;
17801787
17811788 if should_send {
1782- // PRODUCTION: Real network send via HTTP POST
1783- let block_msg = NetworkMessage :: Block {
1784- height,
1785- data : block_data. clone ( ) ,
1786- block_type : "micro" . to_string ( ) ,
1787- } ;
1788- // PRODUCTION DEBUG: Log block size and destination
1789- if height % 10 == 0 || height <= 5 {
1790- println ! ( "[P2P] → Sending Block #{} to {} ({} bytes)" ,
1791- height, peer. addr, block_data. len( ) ) ;
1789+ let peer_addr = peer. addr . clone ( ) ;
1790+ let block_data_clone = Arc :: clone ( & block_data) ;
1791+
1792+ // Spawn thread for parallel sending
1793+ let handle = thread:: spawn ( move || {
1794+ use std:: time:: Duration ;
1795+
1796+ // Create message
1797+ let block_msg = NetworkMessage :: Block {
1798+ height,
1799+ data : ( * block_data_clone) . clone ( ) ,
1800+ block_type : "micro" . to_string ( ) ,
1801+ } ;
1802+
1803+ // Serialize
1804+ let message_json = match serde_json:: to_value ( & block_msg) {
1805+ Ok ( json) => json,
1806+ Err ( e) => {
1807+ println ! ( "[P2P] ❌ Serialize failed: {}" , e) ;
1808+ return Err ( format ! ( "Serialize failed: {}" , e) ) ;
1809+ }
1810+ } ;
1811+
1812+ // Send with fast timeout
1813+ let peer_ip = peer_addr. split ( ':' ) . next ( ) . unwrap_or ( & peer_addr) ;
1814+ let url = format ! ( "http://{}:8001/api/v1/p2p/message" , peer_ip) ;
1815+
1816+ let client = reqwest:: blocking:: Client :: builder ( )
1817+ . timeout ( Duration :: from_secs ( 3 ) ) // Fast timeout for parallel sending
1818+ . connect_timeout ( Duration :: from_secs ( 1 ) )
1819+ . tcp_nodelay ( true )
1820+ . build ( )
1821+ . map_err ( |e| format ! ( "Client failed: {}" , e) ) ?;
1822+
1823+ client. post ( & url)
1824+ . json ( & message_json)
1825+ . send ( )
1826+ . map_err ( |e| format ! ( "Send to {} failed: {}" , peer_ip, e) ) ?;
1827+
1828+ Ok ( ( ) )
1829+ } ) ;
1830+
1831+ handles. push ( ( peer. addr . clone ( ) , handle) ) ;
1832+ }
1833+ }
1834+
1835+ // Wait for all sends to complete (but don't fail if some fail)
1836+ let mut success_count = 0 ;
1837+ let total = handles. len ( ) ;
1838+
1839+ for ( peer_addr, handle) in handles {
1840+ match handle. join ( ) {
1841+ Ok ( Ok ( ( ) ) ) => success_count += 1 ,
1842+ Ok ( Err ( e) ) => {
1843+ if height <= 5 || height % 10 == 0 {
1844+ println ! ( "[P2P] ⚠️ Failed to send block #{} to {}: {}" , height, peer_addr, e) ;
1845+ }
17921846 }
1793- self . send_network_message ( & peer . addr , block_msg ) ;
1847+ Err ( _ ) => println ! ( "[P2P] ⚠️ Thread panicked for {}" , peer_addr ) ,
17941848 }
17951849 }
17961850
1797- Ok ( ( ) )
1851+ // Success if at least one peer received the block
1852+ if success_count > 0 {
1853+ if height <= 5 || height % 10 == 0 {
1854+ println ! ( "[P2P] ✅ Block #{} sent to {}/{} peers" , height, success_count, total) ;
1855+ }
1856+ Ok ( ( ) )
1857+ } else if total > 0 {
1858+ Err ( format ! ( "Failed to send block #{} to any peer" , height) )
1859+ } else {
1860+ Ok ( ( ) ) // No peers to send to
1861+ }
17981862 }
17991863
18001864 /// API DEADLOCK FIX: Get cached network height WITHOUT triggering sync
@@ -5676,6 +5740,50 @@ impl SimplifiedP2P {
56765740 Ok ( ( ) )
56775741 }
56785742
5743+ /// Send network message SYNCHRONOUSLY for critical messages (blocks)
5744+ /// Uses blocking HTTP client to ensure delivery before returning
5745+ pub fn send_network_message_sync ( & self , peer_addr : & str , message : NetworkMessage ) -> Result < ( ) , String > {
5746+ use std:: time:: Duration ;
5747+
5748+ // Only use for critical messages
5749+ let is_critical = matches ! ( message, NetworkMessage :: Block { .. } ) ;
5750+ if !is_critical {
5751+ // Non-critical messages use async version
5752+ self . send_network_message ( peer_addr, message) ;
5753+ return Ok ( ( ) ) ;
5754+ }
5755+
5756+ // Serialize message
5757+ let message_json = serde_json:: to_value ( & message)
5758+ . map_err ( |e| format ! ( "Failed to serialize: {}" , e) ) ?;
5759+
5760+ // Extract IP (skip pseudonym resolution for sync context)
5761+ let peer_ip = peer_addr. split ( ':' ) . next ( ) . unwrap_or ( peer_addr) ;
5762+ let url = format ! ( "http://{}:8001/api/v1/p2p/message" , peer_ip) ;
5763+
5764+ // CRITICAL: Use blocking HTTP client for synchronous delivery
5765+ // This ensures block is delivered before we continue
5766+ let client = reqwest:: blocking:: Client :: builder ( )
5767+ . timeout ( Duration :: from_secs ( 5 ) ) // Fast timeout for local network
5768+ . connect_timeout ( Duration :: from_secs ( 2 ) )
5769+ . tcp_nodelay ( true ) // Disable Nagle's algorithm for faster delivery
5770+ . build ( )
5771+ . map_err ( |e| format ! ( "Client build failed: {}" , e) ) ?;
5772+
5773+ // Send synchronously
5774+ let response = client
5775+ . post ( & url)
5776+ . json ( & message_json)
5777+ . send ( )
5778+ . map_err ( |e| format ! ( "Send failed to {}: {}" , peer_ip, e) ) ?;
5779+
5780+ if !response. status ( ) . is_success ( ) {
5781+ return Err ( format ! ( "HTTP {} from {}" , response. status( ) , peer_ip) ) ;
5782+ }
5783+
5784+ Ok ( ( ) )
5785+ }
5786+
56795787 /// Send network message via HTTP POST to peer's API (with pseudonym resolution)
56805788 pub fn send_network_message ( & self , peer_addr : & str , message : NetworkMessage ) {
56815789 let peer_addr = peer_addr. to_string ( ) ;
@@ -5916,7 +6024,7 @@ impl SimplifiedP2P {
59166024
59176025 // CRITICAL FIX: Deduplicate failover messages to prevent processing same event multiple times
59186026 let failover_key = ( block_height, failed_producer. clone ( ) , new_producer. clone ( ) ) ;
5919-
6027+
59206028 // SCALABILITY: DashSet provides lock-free concurrent access for millions of nodes
59216029 if !PROCESSED_FAILOVERS . insert ( failover_key. clone ( ) ) {
59226030 // Already processed this exact failover event (insert returns false if already exists)
0 commit comments