@@ -149,6 +149,8 @@ malloc_size_of_is_0!(PeerInfo);
149
149
150
150
pub type PacketDecodeError = DecoderError ;
151
151
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 ) ;
152
154
/// Version 64 of the Ethereum protocol and number of packet IDs reserved by the protocol (packet count).
153
155
pub const ETH_PROTOCOL_VERSION_64 : ( u8 , u8 ) = ( 64 , 0x11 ) ;
154
156
/// 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);
200
202
const HEADERS_TIMEOUT : Duration = Duration :: from_secs ( 15 ) ;
201
203
const BODIES_TIMEOUT : Duration = Duration :: from_secs ( 20 ) ;
202
204
const RECEIPTS_TIMEOUT : Duration = Duration :: from_secs ( 10 ) ;
205
+ const POOLED_TRANSACTIONS_TIMEOUT : Duration = Duration :: from_secs ( 10 ) ;
203
206
const FORK_HEADER_TIMEOUT : Duration = Duration :: from_secs ( 3 ) ;
204
207
/// Max time to wait for the Snapshot Manifest packet to arrive from a peer after it's being asked.
205
208
const SNAPSHOT_MANIFEST_TIMEOUT : Duration = Duration :: from_secs ( 5 ) ;
@@ -301,6 +304,7 @@ pub enum PeerAsking {
301
304
BlockHeaders ,
302
305
BlockBodies ,
303
306
BlockReceipts ,
307
+ PooledTransactions ,
304
308
SnapshotManifest ,
305
309
SnapshotData ,
306
310
PrivateState ,
@@ -335,6 +339,8 @@ pub struct PeerInfo {
335
339
network_id : u64 ,
336
340
/// Peer best block hash
337
341
latest_hash : H256 ,
342
+ /// Unpropagated tx pool hashes
343
+ unsent_pooled_hashes : Option < H256FastSet > ,
338
344
/// Peer total difficulty if known
339
345
difficulty : Option < U256 > ,
340
346
/// Type of data currently being requested by us from a peer.
@@ -343,6 +349,8 @@ pub struct PeerInfo {
343
349
asking_blocks : Vec < H256 > ,
344
350
/// Holds requested header hash if currently requesting block header by hash
345
351
asking_hash : Option < H256 > ,
352
+ /// Holds requested transaction IDs
353
+ asking_pooled_transactions : Option < Vec < H256 > > ,
346
354
/// Holds requested private state hash
347
355
asking_private_state : Option < H256 > ,
348
356
/// Holds requested snapshot chunk hash if any.
@@ -641,6 +649,13 @@ enum PeerState {
641
649
SameBlock
642
650
}
643
651
652
+ #[ derive( Clone , MallocSizeOf ) ]
653
+ struct UnfetchedTransaction {
654
+ announcer : PeerId ,
655
+ next_fetch : Instant ,
656
+ tries : usize ,
657
+ }
658
+
644
659
/// Blockchain sync handler.
645
660
/// See module documentation for more details.
646
661
#[ derive( MallocSizeOf ) ]
@@ -676,6 +691,8 @@ pub struct ChainSync {
676
691
sync_start_time : Option < Instant > ,
677
692
/// Transactions propagation statistics
678
693
transactions_stats : TransactionsStats ,
694
+ /// Unfetched transactions
695
+ unfetched_pooled_transactions : H256FastMap < UnfetchedTransaction > ,
679
696
/// Enable ancient block downloading
680
697
download_old_blocks : bool ,
681
698
/// Shared private tx service.
@@ -717,6 +734,7 @@ impl ChainSync {
717
734
snapshot : Snapshot :: new ( ) ,
718
735
sync_start_time : None ,
719
736
transactions_stats : TransactionsStats :: default ( ) ,
737
+ unfetched_pooled_transactions : Default :: default ( ) ,
720
738
private_tx_handler,
721
739
warp_sync : config. warp_sync ,
722
740
status_sinks : Vec :: new ( )
@@ -730,7 +748,7 @@ impl ChainSync {
730
748
let last_imported_number = self . new_blocks . last_imported_block_number ( ) ;
731
749
SyncStatus {
732
750
state : self . state . clone ( ) ,
733
- protocol_version : ETH_PROTOCOL_VERSION_64 . 0 ,
751
+ protocol_version : ETH_PROTOCOL_VERSION_65 . 0 ,
734
752
network_id : self . network_id ,
735
753
start_block_number : self . starting_block ,
736
754
last_imported_block_number : Some ( last_imported_number) ,
@@ -764,8 +782,17 @@ impl ChainSync {
764
782
765
783
/// Updates the set of transactions recently sent to this peer to avoid spamming.
766
784
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 ( ) ) ;
769
796
}
770
797
}
771
798
@@ -1099,6 +1126,36 @@ impl ChainSync {
1099
1126
}
1100
1127
}
1101
1128
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
+
1102
1159
// Only ask for old blocks if the peer has an equal or higher difficulty
1103
1160
let equal_or_higher_difficulty = peer_difficulty. map_or ( true , |pd| pd >= syncing_difficulty) ;
1104
1161
@@ -1290,6 +1347,7 @@ impl ChainSync {
1290
1347
PeerAsking :: BlockHeaders => elapsed > HEADERS_TIMEOUT ,
1291
1348
PeerAsking :: BlockBodies => elapsed > BODIES_TIMEOUT ,
1292
1349
PeerAsking :: BlockReceipts => elapsed > RECEIPTS_TIMEOUT ,
1350
+ PeerAsking :: PooledTransactions => elapsed > POOLED_TRANSACTIONS_TIMEOUT ,
1293
1351
PeerAsking :: Nothing => false ,
1294
1352
PeerAsking :: ForkHeader => elapsed > FORK_HEADER_TIMEOUT ,
1295
1353
PeerAsking :: SnapshotManifest => elapsed > SNAPSHOT_MANIFEST_TIMEOUT ,
@@ -1618,10 +1676,12 @@ pub mod tests {
1618
1676
genesis : H256 :: zero ( ) ,
1619
1677
network_id : 0 ,
1620
1678
latest_hash : peer_latest_hash,
1679
+ unsent_pooled_hashes : Some ( Default :: default ( ) ) ,
1621
1680
difficulty : None ,
1622
1681
asking : PeerAsking :: Nothing ,
1623
1682
asking_blocks : Vec :: new ( ) ,
1624
1683
asking_hash : None ,
1684
+ asking_pooled_transactions : Some ( Vec :: new ( ) ) ,
1625
1685
asking_private_state : None ,
1626
1686
ask_time : Instant :: now ( ) ,
1627
1687
last_sent_transactions : Default :: default ( ) ,
0 commit comments