Replace OnceLock + fn with LazyLock (#256)

* `consensus/`

* `helper/`

* `test-utils/`

* `storage/`

* fix docs + tests + lints

* decomposed_amount: remove `LazyLock`

* clippy
This commit is contained in:
hinto-janai 2024-08-20 17:53:32 -04:00 committed by GitHub
parent 59adf6dcf8
commit aeb070ae8d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 186 additions and 227 deletions

View file

@ -1,36 +1,27 @@
use std::sync::OnceLock;
/// Decomposed amount table.
///
static DECOMPOSED_AMOUNTS: OnceLock<[u64; 172]> = OnceLock::new();
#[rustfmt::skip]
pub fn decomposed_amounts() -> &'static [u64; 172] {
DECOMPOSED_AMOUNTS.get_or_init(|| {
[
1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 20, 30, 40, 50, 60, 70, 80, 90,
100, 200, 300, 400, 500, 600, 700, 800, 900,
1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000,
10000, 20000, 30000, 40000, 50000, 60000, 70000, 80000, 90000,
100000, 200000, 300000, 400000, 500000, 600000, 700000, 800000, 900000,
1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000,
10000000, 20000000, 30000000, 40000000, 50000000, 60000000, 70000000, 80000000, 90000000,
100000000, 200000000, 300000000, 400000000, 500000000, 600000000, 700000000, 800000000, 900000000,
1000000000, 2000000000, 3000000000, 4000000000, 5000000000, 6000000000, 7000000000, 8000000000, 9000000000,
10000000000, 20000000000, 30000000000, 40000000000, 50000000000, 60000000000, 70000000000, 80000000000, 90000000000,
100000000000, 200000000000, 300000000000, 400000000000, 500000000000, 600000000000, 700000000000, 800000000000, 900000000000,
1000000000000, 2000000000000, 3000000000000, 4000000000000, 5000000000000, 6000000000000, 7000000000000, 8000000000000, 9000000000000,
10000000000000, 20000000000000, 30000000000000, 40000000000000, 50000000000000, 60000000000000, 70000000000000, 80000000000000, 90000000000000,
100000000000000, 200000000000000, 300000000000000, 400000000000000, 500000000000000, 600000000000000, 700000000000000, 800000000000000, 900000000000000,
1000000000000000, 2000000000000000, 3000000000000000, 4000000000000000, 5000000000000000, 6000000000000000, 7000000000000000, 8000000000000000, 9000000000000000,
10000000000000000, 20000000000000000, 30000000000000000, 40000000000000000, 50000000000000000, 60000000000000000, 70000000000000000, 80000000000000000, 90000000000000000,
100000000000000000, 200000000000000000, 300000000000000000, 400000000000000000, 500000000000000000, 600000000000000000, 700000000000000000, 800000000000000000, 900000000000000000,
1000000000000000000, 2000000000000000000, 3000000000000000000, 4000000000000000000, 5000000000000000000, 6000000000000000000, 7000000000000000000, 8000000000000000000, 9000000000000000000,
10000000000000000000
]
})
}
/// Decomposed amount table.
pub static DECOMPOSED_AMOUNTS: [u64; 172] = [
1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 20, 30, 40, 50, 60, 70, 80, 90,
100, 200, 300, 400, 500, 600, 700, 800, 900,
1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000,
10000, 20000, 30000, 40000, 50000, 60000, 70000, 80000, 90000,
100000, 200000, 300000, 400000, 500000, 600000, 700000, 800000, 900000,
1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000,
10000000, 20000000, 30000000, 40000000, 50000000, 60000000, 70000000, 80000000, 90000000,
100000000, 200000000, 300000000, 400000000, 500000000, 600000000, 700000000, 800000000, 900000000,
1000000000, 2000000000, 3000000000, 4000000000, 5000000000, 6000000000, 7000000000, 8000000000, 9000000000,
10000000000, 20000000000, 30000000000, 40000000000, 50000000000, 60000000000, 70000000000, 80000000000, 90000000000,
100000000000, 200000000000, 300000000000, 400000000000, 500000000000, 600000000000, 700000000000, 800000000000, 900000000000,
1000000000000, 2000000000000, 3000000000000, 4000000000000, 5000000000000, 6000000000000, 7000000000000, 8000000000000, 9000000000000,
10000000000000, 20000000000000, 30000000000000, 40000000000000, 50000000000000, 60000000000000, 70000000000000, 80000000000000, 90000000000000,
100000000000000, 200000000000000, 300000000000000, 400000000000000, 500000000000000, 600000000000000, 700000000000000, 800000000000000, 900000000000000,
1000000000000000, 2000000000000000, 3000000000000000, 4000000000000000, 5000000000000000, 6000000000000000, 7000000000000000, 8000000000000000, 9000000000000000,
10000000000000000, 20000000000000000, 30000000000000000, 40000000000000000, 50000000000000000, 60000000000000000, 70000000000000000, 80000000000000000, 90000000000000000,
100000000000000000, 200000000000000000, 300000000000000000, 400000000000000000, 500000000000000000, 600000000000000000, 700000000000000000, 800000000000000000, 900000000000000000,
1000000000000000000, 2000000000000000000, 3000000000000000000, 4000000000000000000, 5000000000000000000, 6000000000000000000, 7000000000000000000, 8000000000000000000, 9000000000000000000,
10000000000000000000
];
/// Checks that an output amount is decomposed.
///
@ -40,7 +31,7 @@ pub fn decomposed_amounts() -> &'static [u64; 172] {
/// ref: <https://monero-book.cuprate.org/consensus_rules/blocks/miner_tx.html#output-amounts>
#[inline]
pub fn is_decomposed_amount(amount: &u64) -> bool {
decomposed_amounts().binary_search(amount).is_ok()
DECOMPOSED_AMOUNTS.binary_search(amount).is_ok()
}
#[cfg(test)]
@ -49,7 +40,7 @@ mod tests {
#[test]
fn decomposed_amounts_return_decomposed() {
for amount in decomposed_amounts() {
for amount in DECOMPOSED_AMOUNTS.iter() {
assert!(is_decomposed_amount(amount))
}
}

View file

@ -10,11 +10,11 @@ use proptest::{collection::vec, prelude::*};
use monero_serai::transaction::Output;
use super::*;
use crate::decomposed_amount::decomposed_amounts;
use crate::decomposed_amount::DECOMPOSED_AMOUNTS;
#[test]
fn test_check_output_amount_v1() {
for amount in decomposed_amounts() {
for amount in DECOMPOSED_AMOUNTS.iter() {
assert!(check_output_amount_v1(*amount, &HardFork::V2).is_ok())
}

View file

@ -4,7 +4,7 @@
//! Note that this module's functions uses [`dirs`],
//! which adheres to the XDG standard on Linux.
//!
//! This means that the values returned by these functions
//! This means that the values returned by these statics
//! may change at runtime depending on environment variables,
//! for example:
//!
@ -17,7 +17,7 @@
//! # if cfg!(target_os = "linux") {
//! std::env::set_var("XDG_CONFIG_HOME", "/custom/path");
//! assert_eq!(
//! cuprate_config_dir().to_string_lossy(),
//! CUPRATE_CONFIG_DIR.to_string_lossy(),
//! "/custom/path/cuprate"
//! );
//! # }
@ -28,10 +28,7 @@
//! - <https://docs.rs/dirs>
//---------------------------------------------------------------------------------------------------- Use
use std::{
path::{Path, PathBuf},
sync::OnceLock,
};
use std::{path::PathBuf, sync::LazyLock};
//---------------------------------------------------------------------------------------------------- Const
/// Cuprate's main directory.
@ -62,71 +59,59 @@ pub const CUPRATE_DIR: &str = {
};
//---------------------------------------------------------------------------------------------------- Directories
/// Create a (private) `OnceLock` and accessor function for common PATHs used by Cuprate.
/// Create a `LazyLock` for common PATHs used by Cuprate.
///
/// This currently creates these directories:
/// - [`cuprate_cache_dir()`]
/// - [`cuprate_config_dir()`]
/// - [`cuprate_data_dir()`]
/// - [`cuprate_blockchain_dir()`]
///
/// FIXME: Use `LazyLock` when stabilized.
/// <https://github.com/rust-lang/rust/issues/109736>.
/// <https://doc.rust-lang.org/std/sync/struct.LazyLock.html>.
macro_rules! impl_path_oncelock_and_fn {
/// - [`CUPRATE_CACHE_DIR`]
/// - [`CUPRATE_CONFIG_DIR`]
/// - [`CUPRATE_DATA_DIR`]
/// - [`CUPRATE_BLOCKCHAIN_DIR`]
macro_rules! impl_path_lazylock {
($(
$(#[$attr:meta])* // Documentation and any `derive`'s.
$fn:ident, // Name of the corresponding access function.
$name:ident, // Name of the corresponding `LazyLock`.
$dirs_fn:ident, // Name of the `dirs` function to use, the PATH prefix.
$sub_dirs:literal // Any sub-directories to add onto the PATH.
),* $(,)?) => {$(
// Create the `OnceLock` if needed, append
// Create the `LazyLock` if needed, append
// the Cuprate directory string and return.
$(#[$attr])*
pub fn $fn() -> &'static Path {
/// Local `OnceLock` containing the Path.
static ONCE_LOCK: OnceLock<PathBuf> = OnceLock::new();
pub static $name: LazyLock<PathBuf> = LazyLock::new(|| {
// There's nothing we can do but panic if
// we cannot acquire critical system directories.
//
// Although, this realistically won't panic on
// normal systems for all OS's supported by `dirs`.
let mut path = dirs::$dirs_fn().unwrap();
ONCE_LOCK.get_or_init(|| {
// There's nothing we can do but panic if
// we cannot acquire critical system directories.
//
// Although, this realistically won't panic on
// normal systems for all OS's supported by `dirs`.
let mut path = dirs::$dirs_fn().unwrap();
// FIXME:
// Consider a user who does `HOME=/ ./cuprated`
//
// Should we say "that's stupid" and panic here?
// Or should it be respected?
// We really don't want a `rm -rf /` type of situation...
assert!(
path.parent().is_some(),
"SAFETY: returned OS PATH was either root or empty, aborting"
);
// FIXME:
// Consider a user who does `HOME=/ ./cuprated`
//
// Should we say "that's stupid" and panic here?
// Or should it be respected?
// We really don't want a `rm -rf /` type of situation...
assert!(
path.parent().is_some(),
"SAFETY: returned OS PATH was either root or empty, aborting"
);
// Returned OS PATH should be absolute, not relative.
assert!(path.is_absolute(), "SAFETY: returned OS PATH was not absolute");
// Returned OS PATH should be absolute, not relative.
assert!(path.is_absolute(), "SAFETY: returned OS PATH was not absolute");
// Unconditionally prefix with the top-level Cuprate directory.
path.push(CUPRATE_DIR);
// Unconditionally prefix with the top-level Cuprate directory.
path.push(CUPRATE_DIR);
// Add any sub directories if specified in the macro.
if !$sub_dirs.is_empty() {
path.push($sub_dirs);
}
// Add any sub directories if specified in the macro.
if !$sub_dirs.is_empty() {
path.push($sub_dirs);
}
path
})
}
path
});
)*};
}
// Note that the `OnceLock`'s are prefixed with `__` to indicate:
// 1. They're not really to be used directly
// 2. To avoid name conflicts
impl_path_oncelock_and_fn! {
impl_path_lazylock! {
/// Cuprate's cache directory.
///
/// This is the PATH used for any Cuprate cache files.
@ -136,7 +121,7 @@ impl_path_oncelock_and_fn! {
/// | Windows | `C:\Users\Alice\AppData\Local\Cuprate\` |
/// | macOS | `/Users/Alice/Library/Caches/Cuprate/` |
/// | Linux | `/home/alice/.cache/cuprate/` |
cuprate_cache_dir,
CUPRATE_CACHE_DIR,
cache_dir,
"",
@ -149,7 +134,7 @@ impl_path_oncelock_and_fn! {
/// | Windows | `C:\Users\Alice\AppData\Roaming\Cuprate\` |
/// | macOS | `/Users/Alice/Library/Application Support/Cuprate/` |
/// | Linux | `/home/alice/.config/cuprate/` |
cuprate_config_dir,
CUPRATE_CONFIG_DIR,
config_dir,
"",
@ -162,7 +147,7 @@ impl_path_oncelock_and_fn! {
/// | Windows | `C:\Users\Alice\AppData\Roaming\Cuprate\` |
/// | macOS | `/Users/Alice/Library/Application Support/Cuprate/` |
/// | Linux | `/home/alice/.local/share/cuprate/` |
cuprate_data_dir,
CUPRATE_DATA_DIR,
data_dir,
"",
@ -175,7 +160,7 @@ impl_path_oncelock_and_fn! {
/// | Windows | `C:\Users\Alice\AppData\Roaming\Cuprate\blockchain\` |
/// | macOS | `/Users/Alice/Library/Application Support/Cuprate/blockchain/` |
/// | Linux | `/home/alice/.local/share/cuprate/blockchain/` |
cuprate_blockchain_dir,
CUPRATE_BLOCKCHAIN_DIR,
data_dir,
"blockchain",
}
@ -192,58 +177,58 @@ mod test {
// - It must `ends_with()` the expected end PATH for the OS
#[test]
fn path_sanity_check() {
assert!(cuprate_cache_dir().is_absolute());
assert!(cuprate_config_dir().is_absolute());
assert!(cuprate_data_dir().is_absolute());
assert!(cuprate_blockchain_dir().is_absolute());
assert!(CUPRATE_CACHE_DIR.is_absolute());
assert!(CUPRATE_CONFIG_DIR.is_absolute());
assert!(CUPRATE_DATA_DIR.is_absolute());
assert!(CUPRATE_BLOCKCHAIN_DIR.is_absolute());
if cfg!(target_os = "windows") {
let dir = cuprate_cache_dir();
let dir = &*CUPRATE_CACHE_DIR;
println!("cuprate_cache_dir: {dir:?}");
assert!(dir.ends_with(r"AppData\Local\Cuprate"));
let dir = cuprate_config_dir();
let dir = &*CUPRATE_CONFIG_DIR;
println!("cuprate_config_dir: {dir:?}");
assert!(dir.ends_with(r"AppData\Roaming\Cuprate"));
let dir = cuprate_data_dir();
let dir = &*CUPRATE_DATA_DIR;
println!("cuprate_data_dir: {dir:?}");
assert!(dir.ends_with(r"AppData\Roaming\Cuprate"));
let dir = cuprate_blockchain_dir();
let dir = &*CUPRATE_BLOCKCHAIN_DIR;
println!("cuprate_blockchain_dir: {dir:?}");
assert!(dir.ends_with(r"AppData\Roaming\Cuprate\blockchain"));
} else if cfg!(target_os = "macos") {
let dir = cuprate_cache_dir();
let dir = &*CUPRATE_CACHE_DIR;
println!("cuprate_cache_dir: {dir:?}");
assert!(dir.ends_with("Library/Caches/Cuprate"));
let dir = cuprate_config_dir();
let dir = &*CUPRATE_CONFIG_DIR;
println!("cuprate_config_dir: {dir:?}");
assert!(dir.ends_with("Library/Application Support/Cuprate"));
let dir = cuprate_data_dir();
let dir = &*CUPRATE_DATA_DIR;
println!("cuprate_data_dir: {dir:?}");
assert!(dir.ends_with("Library/Application Support/Cuprate"));
let dir = cuprate_blockchain_dir();
let dir = &*CUPRATE_BLOCKCHAIN_DIR;
println!("cuprate_blockchain_dir: {dir:?}");
assert!(dir.ends_with("Library/Application Support/Cuprate/blockchain"));
} else {
// Assumes Linux.
let dir = cuprate_cache_dir();
let dir = &*CUPRATE_CACHE_DIR;
println!("cuprate_cache_dir: {dir:?}");
assert!(dir.ends_with(".cache/cuprate"));
let dir = cuprate_config_dir();
let dir = &*CUPRATE_CONFIG_DIR;
println!("cuprate_config_dir: {dir:?}");
assert!(dir.ends_with(".config/cuprate"));
let dir = cuprate_data_dir();
let dir = &*CUPRATE_DATA_DIR;
println!("cuprate_data_dir: {dir:?}");
assert!(dir.ends_with(".local/share/cuprate"));
let dir = cuprate_blockchain_dir();
let dir = &*CUPRATE_BLOCKCHAIN_DIR;
println!("cuprate_blockchain_dir: {dir:?}");
assert!(dir.ends_with(".local/share/cuprate/blockchain"));
}

View file

@ -7,7 +7,7 @@ use std::{borrow::Cow, path::Path};
use serde::{Deserialize, Serialize};
use cuprate_database::{config::SyncMode, resize::ResizeAlgorithm};
use cuprate_helper::fs::cuprate_blockchain_dir;
use cuprate_helper::fs::CUPRATE_BLOCKCHAIN_DIR;
// re-exports
pub use cuprate_database_service::ReaderThreads;
@ -38,7 +38,7 @@ impl ConfigBuilder {
Self {
db_directory: None,
db_config: cuprate_database::config::ConfigBuilder::new(Cow::Borrowed(
cuprate_blockchain_dir(),
&*CUPRATE_BLOCKCHAIN_DIR,
)),
reader_threads: None,
}
@ -48,7 +48,7 @@ impl ConfigBuilder {
///
/// # Default values
/// If [`ConfigBuilder::db_directory`] was not called,
/// the default [`cuprate_blockchain_dir`] will be used.
/// the default [`CUPRATE_BLOCKCHAIN_DIR`] will be used.
///
/// For all other values, [`Default::default`] is used.
pub fn build(self) -> Config {
@ -56,7 +56,7 @@ impl ConfigBuilder {
// in `helper::fs`. No need to do them here.
let db_directory = self
.db_directory
.unwrap_or_else(|| Cow::Borrowed(cuprate_blockchain_dir()));
.unwrap_or_else(|| Cow::Borrowed(&*CUPRATE_BLOCKCHAIN_DIR));
let reader_threads = self.reader_threads.unwrap_or_default();
let db_config = self
@ -106,7 +106,7 @@ impl ConfigBuilder {
#[must_use]
pub fn fast(mut self) -> Self {
self.db_config =
cuprate_database::config::ConfigBuilder::new(Cow::Borrowed(cuprate_blockchain_dir()))
cuprate_database::config::ConfigBuilder::new(Cow::Borrowed(&*CUPRATE_BLOCKCHAIN_DIR))
.fast();
self.reader_threads = Some(ReaderThreads::OnePerThread);
@ -120,7 +120,7 @@ impl ConfigBuilder {
#[must_use]
pub fn low_power(mut self) -> Self {
self.db_config =
cuprate_database::config::ConfigBuilder::new(Cow::Borrowed(cuprate_blockchain_dir()))
cuprate_database::config::ConfigBuilder::new(Cow::Borrowed(&*CUPRATE_BLOCKCHAIN_DIR))
.low_power();
self.reader_threads = Some(ReaderThreads::One);
@ -130,7 +130,7 @@ impl ConfigBuilder {
impl Default for ConfigBuilder {
fn default() -> Self {
let db_directory = Cow::Borrowed(cuprate_blockchain_dir());
let db_directory = Cow::Borrowed(&**CUPRATE_BLOCKCHAIN_DIR);
Self {
db_directory: Some(db_directory.clone()),
db_config: cuprate_database::config::ConfigBuilder::new(db_directory),
@ -161,7 +161,7 @@ impl Config {
/// Create a new [`Config`] with sane default settings.
///
/// The [`cuprate_database::config::Config::db_directory`]
/// will be set to [`cuprate_blockchain_dir`].
/// will be set to [`CUPRATE_BLOCKCHAIN_DIR`].
///
/// All other values will be [`Default::default`].
///
@ -179,8 +179,8 @@ impl Config {
///
/// let config = Config::new();
///
/// assert_eq!(config.db_config.db_directory(), cuprate_blockchain_dir());
/// assert!(config.db_config.db_file().starts_with(cuprate_blockchain_dir()));
/// assert_eq!(config.db_config.db_directory(), &*CUPRATE_BLOCKCHAIN_DIR);
/// assert!(config.db_config.db_file().starts_with(&*CUPRATE_BLOCKCHAIN_DIR));
/// assert!(config.db_config.db_file().ends_with(DATABASE_DATA_FILENAME));
/// assert_eq!(config.db_config.sync_mode, SyncMode::default());
/// assert_eq!(config.db_config.resize_algorithm, ResizeAlgorithm::default());

View file

@ -268,7 +268,7 @@ mod test {
use pretty_assertions::assert_eq;
use cuprate_database::{Env, EnvInner, TxRw};
use cuprate_test_utils::data::{block_v16_tx0, block_v1_tx2, block_v9_tx3};
use cuprate_test_utils::data::{BLOCK_V16_TX0, BLOCK_V1_TX2, BLOCK_V9_TX3};
use super::*;
@ -292,9 +292,9 @@ mod test {
assert_all_tables_are_empty(&env);
let mut blocks = [
block_v1_tx2().clone(),
block_v9_tx3().clone(),
block_v16_tx0().clone(),
BLOCK_V1_TX2.clone(),
BLOCK_V9_TX3.clone(),
BLOCK_V16_TX0.clone(),
];
// HACK: `add_block()` asserts blocks with non-sequential heights
// cannot be added, to get around this, manually edit the block height.
@ -440,7 +440,7 @@ mod test {
let tx_rw = env_inner.tx_rw().unwrap();
let mut tables = env_inner.open_tables_mut(&tx_rw).unwrap();
let mut block = block_v9_tx3().clone();
let mut block = BLOCK_V9_TX3.clone();
block.height = usize::try_from(u32::MAX).unwrap() + 1;
add_block(&block, &mut tables).unwrap();
@ -459,7 +459,7 @@ mod test {
let tx_rw = env_inner.tx_rw().unwrap();
let mut tables = env_inner.open_tables_mut(&tx_rw).unwrap();
let mut block = block_v9_tx3().clone();
let mut block = BLOCK_V9_TX3.clone();
// HACK: `add_block()` asserts blocks with non-sequential heights
// cannot be added, to get around this, manually edit the block height.
block.height = 0;

View file

@ -84,7 +84,7 @@ mod test {
use pretty_assertions::assert_eq;
use cuprate_database::{Env, EnvInner, TxRw};
use cuprate_test_utils::data::{block_v16_tx0, block_v1_tx2, block_v9_tx3};
use cuprate_test_utils::data::{BLOCK_V16_TX0, BLOCK_V1_TX2, BLOCK_V9_TX3};
use super::*;
@ -108,9 +108,9 @@ mod test {
assert_all_tables_are_empty(&env);
let mut blocks = [
block_v1_tx2().clone(),
block_v9_tx3().clone(),
block_v16_tx0().clone(),
BLOCK_V1_TX2.clone(),
BLOCK_V9_TX3.clone(),
BLOCK_V16_TX0.clone(),
];
let blocks_len = blocks.len();

View file

@ -54,7 +54,7 @@
//! ```rust
//! use hex_literal::hex;
//!
//! use cuprate_test_utils::data::block_v16_tx0;
//! use cuprate_test_utils::data::BLOCK_V16_TX0;
//! use cuprate_blockchain::{
//! cuprate_database::{
//! ConcreteEnv,
@ -83,7 +83,7 @@
//! let mut tables = env_inner.open_tables_mut(&tx_rw)?;
//!
//! // Write a block to the database.
//! let mut block = block_v16_tx0().clone();
//! let mut block = BLOCK_V16_TX0.clone();
//! # block.height = 0;
//! add_block(&block, &mut tables)?;
//!

View file

@ -322,7 +322,7 @@ mod test {
use pretty_assertions::assert_eq;
use cuprate_database::{Env, EnvInner, TxRw};
use cuprate_test_utils::data::{tx_v1_sig0, tx_v1_sig2, tx_v2_rct3};
use cuprate_test_utils::data::{TX_V1_SIG0, TX_V1_SIG2, TX_V2_RCT3};
use crate::{
tables::{OpenTables, Tables},
@ -337,7 +337,7 @@ mod test {
assert_all_tables_are_empty(&env);
// Monero `Transaction`, not database tx.
let txs = [tx_v1_sig0(), tx_v1_sig2(), tx_v2_rct3()];
let txs = [&*TX_V1_SIG0, &*TX_V1_SIG2, &*TX_V2_RCT3];
// Add transactions.
let tx_ids = {

View file

@ -66,7 +66,7 @@
//! use tower::{Service, ServiceExt};
//!
//! use cuprate_types::{blockchain::{BlockchainReadRequest, BlockchainWriteRequest, BlockchainResponse}, Chain};
//! use cuprate_test_utils::data::block_v16_tx0;
//! use cuprate_test_utils::data::BLOCK_V16_TX0;
//!
//! use cuprate_blockchain::{
//! cuprate_database::Env,
@ -86,7 +86,7 @@
//! let (mut read_handle, mut write_handle, _) = cuprate_blockchain::service::init(config)?;
//!
//! // Prepare a request to write block.
//! let mut block = block_v16_tx0().clone();
//! let mut block = BLOCK_V16_TX0.clone();
//! # block.height = 0_usize; // must be 0th height or panic in `add_block()`
//! let request = BlockchainWriteRequest::WriteBlock(block);
//!

View file

@ -16,7 +16,7 @@ use pretty_assertions::assert_eq;
use tower::{Service, ServiceExt};
use cuprate_database::{ConcreteEnv, DatabaseIter, DatabaseRo, Env, EnvInner, RuntimeError};
use cuprate_test_utils::data::{block_v16_tx0, block_v1_tx2, block_v9_tx3};
use cuprate_test_utils::data::{BLOCK_V16_TX0, BLOCK_V1_TX2, BLOCK_V9_TX3};
use cuprate_types::{
blockchain::{BlockchainReadRequest, BlockchainResponse, BlockchainWriteRequest},
Chain, OutputOnChain, VerifiedBlockInformation,
@ -61,7 +61,7 @@ fn init_service() -> (
#[allow(clippy::future_not_send)] // INVARIANT: tests are using a single threaded runtime
async fn test_template(
// Which block(s) to add?
block_fns: &[fn() -> &'static VerifiedBlockInformation],
blocks: &[&VerifiedBlockInformation],
// Total amount of generated coins after the block(s) have been added.
cumulative_generated_coins: u64,
// What are the table lengths be after the block(s) have been added?
@ -76,8 +76,8 @@ async fn test_template(
// HACK: `add_block()` asserts blocks with non-sequential heights
// cannot be added, to get around this, manually edit the block height.
for (i, block_fn) in block_fns.iter().enumerate() {
let mut block = block_fn().clone();
for (i, block) in blocks.iter().enumerate() {
let mut block = (*block).clone();
block.height = i;
// Request a block to be written, assert it was written.
@ -104,7 +104,7 @@ async fn test_template(
get_block_extended_header_from_height(&0, &tables).unwrap(),
));
let extended_block_header_1 = if block_fns.len() > 1 {
let extended_block_header_1 = if blocks.len() > 1 {
Ok(BlockchainResponse::BlockExtendedHeader(
get_block_extended_header_from_height(&1, &tables).unwrap(),
))
@ -116,7 +116,7 @@ async fn test_template(
get_block_info(&0, tables.block_infos()).unwrap().block_hash,
));
let block_hash_1 = if block_fns.len() > 1 {
let block_hash_1 = if blocks.len() > 1 {
Ok(BlockchainResponse::BlockHash(
get_block_info(&1, tables.block_infos()).unwrap().block_hash,
))
@ -128,7 +128,7 @@ async fn test_template(
get_block_extended_header_from_height(&0, &tables).unwrap(),
]));
let range_0_2 = if block_fns.len() >= 2 {
let range_0_2 = if blocks.len() >= 2 {
Ok(BlockchainResponse::BlockExtendedHeaderInRange(vec![
get_block_extended_header_from_height(&0, &tables).unwrap(),
get_block_extended_header_from_height(&1, &tables).unwrap(),
@ -333,7 +333,7 @@ fn init_drop() {
#[tokio::test]
async fn v1_tx2() {
test_template(
&[block_v1_tx2],
&[&*BLOCK_V1_TX2],
14_535_350_982_449,
AssertTableLen {
block_infos: 1,
@ -359,7 +359,7 @@ async fn v1_tx2() {
#[tokio::test]
async fn v9_tx3() {
test_template(
&[block_v9_tx3],
&[&*BLOCK_V9_TX3],
3_403_774_022_163,
AssertTableLen {
block_infos: 1,
@ -385,7 +385,7 @@ async fn v9_tx3() {
#[tokio::test]
async fn v16_tx0() {
test_template(
&[block_v16_tx0],
&[&*BLOCK_V16_TX0],
600_000_000_000,
AssertTableLen {
block_infos: 1,

View file

@ -126,7 +126,7 @@ fn resize() {
let (env, _tempdir) = tmp_concrete_env();
// Resize by the OS page size.
let page_size = crate::resize::page_size();
let page_size = *crate::resize::PAGE_SIZE;
let old_size = env.current_map_size();
env.resize_map(Some(ResizeAlgorithm::FixedBytes(page_size)));

View file

@ -10,7 +10,7 @@
//!
//! # Page size
//! All free functions in this module will
//! return a multiple of the OS page size ([`page_size()`]),
//! return a multiple of the OS page size ([`PAGE_SIZE`]),
//! [LMDB will error](http://www.lmdb.tech/doc/group__mdb.html#gaa2506ec8dab3d969b0e609cd82e619e5)
//! if this is not the case.
//!
@ -18,10 +18,10 @@
//! All returned [`NonZeroUsize`] values of the free functions in this module
//! (including [`ResizeAlgorithm::resize`]) uphold the following invariants:
//! 1. It will always be `>=` the input `current_size_bytes`
//! 2. It will always be a multiple of [`page_size()`]
//! 2. It will always be a multiple of [`PAGE_SIZE`]
//---------------------------------------------------------------------------------------------------- Import
use std::{num::NonZeroUsize, sync::OnceLock};
use std::{num::NonZeroUsize, sync::LazyLock};
//---------------------------------------------------------------------------------------------------- ResizeAlgorithm
/// The function/algorithm used by the
@ -85,21 +85,14 @@ impl Default for ResizeAlgorithm {
}
//---------------------------------------------------------------------------------------------------- Free functions
/// This function retrieves the systems memory page size.
/// This retrieves the systems memory page size.
///
/// It is just [`page_size::get`](https://docs.rs/page_size) internally.
///
/// This caches the result, so this function is cheap after the 1st call.
///
/// # Panics
/// This function will panic if the OS returns of page size of `0` (impossible?).
#[inline]
pub fn page_size() -> NonZeroUsize {
/// Cached result of [`page_size()`].
static PAGE_SIZE: OnceLock<NonZeroUsize> = OnceLock::new();
*PAGE_SIZE
.get_or_init(|| NonZeroUsize::new(page_size::get()).expect("page_size::get() returned 0"))
}
/// Accessing this [`LazyLock`] will panic if the OS returns of page size of `0` (impossible?).
pub static PAGE_SIZE: LazyLock<NonZeroUsize> =
LazyLock::new(|| NonZeroUsize::new(page_size::get()).expect("page_size::get() returned 0"));
/// Memory map resize closely matching `monerod`.
///
@ -122,7 +115,7 @@ pub fn page_size() -> NonZeroUsize {
/// assert_eq!(monero(0).get(), N);
///
/// // Rounds up to nearest OS page size.
/// assert_eq!(monero(1).get(), N + page_size().get());
/// assert_eq!(monero(1).get(), N + PAGE_SIZE.get());
/// ```
///
/// # Panics
@ -143,7 +136,7 @@ pub fn monero(current_size_bytes: usize) -> NonZeroUsize {
/// <https://github.com/monero-project/monero/blob/059028a30a8ae9752338a7897329fe8012a310d5/src/blockchain_db/lmdb/db_lmdb.cpp#L553>
const ADD_SIZE: usize = 1_usize << 30;
let page_size = page_size().get();
let page_size = PAGE_SIZE.get();
let new_size_bytes = current_size_bytes + ADD_SIZE;
// Round up the new size to the
@ -167,7 +160,7 @@ pub fn monero(current_size_bytes: usize) -> NonZeroUsize {
///
/// ```rust
/// # use cuprate_database::resize::*;
/// let page_size: usize = page_size().get();
/// let page_size: usize = PAGE_SIZE.get();
///
/// // Anything below the page size will round up to the page size.
/// for i in 0..=page_size {
@ -190,7 +183,7 @@ pub fn monero(current_size_bytes: usize) -> NonZeroUsize {
/// fixed_bytes(1, usize::MAX);
/// ```
pub fn fixed_bytes(current_size_bytes: usize, add_bytes: usize) -> NonZeroUsize {
let page_size = page_size();
let page_size = *PAGE_SIZE;
let new_size_bytes = current_size_bytes + add_bytes;
// Guard against < page_size.
@ -222,7 +215,7 @@ pub fn fixed_bytes(current_size_bytes: usize, add_bytes: usize) -> NonZeroUsize
///
/// ```rust
/// # use cuprate_database::resize::*;
/// let page_size: usize = page_size().get();
/// let page_size: usize = PAGE_SIZE.get();
///
/// // Anything below the page size will round up to the page size.
/// for i in 0..=page_size {
@ -265,7 +258,7 @@ pub fn percent(current_size_bytes: usize, percent: f32) -> NonZeroUsize {
_ => 1.0,
};
let page_size = page_size();
let page_size = *PAGE_SIZE;
// INVARIANT: Allow `f32` <-> `usize` casting, we handle all cases.
#[allow(

View file

@ -15,14 +15,14 @@
//! let tx: Transaction = Transaction::read(&mut TX_E57440).unwrap();
//! ```
//!
//! ## Functions
//! The free functions provide access to typed data found in `cuprate_types`:
//! ## Statics
//! The statics provide access to typed data found in `cuprate_types`:
//! ```rust
//! # use cuprate_test_utils::data::*;
//! use cuprate_types::{VerifiedBlockInformation, VerifiedTransactionInformation};
//!
//! let block: VerifiedBlockInformation = block_v16_tx0().clone();
//! let tx: VerifiedTransactionInformation = tx_v1_sig0().clone();
//! let block: VerifiedBlockInformation = BLOCK_V16_TX0.clone();
//! let tx: VerifiedTransactionInformation = TX_V1_SIG0.clone();
//! ```
mod constants;
@ -31,7 +31,7 @@ pub use constants::{
TX_9E3F73, TX_B6B439, TX_D7FEBD, TX_E2D393, TX_E57440,
};
mod free;
pub use free::{
block_v16_tx0, block_v1_tx2, block_v9_tx3, tx_fee, tx_v1_sig0, tx_v1_sig2, tx_v2_rct3,
mod statics;
pub use statics::{
tx_fee, BLOCK_V16_TX0, BLOCK_V1_TX2, BLOCK_V9_TX3, TX_V1_SIG0, TX_V1_SIG2, TX_V2_RCT3,
};

View file

@ -1,4 +1,4 @@
//! Free functions to access data.
//! `static LazyLock`s to access data.
#![allow(
const_item_mutation, // `R: Read` needs `&mut self`
@ -6,7 +6,7 @@
)]
//---------------------------------------------------------------------------------------------------- Import
use std::sync::OnceLock;
use std::sync::LazyLock;
use cuprate_helper::map::combine_low_high_bits_to_u128;
use cuprate_types::{VerifiedBlockInformation, VerifiedTransactionInformation};
@ -141,8 +141,7 @@ pub fn tx_fee(tx: &Transaction) -> u64 {
}
//---------------------------------------------------------------------------------------------------- Blocks
/// Generate a block accessor function with this signature:
/// `fn() -> &'static VerifiedBlockInformation`
/// Generate a `static LazyLock<VerifiedBlockInformation>`.
///
/// This will use `VerifiedBlockMap` type above to do various
/// checks on the input data and makes sure it seems correct.
@ -153,9 +152,9 @@ pub fn tx_fee(tx: &Transaction) -> u64 {
/// - Monero RPC (see cuprate_test_utils::rpc for this)
///
/// See below for actual usage.
macro_rules! verified_block_information_fn {
macro_rules! verified_block_information {
(
fn_name: $fn_name:ident, // Name of the function created
name: $name:ident, // Name of the `LazyLock` created
block_blob: $block_blob:ident, // Block blob ([u8], found in `constants.rs`)
tx_blobs: [$($tx_blob:ident),*], // Array of contained transaction blobs
pow_hash: $pow_hash:literal, // PoW hash as a string literal
@ -183,7 +182,7 @@ macro_rules! verified_block_information_fn {
#[doc = "# use hex_literal::hex;"]
#[doc = "use cuprate_helper::map::combine_low_high_bits_to_u128;"]
#[doc = ""]
#[doc = concat!("let block = ", stringify!($fn_name), "();")]
#[doc = concat!("let block = &*", stringify!($name), ";")]
#[doc = concat!("assert_eq!(&block.block.serialize(), ", stringify!($block_blob), ");")]
#[doc = concat!("assert_eq!(block.pow_hash, hex!(\"", $pow_hash, "\"));")]
#[doc = concat!("assert_eq!(block.height, ", $height, ");")]
@ -201,28 +200,25 @@ macro_rules! verified_block_information_fn {
"));"
)]
/// ```
pub fn $fn_name() -> &'static VerifiedBlockInformation {
static BLOCK: OnceLock<VerifiedBlockInformation> = OnceLock::new();
BLOCK.get_or_init(|| {
VerifiedBlockMap {
block_blob: $block_blob,
pow_hash: hex!($pow_hash),
height: $height,
generated_coins: $generated_coins,
weight: $weight,
long_term_weight: $long_term_weight,
cumulative_difficulty_low: $cumulative_difficulty_low,
cumulative_difficulty_high: $cumulative_difficulty_high,
txs: &[$($tx_blob),*],
}
.into_verified()
})
}
pub static $name: LazyLock<VerifiedBlockInformation> = LazyLock::new(|| {
VerifiedBlockMap {
block_blob: $block_blob,
pow_hash: hex!($pow_hash),
height: $height,
generated_coins: $generated_coins,
weight: $weight,
long_term_weight: $long_term_weight,
cumulative_difficulty_low: $cumulative_difficulty_low,
cumulative_difficulty_high: $cumulative_difficulty_high,
txs: &[$($tx_blob),*],
}
.into_verified()
});
};
}
verified_block_information_fn! {
fn_name: block_v1_tx2,
verified_block_information! {
name: BLOCK_V1_TX2,
block_blob: BLOCK_5ECB7E,
tx_blobs: [TX_2180A8, TX_D7FEBD],
pow_hash: "c960d540000459480560b7816de968c7470083e5874e10040bdd4cc501000000",
@ -235,8 +231,8 @@ verified_block_information_fn! {
tx_len: 2,
}
verified_block_information_fn! {
fn_name: block_v9_tx3,
verified_block_information! {
name: BLOCK_V9_TX3,
block_blob: BLOCK_F91043,
tx_blobs: [TX_E2D393, TX_E57440, TX_B6B439],
pow_hash: "7c78b5b67a112a66ea69ea51477492057dba9cfeaa2942ee7372c61800000000",
@ -249,8 +245,8 @@ verified_block_information_fn! {
tx_len: 3,
}
verified_block_information_fn! {
fn_name: block_v16_tx0,
verified_block_information! {
name: BLOCK_V16_TX0,
block_blob: BLOCK_43BD1F,
tx_blobs: [],
pow_hash: "10b473b5d097d6bfa0656616951840724dfe38c6fb9c4adf8158800300000000",
@ -264,13 +260,12 @@ verified_block_information_fn! {
}
//---------------------------------------------------------------------------------------------------- Transactions
/// Generate a transaction accessor function with this signature:
/// `fn() -> &'static VerifiedTransactionInformation`
/// Generate a `const LazyLock<VerifiedTransactionInformation>`.
///
/// Same as [`verified_block_information_fn`] but for transactions.
macro_rules! transaction_verification_data_fn {
/// Same as [`verified_block_information`] but for transactions.
macro_rules! transaction_verification_data {
(
fn_name: $fn_name:ident, // Name of the function created
name: $name:ident, // Name of the `LazyLock` created
tx_blobs: $tx_blob:ident, // Transaction blob ([u8], found in `constants.rs`)
weight: $weight:literal, // Transaction weight
hash: $hash:literal, // Transaction hash as a string literal
@ -280,35 +275,34 @@ macro_rules! transaction_verification_data_fn {
/// ```rust
#[doc = "# use cuprate_test_utils::data::*;"]
#[doc = "# use hex_literal::hex;"]
#[doc = concat!("let tx = ", stringify!($fn_name), "();")]
#[doc = concat!("let tx = &*", stringify!($name), ";")]
#[doc = concat!("assert_eq!(&tx.tx.serialize(), ", stringify!($tx_blob), ");")]
#[doc = concat!("assert_eq!(tx.tx_blob, ", stringify!($tx_blob), ");")]
#[doc = concat!("assert_eq!(tx.tx_weight, ", $weight, ");")]
#[doc = concat!("assert_eq!(tx.tx_hash, hex!(\"", $hash, "\"));")]
/// ```
pub fn $fn_name() -> &'static VerifiedTransactionInformation {
static TX: OnceLock<VerifiedTransactionInformation> = OnceLock::new();
TX.get_or_init(|| to_tx_verification_data($tx_blob))
}
pub static $name: LazyLock<VerifiedTransactionInformation> = LazyLock::new(|| {
to_tx_verification_data($tx_blob)
});
};
}
transaction_verification_data_fn! {
fn_name: tx_v1_sig0,
transaction_verification_data! {
name: TX_V1_SIG0,
tx_blobs: TX_3BC7FF,
weight: 248,
hash: "3bc7ff015b227e7313cc2e8668bfbb3f3acbee274a9c201d6211cf681b5f6bb1",
}
transaction_verification_data_fn! {
fn_name: tx_v1_sig2,
transaction_verification_data! {
name: TX_V1_SIG2,
tx_blobs: TX_9E3F73,
weight: 448,
hash: "9e3f73e66d7c7293af59c59c1ff5d6aae047289f49e5884c66caaf4aea49fb34",
}
transaction_verification_data_fn! {
fn_name: tx_v2_rct3,
transaction_verification_data! {
name: TX_V2_RCT3,
tx_blobs: TX_84D48D,
weight: 2743,
hash: "84d48dc11ec91950f8b70a85af9db91fe0c8abef71ef5db08304f7344b99ea66",
@ -328,7 +322,7 @@ mod tests {
#[tokio::test]
async fn block_same_as_rpc() {
let rpc = HttpRpcClient::new(None).await;
for block in [block_v1_tx2(), block_v9_tx3(), block_v16_tx0()] {
for block in [&*BLOCK_V1_TX2, &*BLOCK_V9_TX3, &*BLOCK_V16_TX0] {
println!("block_height: {}", block.height);
let block_rpc = rpc.get_verified_block_information(block.height).await;
assert_eq!(block, &block_rpc);
@ -342,16 +336,12 @@ mod tests {
async fn tx_same_as_rpc() {
let rpc = HttpRpcClient::new(None).await;
let mut txs = [block_v1_tx2(), block_v9_tx3(), block_v16_tx0()]
let mut txs = [&*BLOCK_V1_TX2, &*BLOCK_V9_TX3, &*BLOCK_V16_TX0]
.into_iter()
.flat_map(|block| block.txs.iter().cloned())
.collect::<Vec<VerifiedTransactionInformation>>();
txs.extend([
tx_v1_sig0().clone(),
tx_v1_sig2().clone(),
tx_v2_rct3().clone(),
]);
txs.extend([TX_V1_SIG0.clone(), TX_V1_SIG2.clone(), TX_V2_RCT3.clone()]);
for tx in txs {
println!("tx_hash: {:?}", tx.tx_hash);