From 99c869bb503359ccbfdaec51ad20d4369b4eba11 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Fri, 18 Apr 2025 04:07:18 +0700 Subject: [PATCH 1/2] exp tests --- Cargo.lock | 41 ++ .../distribution_function/evaluate.rs | 109 ++-- .../distribution_function/mod.rs | 21 +- .../distribution_function/validation.rs | 236 +++++++- packages/rs-drive-abci/Cargo.toml | 1 + .../distribution/perpetual/block_based.rs | 532 ++++++++++-------- .../distribution/perpetual/time_based.rs | 10 +- packages/rs-drive-abci/src/logging/logger.rs | 24 +- packages/rs-drive-abci/src/logging/mod.rs | 4 +- 9 files changed, 662 insertions(+), 316 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc5ee9e0bfd..1bf29211de1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1649,6 +1649,7 @@ dependencies = [ "rust_decimal_macros", "serde", "serde_json", + "serial_test", "simple-signer", "strategy-tests", "tempfile", @@ -4360,6 +4361,15 @@ dependencies = [ "regex", ] +[[package]] +name = "scc" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea091f6cac2595aa38993f04f4ee692ed43757035c36e67c180b6828356385b1" +dependencies = [ + "sdd", +] + [[package]] name = "schannel" version = "0.1.23" @@ -4375,6 +4385,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sdd" +version = "3.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "584e070911c7017da6cb2eb0788d09f43d789029b5877d3e5ecc8acf86ceee21" + [[package]] name = "seahash" version = "4.1.0" @@ -4616,6 +4632,31 @@ dependencies = [ "serde", ] +[[package]] +name = "serial_test" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9" +dependencies = [ + "futures", + "log", + "once_cell", + "parking_lot", + "scc", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "sha1" version = "0.10.6" diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate.rs b/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate.rs index 3478e904543..78a2dde2c73 100644 --- a/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate.rs +++ b/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate.rs @@ -1,6 +1,7 @@ use crate::balances::credits::TokenAmount; use crate::data_contract::associated_token::token_perpetual_distribution::distribution_function::{ DistributionFunction, DEFAULT_STEP_DECREASING_AMOUNT_MAX_CYCLES_BEFORE_TRAILING_DISTRIBUTION, + MAX_DISTRIBUTION_PARAM, }; use crate::ProtocolError; @@ -204,10 +205,12 @@ impl DistributionFunction { let exponent = (*m as f64) / (*n as f64); let diff = x as i128 - s_val as i128 + *o as i128; - if diff < 0 { - return Err(ProtocolError::Overflow( - "Polynomial function: argument is non-positive", - )); + if diff <= 0 { + return if let Some(min_value) = min_value { + Ok(*min_value) + } else { + Ok(0) + }; } if diff > u64::MAX as i128 { @@ -218,19 +221,50 @@ impl DistributionFunction { let diff_exp = (diff as f64).powf(exponent); - if !diff_exp.is_finite() || diff_exp.abs() > (u64::MAX as f64) { - return Err(ProtocolError::Overflow( - "Polynomial function evaluation overflow or negative", - )); + if !diff_exp.is_finite() { + return if diff_exp.is_sign_positive() { + if let Some(max_value) = max_value { + Ok(*max_value) + } else { + Ok(MAX_DISTRIBUTION_PARAM) + } + } else if let Some(min_value) = min_value { + Ok(*min_value) + } else { + Ok(0) + }; } let pol = diff_exp as i128; - let value = (((*a as i128) * pol / (*d as i128)) as i64) - .checked_add(*b as i64) - .ok_or(ProtocolError::Overflow( - "Polynomial function evaluation overflow or negative", - ))?; + let intermediate = if *d == 1 { + (*a as i128).saturating_mul(pol) + } else { + ((*a as i128).saturating_mul(pol)) / *d as i128 + }; + + if intermediate > MAX_DISTRIBUTION_PARAM as i128 + || intermediate < -(MAX_DISTRIBUTION_PARAM as i128) + { + return if intermediate > 0 { + if let Some(max_value) = max_value { + Ok(*max_value) + } else { + Ok(MAX_DISTRIBUTION_PARAM) + } + } else if let Some(min_value) = min_value { + Ok(*min_value) + } else { + Ok(0) + }; + } + + let value = + (intermediate as i64) + .checked_add(*b as i64) + .ok_or(ProtocolError::Overflow( + "Polynomial function evaluation overflow", + ))?; let value = if value < 0 { 0 } else { value as u64 }; @@ -244,7 +278,12 @@ impl DistributionFunction { return Ok(*max_value); } } - Ok(value) + + if value > MAX_DISTRIBUTION_PARAM { + Ok(MAX_DISTRIBUTION_PARAM) + } else { + Ok(value) + } } DistributionFunction::Exponential { @@ -752,6 +791,7 @@ mod tests { } } mod polynomial { + use crate::data_contract::associated_token::token_perpetual_distribution::distribution_function::{MAX_POL_A_PARAM, MAX_POL_M_PARAM}; use super::*; #[test] fn test_polynomial_function() { @@ -767,18 +807,18 @@ mod tests { max_value: None, }; - assert_eq!(distribution.evaluate(0, 0).unwrap(), 10); + assert_eq!(distribution.evaluate(0, 0).unwrap(), 0); assert_eq!(distribution.evaluate(0, 2).unwrap(), 18); assert_eq!(distribution.evaluate(0, 3).unwrap(), 28); assert_eq!(distribution.evaluate(0, 4).unwrap(), 42); } #[test] - fn test_polynomial_function_overflow() { + fn test_polynomial_function_should_not_overflow() { let distribution = DistributionFunction::Polynomial { - a: i64::MAX, + a: MAX_POL_A_PARAM, d: 1, - m: 2, + m: MAX_POL_M_PARAM, n: 1, o: 0, start_moment: Some(0), @@ -787,12 +827,8 @@ mod tests { max_value: None, }; - let result = distribution.evaluate(0, 1); - assert!( - matches!(result, Err(ProtocolError::Overflow(_))), - "Expected overflow but got {:?}", - result - ); + let result = distribution.evaluate(0, 100000).expect("expected value"); + assert_eq!(result, MAX_DISTRIBUTION_PARAM); } // Test: Fractional exponent (exponent = 3/2) @@ -845,9 +881,8 @@ mod tests { min_value: None, max_value: None, }; - // f(x) = 2 * ((x - 2)^2) + 10. - // At x = 2: (0)^2 = 0, f(2) = 10. - assert_eq!(distribution.evaluate(0, 2).unwrap(), 10); + // since it starts at 2 (that's like the contract registration at 2, so we should get 0 + assert_eq!(distribution.evaluate(0, 2).unwrap(), 0); // At x = 3: (3 - 2)^2 = 1, f(3) = 2*1 + 10 = 12. assert_eq!(distribution.evaluate(0, 3).unwrap(), 12); } @@ -871,26 +906,6 @@ mod tests { assert_eq!(distribution.evaluate(0, 1).unwrap(), 42); } - // Test: Constant function when m = 0 (should ignore x) - #[test] - fn test_polynomial_function_constant() { - let distribution = DistributionFunction::Polynomial { - a: 5, - d: 1, - m: 0, // exponent 0 => (x-s+o)^0 = 1 (for any x where x-s+o ≠ 0) - n: 1, - o: 0, - start_moment: Some(0), - b: 3, - min_value: None, - max_value: None, - }; - // f(x) = 5*1 + 3 = 8 for any x. - for x in [0, 10, 100].iter() { - assert_eq!(distribution.evaluate(0, *x).unwrap(), 8); - } - } - // Test: Linear function when exponent is 1 (m = 1, n = 1) #[test] fn test_polynomial_function_linear() { diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/mod.rs index e2e70b3b345..3ea95c7db8b 100644 --- a/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/mod.rs +++ b/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/mod.rs @@ -10,7 +10,6 @@ pub mod reward_ratio; mod validation; pub const MAX_DISTRIBUTION_PARAM: u64 = 281_474_976_710_655; //u48::Max 2^48 - 1 - /// The max cycles param is the upper limit of cycles the system can ever support /// This is applied to linear distribution. /// For all other distributions we use a versioned max cycles contained in the platform version. @@ -20,12 +19,28 @@ pub const MAX_DISTRIBUTION_CYCLES_PARAM: u64 = 32_767; //u15::Max 2^(63 - 48) - pub const DEFAULT_STEP_DECREASING_AMOUNT_MAX_CYCLES_BEFORE_TRAILING_DISTRIBUTION: u16 = 128; -pub const MAX_LINEAR_SLOPE_PARAM: u64 = 256; +pub const MAX_LINEAR_SLOPE_A_PARAM: u64 = 256; + +pub const MIN_LINEAR_SLOPE_A_PARAM: i64 = -255; + +pub const MIN_POL_M_PARAM: i64 = -8; +pub const MAX_POL_M_PARAM: i64 = 8; + +pub const MAX_POL_N_PARAM: u64 = 32; pub const MIN_LOG_A_PARAM: i64 = -32_766; pub const MAX_LOG_A_PARAM: i64 = 32_767; pub const MAX_EXP_A_PARAM: u64 = 256; +pub const MAX_EXP_M_PARAM: u64 = 8; + +pub const MIN_EXP_M_PARAM: i64 = -8; + +pub const MAX_EXP_N_PARAM: u64 = 32; + +pub const MIN_POL_A_PARAM: i64 = -255; +pub const MAX_POL_A_PARAM: i64 = 256; + #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd)] pub enum DistributionFunction { /// Emits a constant (fixed) number of tokens for every period. @@ -136,6 +151,8 @@ pub enum DistributionFunction { /// - Within each step, the emission remains constant. /// - The keys in the `BTreeMap` represent the starting period for each interval, /// and the corresponding values are the fixed token amounts to emit during that interval. + /// - VERY IMPORTANT: the steps are the amount of intervals, not the time or the block count. + /// So if you have step 5 with interval 10 using blocks that's 50 blocks. /// /// # Use Case /// - Adjusting rewards at specific milestones or time intervals. diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/validation.rs b/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/validation.rs index ae87ad0c97e..e7c8ab06b24 100644 --- a/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/validation.rs +++ b/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/validation.rs @@ -5,8 +5,9 @@ use crate::consensus::basic::data_contract::{ InvalidTokenDistributionFunctionInvalidParameterTupleError, }; use crate::data_contract::associated_token::token_perpetual_distribution::distribution_function::{ - DistributionFunction, MAX_DISTRIBUTION_PARAM, MAX_EXP_A_PARAM, MAX_LINEAR_SLOPE_PARAM, - MAX_LOG_A_PARAM, MIN_LOG_A_PARAM, + DistributionFunction, MAX_DISTRIBUTION_PARAM, MAX_EXP_A_PARAM, MAX_EXP_M_PARAM, + MAX_EXP_N_PARAM, MAX_LINEAR_SLOPE_A_PARAM, MAX_LOG_A_PARAM, MAX_POL_M_PARAM, MAX_POL_N_PARAM, + MIN_EXP_M_PARAM, MIN_LINEAR_SLOPE_A_PARAM, MIN_LOG_A_PARAM, MIN_POL_M_PARAM, }; use crate::validation::SimpleConsensusValidationResult; use crate::ProtocolError; @@ -184,7 +185,7 @@ impl DistributionFunction { a, d, start_step: s, - starting_amount: b, + starting_amount, min_value, max_value, } => { @@ -193,30 +194,19 @@ impl DistributionFunction { InvalidTokenDistributionFunctionDivideByZeroError::new(self.clone()).into(), )); } - if *a == 0 { + if *a == 0 || *a > MAX_LINEAR_SLOPE_A_PARAM as i64 || *a < MIN_LINEAR_SLOPE_A_PARAM + { return Ok(SimpleConsensusValidationResult::new_with_error( InvalidTokenDistributionFunctionInvalidParameterError::new( "a".to_string(), - -(MAX_DISTRIBUTION_PARAM as i64), - MAX_DISTRIBUTION_PARAM as i64, + MIN_LINEAR_SLOPE_A_PARAM, + MAX_LINEAR_SLOPE_A_PARAM as i64, Some(0), ) .into(), )); } - if *a > MAX_LINEAR_SLOPE_PARAM as i64 || *a < -(MAX_LINEAR_SLOPE_PARAM as i64) { - return Ok(SimpleConsensusValidationResult::new_with_error( - InvalidTokenDistributionFunctionInvalidParameterError::new( - "a".to_string(), - -(MAX_LINEAR_SLOPE_PARAM as i64), - MAX_LINEAR_SLOPE_PARAM as i64, - None, - ) - .into(), - )); - } - if let (Some(min), Some(max)) = (min_value, max_value) { if min > max { return Ok(SimpleConsensusValidationResult::new_with_error( @@ -262,7 +252,7 @@ impl DistributionFunction { a: *a, d: *d, start_step: Some(s.unwrap_or(start_moment)), - starting_amount: *b, + starting_amount: *starting_amount, min_value: *min_value, max_value: *max_value, } @@ -321,6 +311,53 @@ impl DistributionFunction { )); } + if *m > 0 && *n == m.unsigned_abs() { + return Ok(SimpleConsensusValidationResult::new_with_error( + InvalidTokenDistributionFunctionInvalidParameterTupleError::new( + "m".to_string(), + "n".to_string(), + "different than".to_string(), + ) + .into(), + )); + } + + if *a == 0 || *a < MIN_LOG_A_PARAM || *a > MAX_LOG_A_PARAM { + return Ok(SimpleConsensusValidationResult::new_with_error( + InvalidTokenDistributionFunctionInvalidParameterError::new( + "a".to_string(), + MIN_LOG_A_PARAM, + MAX_LOG_A_PARAM, + Some(0), + ) + .into(), + )); + } + + if *m == 0 || *m < MIN_POL_M_PARAM || *m > MAX_POL_M_PARAM { + return Ok(SimpleConsensusValidationResult::new_with_error( + InvalidTokenDistributionFunctionInvalidParameterError::new( + "m".to_string(), + MIN_POL_M_PARAM, + MAX_POL_M_PARAM, + Some(0), + ) + .into(), + )); + } + + if *n > MAX_POL_N_PARAM { + return Ok(SimpleConsensusValidationResult::new_with_error( + InvalidTokenDistributionFunctionInvalidParameterError::new( + "n".to_string(), + 1, + MAX_POL_N_PARAM as i64, + None, + ) + .into(), + )); + } + if let Some(s) = s { if *s > MAX_DISTRIBUTION_PARAM { return Ok(SimpleConsensusValidationResult::new_with_error( @@ -450,12 +487,23 @@ impl DistributionFunction { InvalidTokenDistributionFunctionDivideByZeroError::new(self.clone()).into(), )); } - if *m == 0 { + if *n > MAX_EXP_N_PARAM { + return Ok(SimpleConsensusValidationResult::new_with_error( + InvalidTokenDistributionFunctionInvalidParameterError::new( + "n".to_string(), + 1, + MAX_EXP_N_PARAM as i64, + None, + ) + .into(), + )); + } + if *m == 0 || *m > MAX_EXP_M_PARAM as i64 || *m < MIN_EXP_M_PARAM { return Ok(SimpleConsensusValidationResult::new_with_error( InvalidTokenDistributionFunctionInvalidParameterError::new( "m".to_string(), - -(MAX_DISTRIBUTION_PARAM as i64), - MAX_DISTRIBUTION_PARAM as i64, + MIN_EXP_M_PARAM, + MAX_EXP_M_PARAM as i64, Some(0), ) .into(), @@ -1390,6 +1438,30 @@ mod tests { } } } + + #[test] + fn test_polynomial_invalid_zero_a() { + let dist = DistributionFunction::Polynomial { + a: 0, + d: 1, + m: 2, + n: 3, + o: 0, + start_moment: Some(0), + b: 5, + min_value: Some(1), + max_value: Some(50), + }; + let result = dist.validate(START_MOMENT); + assert!( + result + .expect("no error on test_exponential_invalid_zero_a") + .first_error() + .is_some(), + "Expected error: a cannot be zero" + ); + } + #[test] fn test_polynomial_invalid_divide_by_zero() { let dist = DistributionFunction::Polynomial { @@ -1494,6 +1566,126 @@ mod tests { ); } + #[test] + fn test_polynomial_invalid_a_below_min() { + let dist = DistributionFunction::Polynomial { + a: MIN_LOG_A_PARAM - 1, + d: 1, + m: 2, + n: 3, + o: 0, + start_moment: Some(0), + b: 5, + min_value: Some(1), + max_value: Some(50), + }; + let result = dist.validate(START_MOMENT); + assert!( + result.expect("expected result").first_error().is_some(), + "Expected error: a is below minimum" + ); + } + + #[test] + fn test_polynomial_invalid_m_equal_n() { + let dist = DistributionFunction::Polynomial { + a: 1, + d: 1, + m: 3, + n: 3, + o: 0, + start_moment: Some(0), + b: 5, + min_value: None, + max_value: None, + }; + let result = dist.validate(START_MOMENT); + assert!( + result.expect("expected result").first_error().is_some(), + "Expected error: a is below minimum" + ); + } + + #[test] + fn test_polynomial_invalid_a_above_max() { + let dist = DistributionFunction::Polynomial { + a: MAX_LOG_A_PARAM + 1, + d: 1, + m: 2, + n: 3, + o: 0, + start_moment: Some(0), + b: 5, + min_value: Some(1), + max_value: Some(50), + }; + let result = dist.validate(START_MOMENT); + assert!( + result.expect("expected result").first_error().is_some(), + "Expected error: a is above maximum" + ); + } + + #[test] + fn test_polynomial_invalid_m_below_min() { + let dist = DistributionFunction::Polynomial { + a: 2, + d: 1, + m: MIN_POL_M_PARAM - 1, + n: 3, + o: 0, + start_moment: Some(0), + b: 5, + min_value: Some(1), + max_value: Some(50), + }; + let result = dist.validate(START_MOMENT); + assert!( + result.expect("expected result").first_error().is_some(), + "Expected error: m is below minimum" + ); + } + + #[test] + fn test_polynomial_invalid_m_above_max() { + let dist = DistributionFunction::Polynomial { + a: 2, + d: 1, + m: MAX_POL_M_PARAM + 1, + n: 3, + o: 0, + start_moment: Some(0), + b: 5, + min_value: Some(1), + max_value: Some(50), + }; + let result = dist.validate(START_MOMENT); + assert!( + result.expect("expected result").first_error().is_some(), + "Expected error: m is above maximum" + ); + } + + #[test] + fn test_polynomial_invalid_n_above_max() { + let dist = DistributionFunction::Polynomial { + a: 2, + d: 1, + m: 3, + n: MAX_POL_N_PARAM + 1, + o: 0, + start_moment: Some(0), + b: 5, + min_value: Some(1), + max_value: Some(50), + }; + let result = dist.validate(START_MOMENT); + assert!( + result.expect("expected result").first_error().is_some(), + "Expected error: n is above maximum" + ); + } + // 5. Test invalid: max_value exceeds MAX_DISTRIBUTION_PARAM. #[test] fn test_polynomial_invalid_max_exceeds_max_distribution() { diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index 49ea54b19d4..25d9f9f38a8 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -106,6 +106,7 @@ mockall = { version = "0.13" } # For tests of grovedb verify rocksdb = { version = "0.23.0" } integer-encoding = { version = "4.0.0" } +serial_test = { version = "3.2.0" } [features] default = [] diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/distribution/perpetual/block_based.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/distribution/perpetual/block_based.rs index 75c6a982b86..1afa1394231 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/distribution/perpetual/block_based.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/distribution/perpetual/block_based.rs @@ -1091,10 +1091,10 @@ mod step_decreasing { #[test] fn claim_every_block_on_100k_128_default_steps() { - let steps = (1..200).step_by(1).collect::>(); + let steps = (1..140).step_by(1).collect::>(); let start_steps = (1..129).step_by(1).collect::>(); let start_steps_expected_amounts = sum_till_for_100k_step_1_interval_1(start_steps.clone()); - let later_steps = (129..200).step_by(1).collect::>(); + let later_steps = (129..140).step_by(1).collect::>(); let later_steps_expected_amounts = later_steps .iter() .map(|_| *start_steps_expected_amounts.last().unwrap()) @@ -1520,11 +1520,11 @@ mod stepwise { use std::collections::BTreeMap; #[test] - fn fails_stepwise_correct() { + fn distribution_stepwise_correct() { let distribution_interval = 10; let periods = BTreeMap::from([ - (0, 10_000), // h 1-30 - (2, 20_000), // h 31+ + (0, 10_000), // h 1-20 + (2, 20_000), // h 20+ (45, 30_000), (50, 40_000), (70, 50_000), @@ -1539,19 +1539,18 @@ mod stepwise { (10, 110_000, true), (11, 110_000, false), (19, 110_000, false), - (20, 120_000, true), - (21, 120_000, false), - (24, 120_000, false), - (35, 140_000, true), // since 20, we should get one more distribution of 20k at height 30 - (39, 140_000, false), - (46, 160_000, true), - (49, 160_000, false), - (51, 180_000, true), - (52, 180_000, false), - (70, 270_000, true), + (20, 130_000, true), + (21, 130_000, false), + (24, 130_000, false), + (35, 150_000, true), + (39, 150_000, false), + (46, 170_000, true), + (49, 170_000, false), + (51, 190_000, true), + (200, 490_000, true), + (300, 690_000, true), ( - 1_000_000, - 270_000 + 50_000 * (1_000_000 - 70_000) / distribution_interval, + 1_000_000, 6_370_000, // because we only do 128 steps at a time. true, ), ]; @@ -1572,29 +1571,12 @@ mod stepwise { mod linear { use super::test_suite::check_heights; - use dpp::data_contract::associated_token::token_perpetual_distribution::distribution_function::DistributionFunction; + use dpp::data_contract::associated_token::token_perpetual_distribution::distribution_function::{DistributionFunction, MAX_LINEAR_SLOPE_A_PARAM, MIN_LINEAR_SLOPE_A_PARAM}; - /// Given linear distribution with d=0, - /// When I create a token, - /// Then I get an error. - #[test] - fn fails_divide_by_0() -> Result<(), String> { - test_linear( - 1, // a - 0, // d - None, // start_step - 100_000, // starting_amount - None, // min_value - None, // max_value - &[(10, 100_000, false)], // heights - 1, // distribution_interval - ) - } - /// Given linear distribution with d=MAX and starting amount of 1, - /// When I claim tokens, - /// Then I have only one success, and subsequent claims fail because the calculated distribution is lower than 1 #[test] - fn divide_my_max() -> Result<(), String> { + fn linear_distribution_divide_by_max() -> Result<(), String> { + // Given linear distribution with d=MAX and starting amount of 1, + // We expect no claim rewards test_linear( 1, // a u64::MAX, // d @@ -1608,21 +1590,7 @@ mod linear { } #[test] - fn min_eq_max() -> Result<(), String> { - test_linear( - 1, - 1, - None, - 0, - Some(10), - Some(10), - &[(1, 100_010, true), (2, 100_020, true)], - 1, - ) - } - - #[test] - fn fx_eq_x_matrix() -> Result<(), String> { + fn linear_distribution_x_matrix() -> Result<(), String> { let steps = [ (1, 100_001, true), (2, 100_003, true), @@ -1640,35 +1608,20 @@ mod linear { Ok(()) } #[test] - fn negative_a() -> Result<(), String> { - for a in [-1, -100_000, i64::MIN] { - test_linear( - a, - 1, - None, - 0, - None, - None, - &[(1, 100_000, false), (20, 100_000, false)], - 1, - )?; - } - Ok(()) - } - - #[test] - fn fails_max_lt_min() -> Result<(), String> { - for max in [0, 99] { - test_linear( - 1, - 1, - None, - 0, - Some(100), - Some(max), - &[(1, 100_000, false), (20, 100_000, false)], - 1, - )?; + fn linear_distribution_slopes() -> Result<(), String> { + for (a, steps) in [ + (-1, [(1, 100_000, false), (20, 100_000, false)]), + (1, [(1, 100_001, true), (20, 100_210, true)]), + ( + MIN_LINEAR_SLOPE_A_PARAM, + [(1, 100_000, false), (20, 100_000, false)], + ), + ( + MAX_LINEAR_SLOPE_A_PARAM as i64, + [(1, 100_256, true), (20, 153_760, true)], + ), + ] { + test_linear(a, 1, None, 0, None, None, &steps, 1)?; } Ok(()) } @@ -1715,7 +1668,8 @@ mod linear { } } -mod polynomial { +#[cfg(test)] +mod exponential { use super::test_suite::{check_heights, TestStep, TestSuite}; use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult; use dpp::data_contract::{ @@ -1724,7 +1678,7 @@ mod polynomial { token_distribution_key::TokenDistributionType, token_distribution_rules::accessors::v0::TokenDistributionRulesV0Setters, token_perpetual_distribution::{ - distribution_function::DistributionFunction::{self, Polynomial}, + distribution_function::DistributionFunction::{self, Exponential}, distribution_recipient::TokenDistributionRecipient, reward_distribution_type::RewardDistributionType, v0::TokenPerpetualDistributionV0, @@ -1733,114 +1687,209 @@ mod polynomial { }, TokenConfiguration, }; + use dpp::data_contract::associated_token::token_perpetual_distribution::distribution_function::{MAX_DISTRIBUTION_PARAM, MAX_EXP_A_PARAM, MAX_EXP_M_PARAM, MAX_EXP_N_PARAM, MIN_EXP_M_PARAM}; + + // ───────────────────────────────────────────────────────────────────────── + // helper – one‑liner wrapper around `check_heights` (same as polynomial) + // ───────────────────────────────────────────────────────────────────────── + fn test_exponential( + dist: DistributionFunction, + steps: &[(u64, u64, bool)], // (height, expected balance, expect‑pass) + distribution_interval: u64, + ) -> Result<(), String> { + check_heights(dist, steps, None, distribution_interval, None) + .inspect_err(|e| tracing::error!("{e}")) + } + // ───────────────────────────────────────────────────────────────────────── + // 1. Basic positive‑growth example (m > 0) + // ───────────────────────────────────────────────────────────────────────── #[test] - fn ones() -> Result<(), String> { - test_polynomial( - Polynomial { + fn exponential_distribution_growth_basic() -> Result<(), String> { + test_exponential( + Exponential { a: 1, d: 1, - m: 1, + m: 1, // positive ⇒ growth n: 1, - o: 1, + o: 0, start_moment: Some(1), - b: 100_000, + b: 0, min_value: None, - max_value: None, + max_value: Some(1_000_000), }, - &[(10, 1_100_055, true), (20, 2_100_210, true)], + // heights 10 and 20 should both succeed – balances are illustrative + &[(10, 112_814, true), (20, 6_799_881, true)], 1, ) } - /// Divide by 0 - /// claim at height 10: claim failed: assertion 1 failed: expected SuccessfulExecution, got - /// [InternalError(\"storage: protocol: divide by zero error: Polynomial function: divisor d is 0\")]\n expected balance Some(1100055) but got 100000\n\n--> + // ───────────────────────────────────────────────────────────────────────── + // 2. Basic negative‑decay example (m < 0) + // ───────────────────────────────────────────────────────────────────────── #[test] - fn fails_divide_by_0() -> Result<(), String> { - test_polynomial( - Polynomial { - a: 1, - d: 0, - m: 1, + fn exponential_distribution_decay_basic() -> Result<(), String> { + test_exponential( + Exponential { + a: 5, + d: 1, + m: -1, // negative ⇒ decay n: 1, - o: 1, + o: 0, start_moment: Some(1), b: 100_000, - min_value: None, + min_value: Some(50_000), max_value: None, }, - &[(10, 1_100_055, true), (20, 2_100_210, true)], + &[(1, 200_005, true), (4, 500_006, true)], 1, ) } - /// Given max_value < min_value, - /// When I try to use the token distribution function, - /// Then the token distribution function validation fails. + // ───────────────────────────────────────────────────────────────────────── + // 3. o at −MAX_DISTRIBUTION_PARAM ⇒ argument very negative ▶ min / 0 + // ───────────────────────────────────────────────────────────────────────── #[test] - fn fails_max_lt_min_should_fail() -> Result<(), String> { - test_polynomial( - Polynomial { + fn exponential_distribution_o_min() -> Result<(), String> { + test_exponential( + Exponential { a: 1, d: 1, m: 1, n: 1, - o: 1, + o: -(MAX_DISTRIBUTION_PARAM as i64), start_moment: Some(1), - b: 100_000, - min_value: Some(100_000), - max_value: Some(10_000), + b: 0, + min_value: None, + max_value: Some(MAX_DISTRIBUTION_PARAM), }, - &[(10, 100_000, false), (20, 100_000, false)], + &[(1, 100_000, false), (4, 100_000, false)], 1, ) } + // ───────────────────────────────────────────────────────────────────────── + // 4. o at +MAX_DISTRIBUTION_PARAM (huge positive shift) + // ───────────────────────────────────────────────────────────────────────── #[test] - fn negative_a() -> Result<(), String> { - test_polynomial( - Polynomial { - a: -1, + fn exponential_distribution_o_max() -> Result<(), String> { + test_exponential( + Exponential { + a: MAX_EXP_A_PARAM, d: 1, - m: 1, - n: 1, - o: 1, + m: -1, + n: 32, + o: MAX_DISTRIBUTION_PARAM as i64, start_moment: Some(1), - b: 100_000, + b: 10, min_value: None, - max_value: None, + max_value: Some(MAX_DISTRIBUTION_PARAM), }, - &[(1, 199_999, true), (4, 499_990, true)], + &[(1, 100010, true), (10, 100100, true)], 1, ) } + // ───────────────────────────────────────────────────────────────────────── + // 5. Exhaustive combination of extreme parameter values + // ‑ ensure no `InternalError` + // ───────────────────────────────────────────────────────────────────────── #[test] - fn fails_a_min() -> Result<(), String> { - test_polynomial( - Polynomial { - a: i64::MIN, - d: 1, - m: 1, - n: 1, - o: 1, - start_moment: Some(1), - b: 100_000, - min_value: None, - max_value: None, - }, - &[(1, 100_000, false), (4, 100_000, true)], - 1, - ) + fn exponential_distribution_extreme_values() -> Result<(), String> { + for m in [MIN_EXP_M_PARAM, -1, 1, MAX_EXP_M_PARAM as i64] { + for n in [1, MAX_EXP_N_PARAM] { + for a in [1, MAX_EXP_A_PARAM] { + let dist = Exponential { + a, + d: 1, + m, + n, + o: 0, + start_moment: Some(1), + b: 0, + min_value: None, + max_value: Some(MAX_DISTRIBUTION_PARAM), + }; + + let mut suite = TestSuite::new( + 10_200_000_000, // initial balance + 0, // owner balance + TokenDistributionType::Perpetual, + Some(move |cfg: &mut TokenConfiguration| { + cfg.distribution_rules_mut() + .set_perpetual_distribution(Some(TokenPerpetualDistribution::V0( + TokenPerpetualDistributionV0 { + distribution_type: + RewardDistributionType::BlockBasedDistribution { + interval: 1, + function: dist, + }, + distribution_recipient: + TokenDistributionRecipient::ContractOwner, + }, + ))); + }), + ); + + suite = suite.with_contract_start_time(1); + + let step = TestStep { + base_height: 10, + base_time_ms: Default::default(), + expected_balance: None, + claim_transition_assertions: vec![ + |results: &[StateTransitionExecutionResult]| -> Result<(), String> { + let err = results + .iter() + .find(|r| format!("{:?}", r).contains("InternalError")); + + if let Some(e) = err { + Err(format!("InternalError: {:?}", e)) + } else { + Ok(()) + } + }, + ], + name: "extreme".into(), + }; + + suite + .execute(&[step]) + .map_err(|e| format!("failed with a {a} m {m} n {n}: {e}"))?; + } + } + } + Ok(()) } +} + +mod polynomial { + use super::test_suite::{check_heights, TestStep, TestSuite}; + use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult; + use dpp::data_contract::{ + associated_token::{ + token_configuration::accessors::v0::TokenConfigurationV0Getters, + token_distribution_key::TokenDistributionType, + token_distribution_rules::accessors::v0::TokenDistributionRulesV0Setters, + token_perpetual_distribution::{ + distribution_function::DistributionFunction::{self, Polynomial}, + distribution_recipient::TokenDistributionRecipient, + reward_distribution_type::RewardDistributionType, + v0::TokenPerpetualDistributionV0, + TokenPerpetualDistribution, + }, + }, + TokenConfiguration, + }; + use dpp::data_contract::associated_token::token_perpetual_distribution::distribution_function::{MAX_DISTRIBUTION_PARAM, MAX_POL_A_PARAM, MAX_POL_M_PARAM, MAX_POL_N_PARAM, MIN_POL_A_PARAM, MIN_POL_M_PARAM}; + #[test] - fn a_minus_1_b_0() -> Result<(), String> { + fn polynomial_distribution_basic() -> Result<(), String> { test_polynomial( Polynomial { - a: -1, + a: 1, d: 1, - m: 1, + m: 2, n: 1, o: 1, start_moment: Some(1), @@ -1848,42 +1897,39 @@ mod polynomial { min_value: None, max_value: None, }, - &[(1, 100_000, false), (4, 100_000, false)], + &[(10, 100_385, true), (20, 102_870, true)], 1, ) } - /// Given a polynomial distribution function with o=i64::MIN, - /// When I try to use the token distribution function, - /// Then the token distribution function validation fails on creation. #[test] - fn fails_o_min() -> Result<(), String> { + fn polynomial_distribution_negative_a() -> Result<(), String> { test_polynomial( Polynomial { - a: 1, + a: -1, d: 1, - m: 1, + m: 3, n: 1, - o: i64::MIN, + o: 1, start_moment: Some(1), - b: 0, + b: 100_000, min_value: None, max_value: None, }, - &[(1, 100_000, false), (4, 100_000, false)], + &[(1, 199_999, true), (4, 499_900, true)], 1, ) } #[test] - fn o_max() -> Result<(), String> { + fn polynomial_distribution_a_minus_1_b_0() -> Result<(), String> { test_polynomial( Polynomial { - a: 1, + a: -1, d: 1, - m: 1, + m: 2, n: 1, - o: i64::MAX, + o: 1, start_moment: Some(1), b: 0, min_value: None, @@ -1894,29 +1940,29 @@ mod polynomial { ) } + /// Given a polynomial distribution function with o=-MAX_DISTRIBUTION_PARAM, we should + /// have no rewards #[test] - #[should_panic(expected = "invalid distribution function")] - fn zero_pow_minus_1_at_h_1_invalid() { + fn polynomial_distribution_o_min() -> Result<(), String> { test_polynomial( Polynomial { a: 1, d: 1, - m: -1, + m: 2, n: 1, - o: 0, + o: -(MAX_DISTRIBUTION_PARAM as i64), start_moment: Some(1), b: 0, min_value: None, max_value: None, }, - &[(1, 100_000, false), (2, 100_001, true)], + &[(1, 100_000, false), (4, 100_000, false)], 1, ) - .expect("should panic"); - unreachable!("should panic"); } + #[test] - fn fails_zero_pow_minus_1_at_h_2() -> Result<(), String> { + fn polynomial_distribution_pow_minus_1_at_h_2() -> Result<(), String> { test_polynomial( Polynomial { a: 1, @@ -1933,29 +1979,29 @@ mod polynomial { (1, 100_000, false), // this should fail, 0.pow(-1) is unspecified (2, 100_001, true), // it's 1.pow(1/2) == 1 (3, 100_002, true), // 2.pow(1/2) == 1.41 - should round to 1 - (4, 100_004, true), // 3.pow(1/2) == 1.73 - should round to 2; FAILS - (5, 100_006, true), // 4.pow(1/2) == 2 - (6, 100_008, true), // 5.pow(1/2) == 2.23 - should round to 2 + (4, 100_003, true), // 3.pow(1/2) == 1.73 - should round to 1 + (5, 100_005, true), // 4.pow(1/2) == 2 + (6, 100_007, true), // 5.pow(1/2) == 2.23 - should round to 2 ], 1, ) } #[test] - fn fails_o_max_m_2() -> Result<(), String> { + fn polynomial_distribution_o_max() -> Result<(), String> { test_polynomial( Polynomial { a: 1, d: 1, m: 2, n: 1, - o: i64::MAX, + o: MAX_DISTRIBUTION_PARAM as i64, start_moment: Some(1), b: 0, min_value: None, max_value: None, }, - &[(1, 100_000, false), (10, 100_000, false)], + &[(1, 281474976810655, true), (10, 2814749767206550, true)], 1, ) } @@ -1983,70 +2029,82 @@ mod polynomial { /// /// We expect this test not to end with InternalError. #[test] - fn fails_polynomial_power() -> Result<(), String> { - for m in [i64::MIN, -1, 0, 1, i64::MAX] { - for n in [0, 1, u64::MAX] { - let dist = Polynomial { - a: 1, - d: 1, - m, - n, - o: 1, - start_moment: Some(1), - b: 100_000, - min_value: None, - max_value: None, - }; - - let mut suite = TestSuite::new( - 10_200_000_000, - 0, - TokenDistributionType::Perpetual, - Some(move |token_configuration: &mut TokenConfiguration| { - token_configuration - .distribution_rules_mut() - .set_perpetual_distribution(Some(TokenPerpetualDistribution::V0( - TokenPerpetualDistributionV0 { - distribution_type: - RewardDistributionType::BlockBasedDistribution { - interval: 1, - function: dist, - }, - distribution_recipient: - TokenDistributionRecipient::ContractOwner, - }, - ))); - }), - ); - - suite = suite.with_contract_start_time(1); - - let step = TestStep { - base_height: 10, - base_time_ms: Default::default(), - expected_balance: None, - claim_transition_assertions: vec![ - |results: &[StateTransitionExecutionResult]| -> Result<(), String> { - let err = results - .iter() - .find(|r| format!("{:?}", r).contains("InternalError")); - - if let Some(e) = err { - Err(format!("InternalError: {:?}", e)) - } else { - Ok(()) - } - }, - ], - name: "test".to_string(), - }; - - suite - .execute(&[step]) - .inspect_err(|e| { - tracing::error!("{}", e); - }) - .map_err(|e| format!("failed with m {} n {}: {}", m, n, e))?; + fn polynomial_distribution_power_extreme_values() -> Result<(), String> { + for m in [MIN_POL_M_PARAM, MAX_POL_M_PARAM] { + for n in [1, MAX_POL_N_PARAM] { + for a in [MIN_POL_A_PARAM, MAX_POL_A_PARAM] { + for b in [0, MAX_DISTRIBUTION_PARAM] { + for o in [ + -(MAX_DISTRIBUTION_PARAM as i64), + 0, + MAX_DISTRIBUTION_PARAM as i64, + ] { + let dist = Polynomial { + a, + d: 1, + m, + n, + o, + start_moment: Some(1), + b, + min_value: None, + max_value: None, + }; + + let mut suite = TestSuite::new( + 10_200_000_000, + 0, + TokenDistributionType::Perpetual, + Some(move |token_configuration: &mut TokenConfiguration| { + token_configuration + .distribution_rules_mut() + .set_perpetual_distribution( + Some(TokenPerpetualDistribution::V0( + TokenPerpetualDistributionV0 { + distribution_type: + RewardDistributionType::BlockBasedDistribution { + interval: 1, + function: dist, + }, + distribution_recipient: + TokenDistributionRecipient::ContractOwner, + }, + )), + ); + }), + ); + + suite = suite.with_contract_start_time(1); + + let step = TestStep { + base_height: 10, + base_time_ms: Default::default(), + expected_balance: None, + claim_transition_assertions: vec![ + |results: &[StateTransitionExecutionResult]| -> Result<(), String> { + let err = results + .iter() + .find(|r| format!("{:?}", r).contains("InternalError")); + + if let Some(e) = err { + Err(format!("InternalError: {:?}", e)) + } else { + Ok(()) + } + }, + ], + name: "test".to_string(), + }; + + suite + .execute(&[step]) + .inspect_err(|e| { + tracing::error!("{}", e); + }) + .map_err(|e| format!("failed with m {} n {}: {}", m, n, e))?; + } + } + } } } @@ -2410,7 +2468,7 @@ mod test_suite { use dpp::prelude::{DataContract, IdentityPublicKey, TimestampMillis}; use simple_signer::signer::SimpleSigner; - const TIMEOUT: tokio::time::Duration = tokio::time::Duration::from_secs(10); + const TIMEOUT: tokio::time::Duration = tokio::time::Duration::from_secs(60); /// Run provided closure with timeout. /// TODO: Check if it works with sync code fn with_timeout( diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/distribution/perpetual/time_based.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/distribution/perpetual/time_based.rs index 90e0372bfc2..f5433c5fb0f 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/distribution/perpetual/time_based.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/distribution/perpetual/time_based.rs @@ -11,7 +11,7 @@ use rand::prelude::StdRng; mod perpetual_distribution_time { use dpp::block::epoch::Epoch; use dpp::data_contract::associated_token::token_distribution_key::TokenDistributionType; - use dpp::data_contract::associated_token::token_perpetual_distribution::distribution_function::{DistributionFunction, MAX_DISTRIBUTION_PARAM, MAX_LINEAR_SLOPE_PARAM}; + use dpp::data_contract::associated_token::token_perpetual_distribution::distribution_function::{DistributionFunction, MAX_DISTRIBUTION_PARAM, MAX_LINEAR_SLOPE_A_PARAM}; use dpp::data_contract::associated_token::token_perpetual_distribution::distribution_recipient::TokenDistributionRecipient; use dpp::data_contract::associated_token::token_perpetual_distribution::reward_distribution_type::RewardDistributionType; use dpp::data_contract::associated_token::token_perpetual_distribution::TokenPerpetualDistribution; @@ -1102,8 +1102,8 @@ mod perpetual_distribution_time { // every 1 millisecond interval: 1, function: DistributionFunction::Linear { - a: MAX_LINEAR_SLOPE_PARAM as i64, // Strongest slope - d: 1, // No division + a: MAX_LINEAR_SLOPE_A_PARAM as i64, // Strongest slope + d: 1, // No division start_step: None, starting_amount: MAX_DISTRIBUTION_PARAM, min_value: None, @@ -1287,8 +1287,8 @@ mod perpetual_distribution_time { // every 1 millisecond interval: 1, function: DistributionFunction::Linear { - a: MAX_LINEAR_SLOPE_PARAM as i64, // Strongest slope - d: 1, // No division + a: MAX_LINEAR_SLOPE_A_PARAM as i64, // Strongest slope + d: 1, // No division start_step: None, starting_amount: MAX_DISTRIBUTION_PARAM, min_value: None, diff --git a/packages/rs-drive-abci/src/logging/logger.rs b/packages/rs-drive-abci/src/logging/logger.rs index 6646a783c83..b35d4d41132 100644 --- a/packages/rs-drive-abci/src/logging/logger.rs +++ b/packages/rs-drive-abci/src/logging/logger.rs @@ -53,6 +53,12 @@ pub struct LogBuilder { loggers: HashMap, } +use std::sync::OnceLock; +use tracing::Dispatch; +// std, no external crate + +static LOGGING_INSTALLED: OnceLock<()> = OnceLock::new(); + impl LogBuilder { /// Creates a new `LogBuilder` instance with default settings. pub fn new() -> Self { @@ -164,6 +170,12 @@ impl Loggers { self.0.get(id) } + /// Build a subscriber containing all layers from these loggers. + pub fn as_subscriber(&self) -> Result { + let layers = self.tracing_subscriber_layers()?; + Ok(Dispatch::new(Registry::default().with(layers))) + } + /// Installs loggers prepared in the [LogBuilder] as a global tracing handler. /// /// Same as [Loggers::install()], but returns error if the logging subsystem is already initialized. @@ -177,14 +189,22 @@ impl Loggers { /// drive_abci::logging::Loggers::default().try_install().ok(); /// ``` pub fn try_install(&self) -> Result<(), Error> { + // Fast path: somebody already installed – just return Ok(()) + if LOGGING_INSTALLED.get().is_some() { + return Ok(()); // <- second and later calls are ignored + } + let layers = self.tracing_subscriber_layers()?; registry() .with(layers) .try_init() - .map_err(Error::TryInitError) - } + .map_err(Error::TryInitError)?; + // Mark as installed + let _ = LOGGING_INSTALLED.set(()); + Ok(()) + } /// Returns tracing subscriber layers pub fn tracing_subscriber_layers(&self) -> Result>>, Error> { // Based on examples from https://docs.rs/tracing-subscriber/0.3.17/tracing_subscriber/layer/index.html diff --git a/packages/rs-drive-abci/src/logging/mod.rs b/packages/rs-drive-abci/src/logging/mod.rs index 9687e9c9cef..cd0f24cf273 100644 --- a/packages/rs-drive-abci/src/logging/mod.rs +++ b/packages/rs-drive-abci/src/logging/mod.rs @@ -106,7 +106,9 @@ mod tests { .with_config("file_v4", &logger_file_v4) .unwrap() .build(); - loggers.install(); + + let dispatch = loggers.as_subscriber().expect("subscriber failed"); + let _guard = tracing::dispatcher::set_default(&dispatch); const TEST_STRING_DEBUG: &str = "testing debug trace"; const TEST_STRING_ERROR: &str = "testing error trace"; From 5f4ced5bca0eba677790d52d85f8f0c655fe8fa6 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Fri, 18 Apr 2025 04:24:19 +0700 Subject: [PATCH 2/2] disabled random distribution --- .../distribution_function/validation.rs | 222 +++++++++--------- .../distribution/perpetual/block_based.rs | 7 +- 2 files changed, 122 insertions(+), 107 deletions(-) diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/validation.rs b/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/validation.rs index e7c8ab06b24..06bfe831185 100644 --- a/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/validation.rs +++ b/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/validation.rs @@ -4,6 +4,7 @@ use crate::consensus::basic::data_contract::{ InvalidTokenDistributionFunctionInvalidParameterError, InvalidTokenDistributionFunctionInvalidParameterTupleError, }; +use crate::consensus::basic::UnsupportedFeatureError; use crate::data_contract::associated_token::token_perpetual_distribution::distribution_function::{ DistributionFunction, MAX_DISTRIBUTION_PARAM, MAX_EXP_A_PARAM, MAX_EXP_M_PARAM, MAX_EXP_N_PARAM, MAX_LINEAR_SLOPE_A_PARAM, MAX_LOG_A_PARAM, MAX_POL_M_PARAM, MAX_POL_N_PARAM, @@ -11,10 +12,12 @@ use crate::data_contract::associated_token::token_perpetual_distribution::distri }; use crate::validation::SimpleConsensusValidationResult; use crate::ProtocolError; +use platform_version::version::PlatformVersion; impl DistributionFunction { pub fn validate( &self, start_moment: u64, + platform_version: &PlatformVersion, ) -> Result { match self { DistributionFunction::FixedAmount { amount: n } => { @@ -31,31 +34,38 @@ impl DistributionFunction { )); } } - DistributionFunction::Random { min, max } => { + DistributionFunction::Random { .. } => { + return Ok(SimpleConsensusValidationResult::new_with_error( + UnsupportedFeatureError::new( + "token random distribution".to_string(), + platform_version.protocol_version, + ) + .into(), + )); // Ensure that `min` is not greater than `max` - if *min > *max { - return Ok(SimpleConsensusValidationResult::new_with_error( - InvalidTokenDistributionFunctionInvalidParameterTupleError::new( - "min".to_string(), - "max".to_string(), - "smaller than or equal to".to_string(), - ) - .into(), - )); - } - - // Ensure that `max` is within valid bounds - if *max > MAX_DISTRIBUTION_PARAM { - return Ok(SimpleConsensusValidationResult::new_with_error( - InvalidTokenDistributionFunctionInvalidParameterError::new( - "max".to_string(), - 0, - MAX_DISTRIBUTION_PARAM as i64, - None, - ) - .into(), - )); - } + // if *min > *max { + // return Ok(SimpleConsensusValidationResult::new_with_error( + // InvalidTokenDistributionFunctionInvalidParameterTupleError::new( + // "min".to_string(), + // "max".to_string(), + // "smaller than or equal to".to_string(), + // ) + // .into(), + // )); + // } + // + // // Ensure that `max` is within valid bounds + // if *max > MAX_DISTRIBUTION_PARAM { + // return Ok(SimpleConsensusValidationResult::new_with_error( + // InvalidTokenDistributionFunctionInvalidParameterError::new( + // "max".to_string(), + // 0, + // MAX_DISTRIBUTION_PARAM as i64, + // None, + // ) + // .into(), + // )); + // } } DistributionFunction::StepDecreasingAmount { @@ -1017,7 +1027,7 @@ mod tests { #[test] fn test_fixed_amount_valid() { let dist = DistributionFunction::FixedAmount { amount: 100 }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!(result .expect("no error on test_fixed_amount_valid") .first_error() @@ -1027,7 +1037,7 @@ mod tests { #[test] fn test_fixed_amount_zero_invalid() { let dist = DistributionFunction::FixedAmount { amount: 0 }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!(result .expect("no error on test_fixed_amount_zero_invalid") .first_error() @@ -1039,7 +1049,7 @@ mod tests { let dist = DistributionFunction::FixedAmount { amount: u32::MAX as u64, }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!(result .expect("no error on test_fixed_amount_max_valid") .first_error() @@ -1051,7 +1061,7 @@ mod tests { let dist = DistributionFunction::FixedAmount { amount: MAX_DISTRIBUTION_PARAM + 1, }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!(result .expect("no error on test_fixed_amount_exceeds_max_invalid") .first_error() @@ -1073,7 +1083,7 @@ mod tests { trailing_distribution_interval_amount: 0, min_value: Some(10), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!(result .expect("no error on test_step_decreasing_amount_valid") .first_error() @@ -1092,7 +1102,7 @@ mod tests { trailing_distribution_interval_amount: 0, min_value: Some(10), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!(result .expect("no error on test_step_decreasing_amount_invalid_zero_step_count") .first_error() @@ -1111,7 +1121,7 @@ mod tests { trailing_distribution_interval_amount: 0, min_value: Some(10), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!(result .expect("no error on test_step_decreasing_amount_invalid_zero_denominator") .first_error() @@ -1127,7 +1137,7 @@ mod tests { steps.insert(10, 50); steps.insert(20, 25); let dist = DistributionFunction::Stepwise(steps); - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!(result .expect("no error on test_stepwise_valid") .first_error() @@ -1139,7 +1149,7 @@ mod tests { let mut steps = BTreeMap::new(); steps.insert(0, 100); let dist = DistributionFunction::Stepwise(steps); - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!(result .expect("no error on test_stepwise_invalid_single_step") .first_error() @@ -1159,7 +1169,7 @@ mod tests { max_value: Some(150), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); // If the test fails, print the exact error message. if let Err(err) = &result { @@ -1181,7 +1191,7 @@ mod tests { min_value: Some(50), max_value: Some(150), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!(result .expect("no error on test_linear_invalid_divide_by_zero") .first_error() @@ -1198,7 +1208,7 @@ mod tests { min_value: Some(50), max_value: Some(150), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!(result .expect("no error on test_linear_invalid_s_exceeds_max") .first_error() @@ -1215,7 +1225,7 @@ mod tests { min_value: Some(50), max_value: Some(150), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_linear_invalid_a_zero") @@ -1235,7 +1245,7 @@ mod tests { min_value: Some(50), max_value: Some(150), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_linear_invalid_a_too_large") @@ -1255,7 +1265,7 @@ mod tests { min_value: Some(200), // Invalid: min > max max_value: Some(150), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_linear_invalid_min_greater_than_max") @@ -1275,7 +1285,7 @@ mod tests { min_value: Some(50), max_value: Some(150), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_linear_invalid_s_greater_than_max") @@ -1295,7 +1305,7 @@ mod tests { min_value: Some(50), max_value: Some(MAX_DISTRIBUTION_PARAM + 1), // Invalid: max_value exceeds max allowed range }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_linear_invalid_max_exceeds_max_distribution_param") @@ -1315,7 +1325,7 @@ mod tests { min_value: Some(50), max_value: Some(150), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_linear_invalid_starting_at_max_value") @@ -1335,7 +1345,7 @@ mod tests { min_value: Some(50), max_value: Some(150), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_linear_invalid_starting_at_min_value") @@ -1355,7 +1365,7 @@ mod tests { min_value: Some(50), max_value: Some(250), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); match result { Ok(validation_result) => { @@ -1385,7 +1395,7 @@ mod tests { min_value: Some(10), // Valid min boundary max_value: Some(150), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!(result .expect("no error on test_linear_valid_with_min_boundary") .first_error() @@ -1402,7 +1412,7 @@ mod tests { min_value: Some(10), max_value: Some(MAX_DISTRIBUTION_PARAM), // Valid max boundary }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!(result .expect("no error on test_linear_valid_with_max_boundary") .first_error() @@ -1425,7 +1435,7 @@ mod tests { min_value: Some(1), max_value: Some(80), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); match &result { Ok(validation_result) => { @@ -1452,7 +1462,7 @@ mod tests { min_value: Some(1), max_value: Some(50), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_exponential_invalid_zero_a") @@ -1475,7 +1485,7 @@ mod tests { min_value: Some(1), max_value: Some(50), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!(result .expect("no error on test_polynomial_invalid_divide_by_zero") .first_error() @@ -1496,7 +1506,7 @@ mod tests { min_value: Some(1), max_value: Some(50), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected error").first_error().is_some(), "Expected an error when n is zero" @@ -1517,7 +1527,7 @@ mod tests { min_value: Some(1), max_value: Some(50), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected error").first_error().is_some(), "Expected an error when s exceeds MAX_DISTRIBUTION_PARAM" @@ -1538,7 +1548,7 @@ mod tests { min_value: Some(1), max_value: Some(50), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected error").first_error().is_some(), "Expected an error when o is above the allowed maximum" @@ -1559,7 +1569,7 @@ mod tests { min_value: Some(1), max_value: Some(50), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected error").first_error().is_some(), "Expected an error when o is below the allowed minimum" @@ -1579,7 +1589,7 @@ mod tests { min_value: Some(1), max_value: Some(50), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected result").first_error().is_some(), "Expected error: a is below minimum" @@ -1599,7 +1609,7 @@ mod tests { min_value: None, max_value: None, }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected result").first_error().is_some(), "Expected error: a is below minimum" @@ -1619,7 +1629,7 @@ mod tests { min_value: Some(1), max_value: Some(50), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected result").first_error().is_some(), "Expected error: a is above maximum" @@ -1639,7 +1649,7 @@ mod tests { min_value: Some(1), max_value: Some(50), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected result").first_error().is_some(), "Expected error: m is below minimum" @@ -1659,7 +1669,7 @@ mod tests { min_value: Some(1), max_value: Some(50), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected result").first_error().is_some(), "Expected error: m is above maximum" @@ -1679,7 +1689,7 @@ mod tests { min_value: Some(1), max_value: Some(50), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected result").first_error().is_some(), "Expected error: n is above maximum" @@ -1700,7 +1710,7 @@ mod tests { min_value: Some(1), max_value: Some(MAX_DISTRIBUTION_PARAM + 1), // Invalid: max_value too high }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected error").first_error().is_some(), "Expected an error when max_value exceeds MAX_DISTRIBUTION_PARAM" @@ -1721,7 +1731,7 @@ mod tests { min_value: Some(60), // min_value > max_value max_value: Some(50), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected error").first_error().is_some(), "Expected an error when min_value is greater than max_value" @@ -1744,7 +1754,7 @@ mod tests { min_value: Some(1), max_value: Some(100), // Starting at max_value }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected error").first_error().is_some(), "Expected an incoherence error when an increasing function starts at max_value" @@ -1767,7 +1777,7 @@ mod tests { min_value: Some(50), // Starting at min_value max_value: Some(100), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected error").first_error().is_some(), "Expected an incoherence error when a decreasing function starts at min_value" @@ -1788,7 +1798,7 @@ mod tests { min_value: None, max_value: None, }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected valid").first_error().is_none(), "Expected no validation errors when boundaries are omitted" @@ -1818,7 +1828,7 @@ mod tests { 8, "Expected f(4) to be 8 for a fractional exponent of 3/2" ); - let validation_result = dist.validate(4); + let validation_result = dist.validate(4, PlatformVersion::latest()); assert!( validation_result .expect("expected valid") @@ -1843,7 +1853,7 @@ mod tests { min_value: Some(1), max_value: Some(1000000), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); if let Err(err) = &result { panic!("Test failed: unexpected error: {:?}", err); } @@ -1868,7 +1878,7 @@ mod tests { min_value: Some(1), max_value: Some(100), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!(result .expect("no error on test_exponential_invalid_zero_n") .first_error() @@ -1888,7 +1898,7 @@ mod tests { min_value: Some(1), max_value: Some(100), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_exponential_invalid_zero_m") @@ -1911,7 +1921,7 @@ mod tests { min_value: Some(1), max_value: Some(100), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_exponential_invalid_zero_a") @@ -1934,7 +1944,7 @@ mod tests { min_value: Some(1), max_value: None, // Invalid: max_value must be set }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_exponential_invalid_max_missing_when_m_positive") @@ -1957,7 +1967,7 @@ mod tests { min_value: Some(1), max_value: Some(100), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_exponential_invalid_o_too_large") @@ -1980,7 +1990,7 @@ mod tests { min_value: Some(50), // Invalid: min > max max_value: Some(30), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_exponential_invalid_min_greater_than_max") @@ -2003,7 +2013,7 @@ mod tests { min_value: Some(2), max_value: Some(50), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!(result .expect("no error on test_exponential_valid_with_negative_m") .first_error() @@ -2023,7 +2033,7 @@ mod tests { min_value: Some(2), max_value: Some(MAX_DISTRIBUTION_PARAM), // Valid max }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!(result .expect("no error on test_exponential_valid_with_max_boundary") .first_error() @@ -2043,7 +2053,7 @@ mod tests { min_value: Some(1), max_value: Some(MAX_DISTRIBUTION_PARAM), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_exponential_invalid_large_start_token_amount") @@ -2066,7 +2076,7 @@ mod tests { min_value: Some(1), max_value: Some(1000), // Small `max_value` }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_exponential_invalid_a_too_large_for_max") @@ -2089,7 +2099,7 @@ mod tests { min_value: Some(10), // Function starts at `min_value` max_value: Some(1000), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_exponential_invalid_starts_at_min") @@ -2112,7 +2122,7 @@ mod tests { min_value: Some(1), max_value: None, // Should fail }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_exponential_invalid_missing_max_for_positive_m") @@ -2135,7 +2145,7 @@ mod tests { min_value: Some(1), max_value: Some(MAX_DISTRIBUTION_PARAM), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_exponential_invalid_large_o_overflow") @@ -2158,7 +2168,7 @@ mod tests { min_value: Some(10), max_value: Some(100), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_exponential_invalid_a_too_small") @@ -2182,7 +2192,7 @@ mod tests { max_value: Some(1000), }; - let result = dist.validate(5); + let result = dist.validate(5, PlatformVersion::latest()); match result { Ok(validation_result) => { @@ -2212,7 +2222,7 @@ mod tests { min_value: Some(5), max_value: Some(100), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!(result .expect("no error on test_exponential_valid_gentle_decay") .first_error() @@ -2232,7 +2242,7 @@ mod tests { min_value: Some(5), max_value: Some(100), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!(result .expect("no error on test_exponential_valid_negative_m_with_o_offset") .first_error() @@ -2254,7 +2264,7 @@ mod tests { min_value: Some(1), max_value: Some(100), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!(result .expect("no error on test_logarithmic_valid") .first_error() @@ -2274,7 +2284,7 @@ mod tests { min_value: Some(1), max_value: Some(100), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_logarithmic_invalid_zero_d") @@ -2297,7 +2307,7 @@ mod tests { min_value: Some(1), max_value: Some(100), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_logarithmic_invalid_zero_n") @@ -2320,7 +2330,7 @@ mod tests { min_value: Some(1), max_value: Some(100), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_logarithmic_invalid_zero_m") @@ -2343,7 +2353,7 @@ mod tests { min_value: Some(1), max_value: Some(100), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_logarithmic_invalid_x_s_o_non_positive") @@ -2366,7 +2376,7 @@ mod tests { min_value: Some(1), max_value: Some(MAX_DISTRIBUTION_PARAM + 1), // Invalid: max_value too large }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_logarithmic_invalid_max_greater_than_max_param") @@ -2389,7 +2399,7 @@ mod tests { min_value: Some(50), // Invalid: min > max max_value: Some(30), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_logarithmic_invalid_min_greater_than_max") @@ -2412,7 +2422,7 @@ mod tests { min_value: Some(2), max_value: Some(50), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!(result .expect("no error on test_logarithmic_valid_with_s_and_o") .first_error() @@ -2432,7 +2442,7 @@ mod tests { min_value: Some(2), max_value: Some(MAX_DISTRIBUTION_PARAM), // Valid max }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!(result .expect("no error on test_logarithmic_valid_edge_case_max") .first_error() @@ -2454,7 +2464,7 @@ mod tests { min_value: Some(1), max_value: Some(50), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result .expect("no error on test_inverted_logarithmic_valid") @@ -2477,7 +2487,7 @@ mod tests { min_value: Some(1), max_value: Some(MAX_DISTRIBUTION_PARAM), // Valid max boundary }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert_eq!( result.expect("expected valid").first_error().expect("expected error").to_string(), "Invalid parameter `a` in token distribution function. Expected range: -32766 to 32767 except 0 (which we got)" @@ -2497,7 +2507,7 @@ mod tests { min_value: Some(1), max_value: Some(MAX_DISTRIBUTION_PARAM), // Valid max boundary }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert_eq!( result.expect("expected valid").first_error().expect("expected error").to_string(), "Invalid parameter `a` in token distribution function. Expected range: -32766 to 32767 except 0 (which we got)" @@ -2517,7 +2527,7 @@ mod tests { min_value: Some(1), max_value: Some(MAX_DISTRIBUTION_PARAM), // Valid max boundary }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert_eq!( result.expect("expected valid").first_error().expect("expected error").to_string(), "Invalid parameter `a` in token distribution function. Expected range: -32766 to 32767 except 0 (which we got)" @@ -2537,7 +2547,7 @@ mod tests { min_value: Some(1), max_value: Some(50), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected error").first_error().is_some(), "Expected error: division by zero (d = 0)" @@ -2557,7 +2567,7 @@ mod tests { min_value: Some(1), max_value: Some(50), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected error").first_error().is_some(), "Expected error: division by zero (n = 0)" @@ -2577,7 +2587,7 @@ mod tests { min_value: Some(1), max_value: Some(50), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected error").first_error().is_some(), "Expected error: division by zero (m = 0)" @@ -2597,7 +2607,7 @@ mod tests { min_value: Some(1), max_value: Some(50), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected error").first_error().is_some(), "Expected error: log argument must be positive" @@ -2617,7 +2627,7 @@ mod tests { min_value: Some(1), max_value: Some(50), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected error").first_error().is_some(), "Expected error: s exceeds MAX_DISTRIBUTION_PARAM" @@ -2637,7 +2647,7 @@ mod tests { min_value: Some(60), // Invalid: min > max max_value: Some(50), }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected error").first_error().is_some(), "Expected error: min_value > max_value" @@ -2657,7 +2667,7 @@ mod tests { min_value: Some(1), max_value: Some(MAX_DISTRIBUTION_PARAM), // Valid max boundary }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected valid").first_error().is_none(), "Expected valid function with max boundary" @@ -2679,7 +2689,7 @@ mod tests { min_value: Some(1), max_value: Some(MAX_DISTRIBUTION_PARAM), // Valid max boundary }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert_eq!( result.expect("expected valid").first_error().expect("expected error").to_string(), "Invalid parameter `a` in token distribution function. Expected range: -32766 to 32767 except 0 (which we got)" @@ -2699,7 +2709,7 @@ mod tests { min_value: Some(1), max_value: Some(50), // Function already at max }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected error").first_error().is_some(), "Expected error: increasing function starts at max_value" @@ -2719,7 +2729,7 @@ mod tests { min_value: Some(1), max_value: Some(50), // Function already at min }; - let result = dist.validate(START_MOMENT); + let result = dist.validate(START_MOMENT, PlatformVersion::latest()); assert!( result.expect("expected error").first_error().is_some(), "Expected error: decreasing function starts at min_value" diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/distribution/perpetual/block_based.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/distribution/perpetual/block_based.rs index 1afa1394231..0a356690b5d 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/distribution/perpetual/block_based.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/distribution/perpetual/block_based.rs @@ -696,6 +696,7 @@ mod random { /// When I claim tokens at various heights, /// Then I get deterministic balances at those heights. #[test] + #[ignore] fn test_random_max_supply() -> Result<(), String> { let steps = [ TestStep::new(41, 100_192, true), @@ -721,6 +722,7 @@ mod random { /// When I claim tokens at various heights, /// Then claim fails and I get the same balance at those heights. #[test] + #[ignore] fn test_block_based_perpetual_random_0_0() { check_heights( DistributionFunction::Random { min: 0, max: 0 }, @@ -736,6 +738,7 @@ mod random { .expect("no rewards"); } #[test] + #[ignore] fn test_block_based_perpetual_random_0_u64_max_should_error_at_validation() { check_heights( DistributionFunction::Random { @@ -751,6 +754,7 @@ mod random { } #[test] + #[ignore] fn test_block_based_perpetual_random_0_MAX_distribution_param() { check_heights( DistributionFunction::Random { @@ -773,6 +777,7 @@ mod random { /// When I claim tokens at various heights, /// Then I get a distribution of balances that is close to the maximum entropy. #[test] + #[ignore] fn test_block_based_perpetual_random_10_30_entropy() { const N: u64 = 200; const MIN: u64 = 10; @@ -2960,7 +2965,7 @@ mod test_suite { let consensus_result = perpetual_distribution .distribution_type .function() - .validate(contract_start_time) + .validate(contract_start_time, PlatformVersion::latest()) .map_err(|e| format!("invalid distribution function: {:?}", e))?; if let Some(error) = consensus_result.first_error() {