Compare commits

..

No commits in common. "fd84940ee69c971b6d7427f4467817719390e16e" and "79b03e386a3f5ec642905b283200c194613dd548" have entirely different histories.

18 changed files with 223 additions and 399 deletions

34
.github/workflows/audit.yml vendored Normal file
View file

@ -0,0 +1,34 @@
# This runs `cargo audit` on all dependencies (only if Cargo deps changed)
name: Audit
on:
push:
paths:
- '**/Cargo.toml'
- '**/Cargo.lock'
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
jobs:
audit:
runs-on: ubuntu-latest
steps:
- name: Cache
uses: actions/cache@v4
with:
path: |
~/.cargo
target
key: audit
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install dependencies
run: cargo install cargo-audit --locked
- name: Audit
run: cargo audit

74
Cargo.lock generated
View file

@ -87,7 +87,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]
@ -98,7 +98,7 @@ checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]
@ -292,7 +292,7 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
"syn_derive",
]
@ -319,7 +319,7 @@ checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]
@ -399,7 +399,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]
@ -855,14 +855,6 @@ dependencies = [
"tracing",
]
[[package]]
name = "cuprate-p2p-bucket"
version = "0.1.0"
dependencies = [
"arrayvec",
"rand",
]
[[package]]
name = "cuprate-p2p-core"
version = "0.1.0"
@ -1109,7 +1101,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]
@ -1130,12 +1122,11 @@ dependencies = [
[[package]]
name = "dashmap"
version = "6.1.0"
version = "5.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf"
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
dependencies = [
"cfg-if",
"crossbeam-utils",
"hashbrown",
"lock_api",
"once_cell",
@ -1335,7 +1326,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]
@ -2100,7 +2091,7 @@ dependencies = [
"phf_shared",
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]
@ -2129,7 +2120,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]
@ -2226,13 +2217,13 @@ dependencies = [
[[package]]
name = "proptest-derive"
version = "0.5.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ff7ff745a347b87471d859a377a9a404361e7efc2a971d73424a6d183c0fc77"
checksum = "9cf16337405ca084e9c78985114633b6827711d22b9e6ef6c6c0d665eb3f0b6e"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 1.0.109",
]
[[package]]
@ -2381,7 +2372,7 @@ checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]
@ -2588,7 +2579,7 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]
@ -2758,7 +2749,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustversion",
"syn",
"syn 2.0.77",
]
[[package]]
@ -2767,6 +2758,17 @@ version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.77"
@ -2787,7 +2789,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]
@ -2847,7 +2849,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]
@ -2907,7 +2909,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]
@ -3052,7 +3054,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]
@ -3228,7 +3230,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
"wasm-bindgen-shared",
]
@ -3250,7 +3252,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -3332,7 +3334,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]
@ -3343,7 +3345,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]
@ -3555,7 +3557,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]
[[package]]
@ -3575,5 +3577,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.77",
]

View file

@ -16,7 +16,6 @@ members = [
"net/wire",
"p2p/p2p",
"p2p/p2p-core",
"p2p/bucket",
"p2p/dandelion-tower",
"p2p/async-buffer",
"p2p/address-book",
@ -65,7 +64,6 @@ cuprate-levin = { path = "net/levin" ,default-feature
cuprate-wire = { path = "net/wire" ,default-features = false}
cuprate-p2p = { path = "p2p/p2p" ,default-features = false}
cuprate-p2p-core = { path = "p2p/p2p-core" ,default-features = false}
cuprate-p2p-bucket = { path = "p2p/p2p-bucket" ,default-features = false}
cuprate-dandelion-tower = { path = "p2p/dandelion-tower" ,default-features = false}
cuprate-async-buffer = { path = "p2p/async-buffer" ,default-features = false}
cuprate-address-book = { path = "p2p/address-book" ,default-features = false}
@ -81,55 +79,54 @@ cuprate-rpc-types = { path = "rpc/types" ,default-feature
cuprate-rpc-interface = { path = "rpc/interface" ,default-features = false}
# External dependencies
anyhow = { version = "1", default-features = false }
arrayvec = { version = "0.7", default-features = false }
async-trait = { version = "0.1", default-features = false }
bitflags = { version = "2", default-features = false }
anyhow = { version = "1.0.89", default-features = false }
async-trait = { version = "0.1.82", default-features = false }
bitflags = { version = "2.6.0", default-features = false }
blake3 = { version = "1", default-features = false }
borsh = { version = "1", default-features = false }
bytemuck = { version = "1", default-features = false }
bytes = { version = "1", default-features = false }
cfg-if = { version = "1", default-features = false }
clap = { version = "4", default-features = false }
chrono = { version = "0.4", default-features = false }
crypto-bigint = { version = "0.5", default-features = false }
crossbeam = { version = "0.8", default-features = false }
const_format = { version = "0.2", default-features = false }
curve25519-dalek = { version = "4", default-features = false }
dashmap = { version = "6", default-features = false }
dirs = { version = "5", default-features = false }
futures = { version = "0.3", default-features = false }
hex = { version = "0.4", default-features = false }
borsh = { version = "1.5.1", default-features = false }
bytemuck = { version = "1.18.0", default-features = false }
bytes = { version = "1.7.2", default-features = false }
cfg-if = { version = "1.0.0", default-features = false }
clap = { version = "4.5.17", default-features = false }
chrono = { version = "0.4.38", default-features = false }
crypto-bigint = { version = "0.5.5", default-features = false }
crossbeam = { version = "0.8.4", default-features = false }
const_format = { version = "0.2.33", default-features = false }
curve25519-dalek = { version = "4.1.3", default-features = false }
dashmap = { version = "5.5.3", default-features = false }
dirs = { version = "5.0.1", default-features = false }
futures = { version = "0.3.30", default-features = false }
hex = { version = "0.4.3", default-features = false }
hex-literal = { version = "0.4", default-features = false }
indexmap = { version = "2", default-features = false }
indexmap = { version = "2.5.0", default-features = false }
monero-serai = { git = "https://github.com/Cuprate/serai.git", rev = "d5205ce", default-features = false }
paste = { version = "1", default-features = false }
pin-project = { version = "1", default-features = false }
paste = { version = "1.0.15", default-features = false }
pin-project = { version = "1.1.5", default-features = false }
randomx-rs = { git = "https://github.com/Cuprate/randomx-rs.git", rev = "0028464", default-features = false }
rand = { version = "0.8", default-features = false }
rand_distr = { version = "0.4", default-features = false }
rayon = { version = "1", default-features = false }
serde_bytes = { version = "0.11", default-features = false }
serde_json = { version = "1", default-features = false }
serde = { version = "1", default-features = false }
strum = { version = "0.26", default-features = false }
thiserror = { version = "1", default-features = false }
thread_local = { version = "1", default-features = false }
tokio-util = { version = "0.7", default-features = false }
tokio-stream = { version = "0.1", default-features = false }
tokio = { version = "1", default-features = false }
rand = { version = "0.8.5", default-features = false }
rand_distr = { version = "0.4.3", default-features = false }
rayon = { version = "1.10.0", default-features = false }
serde_bytes = { version = "0.11.15", default-features = false }
serde_json = { version = "1.0.128", default-features = false }
serde = { version = "1.0.210", default-features = false }
strum = { version = "0.26.3", default-features = false }
thiserror = { version = "1.0.63", default-features = false }
thread_local = { version = "1.1.8", default-features = false }
tokio-util = { version = "0.7.12", default-features = false }
tokio-stream = { version = "0.1.16", default-features = false }
tokio = { version = "1.40.0", default-features = false }
tower = { git = "https://github.com/Cuprate/tower.git", rev = "6c7faf0", default-features = false } # <https://github.com/tower-rs/tower/pull/796>
tracing-subscriber = { version = "0.3", default-features = false }
tracing = { version = "0.1", default-features = false }
tracing-subscriber = { version = "0.3.18", default-features = false }
tracing = { version = "0.1.40", default-features = false }
## workspace.dev-dependencies
monero-rpc = { git = "https://github.com/Cuprate/serai.git", rev = "d5205ce" }
monero-simple-request-rpc = { git = "https://github.com/Cuprate/serai.git", rev = "d5205ce" }
tempfile = { version = "3" }
pretty_assertions = { version = "1" }
pretty_assertions = { version = "1.4.1" }
proptest = { version = "1" }
proptest-derive = { version = "0.5" }
tokio-test = { version = "0.4" }
proptest-derive = { version = "0.4.0" }
tokio-test = { version = "0.4.4" }
## TODO:
## Potential dependencies.

View file

@ -1,5 +1,3 @@
//! RPC request handler functions (binary endpoints).
use anyhow::Error;
use cuprate_rpc_types::{

View file

@ -1,4 +1,4 @@
//! `cuprated`'s implementation of [`RpcHandler`].
//! Dummy implementation of [`RpcHandler`].
use std::task::{Context, Poll};
@ -7,7 +7,7 @@ use futures::future::BoxFuture;
use monero_serai::block::Block;
use tower::Service;
use cuprate_blockchain::service::BlockchainReadHandle;
use cuprate_blockchain::service::{BlockchainReadHandle, BlockchainWriteHandle};
use cuprate_consensus::BlockChainContextService;
use cuprate_pruning::PruningSeed;
use cuprate_rpc_interface::RpcHandler;
@ -16,7 +16,8 @@ use cuprate_rpc_types::{
json::{JsonRpcRequest, JsonRpcResponse},
other::{OtherRequest, OtherResponse},
};
use cuprate_txpool::service::TxpoolReadHandle;
use cuprate_txpool::service::{TxpoolReadHandle, TxpoolWriteHandle};
use cuprate_types::{AddAuxPow, AuxPow, HardFork};
use crate::rpc::{bin, json, other};

View file

@ -5,16 +5,27 @@
//!
//! These build on-top of [`crate::rpc::request`] functions.
use anyhow::{anyhow, Error};
use monero_serai::block::Block;
use std::sync::Arc;
use cuprate_helper::{cast::usize_to_u64, map::split_u128_into_low_high_bits};
use anyhow::{anyhow, Error};
use futures::StreamExt;
use monero_serai::block::Block;
use tower::{Service, ServiceExt};
use cuprate_consensus::BlockchainResponse;
use cuprate_constants::rpc::{RESTRICTED_BLOCK_COUNT, RESTRICTED_BLOCK_HEADER_RANGE};
use cuprate_helper::{
cast::{u64_to_usize, usize_to_u64},
map::split_u128_into_low_high_bits,
};
use cuprate_rpc_types::misc::{BlockHeader, KeyImageSpentStatus};
use cuprate_types::ExtendedBlockHeader;
use cuprate_types::{
blockchain::BlockchainReadRequest, Chain, ExtendedBlockHeader, VerifiedBlockInformation,
};
use crate::{rpc::request::blockchain, rpc::CupratedRpcHandler};
pub(super) fn into_block_header(
fn into_block_header(
height: u64,
top_height: u64,
fill_pow_hash: bool,

View file

@ -1,8 +1,10 @@
//! RPC request handler functions (JSON-RPC).
use std::time::{Duration, Instant};
use std::{
sync::Arc,
time::{Duration, Instant},
};
use anyhow::{anyhow, Error};
use futures::TryFutureExt;
use monero_serai::block::Block;
use strum::{EnumCount, VariantArray};
use tower::{Service, ServiceExt};
@ -16,7 +18,7 @@ use cuprate_helper::{
cast::{u64_to_usize, usize_to_u64},
map::split_u128_into_low_high_bits,
};
use cuprate_p2p_core::{client::handshaker::builder::DummyAddressBook, ClearNet, Network};
use cuprate_p2p_core::{client::handshaker::builder::DummyAddressBook, ClearNet};
use cuprate_rpc_interface::RpcHandler;
use cuprate_rpc_types::{
base::{AccessResponseBase, ResponseBase},
@ -46,7 +48,7 @@ use cuprate_rpc_types::{
},
CORE_RPC_VERSION,
};
use cuprate_types::HardFork;
use cuprate_types::{Chain, HardFork};
use crate::{
constants::VERSION_BUILD,
@ -58,8 +60,6 @@ use crate::{
statics::START_INSTANT_UNIX,
};
use super::constants::FIELD_NOT_SUPPORTED;
/// Map a [`JsonRpcRequest`] to the function that will lead to a [`JsonRpcResponse`].
pub(super) async fn map_request(
state: CupratedRpcHandler,
@ -135,12 +135,8 @@ async fn on_get_block_hash(
request: OnGetBlockHashRequest,
) -> Result<OnGetBlockHashResponse, Error> {
let [height] = request.block_height;
let hash = blockchain::block_hash(
&mut state.blockchain_read,
height,
todo!("access to `cuprated`'s Chain"),
)
.await?;
let hash = blockchain::block_hash(&mut state.blockchain_read, height, todo!("access to chain"))
.await?;
let block_hash = hex::encode(hash);
Ok(OnGetBlockHashResponse { block_hash })
@ -175,9 +171,8 @@ async fn generate_blocks(
return Err(anyhow!("Regtest required when generating blocks"));
}
// FIXME:
// is this field only used as a local variable in the handler in `monerod`?
// It may not be needed in the request type.
// TODO: is this value only used as a local variable in the handler?
// it may not be needed in the request type.
let prev_block = helper::hex_to_hash(request.prev_block)?;
let (blocks, height) = blockchain_manager::generate_blocks(
@ -278,39 +273,32 @@ async fn get_block_headers_range(
return Err(anyhow!("Invalid start/end heights"));
}
let too_many_blocks = || {
request.end_height.saturating_sub(request.start_height) + 1 > RESTRICTED_BLOCK_HEADER_RANGE
};
if state.restricted() && too_many_blocks() {
if state.restricted()
&& request.end_height.saturating_sub(request.start_height) + 1
> RESTRICTED_BLOCK_HEADER_RANGE
{
return Err(anyhow!("Too many block headers requested."));
}
// FIXME:
// This code currently:
// 1. requests a specific `(Block, BlockHeader)`
// 2. maps them to the RPC type
// 3. pushes them to the a `Vec` sequentially
//
// It could be more efficient by:
// 1. requesting all `(Block, Header)`s in the range at once
// 2. mapping all at once and collect into a `Vec`
//
// This isn't currently possible because there
// is no internal request for a range of blocks.
let block_len = u64_to_usize(request.end_height.saturating_sub(request.start_height));
let mut tasks = Vec::with_capacity(block_len);
let mut headers = Vec::with_capacity(block_len);
let (range, expected_len) = {
let start = u64_to_usize(request.start_height);
let end = u64_to_usize(request.end_height).saturating_add(1);
(start..end, end.saturating_sub(start))
};
{
let ready = state.blockchain_read.ready().await?;
for height in request.start_height..=request.end_height {
let height = u64_to_usize(height);
let task = tokio::task::spawn(ready.call(BlockchainReadRequest::Block { height }));
tasks.push(task);
}
}
let mut headers = Vec::with_capacity(expected_len);
for height in range {
let height = usize_to_u64(height);
let header = helper::block_header(&mut state, height, request.fill_pow_hash).await?;
headers.push(header);
for task in tasks {
let BlockchainResponse::Block(header) = task.await?? else {
unreachable!();
};
// headers.push((&header).into());
headers.push(todo!());
}
Ok(GetBlockHeadersRangeResponse {
@ -402,11 +390,7 @@ async fn get_info(
split_u128_into_low_high_bits(cumulative_difficulty);
let (database_size, free_space) = blockchain::database_size(&mut state.blockchain_read).await?;
let (database_size, free_space) = if restricted {
// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L131-L134>
fn round_up(value: u64, quantum: u64) -> u64 {
(value + quantum - 1) / quantum * quantum
}
let database_size = round_up(database_size, 5 * 1024 * 1024 * 1024);
let database_size = todo!(); // round_up(res.database_size, 5ull* 1024 * 1024 * 1024) */
(database_size, u64::MAX)
} else {
(database_size, free_space)
@ -419,37 +403,22 @@ async fn get_info(
} else {
address_book::connection_count::<ClearNet>(&mut DummyAddressBook).await?
};
let (mainnet, testnet, stagenet) = match todo!("access to `cuprated`'s `Network`") {
Network::Mainnet => (true, false, false),
Network::Testnet => (false, true, false),
Network::Stagenet => (false, false, true),
};
// TODO: make sure this is:
// - the same case as `monerod`
// - untagged (no `Network::`)
let nettype = todo!("access to `cuprated`'s `Network`").to_string();
let offline = todo!("access to CLI/config's `--offline`");
let rpc_connections_count = if restricted {
0
} else {
todo!(
"implement a connection counter in axum/RPC, maybe `AtomicU64` any handler activating"
)
};
let mainnet = todo!();
let nettype = todo!();
let offline = todo!();
let rpc_connections_count = if restricted { 0 } else { todo!() };
let stagenet = todo!();
let start_time = if restricted { 0 } else { *START_INSTANT_UNIX };
let synchronized = blockchain_manager::synced(&mut state.blockchain_manager).await?;
let target_height = blockchain_manager::target_height(&mut state.blockchain_manager).await?;
let target = blockchain_manager::target(&mut state.blockchain_manager)
.await?
.as_secs();
let testnet = todo!();
let top_block_hash = hex::encode(c.top_hash);
let tx_count = blockchain::total_tx_count(&mut state.blockchain_read).await?;
let tx_pool_size = txpool::size(&mut state.txpool_read, !restricted).await?;
let update_available = if restricted {
false
} else {
todo!("implement an update checker for `cuprated`")
};
let update_available = if restricted { false } else { todo!() };
let version = if restricted {
String::new()
} else {
@ -601,16 +570,7 @@ async fn banned(
state: CupratedRpcHandler,
request: BannedRequest,
) -> Result<BannedResponse, Error> {
let peer = match request.address.parse::<std::net::SocketAddr>() {
Ok(p) => p,
Err(e) => {
return Err(anyhow!(
"Failed to parse address: {} ({e})",
request.address
))
}
};
let peer = todo!("create Z::Addr from request.address");
let ban = address_book::get_ban::<ClearNet>(&mut DummyAddressBook, peer).await?;
let (banned, seconds) = if let Some(instant) = ban {
@ -717,7 +677,7 @@ async fn get_version(
let mut hard_forks = Vec::with_capacity(HardFork::COUNT);
// FIXME: use an async iterator `collect()` version.
// FIXME: use an iterator `collect()` version.
for hf in HardFork::VARIANTS {
if let Ok(hf) = blockchain_context::hard_fork_info(&mut state.blockchain_context, *hf).await
{
@ -824,15 +784,16 @@ async fn sync_info(
.map(|info| SyncInfoPeer { info })
.collect();
let next_needed_pruning_seed =
blockchain_manager::next_needed_pruning_seed(&mut state.blockchain_manager)
.await?
.compress();
let spans = blockchain_manager::spans::<ClearNet>(&mut state.blockchain_manager).await?;
// <https://github.com/Cuprate/cuprate/pull/320#discussion_r1811063772>
let overview = String::from(FIELD_NOT_SUPPORTED);
// TODO
// let next_needed_pruning_seed =
// address_book::next_needed_pruning_seed::<ClearNet>(&mut DummyAddressBook)
// .await?
// .compress();
// let overview = blockchain_manager::overview(&mut state.blockchain_manager, height).await?;
// let spans = address_book::spans::<ClearNet>(&mut DummyAddressBook).await?;
let next_needed_pruning_seed = todo!();
let overview = todo!();
let spans = todo!();
Ok(SyncInfoResponse {
base: AccessResponseBase::OK,
@ -872,24 +833,24 @@ async fn get_miner_data(
request: GetMinerDataRequest,
) -> Result<GetMinerDataResponse, Error> {
let context = blockchain_context::context(&mut state.blockchain_context).await?;
let c = context.unchecked_blockchain_context();
let major_version = c.current_hf.as_u8();
let height = usize_to_u64(c.chain_height);
let prev_id = hex::encode(c.top_hash);
let seed_hash = hex::encode(c.top_hash);
let difficulty = format!("{:#x}", c.next_difficulty);
let median_weight = usize_to_u64(c.median_weight_for_block_reward);
let already_generated_coins = c.already_generated_coins;
let tx_backlog = txpool::backlog(&mut state.txpool_read)
.await?
.into_iter()
.map(|entry| GetMinerDataTxBacklogEntry {
id: hex::encode(entry.id),
weight: entry.weight,
fee: entry.fee,
})
.collect();
let context = context.unchecked_blockchain_context();
let major_version = context.current_hf.as_u8();
let height = usize_to_u64(context.chain_height);
let prev_id = hex::encode(context.top_hash);
let seed_hash = todo!();
let difficulty = format!("{:#x}", context.next_difficulty);
let median_weight = usize_to_u64(context.median_weight_for_block_reward);
let already_generated_coins = context.already_generated_coins;
let tx_backlog = todo!();
// let tx_backlog = txpool::block_template_backlog(&mut state.txpool_read)
// .await?
// .into_iter()
// .map(|entry| GetMinerDataTxBacklogEntry {
// id: hex::encode(entry.id),
// weight: entry.weight,
// fee: entry.fee,
// })
// .collect();
Ok(GetMinerDataResponse {
base: ResponseBase::OK,
@ -1010,7 +971,7 @@ async fn get_tx_ids_loose(
request: GetTxIdsLooseRequest,
) -> Result<GetTxIdsLooseResponse, Error> {
// TODO: this RPC call is not yet in the v0.18 branch.
return Err(anyhow!("Not implemented"));
return Err(anyhow!("not implemented"));
Ok(GetTxIdsLooseResponse {
base: ResponseBase::OK,

View file

@ -1,5 +1,3 @@
//! RPC request handler functions (other JSON endpoints).
use anyhow::Error;
use cuprate_rpc_types::other::{

View file

@ -1,5 +1,7 @@
//! Functions for TODO: doc enum message.
use std::convert::Infallible;
use anyhow::{anyhow, Error};
use tower::ServiceExt;
@ -9,7 +11,12 @@ use cuprate_p2p_core::{
types::{BanState, ConnectionId},
AddressBook, NetworkZone,
};
use cuprate_rpc_types::misc::ConnectionInfo;
use cuprate_pruning::PruningSeed;
use cuprate_rpc_types::misc::{ConnectionInfo, Span};
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.

View file

@ -1,7 +1,7 @@
//! Functions for [`BlockchainReadRequest`].
use std::{
collections::{HashMap, HashSet},
collections::{BTreeMap, HashMap, HashSet},
ops::Range,
};
@ -9,12 +9,12 @@ use anyhow::Error;
use monero_serai::block::Block;
use tower::{Service, ServiceExt};
use cuprate_blockchain::service::BlockchainReadHandle;
use cuprate_blockchain::{service::BlockchainReadHandle, types::AltChainInfo};
use cuprate_helper::cast::{u64_to_usize, usize_to_u64};
use cuprate_types::{
blockchain::{BlockchainReadRequest, BlockchainResponse},
Chain, ChainInfo, CoinbaseTxSum, ExtendedBlockHeader, OutputHistogramEntry,
OutputHistogramInput, OutputOnChain,
Chain, ChainInfo, CoinbaseTxSum, ExtendedBlockHeader, HardFork, MinerData,
OutputHistogramEntry, OutputHistogramInput, OutputOnChain,
};
/// [`BlockchainReadRequest::Block`].

View file

@ -1,5 +1,7 @@
//! Functions for [`BlockChainContextRequest`] and [`BlockChainContextResponse`].
use std::convert::Infallible;
use anyhow::{anyhow, Error};
use monero_serai::block::Block;
use tower::{Service, ServiceExt};

View file

@ -8,9 +8,11 @@ use cuprate_helper::cast::{u64_to_usize, usize_to_u64};
use cuprate_p2p_core::{types::ConnectionId, NetworkZone};
use cuprate_pruning::PruningSeed;
use cuprate_rpc_types::misc::Span;
use cuprate_types::{AddAuxPow, AuxPow, HardFork};
use crate::rpc::handler::{
BlockchainManagerHandle, BlockchainManagerRequest, BlockchainManagerResponse,
use crate::rpc::{
constants::FIELD_NOT_SUPPORTED,
handler::{BlockchainManagerHandle, BlockchainManagerRequest, BlockchainManagerResponse},
};
/// [`BlockchainManagerRequest::PopBlocks`]
@ -183,8 +185,7 @@ pub(crate) async fn spans<Z: NetworkZone>(
// unreachable!();
// };
let vec: Vec<cuprate_p2p_core::types::Span<Z::Addr>> =
todo!("waiting on blockchain downloader/syncer: <https://github.com/Cuprate/cuprate/pull/320#discussion_r1811089758>");
let vec: Vec<cuprate_p2p_core::types::Span<Z::Addr>> = todo!();
// FIXME: impl this map somewhere instead of inline.
let vec = vec

View file

@ -35,7 +35,6 @@ cargo doc --open --package cuprate-blockchain
| [`cuprate-async-buffer`](https://doc.cuprate.org/cuprate_async_buffer) | [`p2p/async-buffer/`](https://github.com/Cuprate/cuprate/tree/main/p2p/async-buffer) | A bounded SPSC, FIFO, asynchronous buffer that supports arbitrary weights for values
| [`cuprate-dandelion-tower`](https://doc.cuprate.org/cuprate_dandelion_tower) | [`p2p/dandelion-tower/`](https://github.com/Cuprate/cuprate/tree/main/p2p/dandelion-tower) | TODO
| [`cuprate-p2p`](https://doc.cuprate.org/cuprate_p2p) | [`p2p/p2p/`](https://github.com/Cuprate/cuprate/tree/main/p2p/p2p) | TODO
| [`cuprate-p2p-bucket`](https://doc.cuprate.org/cuprate_p2p_bucket) | [`p2p/bucket/`](https://github.com/Cuprate/cuprate/tree/main/p2p/bucket) | A collection data structure discriminating its items into "buckets" of limited size.
| [`cuprate-p2p-core`](https://doc.cuprate.org/cuprate_p2p_core) | [`p2p/p2p-core/`](https://github.com/Cuprate/cuprate/tree/main/p2p/p2p-core) | TODO
## Storage

View file

@ -1,3 +1,5 @@
#![expect(non_local_definitions, reason = "proptest macro")]
use std::{
future::Future,
pin::Pin,

View file

@ -81,9 +81,6 @@ ignore = [
#{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" },
#"a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish
#{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" },
# TODO: check this is sorted before a beta release.
{ id = "RUSTSEC-2024-0370", reason = "unmaintained crate, not necessarily vulnerable yet." }
]
# If this is true, then cargo deny will use the git executable to fetch advisory database.
# If this is false, then it uses a built-in git library.
@ -113,7 +110,6 @@ allow = [
"Apache-2.0", # https://tldrlegal.com/license/apache-license-2.0-(apache-2.0)
"MPL-2.0", # https://www.mozilla.org/en-US/MPL/2.0/FAQ/
"BSL-1.0", # https://tldrlegal.com/license/boost-software-license-1.0-explained
"Zlib", # https://spdx.org/licenses/Zlib.html
# OpenSSL 3.0+ uses Apache-2.0
# OpenSSL 1.x.x uses https://www.openssl.org/source/license-openssl-ssleay.txt

View file

@ -1,13 +0,0 @@
[package]
name = "cuprate-p2p-bucket"
version = "0.1.0"
edition = "2021"
license = "MIT"
authors = ["SyntheticBird"]
[dependencies]
arrayvec = { workspace = true }
rand = { workspace = true, features = ["std", "std_rng"]}
[lints]
workspace = true

View file

@ -1,172 +0,0 @@
//! Bucket data structure
//!
//! A collection data structure that discriminates its unique items and place them into "buckets".
//!
//! The item must implement the [`Bucketable`] trait that defines how to create the discriminant
//! from the item type. The data structure will internally contain any item into "buckets" or vectors
//! of sized capacity `N` that regroup all the stored items with this specific discriminant.
//!
//! A practical example of this data structure is for storing `N` amount of IP discriminated by their subnets.
//! You can store in each "buckets" corresponding to a `/16` subnet up to `N` IPs of that subnet.
//!
//! # Example
//!
//! ```
//! use cuprate_p2p_bucket::Bucket;
//! use std::net::Ipv4Addr;
//!
//! // Create a new bucket that can store at most 2 IPs in a particular `/16` subnet.
//! let mut bucket = Bucket::<2,Ipv4Addr>::new();
//!
//! // Fulfill the `96.96.0.0/16` bucket.
//! bucket.push("96.96.0.1".parse().unwrap());
//! bucket.push("96.96.0.2".parse().unwrap());
//! assert_eq!(2, bucket.len());
//! assert_eq!(2, bucket.len_bucket(&[96_u8,96_u8]).unwrap());
//!
//! // Push a new IP from another subnet
//! bucket.push("127.0.0.1".parse().unwrap());
//! assert_eq!(3, bucket.len());
//! assert_eq!(2, bucket.len_bucket(&[96_u8,96_u8]).unwrap());
//! assert_eq!(1, bucket.len_bucket(&[127_u8,0_u8]).unwrap());
//!
//! // Attempting to push a new IP within `96.96.0.0/16` bucket will return the IP back
//! // as this subnet is already full.
//! let pushed = bucket.push("96.96.0.3".parse().unwrap());
//! assert!(pushed.is_some());
//! assert_eq!(2, bucket.len_bucket(&[96_u8,96_u8]).unwrap());
//!
//! ```
use arrayvec::{ArrayVec, CapacityError};
use rand::random;
use std::{collections::BTreeMap, net::Ipv4Addr};
/// A discriminant that can be computed from the type.
pub trait Bucketable: Sized + Eq + Clone {
/// The type of the discriminant being used in the Binary tree.
type Discriminant: Ord + AsRef<[u8]>;
/// Method that can compute the discriminant from the item.
fn discriminant(&self) -> Self::Discriminant;
}
/// A collection data structure discriminating its unique items
/// with a specified method. Limiting the amount of items stored
/// with that discriminant to the const `N`.
pub struct Bucket<const N: usize, I: Bucketable> {
/// The storage of the bucket
storage: BTreeMap<I::Discriminant, ArrayVec<I, N>>,
}
impl<const N: usize, I: Bucketable> Bucket<N, I> {
/// Create a new Bucket
pub const fn new() -> Self {
Self {
storage: BTreeMap::new(),
}
}
/// Push a new element into the Bucket
///
/// Will internally create a new vector for each new discriminant being
/// generated from an item.
///
/// This function WILL NOT push the element if it already exists.
///
/// Return `None` if the item has been pushed or ignored. `Some(I)` if
/// the vector is full.
///
/// # Example
///
/// ```
/// use cuprate_p2p_bucket::Bucket;
/// use std::net::Ipv4Addr;
///
/// let mut bucket = Bucket::<8,Ipv4Addr>::new();
///
/// // Push a first IP address.
/// bucket.push("127.0.0.1".parse().unwrap());
/// assert_eq!(1, bucket.len());
///
/// // Push the same IP address a second time.
/// bucket.push("127.0.0.1".parse().unwrap());
/// assert_eq!(1, bucket.len());
/// ```
pub fn push(&mut self, item: I) -> Option<I> {
let discriminant = item.discriminant();
if let Some(vec) = self.storage.get_mut(&discriminant) {
// Push the item if it doesn't exist.
if !vec.contains(&item) {
return vec.try_push(item).err().map(CapacityError::element);
}
} else {
// Initialize the vector if not found.
let mut vec = ArrayVec::<I, N>::new();
vec.push(item);
self.storage.insert(discriminant, vec);
}
None
}
/// Will attempt to remove an item from the bucket.
pub fn remove(&mut self, item: &I) -> Option<I> {
self.storage.get_mut(&item.discriminant()).and_then(|vec| {
vec.iter()
.enumerate()
.find_map(|(i, v)| (item == v).then_some(i))
.map(|index| vec.swap_remove(index))
})
}
/// Return the number of item stored within the storage
pub fn len(&self) -> usize {
self.storage.values().map(ArrayVec::len).sum()
}
/// Return the number of item stored with a specific discriminant.
///
/// This method returns None if the bucket with this discriminant
/// doesn't exist.
pub fn len_bucket(&self, discriminant: &I::Discriminant) -> Option<usize> {
self.storage.get(discriminant).map(ArrayVec::len)
}
/// Return `true` if the storage contains no items
pub fn is_empty(&self) -> bool {
self.len() == 0
}
/// Return a reference to an item chosen at random.
///
/// Repeated use of this function will provide a normal distribution of
/// items based on their discriminants.
pub fn get_random(&mut self) -> Option<&I> {
// Get the total amount of discriminants to explore.
let len = self.storage.len();
// Get a random bucket.
let (_, vec) = self.storage.iter().nth(random::<usize>() / len).unwrap();
// Return a reference chose at random.
vec.get(random::<usize>() / vec.len())
}
}
impl<const N: usize, I: Bucketable> Default for Bucket<N, I> {
fn default() -> Self {
Self::new()
}
}
impl Bucketable for Ipv4Addr {
/// We are discriminating by `/16` subnets.
type Discriminant = [u8; 2];
fn discriminant(&self) -> Self::Discriminant {
[self.octets()[0], self.octets()[1]]
}
}

View file

@ -136,7 +136,7 @@ impl TransactionBlobs {
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PrunedTxBlobEntry {
/// The transaction.
pub blob: Bytes,
pub tx: Bytes,
/// The prunable transaction hash.
pub prunable_hash: ByteArray<32>,
}
@ -144,7 +144,7 @@ pub struct PrunedTxBlobEntry {
#[cfg(feature = "epee")]
epee_object!(
PrunedTxBlobEntry,
blob: Bytes,
tx: Bytes,
prunable_hash: ByteArray<32>,
);