@@ -149,6 +149,8 @@ malloc_size_of_is_0!(PeerInfo);
149149
150150pub type PacketDecodeError = DecoderError ;
151151
152+ /// Version 65 of the Ethereum protocol and number of packet IDs reserved by the protocol (packet count).
153+ pub const ETH_PROTOCOL_VERSION_65 : ( u8 , u8 ) = ( 65 , 0x11 ) ;
152154/// Version 64 of the Ethereum protocol and number of packet IDs reserved by the protocol (packet count).
153155pub const ETH_PROTOCOL_VERSION_64 : ( u8 , u8 ) = ( 64 , 0x11 ) ;
154156/// Version 63 of the Ethereum protocol and number of packet IDs reserved by the protocol (packet count).
@@ -200,6 +202,7 @@ const STATUS_TIMEOUT: Duration = Duration::from_secs(10);
200202const HEADERS_TIMEOUT : Duration = Duration :: from_secs ( 15 ) ;
201203const BODIES_TIMEOUT : Duration = Duration :: from_secs ( 20 ) ;
202204const RECEIPTS_TIMEOUT : Duration = Duration :: from_secs ( 10 ) ;
205+ const POOLED_TRANSACTIONS_TIMEOUT : Duration = Duration :: from_secs ( 10 ) ;
203206const FORK_HEADER_TIMEOUT : Duration = Duration :: from_secs ( 3 ) ;
204207/// Max time to wait for the Snapshot Manifest packet to arrive from a peer after it's being asked.
205208const SNAPSHOT_MANIFEST_TIMEOUT : Duration = Duration :: from_secs ( 5 ) ;
@@ -301,6 +304,7 @@ pub enum PeerAsking {
301304 BlockHeaders ,
302305 BlockBodies ,
303306 BlockReceipts ,
307+ PooledTransactions ,
304308 SnapshotManifest ,
305309 SnapshotData ,
306310 PrivateState ,
@@ -335,6 +339,8 @@ pub struct PeerInfo {
335339 network_id : u64 ,
336340 /// Peer best block hash
337341 latest_hash : H256 ,
342+ /// Unpropagated tx pool hashes
343+ unsent_pooled_hashes : Option < H256FastSet > ,
338344 /// Peer total difficulty if known
339345 difficulty : Option < U256 > ,
340346 /// Type of data currently being requested by us from a peer.
@@ -343,6 +349,8 @@ pub struct PeerInfo {
343349 asking_blocks : Vec < H256 > ,
344350 /// Holds requested header hash if currently requesting block header by hash
345351 asking_hash : Option < H256 > ,
352+ /// Holds requested transaction IDs
353+ asking_pooled_transactions : Option < Vec < H256 > > ,
346354 /// Holds requested private state hash
347355 asking_private_state : Option < H256 > ,
348356 /// Holds requested snapshot chunk hash if any.
@@ -641,6 +649,13 @@ enum PeerState {
641649 SameBlock
642650}
643651
652+ #[ derive( Clone , MallocSizeOf ) ]
653+ struct UnfetchedTransaction {
654+ announcer : PeerId ,
655+ next_fetch : Instant ,
656+ tries : usize ,
657+ }
658+
644659/// Blockchain sync handler.
645660/// See module documentation for more details.
646661#[ derive( MallocSizeOf ) ]
@@ -676,6 +691,8 @@ pub struct ChainSync {
676691 sync_start_time : Option < Instant > ,
677692 /// Transactions propagation statistics
678693 transactions_stats : TransactionsStats ,
694+ /// Unfetched transactions
695+ unfetched_pooled_transactions : H256FastMap < UnfetchedTransaction > ,
679696 /// Enable ancient block downloading
680697 download_old_blocks : bool ,
681698 /// Shared private tx service.
@@ -717,6 +734,7 @@ impl ChainSync {
717734 snapshot : Snapshot :: new ( ) ,
718735 sync_start_time : None ,
719736 transactions_stats : TransactionsStats :: default ( ) ,
737+ unfetched_pooled_transactions : Default :: default ( ) ,
720738 private_tx_handler,
721739 warp_sync : config. warp_sync ,
722740 status_sinks : Vec :: new ( )
@@ -730,7 +748,7 @@ impl ChainSync {
730748 let last_imported_number = self . new_blocks . last_imported_block_number ( ) ;
731749 SyncStatus {
732750 state : self . state . clone ( ) ,
733- protocol_version : ETH_PROTOCOL_VERSION_64 . 0 ,
751+ protocol_version : ETH_PROTOCOL_VERSION_65 . 0 ,
734752 network_id : self . network_id ,
735753 start_block_number : self . starting_block ,
736754 last_imported_block_number : Some ( last_imported_number) ,
@@ -764,8 +782,17 @@ impl ChainSync {
764782
765783 /// Updates the set of transactions recently sent to this peer to avoid spamming.
766784 pub fn transactions_received ( & mut self , txs : & [ UnverifiedTransaction ] , peer_id : PeerId ) {
767- if let Some ( peer_info) = self . peers . get_mut ( & peer_id) {
768- peer_info. last_sent_transactions . extend ( txs. iter ( ) . map ( |tx| tx. hash ( ) ) ) ;
785+ for ( id, peer) in & mut self . peers {
786+ let hashes = txs. iter ( ) . map ( |tx| tx. hash ( ) ) ;
787+ if * id == peer_id {
788+ peer. last_sent_transactions . extend ( hashes) ;
789+ } else if let Some ( s) = & mut peer. unsent_pooled_hashes {
790+ s. extend ( hashes) ;
791+ }
792+ }
793+
794+ for tx in txs {
795+ self . unfetched_pooled_transactions . remove ( & tx. hash ( ) ) ;
769796 }
770797 }
771798
@@ -1099,6 +1126,36 @@ impl ChainSync {
10991126 }
11001127 }
11011128
1129+ // get some peers to give us transaction pool
1130+ if !self . unfetched_pooled_transactions . is_empty ( ) {
1131+ if let Some ( s) = & mut self . peers . get_mut ( & peer_id) . unwrap ( ) . asking_pooled_transactions {
1132+ let now = Instant :: now ( ) ;
1133+
1134+ let mut new_asking_pooled_transactions = s. iter ( ) . copied ( ) . collect :: < HashSet < _ > > ( ) ;
1135+ let mut new_unfetched_pooled_transactions = self . unfetched_pooled_transactions . clone ( ) ;
1136+ while new_asking_pooled_transactions. len ( ) <= 256 {
1137+ for ( hash, mut item) in self . unfetched_pooled_transactions . drain ( ) {
1138+ if item. next_fetch < now {
1139+ new_asking_pooled_transactions. insert ( hash) ;
1140+ item. tries += 1 ;
1141+ if item. tries < 5 {
1142+ item. next_fetch = now + ( POOLED_TRANSACTIONS_TIMEOUT / 2 ) ;
1143+ new_unfetched_pooled_transactions. insert ( hash, item) ;
1144+ }
1145+ }
1146+ }
1147+ }
1148+
1149+ let new_asking_pooled_transactions = new_asking_pooled_transactions. into_iter ( ) . collect :: < Vec < _ > > ( ) ;
1150+ SyncRequester :: request_pooled_transactions ( self , io, peer_id, & new_asking_pooled_transactions) ;
1151+
1152+ self . peers . get_mut ( & peer_id) . unwrap ( ) . asking_pooled_transactions = Some ( new_asking_pooled_transactions) ;
1153+ self . unfetched_pooled_transactions = new_unfetched_pooled_transactions;
1154+
1155+ return ;
1156+ }
1157+ }
1158+
11021159 // Only ask for old blocks if the peer has an equal or higher difficulty
11031160 let equal_or_higher_difficulty = peer_difficulty. map_or ( true , |pd| pd >= syncing_difficulty) ;
11041161
@@ -1290,6 +1347,7 @@ impl ChainSync {
12901347 PeerAsking :: BlockHeaders => elapsed > HEADERS_TIMEOUT ,
12911348 PeerAsking :: BlockBodies => elapsed > BODIES_TIMEOUT ,
12921349 PeerAsking :: BlockReceipts => elapsed > RECEIPTS_TIMEOUT ,
1350+ PeerAsking :: PooledTransactions => elapsed > POOLED_TRANSACTIONS_TIMEOUT ,
12931351 PeerAsking :: Nothing => false ,
12941352 PeerAsking :: ForkHeader => elapsed > FORK_HEADER_TIMEOUT ,
12951353 PeerAsking :: SnapshotManifest => elapsed > SNAPSHOT_MANIFEST_TIMEOUT ,
@@ -1618,10 +1676,12 @@ pub mod tests {
16181676 genesis : H256 :: zero ( ) ,
16191677 network_id : 0 ,
16201678 latest_hash : peer_latest_hash,
1679+ unsent_pooled_hashes : Some ( Default :: default ( ) ) ,
16211680 difficulty : None ,
16221681 asking : PeerAsking :: Nothing ,
16231682 asking_blocks : Vec :: new ( ) ,
16241683 asking_hash : None ,
1684+ asking_pooled_transactions : Some ( Vec :: new ( ) ) ,
16251685 asking_private_state : None ,
16261686 ask_time : Instant :: now ( ) ,
16271687 last_sent_transactions : Default :: default ( ) ,
0 commit comments