mirror of
https://github.com/Cuprate/cuprate.git
synced 2024-12-22 19:49:28 +00:00
fmt + clippy + fix tests
This commit is contained in:
parent
b0588fad2b
commit
376a41deb2
10 changed files with 101 additions and 106 deletions
|
@ -65,6 +65,8 @@ syn = "2.0.37"
|
|||
|
||||
|
||||
[dev-dependencies]
|
||||
monero-consensus = {path = "./rules", features = ["proptest"]}
|
||||
|
||||
tokio = {version = "1", features = ["rt-multi-thread", "macros"]}
|
||||
proptest = "1"
|
||||
proptest-derive = "0.4.0"
|
|
@ -23,7 +23,10 @@ thiserror = { workspace = true }
|
|||
|
||||
rayon = { workspace = true, optional = true }
|
||||
|
||||
# Testing
|
||||
proptest = {workspace = true, optional = true}
|
||||
proptest-derive = {workspace = true, optional = true}
|
||||
|
||||
[dev-dependencies]
|
||||
proptest = {workspace = true}
|
||||
proptest-derive = {workspace = true}
|
||||
tokio = {version = "1.35.0", features = ["rt-multi-thread", "macros"]}
|
|
@ -4,7 +4,7 @@
|
|||
//! an identifier for every current hard-fork.
|
||||
//!
|
||||
//! This module also contains a [`HFVotes`] struct which keeps track of current blockchain voting, and
|
||||
//! has a method [`HFVotes::check_next_hard_fork`] to check if the next hard-fork should be activated.
|
||||
//! has a method [`HFVotes::current_fork`] to check if the next hard-fork should be activated.
|
||||
//!
|
||||
use monero_serai::block::BlockHeader;
|
||||
use std::{
|
||||
|
@ -13,12 +13,15 @@ use std::{
|
|||
time::Duration,
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
/// Target block time for hf 1.
|
||||
const BLOCK_TIME_V1: Duration = Duration::from_secs(60);
|
||||
/// Target block time from v2.
|
||||
const BLOCK_TIME_V2: Duration = Duration::from_secs(120);
|
||||
|
||||
const NUMB_OF_HARD_FORKS: usize = 16;
|
||||
pub const NUMB_OF_HARD_FORKS: usize = 16;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)]
|
||||
pub enum HardForkError {
|
||||
|
@ -51,6 +54,10 @@ impl HFsInfo {
|
|||
self.0[*hf as usize - 1]
|
||||
}
|
||||
|
||||
pub const fn new(hfs: [HFInfo; NUMB_OF_HARD_FORKS]) -> Self {
|
||||
Self(hfs)
|
||||
}
|
||||
|
||||
/// Returns the main-net hard-fork information.
|
||||
///
|
||||
/// https://cuprate.github.io/monero-book/consensus_rules/hardforks.html#Mainnet-Hard-Forks
|
||||
|
@ -78,7 +85,7 @@ impl HFsInfo {
|
|||
|
||||
/// An identifier for every hard-fork Monero has had.
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
|
||||
#[cfg_attr(proptest, derive(proptest_derive::Arbitrary))]
|
||||
#[cfg_attr(any(feature = "proptest", test), derive(proptest_derive::Arbitrary))]
|
||||
#[repr(u8)]
|
||||
pub enum HardFork {
|
||||
V1 = 1,
|
||||
|
@ -245,29 +252,30 @@ impl HFVotes {
|
|||
/// activated.
|
||||
///
|
||||
/// https://cuprate.github.io/monero-book/consensus_rules/hardforks.html#accepting-a-fork
|
||||
pub fn check_next_hard_fork(
|
||||
pub fn current_fork(
|
||||
&self,
|
||||
current_hf: &HardFork,
|
||||
current_height: u64,
|
||||
window: u64,
|
||||
hfs_info: &HFsInfo,
|
||||
) -> Option<HardFork> {
|
||||
let mut approved_next_hf = None;
|
||||
) -> HardFork {
|
||||
let mut current_hf = *current_hf;
|
||||
|
||||
while let Some(next_hf) = current_hf.next_fork() {
|
||||
let hf_info = hfs_info.info_for_hf(&next_hf);
|
||||
if current_height >= hf_info.height
|
||||
&& self.votes_for_hf(&next_hf) >= votes_needed(hf_info.threshold, window)
|
||||
{
|
||||
approved_next_hf = Some(next_hf);
|
||||
current_hf = next_hf;
|
||||
} else {
|
||||
// if we don't have enough votes for this fork any future fork won't have enough votes
|
||||
// as votes are cumulative.
|
||||
// TODO: If a future fork has a lower threshold that could not be true, but as all current forks
|
||||
// have threshold 0 it is ok for now.
|
||||
return approved_next_hf;
|
||||
return current_hf;
|
||||
}
|
||||
}
|
||||
approved_next_hf
|
||||
current_hf
|
||||
}
|
||||
}
|
||||
|
||||
|
|
69
consensus/rules/src/hard_forks/tests.rs
Normal file
69
consensus/rules/src/hard_forks/tests.rs
Normal file
|
@ -0,0 +1,69 @@
|
|||
use std::convert::TryInto;
|
||||
|
||||
use proptest::{arbitrary::any, prop_assert_eq, prop_compose, proptest};
|
||||
|
||||
use crate::hard_forks::{HFVotes, HardFork, NUMB_OF_HARD_FORKS};
|
||||
|
||||
const TEST_WINDOW_SIZE: u64 = 25;
|
||||
|
||||
#[test]
|
||||
fn next_hard_forks() {
|
||||
let mut prev = HardFork::V1;
|
||||
let mut next = HardFork::V2;
|
||||
for _ in 2..NUMB_OF_HARD_FORKS {
|
||||
assert!(prev < next);
|
||||
prev = next;
|
||||
next = next.next_fork().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hard_forks_defined() {
|
||||
for fork in 1..=NUMB_OF_HARD_FORKS {
|
||||
HardFork::from_version(fork.try_into().unwrap()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
prop_compose! {
|
||||
/// Generates an arbitrary full [`HFVotes`].
|
||||
fn arb_full_hf_votes()
|
||||
(
|
||||
// we can't use HardFork as for some reason it overflows the stack, so we use u8.
|
||||
votes in any::<[u8; TEST_WINDOW_SIZE as usize]>()
|
||||
) -> HFVotes {
|
||||
let mut vote_count = HFVotes::new(TEST_WINDOW_SIZE as usize);
|
||||
for vote in votes {
|
||||
vote_count.add_vote_for_hf(&HardFork::from_vote(vote % 17));
|
||||
}
|
||||
vote_count
|
||||
}
|
||||
}
|
||||
|
||||
proptest! {
|
||||
#[test]
|
||||
fn hf_vote_counter_total_correct(hf_votes in arb_full_hf_votes()) {
|
||||
prop_assert_eq!(hf_votes.total_votes(), u64::try_from(hf_votes.vote_list.len()).unwrap());
|
||||
|
||||
let mut votes = [0_u64; NUMB_OF_HARD_FORKS];
|
||||
for vote in hf_votes.vote_list.iter() {
|
||||
// manually go through the list of votes tallying
|
||||
votes[*vote as usize - 1] += 1;
|
||||
}
|
||||
|
||||
prop_assert_eq!(votes, hf_votes.votes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn window_size_kept_constant(mut hf_votes in arb_full_hf_votes(), new_votes in any::<Vec<HardFork>>()) {
|
||||
for new_vote in new_votes.into_iter() {
|
||||
hf_votes.add_vote_for_hf(&new_vote);
|
||||
prop_assert_eq!(hf_votes.total_votes(), TEST_WINDOW_SIZE)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn votes_out_of_range(high_vote in (NUMB_OF_HARD_FORKS+ 1).try_into().unwrap()..u8::MAX) {
|
||||
prop_assert_eq!(HardFork::from_vote(0), HardFork::V1);
|
||||
prop_assert_eq!(HardFork::from_vote(u8::try_from(NUMB_OF_HARD_FORKS).unwrap() + 1_u8), HardFork::from_vote(high_vote));
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
|
|||
pub mod blocks;
|
||||
mod decomposed_amount;
|
||||
pub mod genesis;
|
||||
mod hard_forks;
|
||||
pub mod hard_forks;
|
||||
pub mod miner_tx;
|
||||
pub mod signatures;
|
||||
pub mod transactions;
|
||||
|
|
|
@ -171,7 +171,7 @@ where
|
|||
});
|
||||
|
||||
while let Some(incoming_blocks) = incoming_blocks.next().await {
|
||||
let mut height = 0;
|
||||
let mut height;
|
||||
for block in incoming_blocks {
|
||||
let VerifyBlockResponse::MainChain(verified_block_info) = block_verifier
|
||||
.ready()
|
||||
|
|
|
@ -6,7 +6,7 @@ use std::{
|
|||
};
|
||||
|
||||
use futures::FutureExt;
|
||||
use monero_serai::{block::Block, transaction::Input};
|
||||
use monero_serai::block::Block;
|
||||
use tower::{Service, ServiceExt};
|
||||
|
||||
use monero_consensus::{
|
||||
|
|
|
@ -119,14 +119,12 @@ impl HardForkState {
|
|||
///
|
||||
/// https://cuprate.github.io/monero-docs/consensus_rules/hardforks.html#accepting-a-fork
|
||||
fn check_set_new_hf(&mut self) {
|
||||
if let Some(next_fork) = self.votes.check_next_hard_fork(
|
||||
self.current_hardfork = self.votes.current_fork(
|
||||
&self.current_hardfork,
|
||||
self.last_height + 1,
|
||||
self.config.window,
|
||||
&self.config.info,
|
||||
) {
|
||||
self.current_hardfork = next_fork;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
pub fn current_hardfork(&self) -> HardFork {
|
||||
|
@ -134,13 +132,6 @@ impl HardForkState {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the votes needed for this fork.
|
||||
///
|
||||
/// https://cuprate.github.io/monero-docs/consensus_rules/hardforks.html#accepting-a-fork
|
||||
pub fn votes_needed(threshold: u64, window: u64) -> u64 {
|
||||
(threshold * window + 99) / 100
|
||||
}
|
||||
|
||||
#[instrument(name = "get_votes", skip(database))]
|
||||
async fn get_votes_in_range<D: Database>(
|
||||
database: D,
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
use std::convert::TryInto;
|
||||
use monero_consensus::hard_forks::{HFInfo, HardFork, NUMB_OF_HARD_FORKS};
|
||||
use monero_consensus::HFsInfo;
|
||||
|
||||
use proptest::{arbitrary::any, prop_assert_eq, prop_compose, proptest};
|
||||
|
||||
use super::{HFInfo, HFVotes, HardFork, HardForkConfig, HardForkState, NUMB_OF_HARD_FORKS};
|
||||
use super::{HardForkConfig, HardForkState};
|
||||
use crate::test_utils::mock_db::*;
|
||||
|
||||
const TEST_WINDOW_SIZE: u64 = 25;
|
||||
|
@ -28,27 +27,9 @@ const TEST_HFS: [HFInfo; NUMB_OF_HARD_FORKS] = [
|
|||
|
||||
pub const TEST_HARD_FORK_CONFIG: HardForkConfig = HardForkConfig {
|
||||
window: TEST_WINDOW_SIZE,
|
||||
forks: TEST_HFS,
|
||||
info: HFsInfo::new(TEST_HFS),
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn next_hard_forks() {
|
||||
let mut prev = HardFork::V1;
|
||||
let mut next = HardFork::V2;
|
||||
for _ in 2..NUMB_OF_HARD_FORKS {
|
||||
assert!(prev < next);
|
||||
prev = next;
|
||||
next = next.next_fork().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hard_forks_defined() {
|
||||
for fork in 1..=NUMB_OF_HARD_FORKS {
|
||||
HardFork::from_version(&fork.try_into().unwrap()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn hard_fork_set_depends_on_top_block() {
|
||||
let mut db_builder = DummyDatabaseBuilder::default();
|
||||
|
@ -72,47 +53,3 @@ async fn hard_fork_set_depends_on_top_block() {
|
|||
|
||||
assert_eq!(state.current_hardfork, HardFork::V14);
|
||||
}
|
||||
|
||||
prop_compose! {
|
||||
/// Generates an arbitrary full [`HFVotes`].
|
||||
fn arb_full_hf_votes()
|
||||
(
|
||||
// we can't use HardFork as for some reason it overflows the stack, so we use u8.
|
||||
votes in any::<[u8; TEST_WINDOW_SIZE as usize]>()
|
||||
) -> HFVotes {
|
||||
let mut vote_count = HFVotes::new(TEST_WINDOW_SIZE as usize);
|
||||
for vote in votes {
|
||||
vote_count.add_vote_for_hf(&HardFork::from_vote(&(vote % 17)));
|
||||
}
|
||||
vote_count
|
||||
}
|
||||
}
|
||||
|
||||
proptest! {
|
||||
#[test]
|
||||
fn hf_vote_counter_total_correct(hf_votes in arb_full_hf_votes()) {
|
||||
prop_assert_eq!(hf_votes.total_votes(), u64::try_from(hf_votes.vote_list.len()).unwrap());
|
||||
|
||||
let mut votes = [0_u64; NUMB_OF_HARD_FORKS];
|
||||
for vote in hf_votes.vote_list.iter() {
|
||||
// manually go through the list of votes tallying
|
||||
votes[*vote as usize - 1] += 1;
|
||||
}
|
||||
|
||||
prop_assert_eq!(votes, hf_votes.votes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn window_size_kept_constant(mut hf_votes in arb_full_hf_votes(), new_votes in any::<Vec<HardFork>>()) {
|
||||
for new_vote in new_votes.into_iter() {
|
||||
hf_votes.add_vote_for_hf(&new_vote);
|
||||
prop_assert_eq!(hf_votes.total_votes(), TEST_WINDOW_SIZE)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn votes_out_of_range(high_vote in (NUMB_OF_HARD_FORKS+ 1).try_into().unwrap()..u8::MAX) {
|
||||
prop_assert_eq!(HardFork::from_vote(&0), HardFork::V1);
|
||||
prop_assert_eq!(HardFork::from_vote(&NUMB_OF_HARD_FORKS.try_into().unwrap()), HardFork::from_vote(&high_vote));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@ use std::{
|
|||
time::{SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
|
||||
use curve25519_dalek::edwards::CompressedEdwardsY;
|
||||
|
||||
/// 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
|
||||
|
@ -54,16 +52,3 @@ pub(crate) fn current_time() -> u64 {
|
|||
.unwrap()
|
||||
.as_secs()
|
||||
}
|
||||
|
||||
/// Checks that a point is canonical.
|
||||
///
|
||||
/// https://github.com/dalek-cryptography/curve25519-dalek/issues/380
|
||||
pub(crate) fn check_point(point: &CompressedEdwardsY) -> bool {
|
||||
let bytes = point.as_bytes();
|
||||
|
||||
point
|
||||
.decompress()
|
||||
// Ban points which are either unreduced or -0
|
||||
.filter(|point| point.compress().as_bytes() == bytes)
|
||||
.is_some()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue