TransactionQueue improvements (#5917)

* Order by id instead of hash.

* Minimal gas price bump.

* Avoid to construct oversized transaction packets.

* Fix RPC.

* Never construct oversized transactions packet.

* Never construct oversized packets.
This commit is contained in:
Tomasz Drwięga
2017-06-30 11:57:48 +02:00
committed by Arkadiy Paronyan
parent a3e693d5c3
commit f22745eb0a
3 changed files with 134 additions and 44 deletions

View File

@@ -126,6 +126,8 @@ const MAX_NEW_HASHES: usize = 64;
const MAX_TX_TO_IMPORT: usize = 512;
const MAX_NEW_BLOCK_AGE: BlockNumber = 20;
const MAX_TRANSACTION_SIZE: usize = 300*1024;
// maximal packet size with transactions (cannot be greater than 16MB - protocol limitation).
const MAX_TRANSACTION_PACKET_SIZE: usize = 8 * 1024 * 1024;
// Maximal number of transactions in sent in single packet.
const MAX_TRANSACTIONS_TO_PROPAGATE: usize = 64;
// Min number of blocks to be behind for a snapshot sync
@@ -2044,7 +2046,7 @@ impl ChainSync {
// update stats
for hash in &all_transactions_hashes {
let id = io.peer_session_info(peer_id).and_then(|info| info.id);
stats.propagated(*hash, id, block_number);
stats.propagated(hash, id, block_number);
}
peer_info.last_sent_transactions = all_transactions_hashes.clone();
return Some((peer_id, all_transactions_hashes.len(), all_transactions_rlp.clone()));
@@ -2060,14 +2062,35 @@ impl ChainSync {
}
// Construct RLP
let mut packet = RlpStream::new_list(to_send.len());
for tx in &transactions {
if to_send.contains(&tx.transaction.hash()) {
packet.append(&tx.transaction);
// update stats
let id = io.peer_session_info(peer_id).and_then(|info| info.id);
stats.propagated(tx.transaction.hash(), id, block_number);
let (packet, to_send) = {
let mut to_send = to_send;
let mut packet = RlpStream::new();
packet.begin_unbounded_list();
let mut pushed = 0;
for tx in &transactions {
let hash = tx.transaction.hash();
if to_send.contains(&hash) {
let mut transaction = RlpStream::new();
tx.transaction.rlp_append(&mut transaction);
let appended = packet.append_raw_checked(&transaction.drain(), 1, MAX_TRANSACTION_PACKET_SIZE);
if !appended {
// Maximal packet size reached just proceed with sending
debug!("Transaction packet size limit reached. Sending incomplete set of {}/{} transactions.", pushed, to_send.len());
to_send = to_send.into_iter().take(pushed).collect();
break;
}
pushed += 1;
}
}
packet.complete_unbounded_list();
(packet, to_send)
};
// Update stats
let id = io.peer_session_info(peer_id).and_then(|info| info.id);
for hash in &to_send {
// update stats
stats.propagated(hash, id, block_number);
}
peer_info.last_sent_transactions = all_transactions_hashes

View File

@@ -56,9 +56,9 @@ pub struct TransactionsStats {
impl TransactionsStats {
/// Increases number of propagations to given `enodeid`.
pub fn propagated(&mut self, hash: H256, enode_id: Option<NodeId>, current_block_num: BlockNumber) {
pub fn propagated(&mut self, hash: &H256, enode_id: Option<NodeId>, current_block_num: BlockNumber) {
let enode_id = enode_id.unwrap_or_default();
let mut stats = self.pending_transactions.entry(hash).or_insert_with(|| Stats::new(current_block_num));
let mut stats = self.pending_transactions.entry(*hash).or_insert_with(|| Stats::new(current_block_num));
let mut count = stats.propagated_to.entry(enode_id).or_insert(0);
*count = count.saturating_add(1);
}
@@ -101,9 +101,9 @@ mod tests {
let enodeid2 = 5.into();
// when
stats.propagated(hash, Some(enodeid1), 5);
stats.propagated(hash, Some(enodeid1), 10);
stats.propagated(hash, Some(enodeid2), 15);
stats.propagated(&hash, Some(enodeid1), 5);
stats.propagated(&hash, Some(enodeid1), 10);
stats.propagated(&hash, Some(enodeid2), 15);
// then
let stats = stats.get(&hash);
@@ -122,7 +122,7 @@ mod tests {
let mut stats = TransactionsStats::default();
let hash = 5.into();
let enodeid1 = 5.into();
stats.propagated(hash, Some(enodeid1), 10);
stats.propagated(&hash, Some(enodeid1), 10);
// when
stats.retain(&HashSet::new());