remove empty cuprate bin and common

This commit is contained in:
Boog900 2024-01-22 01:56:34 +00:00
parent b20b6fdee1
commit ed598e374e
No known key found for this signature in database
GPG key ID: 5401367FB7302004
51 changed files with 142 additions and 1027 deletions

67
Cargo.lock generated
View file

@ -428,31 +428,20 @@ dependencies = [
"thiserror", "thiserror",
] ]
[[package]]
name = "cuprate-common"
version = "0.1.0"
dependencies = [
"borsh",
"chrono",
"futures",
"hex",
"thiserror",
]
[[package]] [[package]]
name = "cuprate-consensus" name = "cuprate-consensus"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"borsh", "borsh",
"clap", "clap",
"cuprate-common", "cuprate-helper",
"curve25519-dalek", "curve25519-dalek",
"dalek-ff-group", "dalek-ff-group",
"dirs", "dirs",
"futures", "futures",
"hex", "hex",
"monero-consensus", "monero-consensus",
"monero-epee-bin-serde 1.0.1 (git+https://github.com/monero-rs/monero-epee-bin-serde.git?rev=e4a585a)", "monero-epee-bin-serde",
"monero-serai", "monero-serai",
"monero-wire", "monero-wire",
"multiexp", "multiexp",
@ -472,6 +461,18 @@ dependencies = [
"tracing-subscriber", "tracing-subscriber",
] ]
[[package]]
name = "cuprate-helper"
version = "0.1.0"
dependencies = [
"chrono",
"futures",
"libc",
"rayon",
"tokio",
"windows",
]
[[package]] [[package]]
name = "cuprate-test-utils" name = "cuprate-test-utils"
version = "0.1.0" version = "0.1.0"
@ -816,18 +817,6 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "helper"
version = "0.1.0"
dependencies = [
"chrono",
"futures",
"libc",
"rayon",
"tokio",
"windows",
]
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.3.4" version = "0.3.4"
@ -1098,10 +1087,10 @@ version = "0.1.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"borsh", "borsh",
"cuprate-common",
"cuprate-test-utils", "cuprate-test-utils",
"futures", "futures",
"monero-p2p", "monero-p2p",
"monero-pruning",
"monero-wire", "monero-wire",
"pin-project", "pin-project",
"rand", "rand",
@ -1117,7 +1106,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"crypto-bigint", "crypto-bigint",
"cryptonight-cuprate", "cryptonight-cuprate",
"cuprate-common", "cuprate-helper",
"curve25519-dalek", "curve25519-dalek",
"dalek-ff-group", "dalek-ff-group",
"hex", "hex",
@ -1136,22 +1125,13 @@ dependencies = [
[[package]] [[package]]
name = "monero-epee-bin-serde" name = "monero-epee-bin-serde"
version = "1.0.1" version = "1.0.1"
source = "git+https://github.com/monero-rs/monero-epee-bin-serde.git?rev=aafe4ba#aafe4ba1b9912b03cf616db7403628fc2bd82eb1" source = "git+https://github.com/monero-rs/monero-epee-bin-serde.git?rev=fae7a23#fae7a23f8e57f19553c341c0878b4f0fa5a6994d"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"serde", "serde",
"serde_bytes", "serde_bytes",
] ]
[[package]]
name = "monero-epee-bin-serde"
version = "1.0.1"
source = "git+https://github.com/monero-rs/monero-epee-bin-serde.git?rev=e4a585a#e4a585a9deda5f888ebca766d5e61a2bb987147c"
dependencies = [
"byteorder",
"serde",
]
[[package]] [[package]]
name = "monero-generators" name = "monero-generators"
version = "0.4.0" version = "0.4.0"
@ -1171,10 +1151,11 @@ version = "0.1.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"borsh", "borsh",
"cuprate-common", "cuprate-helper",
"cuprate-test-utils", "cuprate-test-utils",
"futures", "futures",
"hex", "hex",
"monero-pruning",
"monero-wire", "monero-wire",
"thiserror", "thiserror",
"tokio", "tokio",
@ -1185,6 +1166,14 @@ dependencies = [
"tracing-subscriber", "tracing-subscriber",
] ]
[[package]]
name = "monero-pruning"
version = "0.1.0"
dependencies = [
"borsh",
"thiserror",
]
[[package]] [[package]]
name = "monero-serai" name = "monero-serai"
version = "0.1.4-alpha" version = "0.1.4-alpha"
@ -1225,7 +1214,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"hex", "hex",
"levin-cuprate", "levin-cuprate",
"monero-epee-bin-serde 1.0.1 (git+https://github.com/monero-rs/monero-epee-bin-serde.git?rev=aafe4ba)", "monero-epee-bin-serde",
"serde", "serde",
"serde_bytes", "serde_bytes",
"thiserror", "thiserror",

View file

@ -2,18 +2,16 @@
resolver = "2" resolver = "2"
members = [ members = [
"common",
"consensus", "consensus",
"consensus/rules", "consensus/rules",
"cryptonight", "cryptonight",
# "cuprate",
# "database",
"helper", "helper",
"net/levin", "net/levin",
"net/monero-wire", "net/monero-wire",
"p2p/monero-p2p", "p2p/monero-p2p",
"p2p/address-book", "p2p/address-book",
"test-utils" "pruning",
"test-utils",
] ]
[profile.release] [profile.release]
@ -47,7 +45,7 @@ dirs = { version = "5.0.1", default-features = false }
futures = { version = "0.3.29", default-features = false } futures = { version = "0.3.29", default-features = false }
hex = { version = "0.4.3", default-features = false } hex = { version = "0.4.3", default-features = false }
hex-literal = { version = "0.4", default-features = false } hex-literal = { version = "0.4", default-features = false }
monero-epee-bin-serde = { git = "https://github.com/monero-rs/monero-epee-bin-serde.git", rev = "e4a585a", default-features = false } monero-epee-bin-serde = { git = "https://github.com/monero-rs/monero-epee-bin-serde.git", rev = "fae7a23", default-features = false }
monero-serai = { git = "https://github.com/Cuprate/serai.git", rev = "a59966b", default-features = false } monero-serai = { git = "https://github.com/Cuprate/serai.git", rev = "a59966b", default-features = false }
multiexp = { git = "https://github.com/Cuprate/serai.git", rev = "a59966b", default-features = false } multiexp = { git = "https://github.com/Cuprate/serai.git", rev = "a59966b", default-features = false }
pin-project = { version = "1.1.3", default-features = false } pin-project = { version = "1.1.3", default-features = false }

View file

@ -1,19 +0,0 @@
[package]
name = "cuprate-common"
version = "0.1.0"
edition = "2021"
license = "AGPL-3.0-only"
authors = ["Boog900"]
[features]
default = []
borsh = ["dep:borsh"]
[dependencies]
chrono = { workspace = true }
thiserror = { workspace = true }
hex = { workspace = true, features = ["std"] }
futures = { workspace = true, features = ["std"] }
borsh = { workspace = true, features = ["derive", "std"], optional = true }

View file

@ -1,14 +0,0 @@
Copyright (C) 2023 Cuprate Contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.

View file

@ -1,250 +0,0 @@
use chrono::NaiveDateTime;
use crate::network::Network;
// this function blindly unwraps
// SAFETY: only call when you know the timestamp is good
fn time_from_timestamp(stamp: i64) -> NaiveDateTime {
NaiveDateTime::from_timestamp_opt(stamp, 0).unwrap()
}
fn get_hard_forks(network: Network) -> [(u8, u64, NaiveDateTime); 16] {
match network {
Network::MainNet => {
[
// | version | Height | TimeStamp | *timestamp is when fork height was decided
(1, 1, time_from_timestamp(1341378000)),
(2, 1009827, time_from_timestamp(1442763710)),
(3, 1141317, time_from_timestamp(1458558528)),
(4, 1220516, time_from_timestamp(1483574400)),
(5, 1288616, time_from_timestamp(1489520158)),
(6, 1400000, time_from_timestamp(1503046577)),
(7, 1546000, time_from_timestamp(1521303150)),
(8, 1685555, time_from_timestamp(1535889547)),
(9, 1686275, time_from_timestamp(1535889548)),
(10, 1788000, time_from_timestamp(1549792439)),
(11, 1788720, time_from_timestamp(1550225678)),
(12, 1978433, time_from_timestamp(1571419280)),
(13, 2210000, time_from_timestamp(1598180817)),
(14, 2210720, time_from_timestamp(1598180818)),
(15, 2688888, time_from_timestamp(1656629117)),
(16, 2689608, time_from_timestamp(1656629118)),
]
}
Network::TestNet => [
(1, 1, time_from_timestamp(1341378000)),
(2, 624634, time_from_timestamp(1445355000)),
(3, 800500, time_from_timestamp(1472415034)),
(4, 801219, time_from_timestamp(1472415035)),
(5, 802660, time_from_timestamp(1472415036 + 86400 * 180)),
(6, 971400, time_from_timestamp(1501709789)),
(7, 1057027, time_from_timestamp(1512211236)),
(8, 1057058, time_from_timestamp(1533211200)),
(9, 1057778, time_from_timestamp(1533297600)),
(10, 1154318, time_from_timestamp(1550153694)),
(11, 1155038, time_from_timestamp(1550225678)),
(12, 1308737, time_from_timestamp(1569582000)),
(13, 1543939, time_from_timestamp(1599069376)),
(14, 1544659, time_from_timestamp(1599069377)),
(15, 1982800, time_from_timestamp(1652727000)),
(16, 1983520, time_from_timestamp(1652813400)),
],
Network::StageNet => [
(1, 1, time_from_timestamp(1341378000)),
(2, 32000, time_from_timestamp(1521000000)),
(3, 33000, time_from_timestamp(1521120000)),
(4, 34000, time_from_timestamp(1521240000)),
(5, 35000, time_from_timestamp(1521360000)),
(6, 36000, time_from_timestamp(1521480000)),
(7, 37000, time_from_timestamp(1521600000)),
(8, 176456, time_from_timestamp(1537821770)),
(9, 177176, time_from_timestamp(1537821771)),
(10, 269000, time_from_timestamp(1550153694)),
(11, 269720, time_from_timestamp(1550225678)),
(12, 454721, time_from_timestamp(1571419280)),
(13, 675405, time_from_timestamp(1598180817)),
(14, 676125, time_from_timestamp(1598180818)),
(15, 1151000, time_from_timestamp(1656629117)),
(16, 1151720, time_from_timestamp(1656629118)),
],
}
}
pub struct HardForks {
hard_forks: [(u8, u64, NaiveDateTime); 16],
}
impl HardForks {
pub fn new(network: Network) -> Self {
HardForks {
hard_forks: get_hard_forks(network),
}
}
pub fn get_ideal_version_from_height(&self, height: u64) -> u8 {
for hf in self.hard_forks.iter().rev() {
if height >= hf.1 {
return hf.0;
}
}
0
}
pub fn get_earliest_ideal_height_for_version(&self, version: u8) -> Option<u64> {
if self.hard_forks.len() < version as usize {
None
} else if version == 0 {
Some(0)
} else {
Some(self.hard_forks[(version - 1) as usize].1)
}
}
pub fn get_ideal_version(&self) -> u8 {
self.hard_forks.last().expect("This is not empty").0
}
}
#[cfg(test)]
mod tests {
use crate::network::Network;
use super::HardForks;
const MAIN_NET_FORKS: [u64; 16] = [
1, 1009827, 1141317, 1220516, 1288616, 1400000, 1546000, 1685555, 1686275, 1788000,
1788720, 1978433, 2210000, 2210720, 2688888, 2689608,
];
const TEST_NET_FORKS: [u64; 16] = [
1, 624634, 800500, 801219, 802660, 971400, 1057027, 1057058, 1057778, 1154318, 1155038,
1308737, 1543939, 1544659, 1982800, 1983520,
];
const STAGE_NET_FORKS: [u64; 16] = [
1, 32000, 33000, 34000, 35000, 36000, 37000, 176456, 177176, 269000, 269720, 454721,
675405, 676125, 1151000, 1151720,
];
#[test]
fn get_ideal_version() {
let hardforks = HardForks::new(Network::MainNet);
let version = hardforks.get_ideal_version();
assert_eq!(version as usize, MAIN_NET_FORKS.len());
assert_eq!(version as usize, TEST_NET_FORKS.len());
assert_eq!(version as usize, STAGE_NET_FORKS.len());
let height = hardforks
.get_earliest_ideal_height_for_version(version)
.unwrap();
let got_version = hardforks.get_ideal_version_from_height(height);
assert_eq!(version, got_version);
}
#[test]
fn get_earliest_ideal_height_for_version_mainnet() {
let hardforks = HardForks::new(Network::MainNet);
for (height, version) in MAIN_NET_FORKS.iter().zip(1..MAIN_NET_FORKS.len() as u8) {
assert_eq!(
hardforks
.get_earliest_ideal_height_for_version(version)
.unwrap(),
*height
);
assert_eq!(
hardforks
.get_earliest_ideal_height_for_version(version)
.unwrap(),
*height
);
}
assert!(hardforks
.get_earliest_ideal_height_for_version(MAIN_NET_FORKS.len() as u8 + 1)
.is_none())
}
#[test]
fn get_earliest_ideal_height_for_version_testnet() {
let hardforks = HardForks::new(Network::TestNet);
for (height, version) in TEST_NET_FORKS.iter().zip(1..TEST_NET_FORKS.len() as u8) {
assert_eq!(
hardforks
.get_earliest_ideal_height_for_version(version)
.unwrap(),
*height
);
assert_eq!(
hardforks
.get_earliest_ideal_height_for_version(version)
.unwrap(),
*height
);
}
assert!(hardforks
.get_earliest_ideal_height_for_version(TEST_NET_FORKS.len() as u8 + 1)
.is_none())
}
#[test]
fn get_earliest_ideal_height_for_version_stagenet() {
let hardforks = HardForks::new(Network::StageNet);
for (height, version) in STAGE_NET_FORKS.iter().zip(1..STAGE_NET_FORKS.len() as u8) {
assert_eq!(
hardforks
.get_earliest_ideal_height_for_version(version)
.unwrap(),
*height
);
assert_eq!(
hardforks
.get_earliest_ideal_height_for_version(version)
.unwrap(),
*height
);
}
assert!(hardforks
.get_earliest_ideal_height_for_version(STAGE_NET_FORKS.len() as u8 + 1)
.is_none())
}
#[test]
fn get_ideal_version_from_height_mainnet() {
let hardforks = HardForks::new(Network::MainNet);
for (height, version) in MAIN_NET_FORKS.iter().zip(1..MAIN_NET_FORKS.len() as u8) {
assert_eq!(hardforks.get_ideal_version_from_height(*height), version);
assert_eq!(
hardforks.get_ideal_version_from_height(*height - 1),
version - 1
);
}
}
#[test]
fn get_ideal_version_from_height_testnet() {
let hardforks = HardForks::new(Network::TestNet);
for (height, version) in TEST_NET_FORKS.iter().zip(1..TEST_NET_FORKS.len() as u8) {
assert_eq!(hardforks.get_ideal_version_from_height(*height), version);
assert_eq!(
hardforks.get_ideal_version_from_height(*height - 1),
version - 1
);
}
}
#[test]
fn get_ideal_version_from_height_stagenet() {
let hardforks = HardForks::new(Network::StageNet);
for (height, version) in STAGE_NET_FORKS.iter().zip(1..STAGE_NET_FORKS.len() as u8) {
assert_eq!(hardforks.get_ideal_version_from_height(*height), version);
assert_eq!(
hardforks.get_ideal_version_from_height(*height - 1),
version - 1
);
}
}
}

View file

@ -1,37 +0,0 @@
//pub mod hardforks;
pub mod network;
pub mod pruning;
pub mod tower_utils;
use std::fmt::Formatter;
//pub use hardforks::HardForks;
pub use network::Network;
pub use pruning::{PruningError, PruningSeed};
pub const CRYPTONOTE_MAX_BLOCK_NUMBER: u64 = 500000000;
// pruning
pub const CRYPTONOTE_PRUNING_LOG_STRIPES: u32 = 3;
pub const CRYPTONOTE_PRUNING_STRIPE_SIZE: u64 = 4096;
pub const CRYPTONOTE_PRUNING_TIP_BLOCKS: u64 = 5500;
#[derive(Debug, Clone)]
pub enum BlockID {
Hash([u8; 32]),
Height(u64),
}
impl std::fmt::Display for BlockID {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
BlockID::Hash(hash) => f.write_str(&format!("Hash: {}", hex::encode(hash))),
BlockID::Height(height) => f.write_str(&format!("Height: {}", height)),
}
}
}
impl From<u64> for BlockID {
fn from(value: u64) -> Self {
BlockID::Height(value)
}
}

View file

@ -1,28 +0,0 @@
use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
use futures::channel::oneshot;
use futures::FutureExt;
/// A oneshot that doesn't return an Error. This requires the sender to always
/// return a response.
pub struct InfallibleOneshotReceiver<T>(oneshot::Receiver<T>);
impl<T> From<oneshot::Receiver<T>> for InfallibleOneshotReceiver<T> {
fn from(value: oneshot::Receiver<T>) -> Self {
InfallibleOneshotReceiver(value)
}
}
impl<T> Future for InfallibleOneshotReceiver<T> {
type Output = T;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.0
.poll_unpin(cx)
.map(|res| res.expect("Oneshot must not be cancelled before response!"))
}
}

View file

@ -29,7 +29,7 @@ binaries = [
] ]
[dependencies] [dependencies]
cuprate-common = {path = "../common"} cuprate-helper = { path = "../helper", default-features = false, features = ["std", "asynch", "num"] }
monero-consensus = {path = "./rules", features = ["rayon"]} monero-consensus = {path = "./rules", features = ["rayon"]}
thiserror = { workspace = true } thiserror = { workspace = true }

View file

@ -9,8 +9,8 @@ proptest = ["dep:proptest", "dep:proptest-derive"]
rayon = ["dep:rayon"] rayon = ["dep:rayon"]
[dependencies] [dependencies]
cuprate-helper = { path = "../../helper", default-features = false, features = ["std"] }
cryptonight-cuprate = {path = "../../cryptonight"} cryptonight-cuprate = {path = "../../cryptonight"}
cuprate-common = {path = "../../common"}
monero-serai = { workspace = true, features = ["std"] } monero-serai = { workspace = true, features = ["std"] }
multiexp = { workspace = true, features = ["std", "batch"] } multiexp = { workspace = true, features = ["std", "batch"] }

View file

@ -6,7 +6,7 @@ use monero_serai::{
transaction::Transaction, transaction::Transaction,
}; };
use cuprate_common::Network; use cuprate_helper::network::Network;
const fn genesis_nonce(network: &Network) -> u32 { const fn genesis_nonce(network: &Network) -> u32 {
match network { match network {
@ -42,9 +42,7 @@ pub fn generate_genesis_block(network: &Network) -> Block {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use cuprate_common::Network; use super::*;
use super::generate_genesis_block;
#[test] #[test]
fn generate_genesis_blocks() { fn generate_genesis_blocks() {

View file

@ -19,7 +19,7 @@ mod bin {
use tower::{Service, ServiceExt}; use tower::{Service, ServiceExt};
use tracing::level_filters::LevelFilter; use tracing::level_filters::LevelFilter;
use cuprate_common::Network; use cuprate_helper::network::Network;
use cuprate_consensus::{ use cuprate_consensus::{
block::PrePreparedBlockExPOW, block::PrePreparedBlockExPOW,

View file

@ -13,7 +13,7 @@ mod bin {
use monero_serai::transaction::Transaction; use monero_serai::transaction::Transaction;
use tower::{Service, ServiceExt}; use tower::{Service, ServiceExt};
use cuprate_common::tower_utils::InfallibleOneshotReceiver; use cuprate_helper::asynch::InfallibleOneshotReceiver;
use cuprate_consensus::{ use cuprate_consensus::{
context::{ context::{

View file

@ -3,9 +3,9 @@ use std::{collections::VecDeque, ops::Range};
use tower::ServiceExt; use tower::ServiceExt;
use tracing::instrument; use tracing::instrument;
use crate::{ use cuprate_helper::num::median;
helper::median, Database, DatabaseRequest, DatabaseResponse, ExtendedConsensusError, HardFork,
}; use crate::{Database, DatabaseRequest, DatabaseResponse, ExtendedConsensusError, HardFork};
/// The amount of blocks we account for to calculate difficulty /// The amount of blocks we account for to calculate difficulty
const DIFFICULTY_WINDOW: usize = 720; const DIFFICULTY_WINDOW: usize = 720;

View file

@ -79,9 +79,7 @@ impl HardForkState {
let DatabaseResponse::BlockExtendedHeader(ext_header) = database let DatabaseResponse::BlockExtendedHeader(ext_header) = database
.ready() .ready()
.await? .await?
.call(DatabaseRequest::BlockExtendedHeader( .call(DatabaseRequest::BlockExtendedHeader(chain_height - 1))
(chain_height - 1).into(),
))
.await? .await?
else { else {
panic!("Database sent incorrect response!"); panic!("Database sent incorrect response!");

View file

@ -16,12 +16,10 @@ use rayon::prelude::*;
use tower::ServiceExt; use tower::ServiceExt;
use tracing::instrument; use tracing::instrument;
use cuprate_helper::{asynch::rayon_spawn_async, num::median};
use monero_consensus::blocks::{penalty_free_zone, PENALTY_FREE_ZONE_5}; use monero_consensus::blocks::{penalty_free_zone, PENALTY_FREE_ZONE_5};
use crate::{ use crate::{Database, DatabaseRequest, DatabaseResponse, ExtendedConsensusError, HardFork};
helper::{median, rayon_spawn_async},
Database, DatabaseRequest, DatabaseResponse, ExtendedConsensusError, HardFork,
};
const SHORT_TERM_WINDOW: u64 = 100; const SHORT_TERM_WINDOW: u64 = 100;
const LONG_TERM_WINDOW: u64 = 100000; const LONG_TERM_WINDOW: u64 = 100000;

View file

@ -1,44 +0,0 @@
use std::ops::{Add, Div, Mul, Sub};
/// Spawns a task for the rayon thread pool and awaits the result without blocking the async runtime.
pub(crate) async fn rayon_spawn_async<F, R>(f: F) -> R
where
F: FnOnce() -> R + Send + 'static,
R: Send + 'static,
{
let (tx, rx) = tokio::sync::oneshot::channel();
rayon::spawn(|| {
let _ = tx.send(f());
});
rx.await.expect("The sender must not be dropped")
}
pub(crate) fn get_mid<T>(a: T, b: T) -> T
where
T: Add<Output = T> + Sub<Output = T> + Div<Output = T> + Mul<Output = T> + Copy + From<u8>,
{
let two: T = 2_u8.into();
// https://github.com/monero-project/monero/blob/90294f09ae34ef96f3dea5fea544816786df87c8/contrib/epee/include/misc_language.h#L43
(a / two) + (b / two) + ((a - two * (a / two)) + (b - two * (b / two))) / two
}
/// Gets the median from a sorted slice.
///
/// If not sorted the output will be invalid.
pub(crate) fn median<T>(array: &[T]) -> T
where
T: Add<Output = T> + Sub<Output = T> + Div<Output = T> + Mul<Output = T> + Copy + From<u8>,
{
let mid = array.len() / 2;
if array.len() == 1 {
return array[0];
}
if array.len() % 2 == 0 {
get_mid(array[mid - 1], array[mid])
} else {
array[mid]
}
}

View file

@ -6,11 +6,9 @@ use std::{
use monero_consensus::{transactions::OutputOnChain, ConsensusError, HardFork}; use monero_consensus::{transactions::OutputOnChain, ConsensusError, HardFork};
//mod batch_verifier;
mod batch_verifier; mod batch_verifier;
pub mod block; pub mod block;
pub mod context; pub mod context;
mod helper;
pub mod randomx; pub mod randomx;
#[cfg(feature = "binaries")] #[cfg(feature = "binaries")]
pub mod rpc; pub mod rpc;
@ -115,7 +113,7 @@ pub struct ExtendedBlockHeader {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum DatabaseRequest { pub enum DatabaseRequest {
BlockExtendedHeader(cuprate_common::BlockID), BlockExtendedHeader(u64),
BlockHash(u64), BlockHash(u64),
BlockExtendedHeaderInRange(std::ops::Range<u64>), BlockExtendedHeaderInRange(std::ops::Range<u64>),

View file

@ -15,7 +15,9 @@ use futures::{
use tokio::sync::RwLock; use tokio::sync::RwLock;
use tower::{balance::p2c::Balance, ServiceExt}; use tower::{balance::p2c::Balance, ServiceExt};
use crate::{helper::rayon_spawn_async, DatabaseRequest, DatabaseResponse}; use cuprate_helper::asynch::rayon_spawn_async;
use crate::{DatabaseRequest, DatabaseResponse};
pub mod cache; pub mod cache;
mod connection; mod connection;

View file

@ -27,13 +27,10 @@ use tokio::{
use tower::Service; use tower::Service;
use tracing::{instrument, Instrument}; use tracing::{instrument, Instrument};
use cuprate_common::{tower_utils::InfallibleOneshotReceiver, BlockID}; use cuprate_helper::asynch::{rayon_spawn_async, InfallibleOneshotReceiver};
use super::ScanningCache; use super::ScanningCache;
use crate::{ use crate::{DatabaseRequest, DatabaseResponse, ExtendedBlockHeader, HardFork, OutputOnChain};
helper::rayon_spawn_async, DatabaseRequest, DatabaseResponse, ExtendedBlockHeader, HardFork,
OutputOnChain,
};
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(300); const DEFAULT_TIMEOUT: Duration = Duration::from_secs(300);
const OUTPUTS_TIMEOUT: Duration = Duration::from_secs(50); const OUTPUTS_TIMEOUT: Duration = Duration::from_secs(50);
@ -98,17 +95,16 @@ impl RpcConnection {
async fn get_extended_block_header( async fn get_extended_block_header(
&self, &self,
id: BlockID, height: u64,
) -> Result<ExtendedBlockHeader, tower::BoxError> { ) -> Result<ExtendedBlockHeader, tower::BoxError> {
tracing::info!("Retrieving block info with id: {}", id); tracing::info!("Retrieving block info with height: {}", height);
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
struct Response { struct Response {
block_header: BlockInfo, block_header: BlockInfo,
} }
let info = match id { let info = {
BlockID::Height(height) => {
let res = self let res = self
.con .con
.json_rpc_call::<Response>( .json_rpc_call::<Response>(
@ -117,17 +113,6 @@ impl RpcConnection {
) )
.await?; .await?;
res.block_header res.block_header
}
BlockID::Hash(hash) => {
let res = self
.con
.json_rpc_call::<Response>(
"get_block_header_by_hash",
Some(json!({"hash": hash})),
)
.await?;
res.block_header
}
}; };
Ok(ExtendedBlockHeader { Ok(ExtendedBlockHeader {

View file

@ -2,11 +2,14 @@ use proptest::strategy::ValueTree;
use proptest::{strategy::Strategy, test_runner::TestRunner}; use proptest::{strategy::Strategy, test_runner::TestRunner};
use tower::ServiceExt; use tower::ServiceExt;
use crate::context::{ use crate::{
context::{
initialize_blockchain_context, BlockChainContextRequest, BlockChainContextResponse, initialize_blockchain_context, BlockChainContextRequest, BlockChainContextResponse,
ContextConfig, UpdateBlockchainCacheData, ContextConfig, UpdateBlockchainCacheData,
},
tests::mock_db::*,
HardFork,
}; };
use crate::{tests::mock_db::*, HardFork};
pub(crate) mod data; pub(crate) mod data;
mod difficulty; mod difficulty;

View file

@ -2,7 +2,9 @@ use std::collections::VecDeque;
use proptest::{arbitrary::any, prop_assert_eq, prop_compose, proptest}; use proptest::{arbitrary::any, prop_assert_eq, prop_compose, proptest};
use crate::{context::difficulty::*, helper::median, tests::mock_db::*, HardFork}; use cuprate_helper::num::median;
use crate::{context::difficulty::*, tests::mock_db::*, HardFork};
const TEST_WINDOW: usize = 72; const TEST_WINDOW: usize = 72;
const TEST_CUT: usize = 6; const TEST_CUT: usize = 6;

View file

@ -4,8 +4,8 @@ use crate::{
BlockWeightsCacheConfig, BlockWeightsCacheConfig,
}, },
tests::{context::data::BW_2850000_3050000, mock_db::*}, tests::{context::data::BW_2850000_3050000, mock_db::*},
HardFork,
}; };
use monero_consensus::HardFork;
pub const TEST_WEIGHT_CONFIG: BlockWeightsCacheConfig = BlockWeightsCacheConfig::new(100, 5000); pub const TEST_WEIGHT_CONFIG: BlockWeightsCacheConfig = BlockWeightsCacheConfig::new(100, 5000);

View file

@ -15,8 +15,6 @@ use proptest::{
use proptest_derive::Arbitrary; use proptest_derive::Arbitrary;
use tower::{BoxError, Service}; use tower::{BoxError, Service};
use cuprate_common::BlockID;
use crate::{DatabaseRequest, DatabaseResponse, ExtendedBlockHeader, HardFork}; use crate::{DatabaseRequest, DatabaseResponse, ExtendedBlockHeader, HardFork};
prop_compose! { prop_compose! {
@ -140,7 +138,7 @@ impl Service<DatabaseRequest> for DummyDatabase {
async move { async move {
Ok(match req { Ok(match req {
DatabaseRequest::BlockExtendedHeader(BlockID::Height(id)) => { DatabaseRequest::BlockExtendedHeader(id) => {
let mut id = usize::try_from(id).unwrap(); let mut id = usize::try_from(id).unwrap();
if let Some(dummy_height) = dummy_height { if let Some(dummy_height) = dummy_height {
let block_len = blocks.read().unwrap().len(); let block_len = blocks.read().unwrap().len();

View file

@ -14,6 +14,7 @@ use rayon::prelude::*;
use tower::{Service, ServiceExt}; use tower::{Service, ServiceExt};
use tracing::instrument; use tracing::instrument;
use cuprate_helper::asynch::rayon_spawn_async;
use monero_consensus::{ use monero_consensus::{
transactions::{ transactions::{
check_transaction_contextual, check_transaction_semantic, RingCTError, TransactionError, check_transaction_contextual, check_transaction_semantic, RingCTError, TransactionError,
@ -23,8 +24,8 @@ use monero_consensus::{
}; };
use crate::{ use crate::{
batch_verifier::MultiThreadedBatchVerifier, context::ReOrgToken, helper::rayon_spawn_async, batch_verifier::MultiThreadedBatchVerifier, context::ReOrgToken, Database, DatabaseRequest,
Database, DatabaseRequest, DatabaseResponse, ExtendedConsensusError, DatabaseResponse, ExtendedConsensusError,
}; };
mod contextual_data; mod contextual_data;

View file

@ -1,21 +0,0 @@
[package]
name = "cuprate"
authors = []
version = "0.1.0"
edition = "2021"
[dependencies]
clap = "4"
serde = { version = "1", features = ["serde_derive"] }
thiserror = "1"
[dependencies.abscissa_core]
version = "0.7.0"
# optional: use `gimli` to capture backtraces
# see https://github.com/rust-lang/backtrace-rs/issues/189
# features = ["gimli-backtrace"]
[dev-dependencies]
abscissa_core = { version = "0.7.0", features = ["testing"] }
once_cell = "1.2"

View file

@ -1,9 +0,0 @@
This application is authored using [Abscissa], a Rust application framework.
For more information, see:
[Documentation]
[Abscissa]: https://github.com/iqlusioninc/abscissa
[Documentation]: https://docs.rs/abscissa_core/

View file

@ -1,88 +0,0 @@
//! Cuprate Abscissa Application
use crate::{commands::EntryPoint, config::CuprateConfig};
use abscissa_core::{
application::{self, AppCell},
config::{self, CfgCell},
trace, Application, FrameworkError, StandardPaths,
};
/// Application state
pub static APP: AppCell<CuprateApp> = AppCell::new();
/// Cuprate Application
#[derive(Debug)]
pub struct CuprateApp {
/// Application configuration.
config: CfgCell<CuprateConfig>,
/// Application state.
state: application::State<Self>,
}
/// Initialize a new application instance.
///
/// By default no configuration is loaded, and the framework state is
/// initialized to a default, empty state (no components, threads, etc).
impl Default for CuprateApp {
fn default() -> Self {
Self {
config: CfgCell::default(),
state: application::State::default(),
}
}
}
impl Application for CuprateApp {
/// Entrypoint command for this application.
type Cmd = EntryPoint;
/// Application configuration.
type Cfg = CuprateConfig;
/// Paths to resources within the application.
type Paths = StandardPaths;
/// Accessor for application configuration.
fn config(&self) -> config::Reader<CuprateConfig> {
self.config.read()
}
/// Borrow the application state immutably.
fn state(&self) -> &application::State<Self> {
&self.state
}
/// Register all components used by this application.
///
/// If you would like to add additional components to your application
/// beyond the default ones provided by the framework, this is the place
/// to do so.
fn register_components(&mut self, command: &Self::Cmd) -> Result<(), FrameworkError> {
let framework_components = self.framework_components(command)?;
let mut app_components = self.state.components_mut();
app_components.register(framework_components)
}
/// Post-configuration lifecycle callback.
///
/// Called regardless of whether config is loaded to indicate this is the
/// time in app lifecycle when configuration would be loaded if
/// possible.
fn after_config(&mut self, config: Self::Cfg) -> Result<(), FrameworkError> {
// Configure components
let mut components = self.state.components_mut();
components.after_config(&config)?;
self.config.set_once(config);
Ok(())
}
/// Get tracing configuration from command-line options
fn tracing_config(&self, command: &EntryPoint) -> trace::Config {
if command.verbose {
trace::Config::verbose()
} else {
trace::Config::default()
}
}
}

View file

@ -1,11 +0,0 @@
//! Main entry point for Cuprate
#![deny(warnings, missing_docs, trivial_casts, unused_qualifications)]
#![forbid(unsafe_code)]
use cuprate::application::APP;
/// Boot Cuprate
fn main() {
abscissa_core::boot(&APP);
}

View file

@ -1,87 +0,0 @@
//! Cuprate Subcommands
//!
//! This is where you specify the subcommands of your application.
//!
//! The default application comes with two subcommands:
//!
//! - `start`: launches the application
//! - `--version`: print application version
//!
//! See the `impl Configurable` below for how to specify the path to the
//! application's configuration file.
mod start;
use self::start::StartCmd;
use crate::config::CuprateConfig;
use abscissa_core::{config::Override, Command, Configurable, FrameworkError, Runnable};
use std::path::PathBuf;
/// Cuprate Configuration Filename
pub const CONFIG_FILE: &str = "cuprate.toml";
/// Cuprate Subcommands
/// Subcommands need to be listed in an enum.
#[derive(clap::Parser, Command, Debug, Runnable)]
pub enum CuprateCmd {
/// The `start` subcommand
Start(StartCmd),
}
/// Entry point for the application. It needs to be a struct to allow using subcommands!
#[derive(clap::Parser, Command, Debug)]
#[command(author, about, version)]
pub struct EntryPoint {
#[command(subcommand)]
cmd: CuprateCmd,
/// Enable verbose logging
#[arg(short, long)]
pub verbose: bool,
/// Use the specified config file
#[arg(short, long)]
pub config: Option<String>,
}
impl Runnable for EntryPoint {
fn run(&self) {
self.cmd.run()
}
}
/// This trait allows you to define how application configuration is loaded.
impl Configurable<CuprateConfig> for EntryPoint {
/// Location of the configuration file
fn config_path(&self) -> Option<PathBuf> {
// Check if the config file exists, and if it does not, ignore it.
// If you'd like for a missing configuration file to be a hard error
// instead, always return `Some(CONFIG_FILE)` here.
let filename = self
.config
.as_ref()
.map(PathBuf::from)
.unwrap_or_else(|| CONFIG_FILE.into());
if filename.exists() {
Some(filename)
} else {
None
}
}
/// Apply changes to the config after it's been loaded, e.g. overriding
/// values in a config file using command-line options.
///
/// This can be safely deleted if you don't want to override config
/// settings from command-line options.
fn process_config(&self, config: CuprateConfig) -> Result<CuprateConfig, FrameworkError> {
match &self.cmd {
CuprateCmd::Start(cmd) => cmd.override_config(config),
//
// If you don't need special overrides for some
// subcommands, you can just use a catch all
// _ => Ok(config),
}
}
}

View file

@ -1,42 +0,0 @@
//! `start` subcommand - example of how to write a subcommand
/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()`
/// accessors along with logging macros. Customize as you see fit.
use crate::prelude::*;
use crate::config::CuprateConfig;
use abscissa_core::{config, Command, FrameworkError, Runnable};
/// `start` subcommand
///
/// The `Parser` proc macro generates an option parser based on the struct
/// definition, and is defined in the `clap` crate. See their documentation
/// for a more comprehensive example:
///
/// <https://docs.rs/clap/>
#[derive(clap::Parser, Command, Debug)]
pub struct StartCmd {
/// To whom are we saying hello?
recipient: Vec<String>,
}
impl Runnable for StartCmd {
/// Start the application.
fn run(&self) {
let config = APP.config();
println!("Hello, {}!", &config.hello.recipient);
}
}
impl config::Override<CuprateConfig> for StartCmd {
// Process the given command line options, overriding settings from
// a configuration file using explicit flags taken from command-line
// arguments.
fn override_config(&self, mut config: CuprateConfig) -> Result<CuprateConfig, FrameworkError> {
if !self.recipient.is_empty() {
config.hello.recipient = self.recipient.join(" ");
}
Ok(config)
}
}

View file

@ -1,45 +0,0 @@
//! Cuprate Config
//!
//! See instructions in `commands.rs` to specify the path to your
//! application's configuration file and/or command-line options
//! for specifying it.
use serde::{Deserialize, Serialize};
/// Cuprate Configuration
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct CuprateConfig {
/// An example configuration section
pub hello: ExampleSection,
}
/// Default configuration settings.
///
/// Note: if your needs are as simple as below, you can
/// use `#[derive(Default)]` on CuprateConfig instead.
impl Default for CuprateConfig {
fn default() -> Self {
Self {
hello: ExampleSection::default(),
}
}
}
/// Example configuration section.
///
/// Delete this and replace it with your actual configuration structs.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ExampleSection {
/// Example configuration value
pub recipient: String,
}
impl Default for ExampleSection {
fn default() -> Self {
Self {
recipient: "world".to_owned(),
}
}
}

View file

@ -1,70 +0,0 @@
//! Error types
use abscissa_core::error::{BoxError, Context};
use std::{
fmt::{self, Display},
io,
ops::Deref,
};
use thiserror::Error;
/// Kinds of errors
#[derive(Copy, Clone, Debug, Eq, Error, PartialEq)]
pub enum ErrorKind {
/// Error in configuration file
#[error("config error")]
Config,
/// Input/output error
#[error("I/O error")]
Io,
}
impl ErrorKind {
/// Create an error context from this error
pub fn context(self, source: impl Into<BoxError>) -> Context<ErrorKind> {
Context::new(self, Some(source.into()))
}
}
/// Error type
#[derive(Debug)]
pub struct Error(Box<Context<ErrorKind>>);
impl Deref for Error {
type Target = Context<ErrorKind>;
fn deref(&self) -> &Context<ErrorKind> {
&self.0
}
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.0.source()
}
}
impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Self {
Context::new(kind, None).into()
}
}
impl From<Context<ErrorKind>> for Error {
fn from(context: Context<ErrorKind>) -> Self {
Error(Box::new(context))
}
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
ErrorKind::Io.context(err).into()
}
}

View file

@ -1,22 +0,0 @@
//! Cuprate
//!
//! Application based on the [Abscissa] framework.
//!
//! [Abscissa]: https://github.com/iqlusioninc/abscissa
// Tip: Deny warnings with `RUSTFLAGS="-D warnings"` environment variable in CI
#![forbid(unsafe_code)]
#![warn(
missing_docs,
rust_2018_idioms,
trivial_casts,
unused_lifetimes,
unused_qualifications
)]
pub mod application;
pub mod commands;
pub mod config;
pub mod error;
pub mod prelude;

View file

@ -1,9 +0,0 @@
//! Application-local prelude: conveniently import types/functions/macros
//! which are generally useful and should be available in every module with
//! `use crate::prelude::*;
/// Abscissa core prelude
pub use abscissa_core::prelude::*;
/// Application state
pub use crate::application::APP;

View file

@ -1,91 +0,0 @@
//! Acceptance test: runs the application as a subprocess and asserts its
//! output for given argument combinations matches what is expected.
//!
//! Modify and/or delete these as you see fit to test the specific needs of
//! your application.
//!
//! For more information, see:
//! <https://docs.rs/abscissa_core/latest/abscissa_core/testing/index.html>
// Tip: Deny warnings with `RUSTFLAGS="-D warnings"` environment variable in CI
#![forbid(unsafe_code)]
#![warn(
missing_docs,
rust_2018_idioms,
trivial_casts,
unused_lifetimes,
unused_qualifications
)]
use abscissa_core::testing::prelude::*;
use cuprate::config::CuprateConfig;
use once_cell::sync::Lazy;
/// Executes your application binary via `cargo run`.
///
/// Storing this value as a [`Lazy`] static ensures that all instances of
/// the runner acquire a mutex when executing commands and inspecting
/// exit statuses, serializing what would otherwise be multithreaded
/// invocations as `cargo test` executes tests in parallel by default.
pub static RUNNER: Lazy<CmdRunner> = Lazy::new(|| CmdRunner::default());
/// Use `CuprateConfig::default()` value if no config or args
#[test]
fn start_no_args() {
let mut runner = RUNNER.clone();
let mut cmd = runner.arg("start").capture_stdout().run();
cmd.stdout().expect_line("Hello, world!");
cmd.wait().unwrap().expect_success();
}
/// Use command-line argument value
#[test]
fn start_with_args() {
let mut runner = RUNNER.clone();
let mut cmd = runner
.args(&["start", "acceptance", "test"])
.capture_stdout()
.run();
cmd.stdout().expect_line("Hello, acceptance test!");
cmd.wait().unwrap().expect_success();
}
/// Use configured value
#[test]
fn start_with_config_no_args() {
let mut config = CuprateConfig::default();
config.hello.recipient = "configured recipient".to_owned();
let expected_line = format!("Hello, {}!", &config.hello.recipient);
let mut runner = RUNNER.clone();
let mut cmd = runner.config(&config).arg("start").capture_stdout().run();
cmd.stdout().expect_line(&expected_line);
cmd.wait().unwrap().expect_success();
}
/// Override configured value with command-line argument
#[test]
fn start_with_config_and_args() {
let mut config = CuprateConfig::default();
config.hello.recipient = "configured recipient".to_owned();
let mut runner = RUNNER.clone();
let mut cmd = runner
.config(&config)
.args(&["start", "acceptance", "test"])
.capture_stdout()
.run();
cmd.stdout().expect_line("Hello, acceptance test!");
cmd.wait().unwrap().expect_success();
}
/// Example of a test which matches a regular expression
#[test]
fn version_no_args() {
let mut runner = RUNNER.clone();
let mut cmd = runner.arg("--version").capture_stdout().run();
cmd.stdout().expect_regex(r"\A\w+ [\d\.\-]+\z");
}

View file

@ -1,7 +1,12 @@
[package] [package]
name = "helper" name = "cuprate-helper"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
description = "Helper functions used around Cuprate."
license = "MIT"
authors = ["hinto-janai <hinto.janai@protonmail.com>", "Boog900"]
repository = "https://github.com/Cuprate/cuprate/tree/main/consensus"
[features] [features]
# All features on by default. # All features on by default.

View file

@ -38,6 +38,7 @@
pub mod asynch; // async collides pub mod asynch; // async collides
#[cfg(feature = "atomic")] #[cfg(feature = "atomic")]
pub mod atomic; pub mod atomic;
pub mod network;
#[cfg(feature = "num")] #[cfg(feature = "num")]
pub mod num; pub mod num;
#[cfg(feature = "thread")] #[cfg(feature = "thread")]

View file

@ -1,3 +1,11 @@
//! This module contains an enum representing every Monero network: mainnet, testnet, stagenet and functionality
//! related to that.
//!
//! This feels out of place for the helper crate but this is needed through out Cuprate and felt too small to split
//! into it's own crate.
//!
//! `#[no_std]` compatible.
const MAINNET_NETWORK_ID: [u8; 16] = [ const MAINNET_NETWORK_ID: [u8; 16] = [
0x12, 0x30, 0xF1, 0x71, 0x61, 0x04, 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x10, 0x12, 0x30, 0xF1, 0x71, 0x61, 0x04, 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x10,
]; ];
@ -8,15 +16,20 @@ const STAGENET_NETWORK_ID: [u8; 16] = [
0x12, 0x30, 0xF1, 0x71, 0x61, 0x04, 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x12, 0x12, 0x30, 0xF1, 0x71, 0x61, 0x04, 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x12,
]; ];
/// An enum representing every Monero network.
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
pub enum Network { pub enum Network {
/// Mainnet
#[default] #[default]
Mainnet, Mainnet,
/// Testnet
Testnet, Testnet,
/// Stagenet
Stagenet, Stagenet,
} }
impl Network { impl Network {
/// Returns the network ID for the current network.
pub fn network_id(&self) -> [u8; 16] { pub fn network_id(&self) -> [u8; 16] {
match self { match self {
Network::Mainnet => MAINNET_NETWORK_ID, Network::Mainnet => MAINNET_NETWORK_ID,

View file

@ -52,7 +52,7 @@ impl_float!(f32, f64);
/// Returns the average of two numbers; works with at least all integral and floating point types /// Returns the average of two numbers; works with at least all integral and floating point types
/// ///
/// ```rust /// ```rust
/// # use helper::num::*; /// # use cuprate_helper::num::*;
/// assert_eq!(get_mid(0, 10), 5); /// assert_eq!(get_mid(0, 10), 5);
/// assert_eq!(get_mid(0.0, 10.0), 5.0); /// assert_eq!(get_mid(0.0, 10.0), 5.0);
/// assert_eq!(get_mid(-10.0, 10.0), 0.0); /// assert_eq!(get_mid(-10.0, 10.0), 0.0);
@ -76,7 +76,7 @@ where
/// Gets the median from a sorted slice. /// Gets the median from a sorted slice.
/// ///
/// ```rust /// ```rust
/// # use helper::num::*; /// # use cuprate_helper::num::*;
/// let mut vec = vec![10, 5, 1, 4, 2, 8, 9, 7, 3, 6]; /// let mut vec = vec![10, 5, 1, 4, 2, 8, 9, 7, 3, 6];
/// vec.sort(); /// vec.sort();
/// ///
@ -109,7 +109,7 @@ where
/// Compare 2 non-`NaN` floats. /// Compare 2 non-`NaN` floats.
/// ///
/// ```rust /// ```rust
/// # use helper::num::*; /// # use cuprate_helper::num::*;
/// # use core::cmp::Ordering; /// # use core::cmp::Ordering;
/// assert_eq!(cmp_float(0.0, 1.0), Ordering::Less); /// assert_eq!(cmp_float(0.0, 1.0), Ordering::Less);
/// assert_eq!(cmp_float(1.0, 1.0), Ordering::Equal); /// assert_eq!(cmp_float(1.0, 1.0), Ordering::Equal);
@ -128,7 +128,7 @@ where
/// This function panics if either floats are NaNs. /// This function panics if either floats are NaNs.
/// ///
/// ```rust,should_panic /// ```rust,should_panic
/// # use helper::num::*; /// # use cuprate_helper::num::*;
/// cmp_float(0.0, f32::NAN); /// cmp_float(0.0, f32::NAN);
/// ``` /// ```
pub fn cmp_float<F: Float>(a: F, b: F) -> Ordering { pub fn cmp_float<F: Float>(a: F, b: F) -> Ordering {
@ -144,7 +144,7 @@ pub fn cmp_float<F: Float>(a: F, b: F) -> Ordering {
/// Compare 2 floats, `NaN`'s will always return [`Ordering::Equal`]. /// Compare 2 floats, `NaN`'s will always return [`Ordering::Equal`].
/// ///
/// ```rust /// ```rust
/// # use helper::num::*; /// # use cuprate_helper::num::*;
/// # use core::cmp::Ordering; /// # use core::cmp::Ordering;
/// assert_eq!(cmp_float_nan(0.0, 1.0), Ordering::Less); /// assert_eq!(cmp_float_nan(0.0, 1.0), Ordering::Less);
/// assert_eq!(cmp_float_nan(1.0, 1.0), Ordering::Equal); /// assert_eq!(cmp_float_nan(1.0, 1.0), Ordering::Equal);

View file

@ -9,11 +9,11 @@ repository = "https://github.com/SyntheticBird45/cuprate/tree/main/net/monero-wi
[dependencies] [dependencies]
levin-cuprate = {path="../levin"} levin-cuprate = {path="../levin"}
monero-epee-bin-serde = {git = "https://github.com/monero-rs/monero-epee-bin-serde.git", rev="aafe4ba"} monero-epee-bin-serde = { workspace = true, features = ["container_as_blob"] }
serde = {version = "1", features = ["derive"]} serde = { workspace = true, features = ["derive", "std"]}
serde_bytes = "0.11" serde_bytes = { workspace = true, features = ["std"]}
thiserror = "1" thiserror = { workspace = true }
[dev-dependencies] [dev-dependencies]
hex = "0.4.3" hex = { workspace = true, features = ["std"]}

View file

@ -7,9 +7,9 @@ authors = ["Boog900"]
[dependencies] [dependencies]
cuprate-common = {path = "../../common"} monero-pruning = { path = "../../pruning" }
monero-wire = {path= "../../net/monero-wire"} monero-wire = { path= "../../net/monero-wire" }
monero-p2p = {path = "../monero-p2p" } monero-p2p = { path = "../monero-p2p" }
tower = { workspace = true, features = ["util", "buffer"] } tower = { workspace = true, features = ["util", "buffer"] }
tokio = { workspace = true, features = ["time", "fs", "rt"]} tokio = { workspace = true, features = ["time", "fs", "rt"]}

View file

@ -19,13 +19,13 @@ use tokio::{
}; };
use tower::Service; use tower::Service;
use cuprate_common::PruningSeed;
use monero_p2p::{ use monero_p2p::{
client::InternalPeerID, client::InternalPeerID,
handles::ConnectionHandle, handles::ConnectionHandle,
services::{AddressBookRequest, AddressBookResponse, ZoneSpecificPeerListEntryBase}, services::{AddressBookRequest, AddressBookResponse, ZoneSpecificPeerListEntryBase},
NetZoneAddress, NetworkZone, NetZoneAddress, NetworkZone,
}; };
use monero_pruning::PruningSeed;
use crate::{peer_list::PeerList, store::save_peers_to_disk, AddressBookError, Config}; use crate::{peer_list::PeerList, store::save_peers_to_disk, AddressBookError, Config};

View file

@ -4,8 +4,8 @@ use futures::StreamExt;
use tokio::sync::Semaphore; use tokio::sync::Semaphore;
use tokio::time::interval; use tokio::time::interval;
use cuprate_common::PruningSeed;
use monero_p2p::handles::HandleBuilder; use monero_p2p::handles::HandleBuilder;
use monero_pruning::PruningSeed;
use super::{AddressBook, ConnectionPeerEntry, InternalPeerID}; use super::{AddressBook, ConnectionPeerEntry, InternalPeerID};
use crate::{peer_list::tests::make_fake_peer_list, AddressBookError, Config}; use crate::{peer_list::tests::make_fake_peer_list, AddressBookError, Config};

View file

@ -2,8 +2,8 @@ use std::collections::{BTreeMap, HashMap, HashSet};
use rand::{seq::SliceRandom, Rng}; use rand::{seq::SliceRandom, Rng};
use cuprate_common::{PruningSeed, CRYPTONOTE_MAX_BLOCK_NUMBER};
use monero_p2p::{services::ZoneSpecificPeerListEntryBase, NetZoneAddress, NetworkZone}; use monero_p2p::{services::ZoneSpecificPeerListEntryBase, NetZoneAddress, NetworkZone};
use monero_pruning::{PruningSeed, CRYPTONOTE_MAX_BLOCK_NUMBER};
#[cfg(test)] #[cfg(test)]
pub mod tests; pub mod tests;

View file

@ -2,8 +2,8 @@ use std::collections::HashSet;
use rand::Rng; use rand::Rng;
use cuprate_common::PruningSeed;
use monero_p2p::services::ZoneSpecificPeerListEntryBase; use monero_p2p::services::ZoneSpecificPeerListEntryBase;
use monero_pruning::PruningSeed;
use cuprate_test_utils::test_netzone::{TestNetZone, TestNetZoneAddr}; use cuprate_test_utils::test_netzone::{TestNetZone, TestNetZoneAddr};
use monero_p2p::NetZoneAddress; use monero_p2p::NetZoneAddress;

View file

@ -7,11 +7,12 @@ authors = ["Boog900"]
[features] [features]
default = ["borsh"] default = ["borsh"]
borsh = ["dep:borsh"] borsh = ["dep:borsh", "monero-pruning/borsh"]
[dependencies] [dependencies]
monero-wire = {path= "../../net/monero-wire"} cuprate-helper = { path = "../../helper" }
cuprate-common = {path = "../../common", features = ["borsh"]} monero-wire = { path = "../../net/monero-wire" }
monero-pruning = { path = "../../pruning" }
tokio = { workspace = true, features = ["net", "sync", "macros"]} tokio = { workspace = true, features = ["net", "sync", "macros"]}
tokio-util = { workspace = true, features = ["codec"] } tokio-util = { workspace = true, features = ["codec"] }

View file

@ -9,7 +9,7 @@ use tokio::{sync::mpsc, task::JoinHandle};
use tokio_util::sync::PollSender; use tokio_util::sync::PollSender;
use tower::Service; use tower::Service;
use cuprate_common::tower_utils::InfallibleOneshotReceiver; use cuprate_helper::asynch::InfallibleOneshotReceiver;
use crate::{ use crate::{
handles::ConnectionHandle, NetworkZone, PeerError, PeerRequest, PeerResponse, SharedError, handles::ConnectionHandle, NetworkZone, PeerError, PeerRequest, PeerResponse, SharedError,

View file

@ -1,4 +1,4 @@
use cuprate_common::{PruningError, PruningSeed}; use monero_pruning::{PruningError, PruningSeed};
use monero_wire::{NetZone, NetworkAddress, PeerListEntryBase}; use monero_wire::{NetZone, NetworkAddress, PeerListEntryBase};
use crate::{ use crate::{

View file

@ -5,7 +5,7 @@ use futures::{channel::mpsc, StreamExt};
use tokio::sync::{broadcast, Semaphore}; use tokio::sync::{broadcast, Semaphore};
use tower::{Service, ServiceExt}; use tower::{Service, ServiceExt};
use cuprate_common::Network; use cuprate_helper::network::Network;
use monero_wire::{common::PeerSupportFlags, BasicNodeData}; use monero_wire::{common::PeerSupportFlags, BasicNodeData};
use monero_p2p::{ use monero_p2p::{

13
pruning/Cargo.toml Normal file
View file

@ -0,0 +1,13 @@
[package]
name = "monero-pruning"
version = "0.1.0"
edition = "2021"
[features]
default = []
borsh = ["dep:borsh"]
[dependencies]
thiserror = { workspace = true }
borsh = { workspace = true, features = ["derive", "std"], optional = true }

View file

@ -1,6 +1,6 @@
//! # Pruning Mechanism for Monero //! # Pruning Mechanism for Monero
//! //!
//! This module provides an implementation of the pruning mechanism used in Monero. //! This crate provides an implementation of the pruning mechanism used in Monero.
//! The main data structure, `PruningSeed`, encapsulates the logic for creating and manipulating pruning seeds, //! The main data structure, `PruningSeed`, encapsulates the logic for creating and manipulating pruning seeds,
//! which determine the set of blocks to be pruned from the blockchain. //! which determine the set of blocks to be pruned from the blockchain.
//! //!
@ -8,9 +8,9 @@
//! split into 8 parts): //! split into 8 parts):
//! //!
//! ```rust //! ```rust
//! use cuprate_common::pruning::PruningSeed; //! use monero_pruning::PruningSeed;
//! //!
//! let seed: u32 = 386; // the seed you wan't to check is valid //! let seed: u32 = 386; // the seed you want to check is valid
//! match PruningSeed::try_from(seed) { //! match PruningSeed::try_from(seed) {
//! Ok(seed) => seed, // seed is valid //! Ok(seed) => seed, // seed is valid
//! Err(e) => panic!("seed is invalid") //! Err(e) => panic!("seed is invalid")
@ -22,10 +22,11 @@ use std::cmp::Ordering;
use thiserror::Error; use thiserror::Error;
use super::{ pub const CRYPTONOTE_MAX_BLOCK_NUMBER: u64 = 500000000;
CRYPTONOTE_MAX_BLOCK_NUMBER, CRYPTONOTE_PRUNING_LOG_STRIPES, CRYPTONOTE_PRUNING_STRIPE_SIZE,
CRYPTONOTE_PRUNING_TIP_BLOCKS, pub const CRYPTONOTE_PRUNING_LOG_STRIPES: u32 = 3;
}; pub const CRYPTONOTE_PRUNING_STRIPE_SIZE: u64 = 4096;
pub const CRYPTONOTE_PRUNING_TIP_BLOCKS: u64 = 5500;
const PRUNING_SEED_LOG_STRIPES_SHIFT: u32 = 7; const PRUNING_SEED_LOG_STRIPES_SHIFT: u32 = 7;
const PRUNING_SEED_STRIPE_SHIFT: u32 = 0; const PRUNING_SEED_STRIPE_SHIFT: u32 = 0;
@ -289,9 +290,7 @@ fn get_block_pruning_stripe(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::pruning::{get_block_pruning_stripe, PruningSeed}; use super::*;
use super::CRYPTONOTE_PRUNING_LOG_STRIPES;
fn make_all_pruning_seeds() -> Vec<PruningSeed> { fn make_all_pruning_seeds() -> Vec<PruningSeed> {
let possible_stripes = 1..(1 << CRYPTONOTE_PRUNING_LOG_STRIPES); let possible_stripes = 1..(1 << CRYPTONOTE_PRUNING_LOG_STRIPES);