This repository has been archived by the owner on Nov 6, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Improve block and transaction propagation #9954
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
ceb9770
Refactor sync to add priority tasks.
tomusdrw 4a2e2b9
Send priority tasks notifications.
tomusdrw 79bbf07
Propagate blocks, optimize transactions.
tomusdrw 14877da
Implement transaction propagation. Use sync_channel.
tomusdrw 4d58e7a
Merge branch 'master' into td-propagation
tomusdrw 96e0c6b
Tone down info.
tomusdrw e98d5b5
Prevent deadlock by not waiting forever for sync lock.
tomusdrw 5809395
Fix lock order.
tomusdrw abe3b8f
Don't use sync_channel to prevent deadlocks.
tomusdrw 3040e82
Fix tests.
tomusdrw File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -14,7 +14,7 @@ | |||||
// You should have received a copy of the GNU General Public License | ||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>. | ||||||
|
||||||
use std::sync::Arc; | ||||||
use std::sync::{Arc, mpsc, atomic}; | ||||||
use std::collections::{HashMap, BTreeMap}; | ||||||
use std::io; | ||||||
use std::ops::Range; | ||||||
|
@@ -33,10 +33,10 @@ use ethcore::client::{BlockChainClient, ChainNotify, ChainRoute, ChainMessageTyp | |||||
use ethcore::snapshot::SnapshotService; | ||||||
use ethcore::header::BlockNumber; | ||||||
use sync_io::NetSyncIo; | ||||||
use chain::{ChainSync, SyncStatus as EthSyncStatus}; | ||||||
use chain::{ChainSyncApi, SyncStatus as EthSyncStatus}; | ||||||
use std::net::{SocketAddr, AddrParseError}; | ||||||
use std::str::FromStr; | ||||||
use parking_lot::RwLock; | ||||||
use parking_lot::{RwLock, Mutex}; | ||||||
use chain::{ETH_PROTOCOL_VERSION_63, ETH_PROTOCOL_VERSION_62, | ||||||
PAR_PROTOCOL_VERSION_1, PAR_PROTOCOL_VERSION_2, PAR_PROTOCOL_VERSION_3, | ||||||
PRIVATE_TRANSACTION_PACKET, SIGNED_PRIVATE_TRANSACTION_PACKET}; | ||||||
|
@@ -228,6 +228,37 @@ impl AttachedProtocol { | |||||
} | ||||||
} | ||||||
|
||||||
/// A prioritized tasks run in a specialised timer. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
/// Every task should be completed within a hard deadline, | ||||||
/// if it's not it's either cancelled or split into multiple tasks. | ||||||
/// NOTE These tasks might not complete at all, so anything | ||||||
/// that happens here should work even if the task is cancelled. | ||||||
#[derive(Debug)] | ||||||
pub enum PriorityTask { | ||||||
/// Propagate given block | ||||||
PropagateBlock { | ||||||
/// When the task was initiated | ||||||
started: ::std::time::Instant, | ||||||
/// Raw block RLP to propagate | ||||||
block: Bytes, | ||||||
/// Block hash | ||||||
hash: H256, | ||||||
/// Blocks difficulty | ||||||
difficulty: U256, | ||||||
}, | ||||||
/// Propagate a list of transactions | ||||||
PropagateTransactions(::std::time::Instant, Arc<atomic::AtomicBool>), | ||||||
} | ||||||
impl PriorityTask { | ||||||
/// Mark the task as being processed, right after it's retrieved from the queue. | ||||||
pub fn starting(&self) { | ||||||
match *self { | ||||||
PriorityTask::PropagateTransactions(_, ref is_ready) => is_ready.store(true, atomic::Ordering::SeqCst), | ||||||
_ => {}, | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
/// EthSync initialization parameters. | ||||||
pub struct Params { | ||||||
/// Configuration. | ||||||
|
@@ -260,6 +291,8 @@ pub struct EthSync { | |||||
subprotocol_name: [u8; 3], | ||||||
/// Light subprotocol name. | ||||||
light_subprotocol_name: [u8; 3], | ||||||
/// Priority tasks notification channel | ||||||
priority_tasks: Mutex<mpsc::Sender<PriorityTask>>, | ||||||
} | ||||||
|
||||||
fn light_params( | ||||||
|
@@ -312,13 +345,19 @@ impl EthSync { | |||||
}) | ||||||
}; | ||||||
|
||||||
let chain_sync = ChainSync::new(params.config, &*params.chain, params.private_tx_handler.clone()); | ||||||
let (priority_tasks_tx, priority_tasks_rx) = mpsc::channel(); | ||||||
let sync = ChainSyncApi::new( | ||||||
params.config, | ||||||
&*params.chain, | ||||||
params.private_tx_handler.clone(), | ||||||
priority_tasks_rx, | ||||||
); | ||||||
let service = NetworkService::new(params.network_config.clone().into_basic()?, connection_filter)?; | ||||||
|
||||||
let sync = Arc::new(EthSync { | ||||||
network: service, | ||||||
eth_handler: Arc::new(SyncProtocolHandler { | ||||||
sync: RwLock::new(chain_sync), | ||||||
sync, | ||||||
chain: params.chain, | ||||||
snapshot_service: params.snapshot_service, | ||||||
overlay: RwLock::new(HashMap::new()), | ||||||
|
@@ -327,26 +366,32 @@ impl EthSync { | |||||
subprotocol_name: params.config.subprotocol_name, | ||||||
light_subprotocol_name: params.config.light_subprotocol_name, | ||||||
attached_protos: params.attached_protos, | ||||||
priority_tasks: Mutex::new(priority_tasks_tx), | ||||||
}); | ||||||
|
||||||
Ok(sync) | ||||||
} | ||||||
|
||||||
/// Priority tasks producer | ||||||
pub fn priority_tasks(&self) -> mpsc::Sender<PriorityTask> { | ||||||
self.priority_tasks.lock().clone() | ||||||
} | ||||||
} | ||||||
|
||||||
impl SyncProvider for EthSync { | ||||||
/// Get sync status | ||||||
fn status(&self) -> EthSyncStatus { | ||||||
self.eth_handler.sync.read().status() | ||||||
self.eth_handler.sync.status() | ||||||
} | ||||||
|
||||||
/// Get sync peers | ||||||
fn peers(&self) -> Vec<PeerInfo> { | ||||||
self.network.with_context_eval(self.subprotocol_name, |ctx| { | ||||||
let peer_ids = self.network.connected_peers(); | ||||||
let eth_sync = self.eth_handler.sync.read(); | ||||||
let light_proto = self.light_proto.as_ref(); | ||||||
|
||||||
peer_ids.into_iter().filter_map(|peer_id| { | ||||||
let peer_info = self.eth_handler.sync.peer_info(&peer_ids); | ||||||
peer_ids.into_iter().zip(peer_info).filter_map(|(peer_id, peer_info)| { | ||||||
let session_info = match ctx.session_info(peer_id) { | ||||||
None => return None, | ||||||
Some(info) => info, | ||||||
|
@@ -358,7 +403,7 @@ impl SyncProvider for EthSync { | |||||
capabilities: session_info.peer_capabilities.into_iter().map(|c| c.to_string()).collect(), | ||||||
remote_address: session_info.remote_address, | ||||||
local_address: session_info.local_address, | ||||||
eth_info: eth_sync.peer_info(&peer_id), | ||||||
eth_info: peer_info, | ||||||
pip_info: light_proto.as_ref().and_then(|lp| lp.peer_status(peer_id)).map(Into::into), | ||||||
}) | ||||||
}).collect() | ||||||
|
@@ -370,25 +415,24 @@ impl SyncProvider for EthSync { | |||||
} | ||||||
|
||||||
fn transactions_stats(&self) -> BTreeMap<H256, TransactionStats> { | ||||||
let sync = self.eth_handler.sync.read(); | ||||||
sync.transactions_stats() | ||||||
.iter() | ||||||
.map(|(hash, stats)| (*hash, stats.into())) | ||||||
.collect() | ||||||
self.eth_handler.sync.transactions_stats() | ||||||
} | ||||||
} | ||||||
|
||||||
const PEERS_TIMER: TimerToken = 0; | ||||||
const SYNC_TIMER: TimerToken = 1; | ||||||
const TX_TIMER: TimerToken = 2; | ||||||
const PRIORITY_TIMER: TimerToken = 3; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should be careful when merging this PR with #9967 because if it doesn't conflict we end up with duplicate tokens. |
||||||
|
||||||
pub(crate) const PRIORITY_TIMER_INTERVAL: Duration = Duration::from_millis(250); | ||||||
|
||||||
struct SyncProtocolHandler { | ||||||
/// Shared blockchain client. | ||||||
chain: Arc<BlockChainClient>, | ||||||
/// Shared snapshot service. | ||||||
snapshot_service: Arc<SnapshotService>, | ||||||
/// Sync strategy | ||||||
sync: RwLock<ChainSync>, | ||||||
sync: ChainSyncApi, | ||||||
/// Chain overlay used to cache data such as fork block. | ||||||
overlay: RwLock<HashMap<BlockNumber, Bytes>>, | ||||||
} | ||||||
|
@@ -399,11 +443,13 @@ impl NetworkProtocolHandler for SyncProtocolHandler { | |||||
io.register_timer(PEERS_TIMER, Duration::from_millis(700)).expect("Error registering peers timer"); | ||||||
io.register_timer(SYNC_TIMER, Duration::from_millis(1100)).expect("Error registering sync timer"); | ||||||
io.register_timer(TX_TIMER, Duration::from_millis(1300)).expect("Error registering transactions timer"); | ||||||
|
||||||
io.register_timer(PRIORITY_TIMER, PRIORITY_TIMER_INTERVAL).expect("Error registering peers timer"); | ||||||
} | ||||||
} | ||||||
|
||||||
fn read(&self, io: &NetworkContext, peer: &PeerId, packet_id: u8, data: &[u8]) { | ||||||
ChainSync::dispatch_packet(&self.sync, &mut NetSyncIo::new(io, &*self.chain, &*self.snapshot_service, &self.overlay), *peer, packet_id, data); | ||||||
self.sync.dispatch_packet(&mut NetSyncIo::new(io, &*self.chain, &*self.snapshot_service, &self.overlay), *peer, packet_id, data); | ||||||
} | ||||||
|
||||||
fn connected(&self, io: &NetworkContext, peer: &PeerId) { | ||||||
|
@@ -429,15 +475,26 @@ impl NetworkProtocolHandler for SyncProtocolHandler { | |||||
match timer { | ||||||
PEERS_TIMER => self.sync.write().maintain_peers(&mut io), | ||||||
SYNC_TIMER => self.sync.write().maintain_sync(&mut io), | ||||||
TX_TIMER => { | ||||||
self.sync.write().propagate_new_transactions(&mut io); | ||||||
}, | ||||||
TX_TIMER => self.sync.write().propagate_new_transactions(&mut io), | ||||||
PRIORITY_TIMER => self.sync.process_priority_queue(&mut io), | ||||||
_ => warn!("Unknown timer {} triggered.", timer), | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
impl ChainNotify for EthSync { | ||||||
fn block_pre_import(&self, bytes: &Bytes, hash: &H256, difficulty: &U256) { | ||||||
let task = PriorityTask::PropagateBlock { | ||||||
started: ::std::time::Instant::now(), | ||||||
block: bytes.clone(), | ||||||
hash: *hash, | ||||||
difficulty: *difficulty, | ||||||
}; | ||||||
if let Err(e) = self.priority_tasks.lock().send(task) { | ||||||
warn!(target: "sync", "Unexpected error during priority block propagation: {:?}", e); | ||||||
} | ||||||
} | ||||||
|
||||||
fn new_blocks(&self, | ||||||
imported: Vec<H256>, | ||||||
invalid: Vec<H256>, | ||||||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you mind to create a new issue and include an issue number for this TODO item?