use std::{collections::HashSet, fmt};
use zakura_chain::{
block,
transaction::{UnminedTx, UnminedTxId},
};
use super::super::types::Nonce;
use crate::{zakura::ZakuraPeerId, PeerSocketAddr};
#[cfg(any(test, feature = "proptest-impl"))]
use proptest_derive::Arbitrary;
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
pub enum PeerSource {
LegacySocket(PeerSocketAddr),
Zakura(ZakuraPeerId),
}
impl From<PeerSocketAddr> for PeerSource {
fn from(peer_addr: PeerSocketAddr) -> Self {
Self::LegacySocket(peer_addr)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
pub enum Request {
Peers,
#[doc(hidden)]
Ping(Nonce),
BlocksByHash(HashSet<block::Hash>),
BlocksByHashFrom {
hashes: HashSet<block::Hash>,
source: PeerSource,
},
TransactionsById(HashSet<UnminedTxId>),
TransactionsByIdFrom {
ids: HashSet<UnminedTxId>,
source: PeerSource,
},
FindBlocks {
known_blocks: Vec<block::Hash>,
stop: Option<block::Hash>,
},
FindHeaders {
known_blocks: Vec<block::Hash>,
stop: Option<block::Hash>,
},
PushTransaction(UnminedTx, Option<PeerSource>),
AdvertiseTransactionIds(HashSet<UnminedTxId>, Option<PeerSource>),
AdvertiseBlock(block::Hash, Option<PeerSource>),
AdvertiseBlockToAll(block::Hash),
MempoolTransactionIds,
}
impl fmt::Display for Request {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&match self {
Request::Peers => "Peers".to_string(),
Request::Ping(_) => "Ping".to_string(),
Request::BlocksByHash(hashes) => {
format!("BlocksByHash({})", hashes.len())
}
Request::BlocksByHashFrom { hashes, .. } => {
format!("BlocksByHashFrom({})", hashes.len())
}
Request::TransactionsById(ids) => format!("TransactionsById({})", ids.len()),
Request::TransactionsByIdFrom { ids, .. } => {
format!("TransactionsByIdFrom({})", ids.len())
}
Request::FindBlocks { known_blocks, stop } => format!(
"FindBlocks {{ known_blocks: {}, stop: {} }}",
known_blocks.len(),
if stop.is_some() { "Some" } else { "None" },
),
Request::FindHeaders { known_blocks, stop } => format!(
"FindHeaders {{ known_blocks: {}, stop: {} }}",
known_blocks.len(),
if stop.is_some() { "Some" } else { "None" },
),
Request::PushTransaction(_, _) => "PushTransaction".to_string(),
Request::AdvertiseTransactionIds(ids, _) => {
format!("AdvertiseTransactionIds({})", ids.len())
}
Request::AdvertiseBlock(_, _) => "AdvertiseBlock".to_string(),
Request::AdvertiseBlockToAll(_) => "AdvertiseBlockToAll".to_string(),
Request::MempoolTransactionIds => "MempoolTransactionIds".to_string(),
})
}
}
impl Request {
pub fn command(&self) -> &'static str {
match self {
Request::Peers => "Peers",
Request::Ping(_) => "Ping",
Request::BlocksByHash(_) | Request::BlocksByHashFrom { .. } => "BlocksByHash",
Request::TransactionsById(_) | Request::TransactionsByIdFrom { .. } => {
"TransactionsById"
}
Request::FindBlocks { .. } => "FindBlocks",
Request::FindHeaders { .. } => "FindHeaders",
Request::PushTransaction(_, _) => "PushTransaction",
Request::AdvertiseTransactionIds(_, _) => "AdvertiseTransactionIds",
Request::AdvertiseBlock(_, _) | Request::AdvertiseBlockToAll(_) => "AdvertiseBlock",
Request::MempoolTransactionIds => "MempoolTransactionIds",
}
}
pub fn is_inventory_download(&self) -> bool {
matches!(
self,
Request::BlocksByHash(_)
| Request::BlocksByHashFrom { .. }
| Request::TransactionsById(_)
| Request::TransactionsByIdFrom { .. }
)
}
pub fn block_hash_inventory(&self) -> HashSet<block::Hash> {
match self {
Request::BlocksByHash(block_hashes)
| Request::BlocksByHashFrom {
hashes: block_hashes,
..
} => block_hashes.clone(),
_ => HashSet::new(),
}
}
pub fn transaction_id_inventory(&self) -> HashSet<UnminedTxId> {
match self {
Request::TransactionsById(transaction_ids)
| Request::TransactionsByIdFrom {
ids: transaction_ids,
..
} => transaction_ids.clone(),
_ => HashSet::new(),
}
}
pub fn inventory_source(&self) -> Option<PeerSource> {
match self {
Request::BlocksByHashFrom { source, .. }
| Request::TransactionsByIdFrom { source, .. } => Some(source.clone()),
_ => None,
}
}
}