mirror of
https://github.com/hinto-janai/cuprate.git
synced 2024-12-23 03:59:37 +00:00
Compare commits
2 commits
d9787f95ff
...
afab072816
Author | SHA1 | Date | |
---|---|---|---|
|
afab072816 | ||
|
b42a110c98 |
9 changed files with 209 additions and 57 deletions
|
@ -3,6 +3,7 @@
|
||||||
//! Will contain the code to initiate the RPC and a request handler.
|
//! Will contain the code to initiate the RPC and a request handler.
|
||||||
|
|
||||||
mod bin;
|
mod bin;
|
||||||
|
mod constants;
|
||||||
mod handler;
|
mod handler;
|
||||||
mod json;
|
mod json;
|
||||||
mod other;
|
mod other;
|
||||||
|
|
5
binaries/cuprated/src/rpc/constants.rs
Normal file
5
binaries/cuprated/src/rpc/constants.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
//! Constants used within RPC.
|
||||||
|
|
||||||
|
/// The string message used in RPC response fields for when
|
||||||
|
/// `cuprated` does not support a field that `monerod` has.
|
||||||
|
pub(super) const FIELD_NOT_SUPPORTED: &str = "`cuprated` does not support this field.";
|
|
@ -97,20 +97,6 @@ pub enum BlockchainManagerRequest {
|
||||||
/// The address that will receive the coinbase reward.
|
/// The address that will receive the coinbase reward.
|
||||||
wallet_address: String,
|
wallet_address: String,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Get a visual [`String`] overview of blockchain progress.
|
|
||||||
///
|
|
||||||
/// This is a highly implementation specific format used by
|
|
||||||
/// `monerod` in the `sync_info` RPC call's `overview` field;
|
|
||||||
/// it is essentially an ASCII visual of blocks.
|
|
||||||
///
|
|
||||||
/// See also:
|
|
||||||
/// - <https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#sync_info>
|
|
||||||
/// - <https://github.com/monero-project/monero/blob/master/src/cryptonote_protocol/block_queue.cpp#L178>
|
|
||||||
Overview {
|
|
||||||
/// TODO: the current blockchain height? do we need to pass this?
|
|
||||||
height: usize,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO: use real type when public.
|
/// TODO: use real type when public.
|
||||||
|
@ -157,9 +143,6 @@ pub enum BlockchainManagerResponse {
|
||||||
/// The new top height. (TODO: is this correct?)
|
/// The new top height. (TODO: is this correct?)
|
||||||
height: usize,
|
height: usize,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Response to [`BlockchainManagerRequest::Overview`]
|
|
||||||
Overview(String),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO: use real type when public.
|
/// TODO: use real type when public.
|
||||||
|
|
|
@ -14,6 +14,8 @@ use cuprate_p2p_core::{
|
||||||
AddressBook, NetworkZone,
|
AddressBook, NetworkZone,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::rpc::constants::FIELD_NOT_SUPPORTED;
|
||||||
|
|
||||||
// FIXME: use `anyhow::Error` over `tower::BoxError` in address book.
|
// FIXME: use `anyhow::Error` over `tower::BoxError` in address book.
|
||||||
|
|
||||||
/// [`AddressBookRequest::PeerlistSize`]
|
/// [`AddressBookRequest::PeerlistSize`]
|
||||||
|
@ -53,15 +55,20 @@ pub(crate) async fn connection_info<Z: NetworkZone>(
|
||||||
let vec = vec
|
let vec = vec
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|info| {
|
.map(|info| {
|
||||||
use cuprate_p2p_core::types::AddressType as A1;
|
/// Message to use when casting between enums with `u8` fails.
|
||||||
use cuprate_rpc_types::misc::AddressType as A2;
|
/// This should never happen.
|
||||||
|
const EXPECT: &str = "u8 repr between these types should be 1-1";
|
||||||
|
|
||||||
let address_type = match info.address_type {
|
let address_type =
|
||||||
A1::Invalid => A2::Invalid,
|
cuprate_rpc_types::misc::AddressType::from_u8(info.address_type.to_u8())
|
||||||
A1::Ipv4 => A2::Ipv4,
|
.expect(EXPECT);
|
||||||
A1::Ipv6 => A2::Ipv6,
|
|
||||||
A1::I2p => A2::I2p,
|
let state = cuprate_rpc_types::misc::ConnectionState::from_u8(info.state.to_u8())
|
||||||
A1::Tor => A2::Tor,
|
.expect(EXPECT);
|
||||||
|
|
||||||
|
let (ip, port) = match info.socket_addr {
|
||||||
|
Some(socket) => (socket.ip().to_string(), socket.port().to_string()),
|
||||||
|
None => (String::new(), String::new()),
|
||||||
};
|
};
|
||||||
|
|
||||||
ConnectionInfo {
|
ConnectionInfo {
|
||||||
|
@ -69,18 +76,18 @@ pub(crate) async fn connection_info<Z: NetworkZone>(
|
||||||
address_type,
|
address_type,
|
||||||
avg_download: info.avg_download,
|
avg_download: info.avg_download,
|
||||||
avg_upload: info.avg_upload,
|
avg_upload: info.avg_upload,
|
||||||
connection_id: hex::encode(info.connection_id.to_ne_bytes()),
|
connection_id: String::from(FIELD_NOT_SUPPORTED),
|
||||||
current_download: info.current_download,
|
current_download: info.current_download,
|
||||||
current_upload: info.current_upload,
|
current_upload: info.current_upload,
|
||||||
height: info.height,
|
height: info.height,
|
||||||
host: info.host,
|
host: info.host,
|
||||||
incoming: info.incoming,
|
incoming: info.incoming,
|
||||||
ip: info.ip,
|
ip,
|
||||||
live_time: info.live_time,
|
live_time: info.live_time,
|
||||||
localhost: info.localhost,
|
localhost: info.localhost,
|
||||||
local_ip: info.local_ip,
|
local_ip: info.local_ip,
|
||||||
peer_id: info.peer_id,
|
peer_id: hex::encode(info.peer_id.to_ne_bytes()),
|
||||||
port: info.port,
|
port,
|
||||||
pruning_seed: info.pruning_seed.compress(),
|
pruning_seed: info.pruning_seed.compress(),
|
||||||
recv_count: info.recv_count,
|
recv_count: info.recv_count,
|
||||||
recv_idle_time: info.recv_idle_time,
|
recv_idle_time: info.recv_idle_time,
|
||||||
|
@ -88,7 +95,7 @@ pub(crate) async fn connection_info<Z: NetworkZone>(
|
||||||
rpc_port: info.rpc_port,
|
rpc_port: info.rpc_port,
|
||||||
send_count: info.send_count,
|
send_count: info.send_count,
|
||||||
send_idle_time: info.send_idle_time,
|
send_idle_time: info.send_idle_time,
|
||||||
state: info.state,
|
state,
|
||||||
support_flags: info.support_flags,
|
support_flags: info.support_flags,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -190,7 +197,7 @@ pub(crate) async fn spans<Z: NetworkZone>(
|
||||||
let vec = vec
|
let vec = vec
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|span| Span {
|
.map(|span| Span {
|
||||||
connection_id: hex::encode(span.connection_id.to_ne_bytes()),
|
connection_id: String::from(FIELD_NOT_SUPPORTED),
|
||||||
nblocks: span.nblocks,
|
nblocks: span.nblocks,
|
||||||
rate: span.rate,
|
rate: span.rate,
|
||||||
remote_address: span.remote_address.to_string(),
|
remote_address: span.remote_address.to_string(),
|
||||||
|
|
|
@ -214,22 +214,3 @@ pub(crate) async fn generate_blocks(
|
||||||
|
|
||||||
Ok((blocks, usize_to_u64(height)))
|
Ok((blocks, usize_to_u64(height)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [`BlockchainManagerRequest::Overview`]
|
|
||||||
pub(crate) async fn overview(
|
|
||||||
blockchain_manager: &mut BlockchainManagerHandle,
|
|
||||||
height: u64,
|
|
||||||
) -> Result<String, Error> {
|
|
||||||
let BlockchainManagerResponse::Overview(overview) = blockchain_manager
|
|
||||||
.ready()
|
|
||||||
.await?
|
|
||||||
.call(BlockchainManagerRequest::Overview {
|
|
||||||
height: u64_to_usize(height),
|
|
||||||
})
|
|
||||||
.await?
|
|
||||||
else {
|
|
||||||
unreachable!();
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(overview)
|
|
||||||
}
|
|
||||||
|
|
|
@ -81,26 +81,85 @@ impl AddressType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An enumeration of P2P connection states.
|
||||||
|
///
|
||||||
|
/// Used [`ConnectionInfo::state`].
|
||||||
|
///
|
||||||
|
/// Original definition:
|
||||||
|
/// - <https://github.com/monero-project/monero/blob/893916ad091a92e765ce3241b94e706ad012b62a/src/cryptonote_basic/connection_context.h#L49>
|
||||||
|
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum ConnectionState {
|
||||||
|
BeforeHandshake,
|
||||||
|
Synchronizing,
|
||||||
|
Standby,
|
||||||
|
Idle,
|
||||||
|
#[default]
|
||||||
|
Normal,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConnectionState {
|
||||||
|
/// Convert [`Self`] to a [`u8`].
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use cuprate_p2p_core::types::ConnectionState as C;
|
||||||
|
///
|
||||||
|
/// assert_eq!(C::BeforeHandshake.to_u8(), 0);
|
||||||
|
/// assert_eq!(C::Synchronizing.to_u8(), 1);
|
||||||
|
/// assert_eq!(C::Standby.to_u8(), 2);
|
||||||
|
/// assert_eq!(C::Idle.to_u8(), 3);
|
||||||
|
/// assert_eq!(C::Normal.to_u8(), 4);
|
||||||
|
/// ```
|
||||||
|
pub const fn to_u8(self) -> u8 {
|
||||||
|
self as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert a [`u8`] to a [`Self`].
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// This returns [`None`] if `u > 4`.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use cuprate_p2p_core::types::ConnectionState as C;
|
||||||
|
///
|
||||||
|
/// assert_eq!(C::from_u8(0), Some(C::BeforeHandShake));
|
||||||
|
/// assert_eq!(C::from_u8(1), Some(C::Synchronizing));
|
||||||
|
/// assert_eq!(C::from_u8(2), Some(C::Standby));
|
||||||
|
/// assert_eq!(C::from_u8(3), Some(C::Idle));
|
||||||
|
/// assert_eq!(C::from_u8(4), Some(C::Normal));
|
||||||
|
/// assert_eq!(C::from_u8(5), None);
|
||||||
|
/// ```
|
||||||
|
pub const fn from_u8(u: u8) -> Option<Self> {
|
||||||
|
Some(match u {
|
||||||
|
0 => Self::BeforeHandshake,
|
||||||
|
1 => Self::Synchronizing,
|
||||||
|
2 => Self::Standby,
|
||||||
|
3 => Self::Idle,
|
||||||
|
4 => Self::Normal,
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: reduce fields and map to RPC type.
|
// TODO: reduce fields and map to RPC type.
|
||||||
//
|
//
|
||||||
/// Data within [`crate::services::AddressBookResponse::ConnectionInfo`].
|
/// Data within [`crate::services::AddressBookResponse::ConnectionInfo`].
|
||||||
pub struct ConnectionInfo<A: NetZoneAddress> {
|
pub struct ConnectionInfo<A: NetZoneAddress> {
|
||||||
|
// The following fields are mostly the same as `monerod`.
|
||||||
pub address: A,
|
pub address: A,
|
||||||
pub address_type: AddressType,
|
pub address_type: AddressType,
|
||||||
pub avg_download: u64,
|
pub avg_download: u64,
|
||||||
pub avg_upload: u64,
|
pub avg_upload: u64,
|
||||||
pub connection_id: u64, // TODO: boost::uuids::uuid
|
|
||||||
pub current_download: u64,
|
pub current_download: u64,
|
||||||
pub current_upload: u64,
|
pub current_upload: u64,
|
||||||
pub height: u64,
|
pub height: u64,
|
||||||
|
/// Either a domain or an IP without the port.
|
||||||
pub host: String,
|
pub host: String,
|
||||||
pub incoming: bool,
|
pub incoming: bool,
|
||||||
pub ip: String,
|
|
||||||
pub live_time: u64,
|
pub live_time: u64,
|
||||||
pub localhost: bool,
|
pub localhost: bool,
|
||||||
pub local_ip: bool,
|
pub local_ip: bool,
|
||||||
pub peer_id: String,
|
pub peer_id: u64,
|
||||||
pub port: String,
|
|
||||||
pub pruning_seed: PruningSeed,
|
pub pruning_seed: PruningSeed,
|
||||||
pub recv_count: u64,
|
pub recv_count: u64,
|
||||||
pub recv_idle_time: u64,
|
pub recv_idle_time: u64,
|
||||||
|
@ -108,8 +167,16 @@ pub struct ConnectionInfo<A: NetZoneAddress> {
|
||||||
pub rpc_port: u16,
|
pub rpc_port: u16,
|
||||||
pub send_count: u64,
|
pub send_count: u64,
|
||||||
pub send_idle_time: u64,
|
pub send_idle_time: u64,
|
||||||
pub state: String, // TODO: what type is this?
|
pub state: ConnectionState,
|
||||||
pub support_flags: u32,
|
pub support_flags: u32,
|
||||||
|
|
||||||
|
// The following fields are slightly different than `monerod`.
|
||||||
|
//
|
||||||
|
/// [`None`] if Tor/i2p or unknown.
|
||||||
|
pub socket_addr: Option<std::net::SocketAddr>,
|
||||||
|
// This field does not exist for Cuprate:
|
||||||
|
// <https://github.com/Cuprate/cuprate/pull/320#discussion_r1811335020>
|
||||||
|
// pub connection_id: u128,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used in RPC's `sync_info`.
|
/// Used in RPC's `sync_info`.
|
||||||
|
@ -117,7 +184,6 @@ pub struct ConnectionInfo<A: NetZoneAddress> {
|
||||||
/// Data within [`crate::services::AddressBookResponse::Spans`].
|
/// Data within [`crate::services::AddressBookResponse::Spans`].
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct Span<A: NetZoneAddress> {
|
pub struct Span<A: NetZoneAddress> {
|
||||||
pub connection_id: u64, // TODO: boost::uuids::uuid
|
|
||||||
pub nblocks: u64,
|
pub nblocks: u64,
|
||||||
pub rate: u32,
|
pub rate: u32,
|
||||||
pub remote_address: A,
|
pub remote_address: A,
|
||||||
|
|
107
rpc/types/src/misc/connection_state.rs
Normal file
107
rpc/types/src/misc/connection_state.rs
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
//! Types of network addresses; used in P2P.
|
||||||
|
|
||||||
|
use cuprate_epee_encoding::Marker;
|
||||||
|
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[cfg(feature = "epee")]
|
||||||
|
use cuprate_epee_encoding::{
|
||||||
|
error,
|
||||||
|
macros::bytes::{Buf, BufMut},
|
||||||
|
EpeeValue,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Used in [`crate::misc::ConnectionInfo::address_type`].
|
||||||
|
#[doc = crate::macros::monero_definition_link!(
|
||||||
|
cc73fe71162d564ffda8e549b79a350bca53c454,
|
||||||
|
"cryptonote_basic/connection_context.h",
|
||||||
|
49..=56
|
||||||
|
)]
|
||||||
|
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
#[cfg_attr(feature = "serde", serde(untagged, try_from = "u8", into = "u8"))]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum ConnectionState {
|
||||||
|
BeforeHandshake,
|
||||||
|
Synchronizing,
|
||||||
|
Standby,
|
||||||
|
Idle,
|
||||||
|
#[default]
|
||||||
|
Normal,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConnectionState {
|
||||||
|
/// Convert [`Self`] to a [`u8`].
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use cuprate_p2p_core::types::ConnectionState as C;
|
||||||
|
///
|
||||||
|
/// assert_eq!(C::BeforeHandshake.to_u8(), 0);
|
||||||
|
/// assert_eq!(C::Synchronizing.to_u8(), 1);
|
||||||
|
/// assert_eq!(C::Standby.to_u8(), 2);
|
||||||
|
/// assert_eq!(C::Idle.to_u8(), 3);
|
||||||
|
/// assert_eq!(C::Normal.to_u8(), 4);
|
||||||
|
/// ```
|
||||||
|
pub const fn to_u8(self) -> u8 {
|
||||||
|
self as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert a [`u8`] to a [`Self`].
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// This returns [`None`] if `u > 4`.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use cuprate_p2p_core::types::ConnectionState as C;
|
||||||
|
///
|
||||||
|
/// assert_eq!(C::from_u8(0), Some(C::BeforeHandShake));
|
||||||
|
/// assert_eq!(C::from_u8(1), Some(C::Synchronizing));
|
||||||
|
/// assert_eq!(C::from_u8(2), Some(C::Standby));
|
||||||
|
/// assert_eq!(C::from_u8(3), Some(C::Idle));
|
||||||
|
/// assert_eq!(C::from_u8(4), Some(C::Normal));
|
||||||
|
/// assert_eq!(C::from_u8(5), None);
|
||||||
|
/// ```
|
||||||
|
pub const fn from_u8(u: u8) -> Option<Self> {
|
||||||
|
Some(match u {
|
||||||
|
0 => Self::BeforeHandshake,
|
||||||
|
1 => Self::Synchronizing,
|
||||||
|
2 => Self::Standby,
|
||||||
|
3 => Self::Idle,
|
||||||
|
4 => Self::Normal,
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ConnectionState> for u8 {
|
||||||
|
fn from(value: ConnectionState) -> Self {
|
||||||
|
value.to_u8()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for ConnectionState {
|
||||||
|
type Error = u8;
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
match Self::from_u8(value) {
|
||||||
|
Some(s) => Ok(s),
|
||||||
|
None => Err(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "epee")]
|
||||||
|
impl EpeeValue for ConnectionState {
|
||||||
|
const MARKER: Marker = u8::MARKER;
|
||||||
|
|
||||||
|
fn read<B: Buf>(r: &mut B, marker: &Marker) -> error::Result<Self> {
|
||||||
|
let u = u8::read(r, marker)?;
|
||||||
|
Self::from_u8(u).ok_or(error::Error::Format("u8 was greater than 4"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write<B: BufMut>(self, w: &mut B) -> error::Result<()> {
|
||||||
|
let u = self.to_u8();
|
||||||
|
u8::write(u, w)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -135,7 +135,7 @@ define_struct_and_impl_epee! {
|
||||||
// Exists in the original definition, but isn't
|
// Exists in the original definition, but isn't
|
||||||
// used or (de)serialized for RPC purposes.
|
// used or (de)serialized for RPC purposes.
|
||||||
// ssl: bool,
|
// ssl: bool,
|
||||||
state: String,
|
state: crate::misc::ConnectionState,
|
||||||
support_flags: u32,
|
support_flags: u32,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
//---------------------------------------------------------------------------------------------------- Mod
|
//---------------------------------------------------------------------------------------------------- Mod
|
||||||
mod address_type;
|
mod address_type;
|
||||||
mod binary_string;
|
mod binary_string;
|
||||||
|
mod connection_state;
|
||||||
mod distribution;
|
mod distribution;
|
||||||
mod key_image_spent_status;
|
mod key_image_spent_status;
|
||||||
#[expect(clippy::module_inception)]
|
#[expect(clippy::module_inception)]
|
||||||
|
@ -24,6 +25,7 @@ mod tx_entry;
|
||||||
|
|
||||||
pub use address_type::AddressType;
|
pub use address_type::AddressType;
|
||||||
pub use binary_string::BinaryString;
|
pub use binary_string::BinaryString;
|
||||||
|
pub use connection_state::ConnectionState;
|
||||||
pub use distribution::{Distribution, DistributionCompressedBinary, DistributionUncompressed};
|
pub use distribution::{Distribution, DistributionCompressedBinary, DistributionUncompressed};
|
||||||
pub use key_image_spent_status::KeyImageSpentStatus;
|
pub use key_image_spent_status::KeyImageSpentStatus;
|
||||||
pub use misc::{
|
pub use misc::{
|
||||||
|
|
Loading…
Reference in a new issue