test-utils: return &'static verified superset types (#108)

* data: return `&'static` verified superset types

* docs

* fix VerifiedBlockMap, use manual input, add block 5da0a3d

* free: use macros to generate accessor functions

* constants: use macro

* docs

* `tx_data` -> `tx_blob`
This commit is contained in:
hinto-janai 2024-04-20 20:34:04 -04:00 committed by GitHub
parent ad7b750d76
commit fe2366c5df
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 480 additions and 220 deletions

2
Cargo.lock generated
View file

@ -633,8 +633,10 @@ dependencies = [
"borsh",
"bytes",
"bzip2",
"cuprate-types",
"futures",
"hex",
"hex-literal",
"monero-p2p",
"monero-serai",
"monero-wire",

View file

@ -8,6 +8,7 @@ authors = ["Boog900"]
[dependencies]
monero-wire = { path = "../net/monero-wire"}
monero-p2p = { path = "../p2p/monero-p2p", features = ["borsh"] }
cuprate-types = { path = "../types" }
monero-serai = { workspace = true }
futures = { workspace = true, features = ["std"] }
@ -17,6 +18,7 @@ tokio-util = { workspace = true }
reqwest = { workspace = true }
bytes = { workspace = true, features = ["std"] }
tempfile = { workspace = true }
hex-literal = { workspace = true }
borsh = { workspace = true, features = ["derive"]}

View file

@ -6,3 +6,4 @@ Cuprate crate, only in tests.
It currently contains:
- Code to spawn monerod instances and a testing network zone
- Real raw and typed Monero data, e.g. `Block, Transaction`
- An RPC client to generate types from `cuprate_types`

View file

@ -3,147 +3,223 @@
//---------------------------------------------------------------------------------------------------- Import
//---------------------------------------------------------------------------------------------------- Block
/// Block with height `202612` and hash `bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698`.
/// Generate a `const _: &[u8]` pointing to a block blob.
///
/// This will deserialize with `Block` to assume the blob is at least deserializable.
///
/// This requires some static block input for testing.
///
/// The actual block blob data on disk is found in `data/block`.
///
/// See below for actual usage.
macro_rules! const_block_blob {
(
name: $name:ident, // Name of the `const` created
height: $height:literal, // Block height
hash: $hash:literal, // Block hash
data_path: $data_path:literal, // Path to the block blob
major_version: $major_version:literal, // Block's major version
minor_version: $minor_version:literal, // Block's minor version
timestamp: $timestamp:literal, // Block's timestamp
nonce: $nonce:literal, // Block's nonce
miner_tx_generated: $miner_tx_generated:literal, // Generated Monero in block's miner transaction
tx_len: $tx_len:literal, // How many transactions there are in the block
) => {
#[doc = concat!("Block with hash `", $hash, "`.")]
///
#[doc = concat!("Height: `", $height, "`.")]
///
/// ```rust
/// use monero_serai::{block::Block, transaction::Input};
///
/// let block = Block::read(&mut
/// cuprate_test_utils::data::BLOCK_BBD604
/// ).unwrap();
///
/// assert_eq!(block.header.major_version, 1);
/// assert_eq!(block.header.minor_version, 0);
/// assert_eq!(block.header.timestamp, 1409804570);
/// assert_eq!(block.header.nonce, 1073744198);
/// assert!(matches!(block.miner_tx.prefix.inputs[0], Input::Gen(202612)));
/// assert_eq!(block.txs.len(), 513);
///
/// assert_eq!(
/// hex::encode(block.hash()),
/// "bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698",
/// );
#[doc = "# use cuprate_test_utils::data::*;"]
#[doc = "use monero_serai::{block::Block, transaction::Input};"]
#[doc = ""]
#[doc = concat!("let block = Block::read(&mut ", stringify!($name), ").unwrap();")]
#[doc = ""]
#[doc = concat!("assert_eq!(block.header.major_version, ", $major_version, ");")]
#[doc = concat!("assert_eq!(block.header.minor_version, ", $minor_version, ");")]
#[doc = concat!("assert_eq!(block.header.timestamp, ", $timestamp, ");")]
#[doc = concat!("assert_eq!(block.header.nonce, ", $nonce, ");")]
#[doc = concat!("assert!(matches!(block.miner_tx.prefix.inputs[0], Input::Gen(", $miner_tx_generated, ")));")]
#[doc = concat!("assert_eq!(block.txs.len(), ", $tx_len, ");")]
#[doc = concat!("assert_eq!(hex::encode(block.hash()), \"", $hash, "\")")]
/// ```
pub const BLOCK_BBD604: &[u8] =
include_bytes!("block/bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698.bin");
pub const $name: &[u8] = include_bytes!($data_path);
};
}
/// Block with height `2751506` and hash `f910435a5477ca27be1986c080d5476aeab52d0c07cf3d9c72513213350d25d4`.
///
/// ```rust
/// use monero_serai::{block::Block, transaction::Input};
///
/// let block = Block::read(&mut
/// cuprate_test_utils::data::BLOCK_F91043
/// ).unwrap();
///
/// assert_eq!(block.header.major_version, 9);
/// assert_eq!(block.header.minor_version, 9);
/// assert_eq!(block.header.timestamp, 1545423190);
/// assert_eq!(block.header.nonce, 4123173351);
/// assert!(matches!(block.miner_tx.prefix.inputs[0], Input::Gen(1731606)));
/// assert_eq!(block.txs.len(), 3);
///
/// assert_eq!(
/// hex::encode(block.hash()),
/// "f910435a5477ca27be1986c080d5476aeab52d0c07cf3d9c72513213350d25d4",
/// );
/// ```
pub const BLOCK_F91043: &[u8] =
include_bytes!("block/f910435a5477ca27be1986c080d5476aeab52d0c07cf3d9c72513213350d25d4.bin");
const_block_blob! {
name: BLOCK_BBD604,
height: 202_612,
hash: "bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698",
data_path: "block/bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698.bin",
major_version: 1,
minor_version: 0,
timestamp: 1409804570,
nonce: 1073744198,
miner_tx_generated: 202612,
tx_len: 513,
}
/// Block with height `2751506` and hash `43bd1f2b6556dcafa413d8372974af59e4e8f37dbf74dc6b2a9b7212d0577428`.
///
/// ```rust
/// use monero_serai::{block::Block, transaction::Input};
///
/// let block = Block::read(&mut
/// cuprate_test_utils::data::BLOCK_43BD1F
/// ).unwrap();
///
/// assert_eq!(block.header.major_version, 16);
/// assert_eq!(block.header.minor_version, 16);
/// assert_eq!(block.header.timestamp, 1667941829);
/// assert_eq!(block.header.nonce, 4110909056);
/// assert!(matches!(block.miner_tx.prefix.inputs[0], Input::Gen(2751506)));
/// assert_eq!(block.txs.len(), 0);
///
/// assert_eq!(
/// hex::encode(block.hash()),
/// "43bd1f2b6556dcafa413d8372974af59e4e8f37dbf74dc6b2a9b7212d0577428",
/// );
/// ```
pub const BLOCK_43BD1F: &[u8] =
include_bytes!("block/43bd1f2b6556dcafa413d8372974af59e4e8f37dbf74dc6b2a9b7212d0577428.bin");
const_block_blob! {
name: BLOCK_5ECB7E,
height: 202_609,
hash: "5ecb7e663bbe947c734c8059e7d7d52dc7d6644bb82d81a6ad4057d127ee8eda",
data_path: "block/5ecb7e663bbe947c734c8059e7d7d52dc7d6644bb82d81a6ad4057d127ee8eda.bin",
major_version: 1,
minor_version: 0,
timestamp: 1409804315,
nonce: 48426,
miner_tx_generated: 202609,
tx_len: 2,
}
const_block_blob! {
name: BLOCK_F91043,
height: 2_751_506,
hash: "f910435a5477ca27be1986c080d5476aeab52d0c07cf3d9c72513213350d25d4",
data_path: "block/f910435a5477ca27be1986c080d5476aeab52d0c07cf3d9c72513213350d25d4.bin",
major_version: 9,
minor_version: 9,
timestamp: 1545423190,
nonce: 4123173351,
miner_tx_generated: 1731606,
tx_len: 3,
}
const_block_blob! {
name: BLOCK_43BD1F,
height: 2_751_506,
hash: "43bd1f2b6556dcafa413d8372974af59e4e8f37dbf74dc6b2a9b7212d0577428",
data_path: "block/43bd1f2b6556dcafa413d8372974af59e4e8f37dbf74dc6b2a9b7212d0577428.bin",
major_version: 16,
minor_version: 16,
timestamp: 1667941829,
nonce: 4110909056,
miner_tx_generated: 2751506,
tx_len: 0,
}
//---------------------------------------------------------------------------------------------------- Transaction
/// Transaction with hash `3bc7ff015b227e7313cc2e8668bfbb3f3acbee274a9c201d6211cf681b5f6bb1`.
/// Generate a `const _: &[u8]` pointing to a transaction blob.
///
/// Same as [`const_block_blob`] but for transactions.
macro_rules! const_tx_blob {
(
name: $name:ident, // Name of the `const` created
hash: $hash:literal, // Transaction hash
data_path: $data_path:literal, // Path to the transaction blob
version: $version:literal, // Transaction version
timelock: $timelock:expr, // Transaction's timelock (use the real type `Timelock`)
input_len: $input_len:literal, // Amount of inputs
output_len: $output_len:literal, // Amount of outputs
signatures_len: $signatures_len:literal, // Amount of signatures
) => {
#[doc = concat!("Transaction with hash `", $hash, "`.")]
///
/// ```rust
/// use monero_serai::transaction::{Transaction, Timelock};
///
/// let tx = Transaction::read(&mut
/// cuprate_test_utils::data::TX_3BC7FF
/// ).unwrap();
///
/// assert_eq!(tx.prefix.version, 1);
/// assert_eq!(tx.prefix.timelock, Timelock::Block(100_081));
/// assert_eq!(tx.prefix.inputs.len(), 1);
/// assert_eq!(tx.prefix.outputs.len(), 5);
/// assert_eq!(tx.signatures.len(), 0);
///
/// assert_eq!(
/// hex::encode(tx.hash()),
/// "3bc7ff015b227e7313cc2e8668bfbb3f3acbee274a9c201d6211cf681b5f6bb1",
/// );
#[doc = "# use cuprate_test_utils::data::*;"]
#[doc = "use monero_serai::transaction::{Transaction, Timelock};"]
#[doc = ""]
#[doc = concat!("let tx = Transaction::read(&mut ", stringify!($name), ").unwrap();")]
#[doc = ""]
#[doc = concat!("assert_eq!(tx.prefix.version, ", $version, ");")]
#[doc = concat!("assert_eq!(tx.prefix.timelock, ", stringify!($timelock), ");")]
#[doc = concat!("assert_eq!(tx.prefix.inputs.len(), ", $input_len, ");")]
#[doc = concat!("assert_eq!(tx.prefix.outputs.len(), ", $output_len, ");")]
#[doc = concat!("assert_eq!(tx.signatures.len(), ", $signatures_len, ");")]
#[doc = concat!("assert_eq!(hex::encode(tx.hash()), \"", $hash, "\")")]
/// ```
pub const TX_3BC7FF: &[u8] =
include_bytes!("tx/3bc7ff015b227e7313cc2e8668bfbb3f3acbee274a9c201d6211cf681b5f6bb1.bin");
pub const $name: &[u8] = include_bytes!($data_path);
};
}
/// Transaction with hash `9e3f73e66d7c7293af59c59c1ff5d6aae047289f49e5884c66caaf4aea49fb34`.
///
/// ```rust
/// use monero_serai::transaction::{Transaction, Timelock};
///
/// let tx = Transaction::read(&mut
/// cuprate_test_utils::data::TX_9E3F73
/// ).unwrap();
///
/// assert_eq!(tx.prefix.version, 1);
/// assert_eq!(tx.prefix.timelock, Timelock::None);
/// assert_eq!(tx.prefix.inputs.len(), 2);
/// assert_eq!(tx.prefix.outputs.len(), 5);
/// assert_eq!(tx.signatures.len(), 2);
///
/// assert_eq!(
/// hex::encode(tx.hash()),
/// "9e3f73e66d7c7293af59c59c1ff5d6aae047289f49e5884c66caaf4aea49fb34",
/// );
/// ```
pub const TX_9E3F73: &[u8] =
include_bytes!("tx/9e3f73e66d7c7293af59c59c1ff5d6aae047289f49e5884c66caaf4aea49fb34.bin");
const_tx_blob! {
name: TX_3BC7FF,
hash: "3bc7ff015b227e7313cc2e8668bfbb3f3acbee274a9c201d6211cf681b5f6bb1",
data_path: "tx/3bc7ff015b227e7313cc2e8668bfbb3f3acbee274a9c201d6211cf681b5f6bb1.bin",
version: 1,
timelock: Timelock::Block(100_081),
input_len: 1,
output_len: 5,
signatures_len: 0,
}
/// Transaction with hash `84d48dc11ec91950f8b70a85af9db91fe0c8abef71ef5db08304f7344b99ea66`.
///
/// ```rust
/// use monero_serai::transaction::{Transaction, Timelock};
///
/// let tx = Transaction::read(&mut
/// cuprate_test_utils::data::TX_84D48D
/// ).unwrap();
///
/// assert_eq!(tx.prefix.version, 2);
/// assert_eq!(tx.prefix.timelock, Timelock::None);
/// assert_eq!(tx.prefix.inputs.len(), 2);
/// assert_eq!(tx.prefix.outputs.len(), 2);
/// assert_eq!(tx.signatures.len(), 0);
///
/// assert_eq!(
/// hex::encode(tx.hash()),
/// "84d48dc11ec91950f8b70a85af9db91fe0c8abef71ef5db08304f7344b99ea66",
/// );
/// ```
pub const TX_84D48D: &[u8] =
include_bytes!("tx/84d48dc11ec91950f8b70a85af9db91fe0c8abef71ef5db08304f7344b99ea66.bin");
const_tx_blob! {
name: TX_2180A8,
hash: "2180a87f724702d37af087e22476297e818a73579ef7b7da947da963245202a3",
data_path: "tx/2180a87f724702d37af087e22476297e818a73579ef7b7da947da963245202a3.bin",
version: 1,
timelock: Timelock::None,
input_len: 19,
output_len: 61,
signatures_len: 19,
}
const_tx_blob! {
name: TX_D7FEBD,
hash: "d7febd16293799d9c6a8e0fe9199b8a0a3e0da5a8a165098937b60f0bbd582df",
data_path: "tx/d7febd16293799d9c6a8e0fe9199b8a0a3e0da5a8a165098937b60f0bbd582df.bin",
version: 1,
timelock: Timelock::None,
input_len: 46,
output_len: 46,
signatures_len: 46,
}
const_tx_blob! {
name: TX_E2D393,
hash: "e2d39395dd1625b2d707b98af789e7eab9d24c2bd2978ec38ef910961a8cdcee",
data_path: "tx/e2d39395dd1625b2d707b98af789e7eab9d24c2bd2978ec38ef910961a8cdcee.bin",
version: 2,
timelock: Timelock::None,
input_len: 1,
output_len: 2,
signatures_len: 0,
}
const_tx_blob! {
name: TX_E57440,
hash: "e57440ec66d2f3b2a5fa2081af40128868973e7c021bb3877290db3066317474",
data_path: "tx/e57440ec66d2f3b2a5fa2081af40128868973e7c021bb3877290db3066317474.bin",
version: 2,
timelock: Timelock::None,
input_len: 1,
output_len: 2,
signatures_len: 0,
}
const_tx_blob! {
name: TX_B6B439,
hash: "b6b4394d4ec5f08ad63267c07962550064caa8d225dd9ad6d739ebf60291c169",
data_path: "tx/b6b4394d4ec5f08ad63267c07962550064caa8d225dd9ad6d739ebf60291c169.bin",
version: 2,
timelock: Timelock::None,
input_len: 2,
output_len: 2,
signatures_len: 0,
}
const_tx_blob! {
name: TX_9E3F73,
hash: "9e3f73e66d7c7293af59c59c1ff5d6aae047289f49e5884c66caaf4aea49fb34",
data_path: "tx/9e3f73e66d7c7293af59c59c1ff5d6aae047289f49e5884c66caaf4aea49fb34.bin",
version: 1,
timelock: Timelock::None,
input_len: 2,
output_len: 5,
signatures_len: 2,
}
const_tx_blob! {
name: TX_84D48D,
hash: "84d48dc11ec91950f8b70a85af9db91fe0c8abef71ef5db08304f7344b99ea66",
data_path: "tx/84d48dc11ec91950f8b70a85af9db91fe0c8abef71ef5db08304f7344b99ea66.bin",
version: 2,
timelock: Timelock::None,
input_len: 2,
output_len: 2,
signatures_len: 0,
}
//---------------------------------------------------------------------------------------------------- Tests
#[cfg(test)]

View file

@ -6,105 +6,260 @@
)]
//---------------------------------------------------------------------------------------------------- Import
use std::sync::OnceLock;
use std::sync::{Arc, OnceLock};
use hex_literal::hex;
use monero_serai::{block::Block, transaction::Transaction};
use cuprate_types::{TransactionVerificationData, VerifiedBlockInformation};
use crate::data::constants::{
BLOCK_43BD1F, BLOCK_BBD604, BLOCK_F91043, TX_3BC7FF, TX_84D48D, TX_9E3F73,
BLOCK_43BD1F, BLOCK_5ECB7E, BLOCK_F91043, TX_2180A8, TX_3BC7FF, TX_84D48D, TX_9E3F73,
TX_B6B439, TX_D7FEBD, TX_E2D393, TX_E57440,
};
//---------------------------------------------------------------------------------------------------- Conversion
/// Converts `monero_serai`'s `Block` into a
/// `cuprate_types::VerifiedBlockInformation` (superset).
///
/// To prevent pulling other code in order to actually calculate things
/// (e.g. `pow_hash`), some information must be provided statically,
/// this struct represents that data that must be provided.
///
/// Consider using `cuprate_test_utils::rpc` to get this data easily.
struct VerifiedBlockMap<'a> {
block: Block,
pow_hash: [u8; 32],
height: u64,
generated_coins: u64,
weight: usize,
long_term_weight: usize,
cumulative_difficulty: u128,
// Vec of `tx_blob`'s, i.e. the data in `/test-utils/src/data/tx/`.
// This should the actual `tx_blob`'s of the transactions within this block.
txs: Vec<&'a [u8]>,
}
impl VerifiedBlockMap<'_> {
/// Turn the various static data bits in `self` into a `VerifiedBlockInformation`.
///
/// Transactions are verified that they at least match the block's,
/// although the correctness of data (whether this block actually existed or not)
/// is not checked.
fn into_verified(self) -> VerifiedBlockInformation {
let Self {
block,
pow_hash,
height,
generated_coins,
weight,
long_term_weight,
cumulative_difficulty,
txs,
} = self;
let txs: Vec<Arc<TransactionVerificationData>> = txs
.into_iter()
.map(to_tx_verification_data)
.map(Arc::new)
.collect();
assert_eq!(
txs.len(),
block.txs.len(),
"(deserialized txs).len() != (txs hashes in block).len()"
);
for (tx, tx_hash_in_block) in txs.iter().zip(&block.txs) {
assert_eq!(
&tx.tx_hash, tx_hash_in_block,
"deserialized tx hash is not the same as the one in the parent block"
);
}
VerifiedBlockInformation {
block_hash: block.hash(),
block,
txs,
pow_hash,
height,
generated_coins,
weight,
long_term_weight,
cumulative_difficulty,
}
}
}
// Same as [`VerifiedBlockMap`] but for [`TransactionVerificationData`].
fn to_tx_verification_data(tx_blob: &[u8]) -> TransactionVerificationData {
let tx_blob = tx_blob.to_vec();
let tx = Transaction::read(&mut tx_blob.as_slice()).unwrap();
TransactionVerificationData {
tx_weight: tx.weight(),
fee: tx.rct_signatures.base.fee,
tx_hash: tx.hash(),
tx_blob,
tx,
}
}
//---------------------------------------------------------------------------------------------------- Blocks
/// Return [`BLOCK_BBD604`] as a [`Block`].
/// Generate a block accessor function with this signature:
/// `fn() -> &'static VerifiedBlockInformation`
///
/// This will use `VerifiedBlockMap` type above to do various
/// checks on the input data and makes sure it seems correct.
///
/// This requires some static block/tx input (from data) and some fields.
/// This data can be accessed more easily via:
/// - A block explorer (https://xmrchain.net)
/// - Monero RPC (see cuprate_test_utils::rpc for this)
///
/// See below for actual usage.
macro_rules! verified_block_information_fn {
(
fn_name: $fn_name:ident, // Name of the function 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
height: $height:literal, // Block height
generated_coins: $generated_coins:literal, // Generated coins in block (`reward`)
weight: $weight:literal, // Block weight
long_term_weight: $long_term_weight:literal, // Block long term weight
cumulative_difficulty: $cumulative_difficulty:literal, // Block cumulative difficulty
tx_len: $tx_len:literal, // Amount of transactions in this block
) => {
#[doc = concat!(
"Return [`",
stringify!($block_blob),
"`] as a [`VerifiedBlockInformation`].",
)]
///
/// Contained transactions:
$(
#[doc = concat!("- [`", stringify!($tx_blob), "`]")]
)*
///
/// ```rust
/// assert_eq!(
/// &cuprate_test_utils::data::block_v1_tx513().serialize(),
/// cuprate_test_utils::data::BLOCK_BBD604
/// );
#[doc = "# use cuprate_test_utils::data::*;"]
#[doc = "# use hex_literal::hex;"]
#[doc = concat!("let block = ", stringify!($fn_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, ");")]
#[doc = concat!("assert_eq!(block.generated_coins, ", $generated_coins, ");")]
#[doc = concat!("assert_eq!(block.weight, ", $weight, ");")]
#[doc = concat!("assert_eq!(block.long_term_weight, ", $long_term_weight, ");")]
#[doc = concat!("assert_eq!(block.cumulative_difficulty, ", $cumulative_difficulty, ");")]
#[doc = concat!("assert_eq!(block.txs.len(), ", $tx_len, ");")]
/// ```
pub fn block_v1_tx513() -> Block {
/// `OnceLock` holding the data.
static BLOCK: OnceLock<Block> = OnceLock::new();
BLOCK
.get_or_init(|| Block::read(&mut BLOCK_BBD604).unwrap())
.clone()
pub fn $fn_name() -> &'static VerifiedBlockInformation {
static BLOCK: OnceLock<VerifiedBlockInformation> = OnceLock::new();
BLOCK.get_or_init(|| {
VerifiedBlockMap {
block: Block::read(&mut $block_blob).unwrap(),
pow_hash: hex!($pow_hash),
height: $height,
generated_coins: $generated_coins,
weight: $weight,
long_term_weight: $long_term_weight,
cumulative_difficulty: $cumulative_difficulty,
txs: vec![$($tx_blob),*],
}
.into_verified()
})
}
};
}
/// Return [`BLOCK_F91043`] as a [`Block`].
///
/// ```rust
/// assert_eq!(
/// &cuprate_test_utils::data::block_v9_tx3().serialize(),
/// cuprate_test_utils::data::BLOCK_F91043
/// );
/// ```
pub fn block_v9_tx3() -> Block {
/// `OnceLock` holding the data.
static BLOCK: OnceLock<Block> = OnceLock::new();
BLOCK
.get_or_init(|| Block::read(&mut BLOCK_F91043).unwrap())
.clone()
verified_block_information_fn! {
fn_name: block_v1_tx2,
block_blob: BLOCK_5ECB7E,
tx_blobs: [TX_2180A8, TX_D7FEBD],
pow_hash: "84f64766475d51837ac9efbef1926486e58563c95a19fef4aec3254f03000000",
height: 202_612,
generated_coins: 13_138_270_468_431,
weight: 55_503,
long_term_weight: 55_503,
cumulative_difficulty: 126_654_460_829_362,
tx_len: 2,
}
/// Return [`BLOCK_43BD1F`] as a [`Block`].
///
/// ```rust
/// assert_eq!(
/// &cuprate_test_utils::data::block_v16_tx0().serialize(),
/// cuprate_test_utils::data::BLOCK_43BD1F
/// );
/// ```
pub fn block_v16_tx0() -> Block {
/// `OnceLock` holding the data.
static BLOCK: OnceLock<Block> = OnceLock::new();
BLOCK
.get_or_init(|| Block::read(&mut BLOCK_43BD1F).unwrap())
.clone()
verified_block_information_fn! {
fn_name: block_v9_tx3,
block_blob: BLOCK_F91043,
tx_blobs: [TX_E2D393, TX_E57440, TX_B6B439],
pow_hash: "7c78b5b67a112a66ea69ea51477492057dba9cfeaa2942ee7372c61800000000",
height: 1_731_606,
generated_coins: 3_403_921_682_163,
weight: 6_597,
long_term_weight: 6_597,
cumulative_difficulty: 23_558_910_234_058_343,
tx_len: 3,
}
verified_block_information_fn! {
fn_name: block_v16_tx0,
block_blob: BLOCK_43BD1F,
tx_blobs: [],
pow_hash: "10b473b5d097d6bfa0656616951840724dfe38c6fb9c4adf8158800300000000",
height: 2_751_506,
generated_coins: 600_000_000_000,
weight: 106,
long_term_weight: 176_470,
cumulative_difficulty: 236_046_001_376_524_168,
tx_len: 0,
}
//---------------------------------------------------------------------------------------------------- Transactions
/// Return [`TX_3BC7FF`] as a [`Transaction`].
/// Generate a transaction accessor function with this signature:
/// `fn() -> &'static TransactionVerificationData`
///
/// Same as [`verified_block_information_fn`] but for transactions.
macro_rules! transaction_verification_data_fn {
(
fn_name: $fn_name:ident, // Name of the function 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
) => {
#[doc = concat!("Return [`", stringify!($tx_blob), "`] as a [`TransactionVerificationData`].")]
///
/// ```rust
/// assert_eq!(
/// &cuprate_test_utils::data::tx_v1_sig0().serialize(),
/// cuprate_test_utils::data::TX_3BC7FF
/// );
#[doc = "# use cuprate_test_utils::data::*;"]
#[doc = "# use hex_literal::hex;"]
#[doc = concat!("let tx = ", stringify!($fn_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, "\"));")]
#[doc = "assert_eq!(tx.fee, tx.tx.rct_signatures.base.fee);"]
/// ```
pub fn tx_v1_sig0() -> Transaction {
/// `OnceLock` holding the data.
static TX: OnceLock<Transaction> = OnceLock::new();
TX.get_or_init(|| Transaction::read(&mut TX_3BC7FF).unwrap())
.clone()
pub fn $fn_name() -> &'static TransactionVerificationData {
static TX: OnceLock<TransactionVerificationData> = OnceLock::new();
TX.get_or_init(|| to_tx_verification_data($tx_blob))
}
};
}
/// Return [`TX_9E3F73`] as a [`Transaction`].
///
/// ```rust
/// assert_eq!(
/// &cuprate_test_utils::data::tx_v1_sig2().serialize(),
/// cuprate_test_utils::data::TX_9E3F73
/// );
/// ```
pub fn tx_v1_sig2() -> Transaction {
/// `OnceLock` holding the data.
static TX: OnceLock<Transaction> = OnceLock::new();
TX.get_or_init(|| Transaction::read(&mut TX_9E3F73).unwrap())
.clone()
transaction_verification_data_fn! {
fn_name: tx_v1_sig0,
tx_blobs: TX_3BC7FF,
weight: 248,
hash: "3bc7ff015b227e7313cc2e8668bfbb3f3acbee274a9c201d6211cf681b5f6bb1",
}
/// Return [`TX_84D48D`] as a [`Transaction`].
///
/// ```rust
/// assert_eq!(
/// &cuprate_test_utils::data::tx_v2_rct3().serialize(),
/// cuprate_test_utils::data::TX_84D48D
/// );
/// ```
pub fn tx_v2_rct3() -> Transaction {
/// `OnceLock` holding the data.
static TX: OnceLock<Transaction> = OnceLock::new();
TX.get_or_init(|| Transaction::read(&mut TX_84D48D).unwrap())
.clone()
transaction_verification_data_fn! {
fn_name: tx_v1_sig2,
tx_blobs: TX_9E3F73,
weight: 448,
hash: "9e3f73e66d7c7293af59c59c1ff5d6aae047289f49e5884c66caaf4aea49fb34",
}
transaction_verification_data_fn! {
fn_name: tx_v2_rct3,
tx_blobs: TX_84D48D,
weight: 2743,
hash: "84d48dc11ec91950f8b70a85af9db91fe0c8abef71ef5db08304f7344b99ea66",
}

View file

@ -1,9 +1,35 @@
//! Testing data and utilities.
//! Real Monero data.
//!
//! Raw data is found in `data/`.
//! This module provides access to _real_ Monero data,
//! either in raw bytes or typed.
//!
//! ## Constants
//! The `const`ants provide byte slices representing block
//! and transaction blobs that can be directly deserialized:
//!
//! ```rust
//! # use cuprate_test_utils::data::*;
//! use monero_serai::{block::Block, transaction::Transaction};
//!
//! let block: Block = Block::read(&mut BLOCK_43BD1F).unwrap();
//! let tx: Transaction = Transaction::read(&mut TX_E57440).unwrap();
//! ```
//!
//! ## Functions
//! The free functions provide access to typed data found in `cuprate_types`:
//! ```rust
//! # use cuprate_test_utils::data::*;
//! use cuprate_types::{VerifiedBlockInformation, TransactionVerificationData};
//!
//! let block: VerifiedBlockInformation = block_v16_tx0().clone();
//! let tx: TransactionVerificationData = tx_v1_sig0().clone();
//! ```
mod constants;
pub use constants::{BLOCK_43BD1F, BLOCK_BBD604, BLOCK_F91043, TX_3BC7FF, TX_84D48D, TX_9E3F73};
pub use constants::{
BLOCK_43BD1F, BLOCK_5ECB7E, BLOCK_BBD604, BLOCK_F91043, TX_2180A8, TX_3BC7FF, TX_84D48D,
TX_9E3F73, TX_B6B439, TX_D7FEBD, TX_E2D393, TX_E57440,
};
mod free;
pub use free::{block_v16_tx0, block_v1_tx513, block_v9_tx3, tx_v1_sig0, tx_v1_sig2, tx_v2_rct3};
pub use free::{block_v16_tx0, block_v1_tx2, block_v9_tx3, tx_v1_sig0, tx_v1_sig2, tx_v2_rct3};

View file

@ -1,6 +1,4 @@
//! Cuprate testing utilities.
//!
//! See the `README.md` for more info.
#![doc = include_str!("../README.md")]
pub mod data;
pub mod monerod;