Private packets verification and queue refactoring (#8715)
* Verify private transaction before propagating * Private transactions queue reworked with tx pool queue direct usage * Styling fixed * Prevent resending private packets to the sender * Process signed private transaction packets via io queue * Test fixed * Build and test fixed after merge * Comments after review fixed * Signed transaction taken from verified * Fix after merge * Pool scoring generalized in order to use externally * Lib refactored according to the review comments * Ready state refactored * Redundant bound and copying removed * Fixed build after the merge * Forgotten case reworked * Review comments fixed * Logging reworked, target added * Fix after merge
This commit is contained in:
@@ -38,7 +38,8 @@ use std::net::{SocketAddr, AddrParseError};
|
||||
use std::str::FromStr;
|
||||
use parking_lot::RwLock;
|
||||
use chain::{ETH_PROTOCOL_VERSION_63, ETH_PROTOCOL_VERSION_62,
|
||||
PAR_PROTOCOL_VERSION_1, PAR_PROTOCOL_VERSION_2, PAR_PROTOCOL_VERSION_3};
|
||||
PAR_PROTOCOL_VERSION_1, PAR_PROTOCOL_VERSION_2, PAR_PROTOCOL_VERSION_3,
|
||||
PRIVATE_TRANSACTION_PACKET, SIGNED_PRIVATE_TRANSACTION_PACKET};
|
||||
use light::client::AsLightClient;
|
||||
use light::Provider;
|
||||
use light::net::{
|
||||
@@ -522,8 +523,10 @@ impl ChainNotify for EthSync {
|
||||
let mut sync_io = NetSyncIo::new(context, &*self.eth_handler.chain, &*self.eth_handler.snapshot_service, &self.eth_handler.overlay);
|
||||
match message_type {
|
||||
ChainMessageType::Consensus(message) => self.eth_handler.sync.write().propagate_consensus_packet(&mut sync_io, message),
|
||||
ChainMessageType::PrivateTransaction(message) => self.eth_handler.sync.write().propagate_private_transaction(&mut sync_io, message),
|
||||
ChainMessageType::SignedPrivateTransaction(message) => self.eth_handler.sync.write().propagate_signed_private_transaction(&mut sync_io, message),
|
||||
ChainMessageType::PrivateTransaction(transaction_hash, message) =>
|
||||
self.eth_handler.sync.write().propagate_private_transaction(&mut sync_io, transaction_hash, PRIVATE_TRANSACTION_PACKET, message),
|
||||
ChainMessageType::SignedPrivateTransaction(transaction_hash, message) =>
|
||||
self.eth_handler.sync.write().propagate_private_transaction(&mut sync_io, transaction_hash, SIGNED_PRIVATE_TRANSACTION_PACKET, message),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -552,6 +552,7 @@ impl SyncHandler {
|
||||
asking_hash: None,
|
||||
ask_time: Instant::now(),
|
||||
last_sent_transactions: HashSet::new(),
|
||||
last_sent_private_transactions: HashSet::new(),
|
||||
expired: false,
|
||||
confirmation: if sync.fork_block.is_none() { ForkConfirmation::Confirmed } else { ForkConfirmation::Unconfirmed },
|
||||
asking_snapshot_data: None,
|
||||
@@ -631,21 +632,29 @@ impl SyncHandler {
|
||||
}
|
||||
|
||||
/// Called when peer sends us signed private transaction packet
|
||||
fn on_signed_private_transaction(sync: &ChainSync, _io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), DownloaderImportError> {
|
||||
fn on_signed_private_transaction(sync: &mut ChainSync, _io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), DownloaderImportError> {
|
||||
if !sync.peers.get(&peer_id).map_or(false, |p| p.can_sync()) {
|
||||
trace!(target: "sync", "{} Ignoring packet from unconfirmed/unknown peer", peer_id);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
trace!(target: "sync", "Received signed private transaction packet from {:?}", peer_id);
|
||||
if let Err(e) = sync.private_tx_handler.import_signed_private_transaction(r.as_raw()) {
|
||||
trace!(target: "sync", "Ignoring the message, error queueing: {}", e);
|
||||
}
|
||||
match sync.private_tx_handler.import_signed_private_transaction(r.as_raw()) {
|
||||
Ok(transaction_hash) => {
|
||||
//don't send the packet back
|
||||
if let Some(ref mut peer) = sync.peers.get_mut(&peer_id) {
|
||||
peer.last_sent_private_transactions.insert(transaction_hash);
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
trace!(target: "sync", "Ignoring the message, error queueing: {}", e);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Called when peer sends us new private transaction packet
|
||||
fn on_private_transaction(sync: &ChainSync, _io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), DownloaderImportError> {
|
||||
fn on_private_transaction(sync: &mut ChainSync, _io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), DownloaderImportError> {
|
||||
if !sync.peers.get(&peer_id).map_or(false, |p| p.can_sync()) {
|
||||
trace!(target: "sync", "{} Ignoring packet from unconfirmed/unknown peer", peer_id);
|
||||
return Ok(());
|
||||
@@ -653,9 +662,17 @@ impl SyncHandler {
|
||||
|
||||
trace!(target: "sync", "Received private transaction packet from {:?}", peer_id);
|
||||
|
||||
if let Err(e) = sync.private_tx_handler.import_private_transaction(r.as_raw()) {
|
||||
trace!(target: "sync", "Ignoring the message, error queueing: {}", e);
|
||||
}
|
||||
match sync.private_tx_handler.import_private_transaction(r.as_raw()) {
|
||||
Ok(transaction_hash) => {
|
||||
//don't send the packet back
|
||||
if let Some(ref mut peer) = sync.peers.get_mut(&peer_id) {
|
||||
peer.last_sent_private_transactions.insert(transaction_hash);
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
trace!(target: "sync", "Ignoring the message, error queueing: {}", e);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,8 +173,8 @@ pub const SNAPSHOT_MANIFEST_PACKET: u8 = 0x12;
|
||||
pub const GET_SNAPSHOT_DATA_PACKET: u8 = 0x13;
|
||||
pub const SNAPSHOT_DATA_PACKET: u8 = 0x14;
|
||||
pub const CONSENSUS_DATA_PACKET: u8 = 0x15;
|
||||
const PRIVATE_TRANSACTION_PACKET: u8 = 0x16;
|
||||
const SIGNED_PRIVATE_TRANSACTION_PACKET: u8 = 0x17;
|
||||
pub const PRIVATE_TRANSACTION_PACKET: u8 = 0x16;
|
||||
pub const SIGNED_PRIVATE_TRANSACTION_PACKET: u8 = 0x17;
|
||||
|
||||
const MAX_SNAPSHOT_CHUNKS_DOWNLOAD_AHEAD: usize = 3;
|
||||
|
||||
@@ -324,6 +324,8 @@ pub struct PeerInfo {
|
||||
ask_time: Instant,
|
||||
/// Holds a set of transactions recently sent to this peer to avoid spamming.
|
||||
last_sent_transactions: HashSet<H256>,
|
||||
/// Holds a set of private transactions and their signatures recently sent to this peer to avoid spamming.
|
||||
last_sent_private_transactions: HashSet<H256>,
|
||||
/// Pending request is expired and result should be ignored
|
||||
expired: bool,
|
||||
/// Peer fork confirmation status
|
||||
@@ -353,6 +355,10 @@ impl PeerInfo {
|
||||
self.expired = true;
|
||||
}
|
||||
}
|
||||
|
||||
fn reset_private_stats(&mut self) {
|
||||
self.last_sent_private_transactions.clear();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
@@ -1056,8 +1062,15 @@ impl ChainSync {
|
||||
self.peers.iter().filter_map(|(id, p)| if p.protocol_version >= PAR_PROTOCOL_VERSION_2.0 { Some(*id) } else { None }).collect()
|
||||
}
|
||||
|
||||
fn get_private_transaction_peers(&self) -> Vec<PeerId> {
|
||||
self.peers.iter().filter_map(|(id, p)| if p.protocol_version >= PAR_PROTOCOL_VERSION_3.0 { Some(*id) } else { None }).collect()
|
||||
fn get_private_transaction_peers(&self, transaction_hash: &H256) -> Vec<PeerId> {
|
||||
self.peers.iter().filter_map(
|
||||
|(id, p)| if p.protocol_version >= PAR_PROTOCOL_VERSION_3.0
|
||||
&& !p.last_sent_private_transactions.contains(transaction_hash) {
|
||||
Some(*id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
).collect()
|
||||
}
|
||||
|
||||
/// Maintain other peers. Send out any new blocks and transactions
|
||||
@@ -1085,8 +1098,10 @@ impl ChainSync {
|
||||
// Select random peer to re-broadcast transactions to.
|
||||
let peer = random::new().gen_range(0, self.peers.len());
|
||||
trace!(target: "sync", "Re-broadcasting transactions to a random peer.");
|
||||
self.peers.values_mut().nth(peer).map(|peer_info|
|
||||
peer_info.last_sent_transactions.clear()
|
||||
self.peers.values_mut().nth(peer).map(|peer_info| {
|
||||
peer_info.last_sent_transactions.clear();
|
||||
peer_info.reset_private_stats()
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1127,13 +1142,8 @@ impl ChainSync {
|
||||
}
|
||||
|
||||
/// Broadcast private transaction message to peers.
|
||||
pub fn propagate_private_transaction(&mut self, io: &mut SyncIo, packet: Bytes) {
|
||||
SyncPropagator::propagate_private_transaction(self, io, packet);
|
||||
}
|
||||
|
||||
/// Broadcast signed private transaction message to peers.
|
||||
pub fn propagate_signed_private_transaction(&mut self, io: &mut SyncIo, packet: Bytes) {
|
||||
SyncPropagator::propagate_signed_private_transaction(self, io, packet);
|
||||
pub fn propagate_private_transaction(&mut self, io: &mut SyncIo, transaction_hash: H256, packet_id: PacketId, packet: Bytes) {
|
||||
SyncPropagator::propagate_private_transaction(self, io, transaction_hash, packet_id, packet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1256,6 +1266,7 @@ pub mod tests {
|
||||
asking_hash: None,
|
||||
ask_time: Instant::now(),
|
||||
last_sent_transactions: HashSet::new(),
|
||||
last_sent_private_transactions: HashSet::new(),
|
||||
expired: false,
|
||||
confirmation: super::ForkConfirmation::Confirmed,
|
||||
snapshot_number: None,
|
||||
|
||||
@@ -36,8 +36,6 @@ use super::{
|
||||
CONSENSUS_DATA_PACKET,
|
||||
NEW_BLOCK_HASHES_PACKET,
|
||||
NEW_BLOCK_PACKET,
|
||||
PRIVATE_TRANSACTION_PACKET,
|
||||
SIGNED_PRIVATE_TRANSACTION_PACKET,
|
||||
TRANSACTIONS_PACKET,
|
||||
};
|
||||
|
||||
@@ -293,20 +291,14 @@ impl SyncPropagator {
|
||||
}
|
||||
|
||||
/// Broadcast private transaction message to peers.
|
||||
pub fn propagate_private_transaction(sync: &mut ChainSync, io: &mut SyncIo, packet: Bytes) {
|
||||
let lucky_peers = ChainSync::select_random_peers(&sync.get_private_transaction_peers());
|
||||
pub fn propagate_private_transaction(sync: &mut ChainSync, io: &mut SyncIo, transaction_hash: H256, packet_id: PacketId, packet: Bytes) {
|
||||
let lucky_peers = ChainSync::select_random_peers(&sync.get_private_transaction_peers(&transaction_hash));
|
||||
trace!(target: "sync", "Sending private transaction packet to {:?}", lucky_peers);
|
||||
for peer_id in lucky_peers {
|
||||
SyncPropagator::send_packet(io, peer_id, PRIVATE_TRANSACTION_PACKET, packet.clone());
|
||||
}
|
||||
}
|
||||
|
||||
/// Broadcast signed private transaction message to peers.
|
||||
pub fn propagate_signed_private_transaction(sync: &mut ChainSync, io: &mut SyncIo, packet: Bytes) {
|
||||
let lucky_peers = ChainSync::select_random_peers(&sync.get_private_transaction_peers());
|
||||
trace!(target: "sync", "Sending signed private transaction packet to {:?}", lucky_peers);
|
||||
for peer_id in lucky_peers {
|
||||
SyncPropagator::send_packet(io, peer_id, SIGNED_PRIVATE_TRANSACTION_PACKET, packet.clone());
|
||||
if let Some(ref mut peer) = sync.peers.get_mut(&peer_id) {
|
||||
peer.last_sent_private_transactions.insert(transaction_hash);
|
||||
}
|
||||
SyncPropagator::send_packet(io, peer_id, packet_id, packet.clone());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,6 +420,7 @@ mod tests {
|
||||
asking_hash: None,
|
||||
ask_time: Instant::now(),
|
||||
last_sent_transactions: HashSet::new(),
|
||||
last_sent_private_transactions: HashSet::new(),
|
||||
expired: false,
|
||||
confirmation: ForkConfirmation::Confirmed,
|
||||
snapshot_number: None,
|
||||
|
||||
@@ -15,26 +15,29 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use parking_lot::Mutex;
|
||||
use ethereum_types::H256;
|
||||
|
||||
/// Trait which should be implemented by a private transaction handler.
|
||||
pub trait PrivateTxHandler: Send + Sync + 'static {
|
||||
/// Function called on new private transaction received.
|
||||
fn import_private_transaction(&self, rlp: &[u8]) -> Result<(), String>;
|
||||
/// Returns the hash of the imported transaction
|
||||
fn import_private_transaction(&self, rlp: &[u8]) -> Result<H256, String>;
|
||||
|
||||
/// Function called on new signed private transaction received.
|
||||
fn import_signed_private_transaction(&self, rlp: &[u8]) -> Result<(), String>;
|
||||
/// Returns the hash of the imported transaction
|
||||
fn import_signed_private_transaction(&self, rlp: &[u8]) -> Result<H256, String>;
|
||||
}
|
||||
|
||||
/// Nonoperative private transaction handler.
|
||||
pub struct NoopPrivateTxHandler;
|
||||
|
||||
impl PrivateTxHandler for NoopPrivateTxHandler {
|
||||
fn import_private_transaction(&self, _rlp: &[u8]) -> Result<(), String> {
|
||||
Ok(())
|
||||
fn import_private_transaction(&self, _rlp: &[u8]) -> Result<H256, String> {
|
||||
Ok(H256::default())
|
||||
}
|
||||
|
||||
fn import_signed_private_transaction(&self, _rlp: &[u8]) -> Result<(), String> {
|
||||
Ok(())
|
||||
fn import_signed_private_transaction(&self, _rlp: &[u8]) -> Result<H256, String> {
|
||||
Ok(H256::default())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,13 +51,13 @@ pub struct SimplePrivateTxHandler {
|
||||
}
|
||||
|
||||
impl PrivateTxHandler for SimplePrivateTxHandler {
|
||||
fn import_private_transaction(&self, rlp: &[u8]) -> Result<(), String> {
|
||||
fn import_private_transaction(&self, rlp: &[u8]) -> Result<H256, String> {
|
||||
self.txs.lock().push(rlp.to_vec());
|
||||
Ok(())
|
||||
Ok(H256::default())
|
||||
}
|
||||
|
||||
fn import_signed_private_transaction(&self, rlp: &[u8]) -> Result<(), String> {
|
||||
fn import_signed_private_transaction(&self, rlp: &[u8]) -> Result<H256, String> {
|
||||
self.signed_txs.lock().push(rlp.to_vec());
|
||||
Ok(())
|
||||
Ok(H256::default())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ use ethcore::test_helpers;
|
||||
use sync_io::SyncIo;
|
||||
use io::{IoChannel, IoContext, IoHandler};
|
||||
use api::WARP_SYNC_PROTOCOL_ID;
|
||||
use chain::{ChainSync, ETH_PROTOCOL_VERSION_63, PAR_PROTOCOL_VERSION_3};
|
||||
use chain::{ChainSync, ETH_PROTOCOL_VERSION_63, PAR_PROTOCOL_VERSION_3, PRIVATE_TRANSACTION_PACKET, SIGNED_PRIVATE_TRANSACTION_PACKET};
|
||||
use SyncConfig;
|
||||
use private_tx::SimplePrivateTxHandler;
|
||||
|
||||
@@ -230,8 +230,10 @@ impl<C> EthPeer<C> where C: FlushingBlockChainClient {
|
||||
let mut io = TestIo::new(&*self.chain, &self.snapshot_service, &self.queue, None);
|
||||
match message {
|
||||
ChainMessageType::Consensus(data) => self.sync.write().propagate_consensus_packet(&mut io, data),
|
||||
ChainMessageType::PrivateTransaction(data) => self.sync.write().propagate_private_transaction(&mut io, data),
|
||||
ChainMessageType::SignedPrivateTransaction(data) => self.sync.write().propagate_signed_private_transaction(&mut io, data),
|
||||
ChainMessageType::PrivateTransaction(transaction_hash, data) =>
|
||||
self.sync.write().propagate_private_transaction(&mut io, transaction_hash, PRIVATE_TRANSACTION_PACKET, data),
|
||||
ChainMessageType::SignedPrivateTransaction(transaction_hash, data) =>
|
||||
self.sync.write().propagate_private_transaction(&mut io, transaction_hash, SIGNED_PRIVATE_TRANSACTION_PACKET, data),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,11 +24,12 @@ use ethcore::CreateContractAddress;
|
||||
use transaction::{Transaction, Action};
|
||||
use ethcore::executive::{contract_address};
|
||||
use ethcore::test_helpers::{push_block_with_transactions};
|
||||
use ethcore_private_tx::{Provider, ProviderConfig, NoopEncryptor, Importer};
|
||||
use ethcore_private_tx::{Provider, ProviderConfig, NoopEncryptor, Importer, SignedPrivateTransaction};
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use ethkey::{KeyPair};
|
||||
use tests::helpers::{TestNet, TestIoHandler};
|
||||
use rustc_hex::FromHex;
|
||||
use rlp::Rlp;
|
||||
use SyncConfig;
|
||||
|
||||
fn seal_spec() -> Spec {
|
||||
@@ -144,6 +145,8 @@ fn send_private_transaction() {
|
||||
//process signed response
|
||||
let signed_private_transaction = received_signed_private_transactions[0].clone();
|
||||
assert!(pm0.import_signed_private_transaction(&signed_private_transaction).is_ok());
|
||||
let signature: SignedPrivateTransaction = Rlp::new(&signed_private_transaction).as_val().unwrap();
|
||||
assert!(pm0.process_signature(&signature).is_ok());
|
||||
let local_transactions = net.peer(0).miner.local_transactions();
|
||||
assert_eq!(local_transactions.len(), 1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user