parity-zcash/p2p/src/protocol/sync.rs

276 lines
10 KiB
Rust

use bytes::Bytes;
use net::PeerContext;
use protocol::Protocol;
use std::sync::Arc;
use zebra_message::{deserialize_payload, types, Command, Error, Payload, Services};
pub type InboundSyncConnectionRef = Box<InboundSyncConnection>;
pub type OutboundSyncConnectionRef = Arc<OutboundSyncConnection>;
pub type LocalSyncNodeRef = Box<LocalSyncNode>;
pub type InboundSyncConnectionStateRef = Arc<InboundSyncConnectionState>;
pub trait LocalSyncNode: Send + Sync {
fn create_sync_session(
&self,
height: i32,
services: Services,
outbound: OutboundSyncConnectionRef,
) -> InboundSyncConnectionRef;
}
pub trait InboundSyncConnectionState: Send + Sync {
fn synchronizing(&self) -> bool;
}
pub trait InboundSyncConnection: Send + Sync {
fn sync_state(&self) -> InboundSyncConnectionStateRef;
fn start_sync_session(&self, peer_name: String, version: types::Version);
fn close_session(&self);
fn on_inventory(&self, message: types::Inv);
fn on_getdata(&self, message: types::GetData);
fn on_getblocks(&self, message: types::GetBlocks);
fn on_getheaders(&self, message: types::GetHeaders, id: u32);
fn on_transaction(&self, message: types::Tx);
fn on_block(&self, message: types::Block);
fn on_headers(&self, message: types::Headers);
fn on_mempool(&self, message: types::MemPool);
fn on_filterload(&self, message: types::FilterLoad);
fn on_filteradd(&self, message: types::FilterAdd);
fn on_filterclear(&self, message: types::FilterClear);
fn on_merkleblock(&self, message: types::MerkleBlock);
fn on_sendheaders(&self, message: types::SendHeaders);
fn on_feefilter(&self, message: types::FeeFilter);
fn on_notfound(&self, message: types::NotFound);
}
pub trait OutboundSyncConnection: Send + Sync {
fn send_inventory(&self, message: &types::Inv);
fn send_getdata(&self, message: &types::GetData);
fn send_getblocks(&self, message: &types::GetBlocks);
fn send_getheaders(&self, message: &types::GetHeaders);
fn send_transaction(&self, message: &types::Tx);
fn send_block(&self, message: &types::Block);
fn send_headers(&self, message: &types::Headers);
fn respond_headers(&self, message: &types::Headers, id: u32);
fn send_mempool(&self, message: &types::MemPool);
fn send_filterload(&self, message: &types::FilterLoad);
fn send_filteradd(&self, message: &types::FilterAdd);
fn send_filterclear(&self, message: &types::FilterClear);
fn send_merkleblock(&self, message: &types::MerkleBlock);
fn send_sendheaders(&self, message: &types::SendHeaders);
fn send_feefilter(&self, message: &types::FeeFilter);
fn send_notfound(&self, message: &types::NotFound);
fn ignored(&self, id: u32);
fn close(&self);
}
struct OutboundSync {
context: Arc<PeerContext>,
}
impl OutboundSync {
pub fn new(context: Arc<PeerContext>) -> OutboundSync {
OutboundSync { context: context }
}
}
impl OutboundSyncConnection for OutboundSync {
fn send_inventory(&self, message: &types::Inv) {
self.context.send_request(message);
}
fn send_getdata(&self, message: &types::GetData) {
self.context.send_request(message);
}
fn send_getblocks(&self, message: &types::GetBlocks) {
self.context.send_request(message);
}
fn send_getheaders(&self, message: &types::GetHeaders) {
self.context.send_request(message);
}
fn send_transaction(&self, message: &types::Tx) {
self.context.send_request(message);
}
fn send_block(&self, message: &types::Block) {
self.context.send_request(message);
}
fn send_headers(&self, message: &types::Headers) {
self.context.send_request(message);
}
fn respond_headers(&self, message: &types::Headers, id: u32) {
self.context.send_response(message, id, true);
}
fn send_mempool(&self, message: &types::MemPool) {
self.context.send_request(message);
}
fn send_filterload(&self, message: &types::FilterLoad) {
self.context.send_request(message);
}
fn send_filteradd(&self, message: &types::FilterAdd) {
self.context.send_request(message);
}
fn send_filterclear(&self, message: &types::FilterClear) {
self.context.send_request(message);
}
fn send_merkleblock(&self, message: &types::MerkleBlock) {
self.context.send_request(message);
}
fn send_sendheaders(&self, message: &types::SendHeaders) {
self.context.send_request(message);
}
fn send_feefilter(&self, message: &types::FeeFilter) {
self.context.send_request(message);
}
fn send_notfound(&self, message: &types::NotFound) {
self.context.send_request(message);
}
fn ignored(&self, id: u32) {
self.context.ignore_response(id);
}
fn close(&self) {
self.context
.global()
.penalize_node(&self.context.info().address);
self.context.close()
}
}
pub struct SyncProtocol {
inbound_connection: InboundSyncConnectionRef,
context: Arc<PeerContext>,
state: InboundSyncConnectionStateRef,
}
impl SyncProtocol {
pub fn new(context: Arc<PeerContext>) -> Self {
let outbound_connection = Arc::new(OutboundSync::new(context.clone()));
let inbound_connection = context.global().create_sync_session(
0,
context.info().version_message.services(),
outbound_connection,
);
let state = inbound_connection.sync_state();
SyncProtocol {
inbound_connection: inbound_connection,
context: context,
state: state,
}
}
}
impl Protocol for SyncProtocol {
fn initialize(&mut self) {
let info = self.context.info();
self.inbound_connection.start_sync_session(
format!("{}/{}", info.address, info.user_agent),
info.version_message.clone(),
);
}
fn on_message(&mut self, command: &Command, payload: &Bytes) -> Result<(), Error> {
let version = self.context.info().version;
if command == &types::Inv::command() {
// we are synchronizing => we ask only for blocks with known headers => there are no useful blocks hashes for us
// we are synchronizing => we ignore all transactions until it is completed => there are no useful transactions hashes for us
if self.state.synchronizing() {
return Ok(());
}
let message: types::Inv = try!(deserialize_payload(payload, version));
self.inbound_connection.on_inventory(message);
} else if command == &types::GetData::command() {
if self.state.synchronizing() {
return Ok(());
}
let message: types::GetData = try!(deserialize_payload(payload, version));
self.inbound_connection.on_getdata(message);
} else if command == &types::GetBlocks::command() {
if self.state.synchronizing() {
return Ok(());
}
let message: types::GetBlocks = try!(deserialize_payload(payload, version));
self.inbound_connection.on_getblocks(message);
} else if command == &types::GetHeaders::command() {
if self.state.synchronizing() {
return Ok(());
}
let message: types::GetHeaders = try!(deserialize_payload(payload, version));
let id = self.context.declare_response();
trace!(
"declared response {} for request: {}",
id,
types::GetHeaders::command()
);
self.inbound_connection.on_getheaders(message, id);
} else if command == &types::Tx::command() {
// we ignore all transactions while synchronizing, as memory pool contains
// only verified transactions && we can not verify on-top transactions while
// we are not on the top
if self.state.synchronizing() {
return Ok(());
}
let message: types::Tx = try!(deserialize_payload(payload, version));
self.inbound_connection.on_transaction(message);
} else if command == &types::Block::command() {
let message: types::Block = try!(deserialize_payload(payload, version));
self.inbound_connection.on_block(message);
} else if command == &types::MemPool::command() {
if self.state.synchronizing() {
return Ok(());
}
let message: types::MemPool = try!(deserialize_payload(payload, version));
self.inbound_connection.on_mempool(message);
} else if command == &types::Headers::command() {
let message: types::Headers = try!(deserialize_payload(payload, version));
self.inbound_connection.on_headers(message);
} else if command == &types::FilterLoad::command() {
let message: types::FilterLoad = try!(deserialize_payload(payload, version));
self.inbound_connection.on_filterload(message);
} else if command == &types::FilterAdd::command() {
let message: types::FilterAdd = try!(deserialize_payload(payload, version));
self.inbound_connection.on_filteradd(message);
} else if command == &types::FilterClear::command() {
let message: types::FilterClear = try!(deserialize_payload(payload, version));
self.inbound_connection.on_filterclear(message);
} else if command == &types::MerkleBlock::command() {
let message: types::MerkleBlock = try!(deserialize_payload(payload, version));
self.inbound_connection.on_merkleblock(message);
} else if command == &types::SendHeaders::command() {
let message: types::SendHeaders = try!(deserialize_payload(payload, version));
self.inbound_connection.on_sendheaders(message);
} else if command == &types::FeeFilter::command() {
let message: types::FeeFilter = try!(deserialize_payload(payload, version));
self.inbound_connection.on_feefilter(message);
} else if command == &types::NotFound::command() {
let message: types::NotFound = try!(deserialize_payload(payload, version));
self.inbound_connection.on_notfound(message);
}
Ok(())
}
fn on_close(&mut self) {
self.inbound_connection.close_session()
}
}