276 lines
10 KiB
Rust
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()
|
|
}
|
|
}
|