use bitflags::bitflags;
use bytes::{Buf, BufMut, Bytes};
use cuprate_epee_encoding::{epee_object, EpeeValue, InnerMarker};
use cuprate_fixed_bytes::ByteArray;
use crate::NetworkAddress;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PeerSupportFlags(u32);
bitflags! {
impl PeerSupportFlags: u32 {
const FLUFFY_BLOCKS = 0b0000_0001;
const _ = !0;
}
}
impl From<u32> for PeerSupportFlags {
fn from(value: u32) -> Self {
PeerSupportFlags(value)
}
}
impl From<PeerSupportFlags> for u32 {
fn from(value: PeerSupportFlags) -> Self {
value.0
}
}
impl<'a> From<&'a PeerSupportFlags> for &'a u32 {
fn from(value: &'a PeerSupportFlags) -> Self {
&value.0
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BasicNodeData {
pub my_port: u32,
pub network_id: [u8; 16],
pub peer_id: u64,
pub support_flags: PeerSupportFlags,
pub rpc_port: u16,
pub rpc_credits_per_hash: u32,
}
epee_object! {
BasicNodeData,
my_port: u32,
network_id: [u8; 16],
peer_id: u64,
support_flags: PeerSupportFlags as u32 = 0_u32,
rpc_port: u16 = 0_u16,
rpc_credits_per_hash: u32 = 0_u32,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CoreSyncData {
pub cumulative_difficulty: u64,
pub cumulative_difficulty_top64: u64,
pub current_height: u64,
pub pruning_seed: u32,
pub top_id: [u8; 32],
pub top_version: u8,
}
epee_object! {
CoreSyncData,
cumulative_difficulty: u64,
cumulative_difficulty_top64: u64 = 0_u64,
current_height: u64,
pruning_seed: u32 = 0_u32,
top_id: [u8; 32],
top_version: u8 = 0_u8,
}
impl CoreSyncData {
pub fn new(
cumulative_difficulty_128: u128,
current_height: u64,
pruning_seed: u32,
top_id: [u8; 32],
top_version: u8,
) -> CoreSyncData {
let cumulative_difficulty = cumulative_difficulty_128 as u64;
let cumulative_difficulty_top64 = (cumulative_difficulty_128 >> 64) as u64;
CoreSyncData {
cumulative_difficulty,
cumulative_difficulty_top64,
current_height,
pruning_seed,
top_id,
top_version,
}
}
pub fn cumulative_difficulty(&self) -> u128 {
let mut ret: u128 = self.cumulative_difficulty_top64.into();
ret <<= 64;
ret | (Into::<u128>::into(self.cumulative_difficulty))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct PeerListEntryBase {
pub adr: NetworkAddress,
pub id: u64,
pub last_seen: i64,
pub pruning_seed: u32,
pub rpc_port: u16,
pub rpc_credits_per_hash: u32,
}
epee_object! {
PeerListEntryBase,
adr: NetworkAddress,
id: u64,
last_seen: i64 = 0_i64,
pruning_seed: u32 = 0_u32,
rpc_port: u16 = 0_u16,
rpc_credits_per_hash: u32 = 0_u32,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PrunedTxBlobEntry {
pub tx: Bytes,
pub prunable_hash: ByteArray<32>,
}
epee_object!(
PrunedTxBlobEntry,
tx: Bytes,
prunable_hash: ByteArray<32>,
);
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum TransactionBlobs {
Pruned(Vec<PrunedTxBlobEntry>),
Normal(Vec<Bytes>),
None,
}
impl TransactionBlobs {
pub fn take_pruned(self) -> Option<Vec<PrunedTxBlobEntry>> {
match self {
TransactionBlobs::Normal(_) => None,
TransactionBlobs::Pruned(txs) => Some(txs),
TransactionBlobs::None => Some(vec![]),
}
}
pub fn take_normal(self) -> Option<Vec<Bytes>> {
match self {
TransactionBlobs::Normal(txs) => Some(txs),
TransactionBlobs::Pruned(_) => None,
TransactionBlobs::None => Some(vec![]),
}
}
pub fn len(&self) -> usize {
match self {
TransactionBlobs::Normal(txs) => txs.len(),
TransactionBlobs::Pruned(txs) => txs.len(),
TransactionBlobs::None => 0,
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BlockCompleteEntry {
pub pruned: bool,
pub block: Bytes,
pub block_weight: u64,
pub txs: TransactionBlobs,
}
epee_object!(
BlockCompleteEntry,
pruned: bool = false,
block: Bytes,
block_weight: u64 = 0_u64,
txs: TransactionBlobs = TransactionBlobs::None => tx_blob_read, tx_blob_write, should_write_tx_blobs,
);
fn tx_blob_read<B: Buf>(b: &mut B) -> cuprate_epee_encoding::Result<TransactionBlobs> {
let marker = cuprate_epee_encoding::read_marker(b)?;
match marker.inner_marker {
InnerMarker::Object => Ok(TransactionBlobs::Pruned(Vec::read(b, &marker)?)),
InnerMarker::String => Ok(TransactionBlobs::Normal(Vec::read(b, &marker)?)),
_ => Err(cuprate_epee_encoding::Error::Value(
"Invalid marker for tx blobs".to_string(),
)),
}
}
fn tx_blob_write<B: BufMut>(
val: TransactionBlobs,
field_name: &str,
w: &mut B,
) -> cuprate_epee_encoding::Result<()> {
if should_write_tx_blobs(&val) {
match val {
TransactionBlobs::Normal(bytes) => {
cuprate_epee_encoding::write_field(bytes, field_name, w)?
}
TransactionBlobs::Pruned(obj) => {
cuprate_epee_encoding::write_field(obj, field_name, w)?
}
TransactionBlobs::None => (),
}
}
Ok(())
}
fn should_write_tx_blobs(val: &TransactionBlobs) -> bool {
!val.is_empty()
}
#[cfg(test)]
mod tests {
use super::CoreSyncData;
#[test]
fn core_sync_cumulative_difficulty() {
let core_sync = CoreSyncData::new(u128::MAX, 80085, 200, [0; 32], 21);
assert_eq!(core_sync.cumulative_difficulty(), u128::MAX);
let core_sync = CoreSyncData::new(21, 80085, 200, [0; 32], 21);
assert_eq!(core_sync.cumulative_difficulty(), 21);
}
}