diff --git a/Cargo.lock b/Cargo.lock index 39f0b306761..a08713d81be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1935,6 +1935,7 @@ dependencies = [ "key-wallet", "key-wallet-manager", "lazy_static", + "libm", "log", "nohash-hasher", "num_enum 0.7.6", diff --git a/packages/rs-dpp/Cargo.toml b/packages/rs-dpp/Cargo.toml index 726bbedb8cc..c3cb4c37916 100644 --- a/packages/rs-dpp/Cargo.toml +++ b/packages/rs-dpp/Cargo.toml @@ -46,6 +46,7 @@ jsonschema = { git = "https://github.com/dashpay/jsonschema-rs", branch = "confi "draft202012", ], optional = true } lazy_static = { version = "1.4" } +libm = "0.2" num_enum = "0.7" bincode = { version = "=2.0.1", features = ["serde"] } rand = { version = "0.8.5", features = ["small_rng"] } 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 9b7326781b0..bca5524ff62 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 @@ -4,6 +4,8 @@ use crate::data_contract::associated_token::token_perpetual_distribution::distri MAX_DISTRIBUTION_PARAM, }; use crate::ProtocolError; +use libm::{exp, log, pow}; +use platform_version::version::PlatformVersion; impl DistributionFunction { /// Evaluates the distribution function at the given period `x`. @@ -19,6 +21,7 @@ impl DistributionFunction { &self, contract_registration_step: u64, x: u64, + platform_version: &PlatformVersion, ) -> Result { match self { DistributionFunction::FixedAmount { amount: n } => { @@ -222,7 +225,14 @@ impl DistributionFunction { )); } - let diff_exp = (diff as f64).powf(exponent); + let diff_exp = match platform_version + .dpp + .token_versions + .distribution_function_evaluate_version + { + 0 => (diff as f64).powf(exponent), + _ => pow(diff as f64, exponent), + }; if !diff_exp.is_finite() { return if diff_exp.is_sign_positive() { @@ -326,7 +336,15 @@ impl DistributionFunction { } let exponent = (*m as f64) * (diff as f64) / (*n as f64); - let value = ((*a as f64) * exponent.exp() / (*d as f64)) + (*b as f64); + let exp_val = match platform_version + .dpp + .token_versions + .distribution_function_evaluate_version + { + 0 => exponent.exp(), + _ => exp(exponent), + }; + let value = ((*a as f64) * exp_val / (*d as f64)) + (*b as f64); if let Some(max_value) = max_value { if value.is_infinite() && value.is_sign_positive() || value > *max_value as f64 { @@ -400,7 +418,14 @@ impl DistributionFunction { (*m as f64) * (diff as f64) / (*n as f64) }; - let log_val = argument.ln(); + let log_val = match platform_version + .dpp + .token_versions + .distribution_function_evaluate_version + { + 0 => argument.ln(), + _ => log(argument), + }; // Ensure the computed value is finite and within the u64 range. if !log_val.is_finite() || log_val > (u64::MAX as f64) { @@ -538,7 +563,14 @@ impl DistributionFunction { )); } - let log_val = argument.ln(); + let log_val = match platform_version + .dpp + .token_versions + .distribution_function_evaluate_version + { + 0 => argument.ln(), + _ => log(argument), + }; // Ensure the computed value is finite and within the u64 range. if !log_val.is_finite() || log_val > (u64::MAX as f64) { @@ -606,14 +638,15 @@ impl DistributionFunction { #[cfg(test)] mod tests { use super::*; + use platform_version::version::PlatformVersion; use std::collections::BTreeMap; #[test] fn test_fixed_amount() { let distribution = DistributionFunction::FixedAmount { amount: 100 }; - assert_eq!(distribution.evaluate(0, 0).unwrap(), 100); - assert_eq!(distribution.evaluate(0, 50).unwrap(), 100); - assert_eq!(distribution.evaluate(0, 1000).unwrap(), 100); + assert_eq!(distribution.evaluate(0, 0, PlatformVersion::latest()).unwrap(), 100); + assert_eq!(distribution.evaluate(0, 50, PlatformVersion::latest()).unwrap(), 100); + assert_eq!(distribution.evaluate(0, 1000, PlatformVersion::latest()).unwrap(), 100); } #[test] @@ -624,12 +657,12 @@ mod tests { steps.insert(20, 25); let distribution = DistributionFunction::Stepwise(steps); - assert_eq!(distribution.evaluate(0, 0).unwrap(), 100); - assert_eq!(distribution.evaluate(0, 5).unwrap(), 100); - assert_eq!(distribution.evaluate(0, 10).unwrap(), 50); - assert_eq!(distribution.evaluate(0, 15).unwrap(), 50); - assert_eq!(distribution.evaluate(0, 20).unwrap(), 25); - assert_eq!(distribution.evaluate(0, 30).unwrap(), 25); + assert_eq!(distribution.evaluate(0, 0, PlatformVersion::latest()).unwrap(), 100); + assert_eq!(distribution.evaluate(0, 5, PlatformVersion::latest()).unwrap(), 100); + assert_eq!(distribution.evaluate(0, 10, PlatformVersion::latest()).unwrap(), 50); + assert_eq!(distribution.evaluate(0, 15, PlatformVersion::latest()).unwrap(), 50); + assert_eq!(distribution.evaluate(0, 20, PlatformVersion::latest()).unwrap(), 25); + assert_eq!(distribution.evaluate(0, 30, PlatformVersion::latest()).unwrap(), 25); } #[test] @@ -645,12 +678,12 @@ mod tests { min_value: Some(10), }; - assert_eq!(distribution.evaluate(0, 0).unwrap(), 100); - assert_eq!(distribution.evaluate(0, 9).unwrap(), 100); - assert_eq!(distribution.evaluate(0, 10).unwrap(), 50); - assert_eq!(distribution.evaluate(0, 20).unwrap(), 25); - assert_eq!(distribution.evaluate(0, 30).unwrap(), 12); - assert_eq!(distribution.evaluate(0, 40).unwrap(), 10); // Should not go below min_value + assert_eq!(distribution.evaluate(0, 0, PlatformVersion::latest()).unwrap(), 100); + assert_eq!(distribution.evaluate(0, 9, PlatformVersion::latest()).unwrap(), 100); + assert_eq!(distribution.evaluate(0, 10, PlatformVersion::latest()).unwrap(), 50); + assert_eq!(distribution.evaluate(0, 20, PlatformVersion::latest()).unwrap(), 25); + assert_eq!(distribution.evaluate(0, 30, PlatformVersion::latest()).unwrap(), 12); + assert_eq!(distribution.evaluate(0, 40, PlatformVersion::latest()).unwrap(), 10); // Should not go below min_value } #[test] @@ -667,7 +700,7 @@ mod tests { }; assert!(matches!( - distribution.evaluate(0, 10), + distribution.evaluate(0, 10, PlatformVersion::latest()), Err(ProtocolError::DivideByZero(_)) )); } @@ -679,7 +712,7 @@ mod tests { let distribution = DistributionFunction::Random { min: 10, max: 100 }; for x in 0..100 { - let result = distribution.evaluate(0, x).unwrap(); + let result = distribution.evaluate(0, x, PlatformVersion::latest()).unwrap(); assert!( (10..=100).contains(&result), "Random value {} is out of range for x = {}", @@ -694,7 +727,7 @@ mod tests { let distribution = DistributionFunction::Random { min: 42, max: 42 }; for x in 0..10 { - let result = distribution.evaluate(0, x).unwrap(); + let result = distribution.evaluate(0, x, PlatformVersion::latest()).unwrap(); assert_eq!( result, 42, "Expected fixed output 42, got {} for x = {}", @@ -707,7 +740,7 @@ mod tests { fn test_random_distribution_invalid_range() { let distribution = DistributionFunction::Random { min: 50, max: 40 }; - let result = distribution.evaluate(0, 0); + let result = distribution.evaluate(0, 0, PlatformVersion::latest()); assert!( matches!(result, Err(ProtocolError::Overflow(_))), "Expected ProtocolError::Overflow but got {:?}", @@ -719,8 +752,8 @@ mod tests { fn test_random_distribution_deterministic_for_same_x() { let distribution = DistributionFunction::Random { min: 10, max: 100 }; - let value1 = distribution.evaluate(0, 42).unwrap(); - let value2 = distribution.evaluate(0, 42).unwrap(); + let value1 = distribution.evaluate(0, 42, PlatformVersion::latest()).unwrap(); + let value2 = distribution.evaluate(0, 42, PlatformVersion::latest()).unwrap(); assert_eq!( value1, value2, @@ -732,8 +765,8 @@ mod tests { fn test_random_distribution_varies_for_different_x() { let distribution = DistributionFunction::Random { min: 10, max: 100 }; - let value1 = distribution.evaluate(0, 1).unwrap(); - let value2 = distribution.evaluate(0, 2).unwrap(); + let value1 = distribution.evaluate(0, 1, PlatformVersion::latest()).unwrap(); + let value2 = distribution.evaluate(0, 2, PlatformVersion::latest()).unwrap(); assert_ne!( value1, value2, @@ -754,10 +787,10 @@ mod tests { max_value: None, }; - assert_eq!(distribution.evaluate(0, 0).unwrap(), 50); - assert_eq!(distribution.evaluate(0, 2).unwrap(), 60); - assert_eq!(distribution.evaluate(0, 4).unwrap(), 70); - assert_eq!(distribution.evaluate(0, 6).unwrap(), 80); + assert_eq!(distribution.evaluate(0, 0, PlatformVersion::latest()).unwrap(), 50); + assert_eq!(distribution.evaluate(0, 2, PlatformVersion::latest()).unwrap(), 60); + assert_eq!(distribution.evaluate(0, 4, PlatformVersion::latest()).unwrap(), 70); + assert_eq!(distribution.evaluate(0, 6, PlatformVersion::latest()).unwrap(), 80); } #[test] @@ -771,9 +804,9 @@ mod tests { max_value: None, }; - assert_eq!(distribution.evaluate(0, 0).unwrap(), 100); - assert_eq!(distribution.evaluate(0, 10).unwrap(), 50); - assert_eq!(distribution.evaluate(0, 20).unwrap(), 10); // Should not go below min_value + assert_eq!(distribution.evaluate(0, 0, PlatformVersion::latest()).unwrap(), 100); + assert_eq!(distribution.evaluate(0, 10, PlatformVersion::latest()).unwrap(), 50); + assert_eq!(distribution.evaluate(0, 20, PlatformVersion::latest()).unwrap(), 10); // Should not go below min_value } #[test] @@ -788,7 +821,7 @@ mod tests { }; assert!(matches!( - distribution.evaluate(0, 10), + distribution.evaluate(0, 10, PlatformVersion::latest()), Err(ProtocolError::DivideByZero(_)) )); } @@ -810,10 +843,10 @@ mod tests { max_value: None, }; - 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); + assert_eq!(distribution.evaluate(0, 0, PlatformVersion::latest()).unwrap(), 0); + assert_eq!(distribution.evaluate(0, 2, PlatformVersion::latest()).unwrap(), 18); + assert_eq!(distribution.evaluate(0, 3, PlatformVersion::latest()).unwrap(), 28); + assert_eq!(distribution.evaluate(0, 4, PlatformVersion::latest()).unwrap(), 42); } #[test] @@ -830,7 +863,7 @@ mod tests { max_value: None, }; - let result = distribution.evaluate(0, 100000).expect("expected value"); + let result = distribution.evaluate(0, 100000, PlatformVersion::latest()).expect("expected value"); assert_eq!(result, MAX_DISTRIBUTION_PARAM); } @@ -849,7 +882,35 @@ mod tests { max_value: None, }; // (4 - 0 + 0)^(3/2) = 4^(3/2) = (sqrt(4))^3 = 2^3 = 8. - assert_eq!(distribution.evaluate(0, 4).unwrap(), 8); + assert_eq!(distribution.evaluate(0, 4, PlatformVersion::latest()).unwrap(), 8); + } + + #[test] + fn test_polynomial_fractional_power_rounding_boundary_is_deterministic() { + let distribution = DistributionFunction::Polynomial { + a: 1, + d: 1, + m: 1, + n: 3, + o: 0, + start_moment: Some(0), + b: 0, + min_value: None, + max_value: None, + }; + + // cbrt(125) is exactly 5. The std f64 powf() on some platforms rounds + // the intermediate result below 5.0 and truncates to 4 when cast to u64. + // The deterministic libm path (version >= 1) must always return 5. + let mut deterministic_version = PlatformVersion::latest().clone(); + deterministic_version + .dpp + .token_versions + .distribution_function_evaluate_version = 1; + assert_eq!( + distribution.evaluate(0, 125, &deterministic_version).unwrap(), + 5 + ); } // Test: Negative coefficient a (should flip the sign) @@ -867,7 +928,7 @@ mod tests { max_value: None, }; // f(x) = -1 * (x^2). For x = 3: -1 * (3^2) = -9. - assert_eq!(distribution.evaluate(0, 3).unwrap(), 0); + assert_eq!(distribution.evaluate(0, 3, PlatformVersion::latest()).unwrap(), 0); } // Test: Non-zero shift parameter s (shifting the x coordinate) @@ -885,9 +946,9 @@ mod tests { max_value: None, }; // 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); + assert_eq!(distribution.evaluate(0, 2, PlatformVersion::latest()).unwrap(), 0); // At x = 3: (3 - 2)^2 = 1, f(3) = 2*1 + 10 = 12. - assert_eq!(distribution.evaluate(0, 3).unwrap(), 12); + assert_eq!(distribution.evaluate(0, 3, PlatformVersion::latest()).unwrap(), 12); } // Test: Non-zero offset o (shifting the base of the power) @@ -906,7 +967,7 @@ mod tests { }; // f(x) = 2 * ((x - 0 + 3)^2) + 10. // At x = 1: (1 + 3) = 4, 4^2 = 16, then 2*16 + 10 = 42. - assert_eq!(distribution.evaluate(0, 1).unwrap(), 42); + assert_eq!(distribution.evaluate(0, 1, PlatformVersion::latest()).unwrap(), 42); } // Test: Linear function when exponent is 1 (m = 1, n = 1) @@ -924,7 +985,7 @@ mod tests { max_value: None, }; // f(x) = 3*x + 5. At x = 10, f(10) = 30 + 5 = 35. - assert_eq!(distribution.evaluate(0, 10).unwrap(), 35); + assert_eq!(distribution.evaluate(0, 10, PlatformVersion::latest()).unwrap(), 35); } // Test: Cubic function (m = 3, n = 1) @@ -942,7 +1003,7 @@ mod tests { max_value: None, }; // f(x) = x^3. At x = 4, f(4) = 64. - assert_eq!(distribution.evaluate(0, 4).unwrap(), 64); + assert_eq!(distribution.evaluate(0, 4, PlatformVersion::latest()).unwrap(), 64); } // Test: Combination of non-zero offset and shift @@ -961,7 +1022,7 @@ mod tests { }; // f(x) = ( (x - 1 + 2)^2 ). // At x = 3: (3 - 1 + 2) = 4, and 4^2 = 16. - assert_eq!(distribution.evaluate(0, 3).unwrap(), 16); + assert_eq!(distribution.evaluate(0, 3, PlatformVersion::latest()).unwrap(), 16); } } mod exp { @@ -980,8 +1041,8 @@ mod tests { max_value: None, }; - assert_eq!(distribution.evaluate(0, 0).unwrap(), 11); - assert!(distribution.evaluate(0, 10).unwrap() > 20); + assert_eq!(distribution.evaluate(0, 0, PlatformVersion::latest()).unwrap(), 11); + assert!(distribution.evaluate(0, 10, PlatformVersion::latest()).unwrap() > 20); } #[test] @@ -999,7 +1060,7 @@ mod tests { }; assert!(matches!( - distribution.evaluate(0, 10), + distribution.evaluate(0, 10, PlatformVersion::latest()), Err(ProtocolError::DivideByZero(_)) )); } @@ -1018,9 +1079,9 @@ mod tests { max_value: None, }; - assert_eq!(distribution.evaluate(0, 0).unwrap(), 7); - assert_eq!(distribution.evaluate(0, 5).unwrap(), 301); - assert_eq!(distribution.evaluate(0, 10).unwrap(), 44057); + assert_eq!(distribution.evaluate(0, 0, PlatformVersion::latest()).unwrap(), 7); + assert_eq!(distribution.evaluate(0, 5, PlatformVersion::latest()).unwrap(), 301); + assert_eq!(distribution.evaluate(0, 10, PlatformVersion::latest()).unwrap(), 44057); } #[test] @@ -1037,9 +1098,9 @@ mod tests { max_value: None, }; - assert_eq!(distribution.evaluate(0, 0).unwrap(), 0); - assert_eq!(distribution.evaluate(0, 50).unwrap(), 14); - assert_eq!(distribution.evaluate(0, 100).unwrap(), 2202); + assert_eq!(distribution.evaluate(0, 0, PlatformVersion::latest()).unwrap(), 0); + assert_eq!(distribution.evaluate(0, 50, PlatformVersion::latest()).unwrap(), 14); + assert_eq!(distribution.evaluate(0, 100, PlatformVersion::latest()).unwrap(), 2202); } #[test] @@ -1056,11 +1117,11 @@ mod tests { max_value: Some(100000000), }; - assert_eq!(distribution.evaluate(0, 0).unwrap(), 1); - assert_eq!(distribution.evaluate(0, 2).unwrap(), 2980); - assert_eq!(distribution.evaluate(0, 4).unwrap(), 8886110); - assert_eq!(distribution.evaluate(0, 10).unwrap(), 100000000); - assert_eq!(distribution.evaluate(0, 100000).unwrap(), 100000000); + assert_eq!(distribution.evaluate(0, 0, PlatformVersion::latest()).unwrap(), 1); + assert_eq!(distribution.evaluate(0, 2, PlatformVersion::latest()).unwrap(), 2980); + assert_eq!(distribution.evaluate(0, 4, PlatformVersion::latest()).unwrap(), 8886110); + assert_eq!(distribution.evaluate(0, 10, PlatformVersion::latest()).unwrap(), 100000000); + assert_eq!(distribution.evaluate(0, 100000, PlatformVersion::latest()).unwrap(), 100000000); } #[test] @@ -1077,9 +1138,9 @@ mod tests { max_value: None, }; - assert_eq!(distribution.evaluate(0, 0).unwrap(), 12); // f(0) = (2 * e^(-1 * (0 - 0 + 0) / 1)) / 1 + 10 - assert_eq!(distribution.evaluate(0, 5).unwrap(), 10); - assert_eq!(distribution.evaluate(0, 10000).unwrap(), 10); + assert_eq!(distribution.evaluate(0, 0, PlatformVersion::latest()).unwrap(), 12); // f(0) = (2 * e^(-1 * (0 - 0 + 0) / 1)) / 1 + 10 + assert_eq!(distribution.evaluate(0, 5, PlatformVersion::latest()).unwrap(), 10); + assert_eq!(distribution.evaluate(0, 10000, PlatformVersion::latest()).unwrap(), 10); } #[test] @@ -1096,9 +1157,9 @@ mod tests { max_value: None, }; - assert_eq!(distribution.evaluate(0, 0).unwrap(), 12); // f(0) = (2 * e^(-1 * (0 - 0 + 0) / 1)) / 1 + 10 - assert_eq!(distribution.evaluate(0, 5).unwrap(), 11); - assert_eq!(distribution.evaluate(0, 100).unwrap(), 11); + assert_eq!(distribution.evaluate(0, 0, PlatformVersion::latest()).unwrap(), 12); // f(0) = (2 * e^(-1 * (0 - 0 + 0) / 1)) / 1 + 10 + assert_eq!(distribution.evaluate(0, 5, PlatformVersion::latest()).unwrap(), 11); + assert_eq!(distribution.evaluate(0, 100, PlatformVersion::latest()).unwrap(), 11); } #[test] @@ -1116,12 +1177,12 @@ mod tests { }; assert_eq!( - distribution.evaluate(0, 0).unwrap(), + distribution.evaluate(0, 0, PlatformVersion::latest()).unwrap(), 11, "Function should start at the max value" ); assert_eq!( - distribution.evaluate(0, 5).unwrap(), + distribution.evaluate(0, 5, PlatformVersion::latest()).unwrap(), 11, "Function should be clamped at max value" ); @@ -1141,13 +1202,57 @@ mod tests { max_value: None, }; - let result = distribution.evaluate(0, 100000); + let result = distribution.evaluate(0, 100000, PlatformVersion::latest()); assert!( matches!(result, Err(ProtocolError::Overflow(_))), "Expected overflow but got {:?}", result ); } + + #[test] + fn test_exponential_deterministic_libm_path() { + let distribution = DistributionFunction::Exponential { + a: 1, + d: 1, + m: -20, + n: 1, + o: 0, + start_moment: Some(0), + b: 0, + min_value: None, + max_value: None, + }; + + // Verify the deterministic libm path produces a consistent result + let mut deterministic_version = PlatformVersion::latest().clone(); + deterministic_version + .dpp + .token_versions + .distribution_function_evaluate_version = 1; + let v1_result = distribution + .evaluate(0, 2, &deterministic_version) + .unwrap(); + // e^(-40) is extremely small but nonzero; result should be 0 after truncation + assert_eq!(v1_result, 0); + + // A case with a larger result: e^(2) ≈ 7.389 + let distribution2 = DistributionFunction::Exponential { + a: 1, + d: 1, + m: 1, + n: 1, + o: 0, + start_moment: Some(0), + b: 0, + min_value: None, + max_value: None, + }; + let v1_result2 = distribution2 + .evaluate(0, 2, &deterministic_version) + .unwrap(); + assert_eq!(v1_result2, 7); + } } mod log { use super::*; @@ -1165,8 +1270,8 @@ mod tests { max_value: None, }; - assert_eq!(distribution.evaluate(0, 1).unwrap(), 5); - assert!(distribution.evaluate(0, 10).unwrap() > 5); + assert_eq!(distribution.evaluate(0, 1, PlatformVersion::latest()).unwrap(), 5); + assert!(distribution.evaluate(0, 10, PlatformVersion::latest()).unwrap() > 5); } #[test] @@ -1183,8 +1288,8 @@ mod tests { max_value: Some(20), // Maximum bound should be enforced }; - assert_eq!(distribution.evaluate(0, 1).unwrap(), 7); // Clamped to min_value - assert!(distribution.evaluate(0, 10).unwrap() <= 20); // Should not exceed max_value + assert_eq!(distribution.evaluate(0, 1, PlatformVersion::latest()).unwrap(), 7); // Clamped to min_value + assert!(distribution.evaluate(0, 10, PlatformVersion::latest()).unwrap() <= 20); // Should not exceed max_value } #[test] @@ -1202,7 +1307,7 @@ mod tests { }; assert!(matches!( - distribution.evaluate(0, 1), + distribution.evaluate(0, 1, PlatformVersion::latest()), Err(ProtocolError::Overflow(_)) )); } @@ -1221,7 +1326,7 @@ mod tests { max_value: None, }; - let result = distribution.evaluate(0, 100); + let result = distribution.evaluate(0, 100, PlatformVersion::latest()); assert!(result.is_ok()); assert!(result.unwrap() > 10); // Function should increase over time } @@ -1241,7 +1346,7 @@ mod tests { }; assert!(matches!( - distribution.evaluate(0, 10), + distribution.evaluate(0, 10, PlatformVersion::latest()), Err(ProtocolError::DivideByZero(_)) )); } @@ -1261,10 +1366,37 @@ mod tests { }; assert!(matches!( - distribution.evaluate(0, 10), + distribution.evaluate(0, 10, PlatformVersion::latest()), Err(ProtocolError::DivideByZero(_)) )); } + + #[test] + fn test_logarithmic_deterministic_libm_path() { + // f(x) = 10 * ln(x) / 1 + 0, evaluate at x=100 + // ln(100) ≈ 4.605, * 10 = 46.05, truncated to 46 + let distribution = DistributionFunction::Logarithmic { + a: 10, + d: 1, + m: 1, + n: 1, + o: 1, + start_moment: Some(0), + b: 0, + min_value: None, + max_value: None, + }; + + let mut deterministic_version = PlatformVersion::latest().clone(); + deterministic_version + .dpp + .token_versions + .distribution_function_evaluate_version = 1; + let v1_result = distribution + .evaluate(0, 100, &deterministic_version) + .unwrap(); + assert_eq!(v1_result, 46); + } } mod inverted_log { use super::*; @@ -1282,8 +1414,8 @@ mod tests { max_value: None, }; - assert!(distribution.evaluate(0, 1).unwrap() > distribution.evaluate(0, 5).unwrap()); - assert!(distribution.evaluate(0, 5).unwrap() > distribution.evaluate(0, 10).unwrap()); + assert!(distribution.evaluate(0, 1, PlatformVersion::latest()).unwrap() > distribution.evaluate(0, 5, PlatformVersion::latest()).unwrap()); + assert!(distribution.evaluate(0, 5, PlatformVersion::latest()).unwrap() > distribution.evaluate(0, 10, PlatformVersion::latest()).unwrap()); } #[test] @@ -1301,9 +1433,9 @@ mod tests { max_value: None, }; - let val1000 = distribution.evaluate(0, 1000).unwrap(); - let val2000 = distribution.evaluate(0, 2000).unwrap(); - let val3000 = distribution.evaluate(0, 3000).unwrap(); + let val1000 = distribution.evaluate(0, 1000, PlatformVersion::latest()).unwrap(); + let val2000 = distribution.evaluate(0, 2000, PlatformVersion::latest()).unwrap(); + let val3000 = distribution.evaluate(0, 3000, PlatformVersion::latest()).unwrap(); assert!(val1000 < val2000, "Function should be increasing"); assert!(val2000 < val3000, "Function should be increasing"); @@ -1323,7 +1455,7 @@ mod tests { max_value: None, }; - assert_eq!(distribution.evaluate(0, 1).unwrap(), 0); // Should be clamped to 0 + assert_eq!(distribution.evaluate(0, 1, PlatformVersion::latest()).unwrap(), 0); // Should be clamped to 0 } #[test] @@ -1340,7 +1472,7 @@ mod tests { max_value: None, }; - assert_eq!(distribution.evaluate(0, 1000).unwrap(), 7); // Should be clamped to min_value + assert_eq!(distribution.evaluate(0, 1000, PlatformVersion::latest()).unwrap(), 7); // Should be clamped to min_value } #[test] @@ -1358,7 +1490,7 @@ mod tests { max_value: Some(20), }; - assert_eq!(distribution.evaluate(0, 500).unwrap(), 20); // Should be clamped to max_value + assert_eq!(distribution.evaluate(0, 500, PlatformVersion::latest()).unwrap(), 20); // Should be clamped to max_value } #[test] @@ -1376,7 +1508,7 @@ mod tests { }; assert!(matches!( - distribution.evaluate(0, 1), + distribution.evaluate(0, 1, PlatformVersion::latest()), Err(ProtocolError::Overflow(_)) )); } @@ -1396,7 +1528,7 @@ mod tests { }; assert!(matches!( - distribution.evaluate(0, 10), + distribution.evaluate(0, 10, PlatformVersion::latest()), Err(ProtocolError::DivideByZero(_)) )); } @@ -1416,7 +1548,7 @@ mod tests { }; assert!(matches!( - distribution.evaluate(0, 10), + distribution.evaluate(0, 10, PlatformVersion::latest()), Err(ProtocolError::DivideByZero(_)) )); } @@ -1436,12 +1568,12 @@ mod tests { }; assert_eq!( - distribution.evaluate(0, 0).unwrap(), + distribution.evaluate(0, 0, PlatformVersion::latest()).unwrap(), 1, "Function should start at the max value" ); assert_eq!( - distribution.evaluate(0, 200).unwrap(), + distribution.evaluate(0, 200, PlatformVersion::latest()).unwrap(), 10, "Function should remain clamped at max value" ); @@ -1462,10 +1594,37 @@ mod tests { }; assert_eq!( - distribution.evaluate(0, 1000).unwrap(), + distribution.evaluate(0, 1000, PlatformVersion::latest()).unwrap(), 3, "Function should remain clamped at min value" ); } + + #[test] + fn test_inverted_logarithmic_deterministic_libm_path() { + // f(x) = 10 * ln(100 / (1 * x)) / 1 + 5 + // At x=1 (with o=1, so arg = 100/1 = 100): ln(100) ≈ 4.605, * 10 = 46.05 + 5 = 51 + let distribution = DistributionFunction::InvertedLogarithmic { + a: 10, + d: 1, + m: 1, + n: 100, + o: 1, + start_moment: Some(0), + b: 5, + min_value: None, + max_value: None, + }; + + let mut deterministic_version = PlatformVersion::latest().clone(); + deterministic_version + .dpp + .token_versions + .distribution_function_evaluate_version = 1; + let v1_result = distribution + .evaluate(0, 0, &deterministic_version) + .unwrap(); + assert_eq!(v1_result, 51); + } } } diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate_interval.rs b/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate_interval.rs index dd43374ad13..29942129607 100644 --- a/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate_interval.rs +++ b/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate_interval.rs @@ -1,5 +1,4 @@ use std::ops::{Div, RangeInclusive}; -#[cfg(feature = "token-reward-explanations")] use platform_version::version::PlatformVersion; use crate::balances::credits::TokenAmount; use crate::block::epoch::EpochIndex; @@ -1571,6 +1570,7 @@ impl DistributionFunction { interval_end_included: RewardDistributionMoment, step: RewardDistributionMoment, get_epoch_reward_ratio: Option, + platform_version: &PlatformVersion, ) -> Result where F: Fn(RangeInclusive) -> Option, @@ -1650,7 +1650,7 @@ impl DistributionFunction { while current_point <= last_step { let base_amount = - self.evaluate(distribution_start_step.to_u64(), current_point.to_u64())?; + self.evaluate(distribution_start_step.to_u64(), current_point.to_u64(), platform_version)?; let amount = if let ( RewardDistributionMoment::EpochBasedMoment(epoch_index), @@ -1715,6 +1715,7 @@ impl DistributionFunction { step: RewardDistributionMoment, get_epoch_reward_ratio: Option, is_first_claim: bool, + platform_version: &PlatformVersion, ) -> Result where F: Fn(RangeInclusive) -> Option, @@ -1839,7 +1840,7 @@ impl DistributionFunction { while current_point <= last_step { let base_amount = - self.evaluate(distribution_start_step.to_u64(), current_point.to_u64())?; + self.evaluate(distribution_start_step.to_u64(), current_point.to_u64(), platform_version)?; let (amount, reward_ratio) = if let ( RewardDistributionMoment::EpochBasedMoment(epoch_index), @@ -1915,6 +1916,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -1946,6 +1948,7 @@ mod tests { step, None::) -> Option>, false, + PlatformVersion::latest(), ) .unwrap(); @@ -1976,6 +1979,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -2007,6 +2011,7 @@ mod tests { step, None::) -> Option>, false, + PlatformVersion::latest(), ) .unwrap(); @@ -2048,6 +2053,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -2086,6 +2092,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -2124,6 +2131,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -2165,6 +2173,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -2206,6 +2215,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -2247,6 +2257,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -2288,6 +2299,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -2318,6 +2330,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -2359,6 +2372,7 @@ mod tests { step, Some(get_ratio), true, + PlatformVersion::latest(), ) .unwrap(); @@ -2383,6 +2397,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -2415,6 +2430,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -2451,6 +2467,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -2476,6 +2493,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -2504,6 +2522,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -2542,6 +2561,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -2575,6 +2595,7 @@ mod tests { step, None::) -> Option>, false, + PlatformVersion::latest(), ) .unwrap(); @@ -2621,6 +2642,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -2651,6 +2673,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -2693,6 +2716,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -2718,6 +2742,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -2743,6 +2768,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -2772,6 +2798,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -2813,6 +2840,7 @@ mod tests { step, None::) -> Option>, false, + PlatformVersion::latest(), ) .unwrap(); @@ -2855,6 +2883,7 @@ mod tests { step, None::) -> Option>, false, + PlatformVersion::latest(), ) .unwrap(); @@ -2885,6 +2914,7 @@ mod tests { step, None::) -> Option>, false, + PlatformVersion::latest(), ) .unwrap(); @@ -2911,6 +2941,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -2942,6 +2973,7 @@ mod tests { step, None::) -> Option>, false, + PlatformVersion::latest(), ) .unwrap(); @@ -2980,6 +3012,7 @@ mod tests { step, None::) -> Option>, false, + PlatformVersion::latest(), ) .unwrap(); @@ -3018,6 +3051,7 @@ mod tests { step, None::) -> Option>, false, + PlatformVersion::latest(), ) .unwrap(); @@ -3059,6 +3093,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -3100,6 +3135,7 @@ mod tests { step, None::) -> Option>, false, + PlatformVersion::latest(), ) .unwrap(); @@ -3141,6 +3177,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -3182,6 +3219,7 @@ mod tests { step, None::) -> Option>, false, + PlatformVersion::latest(), ) .unwrap(); @@ -3223,6 +3261,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -3264,6 +3303,7 @@ mod tests { step, None::) -> Option>, false, + PlatformVersion::latest(), ) .unwrap(); @@ -3294,6 +3334,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -3334,6 +3375,7 @@ mod tests { step, Some(get_ratio), true, + PlatformVersion::latest(), ) .unwrap(); @@ -3358,6 +3400,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -3393,6 +3436,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -3431,6 +3475,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -3464,6 +3509,7 @@ mod tests { step, None::) -> Option>, false, + PlatformVersion::latest(), ) .unwrap(); @@ -3494,6 +3540,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -3535,6 +3582,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -3575,6 +3623,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -3607,6 +3656,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -3638,6 +3688,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -3671,6 +3722,7 @@ mod tests { step, None::) -> Option>, false, + PlatformVersion::latest(), ) .unwrap(); @@ -3714,6 +3766,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -3757,6 +3810,7 @@ mod tests { step, None::) -> Option>, false, + PlatformVersion::latest(), ) .unwrap(); @@ -3797,6 +3851,7 @@ mod tests { step, None::) -> Option>, false, + PlatformVersion::latest(), ) .unwrap(); @@ -3837,6 +3892,7 @@ mod tests { step, None::) -> Option>, false, + PlatformVersion::latest(), ) .unwrap(); @@ -3880,6 +3936,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -3928,6 +3985,7 @@ mod tests { step, None::) -> Option>, false, + PlatformVersion::latest(), ) .unwrap(); @@ -3976,6 +4034,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -4024,6 +4083,7 @@ mod tests { step, None::) -> Option>, false, + PlatformVersion::latest(), ) .unwrap(); @@ -4072,6 +4132,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -4120,6 +4181,7 @@ mod tests { step, None::) -> Option>, false, + PlatformVersion::latest(), ) .unwrap(); @@ -4168,6 +4230,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -4216,6 +4279,7 @@ mod tests { step, None::) -> Option>, false, + PlatformVersion::latest(), ) .unwrap(); @@ -4253,6 +4317,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -4290,6 +4355,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -4315,6 +4381,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -4340,6 +4407,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -4379,6 +4447,7 @@ mod tests { step, Some(get_ratio), true, + PlatformVersion::latest(), ) .unwrap(); @@ -4403,6 +4472,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -4435,6 +4505,7 @@ mod tests { step, None::) -> Option>, true, + PlatformVersion::latest(), ) .unwrap(); @@ -4477,6 +4548,7 @@ mod tests { step, Some(get_ratio), false, + PlatformVersion::latest(), ) .unwrap(); @@ -4520,6 +4592,7 @@ mod tests { step, Some(get_ratio), true, // first claim + PlatformVersion::latest(), ) .unwrap(); @@ -4563,6 +4636,7 @@ mod tests { step, Some(get_ratio), false, + PlatformVersion::latest(), ) .unwrap(); @@ -4620,6 +4694,7 @@ mod tests { step, Some(get_ratio), false, + PlatformVersion::latest(), ) .unwrap(); @@ -4678,6 +4753,7 @@ mod tests { step, None::) -> Option>, false, + PlatformVersion::latest(), ) .unwrap(); 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 c9738c71f1f..3fb4a0a964b 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 @@ -266,7 +266,7 @@ impl DistributionFunction { min_value: *min_value, max_value: *max_value, } - .evaluate(0, start_moment)?; + .evaluate(0, start_moment, platform_version)?; if *a > 0 { // we want to put in the max value to see if we are starting off at the max @@ -444,7 +444,7 @@ impl DistributionFunction { min_value: *min_value, max_value: *max_value, } - .evaluate(0, start_moment)?; + .evaluate(0, start_moment, platform_version)?; // Now, based on the monotonicity implied by (*a) * (*m), // check for incoherence: @@ -634,7 +634,7 @@ impl DistributionFunction { min_value: *min_value, max_value: *max_value, } - .evaluate(0, start_moment)?; + .evaluate(0, start_moment, platform_version)?; if *m > 0 { // we want to put in the max value to see if we are starting off at the max @@ -812,7 +812,7 @@ impl DistributionFunction { min_value: *min_value, max_value: *max_value, } - .evaluate(0, start_moment)?; + .evaluate(0, start_moment, platform_version)?; if let Some(max) = max_value { if start_token_amount == *max { @@ -976,7 +976,7 @@ impl DistributionFunction { min_value: *min_value, max_value: *max_value, } - .evaluate(0, start_moment)?; + .evaluate(0, start_moment, platform_version)?; // Determine the function's monotonicity. // For InvertedLogarithmic, f'(x) = -a / (d * (x - s + o)). @@ -1822,7 +1822,7 @@ mod tests { min_value: Some(0), max_value: Some(100), }; - let eval_result = dist.evaluate(0, 4); + let eval_result = dist.evaluate(0, 4, PlatformVersion::latest()); assert_eq!( eval_result.unwrap(), 8, diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/reward_distribution_type/evaluate_interval.rs b/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/reward_distribution_type/evaluate_interval.rs index 7559a377950..1cd2fccbef3 100644 --- a/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/reward_distribution_type/evaluate_interval.rs +++ b/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/reward_distribution_type/evaluate_interval.rs @@ -7,6 +7,7 @@ use crate::data_contract::associated_token::token_perpetual_distribution::distri use crate::data_contract::associated_token::token_perpetual_distribution::reward_distribution_moment::RewardDistributionMoment; use crate::data_contract::associated_token::token_perpetual_distribution::reward_distribution_type::RewardDistributionType; use crate::ProtocolError; +use platform_version::version::PlatformVersion; impl RewardDistributionType { /// Computes the total rewards emitted in a given interval based on the provided distribution moments. @@ -36,6 +37,7 @@ impl RewardDistributionType { start_at_moment: RewardDistributionMoment, current_moment_included: RewardDistributionMoment, get_epoch_reward_ratio: Option, + platform_version: &PlatformVersion, ) -> Result where F: Fn(RangeInclusive) -> Option, @@ -46,6 +48,7 @@ impl RewardDistributionType { current_moment_included, self.interval(), get_epoch_reward_ratio, + platform_version, ) } @@ -80,6 +83,7 @@ impl RewardDistributionType { current_moment_included: RewardDistributionMoment, get_epoch_reward_ratio: Option, is_first_claim: bool, + platform_version: &PlatformVersion, ) -> Result where F: Fn(RangeInclusive) -> Option, @@ -91,6 +95,7 @@ impl RewardDistributionType { self.interval(), get_epoch_reward_ratio, is_first_claim, + platform_version, ) } } 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 c013cf6483e..37e516b3fe1 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 @@ -2293,9 +2293,9 @@ mod inverted_logarithmic { (2, 100_001, false), (50000, 100_001, false), ]; - let x_1 = dist.evaluate(0, 1).expect("expected to evaluate"); + let x_1 = dist.evaluate(0, 1, PlatformVersion::latest()).expect("expected to evaluate"); assert_eq!(x_1, 1); // This is ln (1/ (1 - 1 + 1)), or basically ln(1) = 1 - let x_2 = dist.evaluate(0, 2).expect("expected to evaluate"); + let x_2 = dist.evaluate(0, 2, PlatformVersion::latest()).expect("expected to evaluate"); assert_eq!(x_2, 0); // This is ln (1/ (1 - 1 + 2)), or basically ln(1/2) = 0 run_test(dist, &steps, 1) } @@ -2327,12 +2327,12 @@ mod inverted_logarithmic { min_value: None, // min_value: Option, max_value: None, // max_value: Option, }; - let x_1 = dist.evaluate(0, 1).expect("expected to evaluate"); - let x_2 = dist.evaluate(0, 2).expect("expected to evaluate"); - let x_1000 = dist.evaluate(0, 1000).expect("expected to evaluate"); - let x_4000 = dist.evaluate(0, 4000).expect("expected to evaluate"); - let x_5000 = dist.evaluate(0, 5000).expect("expected to evaluate"); - let x_6000 = dist.evaluate(0, 6000).expect("expected to evaluate"); + let x_1 = dist.evaluate(0, 1, PlatformVersion::latest()).expect("expected to evaluate"); + let x_2 = dist.evaluate(0, 2, PlatformVersion::latest()).expect("expected to evaluate"); + let x_1000 = dist.evaluate(0, 1000, PlatformVersion::latest()).expect("expected to evaluate"); + let x_4000 = dist.evaluate(0, 4000, PlatformVersion::latest()).expect("expected to evaluate"); + let x_5000 = dist.evaluate(0, 5000, PlatformVersion::latest()).expect("expected to evaluate"); + let x_6000 = dist.evaluate(0, 6000, PlatformVersion::latest()).expect("expected to evaluate"); assert_eq!(x_1, 85171); assert_eq!(x_2, 78240); assert_eq!(x_1000, 16094); @@ -2410,10 +2410,10 @@ mod inverted_logarithmic { min_value: None, // min_value: Option, max_value: None, // max_value: Option, }; - let x_1 = dist.evaluate(0, 1).expect("expected to evaluate"); - let x_2 = dist.evaluate(0, 2).expect("expected to evaluate"); - let x_1000 = dist.evaluate(0, 1000).expect("expected to evaluate"); - let x_4000 = dist.evaluate(0, 4000).expect("expected to evaluate"); + let x_1 = dist.evaluate(0, 1, PlatformVersion::latest()).expect("expected to evaluate"); + let x_2 = dist.evaluate(0, 2, PlatformVersion::latest()).expect("expected to evaluate"); + let x_1000 = dist.evaluate(0, 1000, PlatformVersion::latest()).expect("expected to evaluate"); + let x_4000 = dist.evaluate(0, 4000, PlatformVersion::latest()).expect("expected to evaluate"); assert_eq!(x_1, 1351); assert_eq!(x_2, 1352); assert_eq!(x_1000, 1984); diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_claim_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_claim_transition_action/v0/transformer.rs index 205a2f6be72..b802324457e 100644 --- a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_claim_transition_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_claim_transition_action/v0/transformer.rs @@ -446,6 +446,7 @@ impl TokenClaimTransitionActionV0 { start_from_moment_for_distribution, max_cycle_moment, None, + platform_version, )?, ), TokenDistributionRecipient::Identity(identifier) => ( @@ -457,6 +458,7 @@ impl TokenClaimTransitionActionV0 { start_from_moment_for_distribution, max_cycle_moment, None, + platform_version, )?, ), TokenDistributionRecipient::EvonodesByParticipation => { @@ -520,6 +522,7 @@ impl TokenClaimTransitionActionV0 { } } }), + platform_version, )?; ( diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/mod.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/mod.rs index ede323f1d33..77bc8faccaa 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/mod.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/mod.rs @@ -1,5 +1,6 @@ pub mod v1; pub mod v2; +pub mod v3; use versioned_feature_core::FeatureVersion; @@ -16,4 +17,8 @@ pub struct DPPTokenVersions { /// v0: uses only minimum_purchase_amount_and_price().1 (vulnerable to schedule swap) /// v1: includes the full serialized TokenPricingSchedule in the hash pub token_set_price_action_id_version: FeatureVersion, + /// Version for distribution function floating-point evaluation. + /// v0: uses std f64 transcendental methods (.powf(), .exp(), .ln()) -- platform-dependent + /// v1: uses libm functions (pow, exp, log) -- cross-platform deterministic + pub distribution_function_evaluate_version: FeatureVersion, } diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/v1.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/v1.rs index e5114478c72..63b7824cbc1 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/v1.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/v1.rs @@ -6,4 +6,5 @@ pub const TOKEN_VERSIONS_V1: DPPTokenVersions = DPPTokenVersions { token_contract_info_default_structure_version: 0, token_config_update_action_id_version: 0, token_set_price_action_id_version: 0, + distribution_function_evaluate_version: 0, }; diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/v2.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/v2.rs index c9f0cc893e0..9109ceefaed 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/v2.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/v2.rs @@ -6,4 +6,5 @@ pub const TOKEN_VERSIONS_V2: DPPTokenVersions = DPPTokenVersions { token_contract_info_default_structure_version: 0, token_config_update_action_id_version: 1, token_set_price_action_id_version: 1, + distribution_function_evaluate_version: 0, }; diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/v3.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/v3.rs new file mode 100644 index 00000000000..b669be8c9cc --- /dev/null +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/v3.rs @@ -0,0 +1,10 @@ +use crate::version::dpp_versions::dpp_token_versions::DPPTokenVersions; + +pub const TOKEN_VERSIONS_V3: DPPTokenVersions = DPPTokenVersions { + identity_token_info_default_structure_version: 0, + identity_token_status_default_structure_version: 0, + token_contract_info_default_structure_version: 0, + token_config_update_action_id_version: 1, + token_set_price_action_id_version: 1, + distribution_function_evaluate_version: 1, +};