Skip to content

fix(dpp)!: version-gate distribution function floating-point evaluation#3462

Open
PastaPastaPasta wants to merge 2 commits into
v3.1-devfrom
fix/version-gate-float-reward-evaluation
Open

fix(dpp)!: version-gate distribution function floating-point evaluation#3462
PastaPastaPasta wants to merge 2 commits into
v3.1-devfrom
fix/version-gate-float-reward-evaluation

Conversation

@PastaPastaPasta
Copy link
Copy Markdown
Member

@PastaPastaPasta PastaPastaPasta commented Apr 8, 2026

Issue being fixed or feature implemented

DistributionFunction::evaluate() uses f64 transcendental functions (powf/exp/ln) to compute consensus-critical token rewards. The std implementations are platform-dependent (varying across CPU architectures and libm versions), risking consensus divergence between nodes computing different integer rewards for the same claim.

Concrete proof: 125^(1/3) yields 4 on some platforms (std powf) vs 5 on others. The deterministic libm path always returns 5.

What was done?

Gate transcendental float operations behind distribution_function_evaluate_version in DPPTokenVersions:

  • Version 0 (all current protocol versions through v12): preserves original std behavior (.powf(), .exp(), .ln())
  • Version 1+: uses deterministic libm functions (pow, exp, log)

Changes:

  • Add distribution_function_evaluate_version field to DPPTokenVersions
  • Create TOKEN_VERSIONS_V3 with deterministic evaluation enabled (for use in a future protocol version)
  • Add libm = "0.2" dependency to rs-dpp
  • Thread platform_version through evaluate()evaluate_interval()rewards_in_interval() call chain
  • Version-gate 4 transcendental call sites: Polynomial (pow), Exponential (exp), Logarithmic (log), InvertedLogarithmic (log)
  • 5 unaffected variants use only integer math: FixedAmount, Random, StepDecreasingAmount, Stepwise, Linear

Note: TOKEN_VERSIONS_V3 is created but not yet assigned to a platform version. A future PR creating PLATFORM_V13 should reference it to activate deterministic evaluation on the network.

How Has This Been Tested?

  • All 50 evaluate() unit tests pass (47 existing + 3 new determinism tests)
  • All 82 validation.rs tests pass
  • All 72 evaluate_interval tests pass (with token-reward-explanations feature)
  • Determinism regression tests for all 4 affected variants using distribution_function_evaluate_version = 1
  • cargo check -p dpp -p drive compiles clean

Breaking Changes

Function signature changes (compile-time only, no behavioral change for existing protocol versions):

  • DistributionFunction::evaluate() now requires platform_version: &PlatformVersion
  • DistributionFunction::evaluate_interval() now requires platform_version: &PlatformVersion
  • RewardDistributionType::rewards_in_interval() now requires platform_version: &PlatformVersion

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed

Summary by CodeRabbit

  • New Features

    • Added version control for token distribution evaluation methods, enabling consistent calculation results across different platform configurations.
  • Improvements

    • Updated token perpetual distribution calculations to support versioned mathematical evaluation methods based on platform version.
    • Token reward interval calculations and validations now properly propagate platform version information for deterministic results.

DistributionFunction::evaluate() uses f64 transcendental functions (pow/exp/log) to compute consensus-critical token rewards. The std implementations are platform-dependent, risking consensus divergence between nodes with different architectures or libm versions.

Gate these operations behind distribution_function_evaluate_version in DPPTokenVersions. Version 0 preserves the original std behavior (.powf/.exp/.ln) for existing protocol versions. Version 1+ uses deterministic libm functions for cross-platform consistency.

Changes: - Add distribution_function_evaluate_version field to DPPTokenVersions - Create TOKEN_VERSIONS_V3 with deterministic evaluation enabled - Add libm 0.2 dependency to rs-dpp - Thread platform_version through evaluate() -> evaluate_interval() -> rewards_in_interval() call chain - Version-gate 4 transcendental call sites: Polynomial (pow), Exponential (exp), Logarithmic (log), InvertedLogarithmic (log) - Add determinism regression tests for all 4 affected variants
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 8, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

The PR enables platform-version-controlled selection of math implementations for token distribution evaluation. It adds libm 0.2 as a dependency, extends the platform version schema with a distribution_function_evaluate_version field, and modifies the evaluation call chain to route between standard f64 transcendental operations and deterministic libm equivalents based on protocol version.

Changes

Token Distribution Math Versioning

Layer / File(s) Summary
Platform version infrastructure for distribution evaluation
packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/mod.rs, packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/v1.rs, packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/v2.rs, packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/v3.rs
DPPTokenVersions struct gains distribution_function_evaluate_version field; TOKEN_VERSIONS_V1 and V2 set it to 0 (std math); new TOKEN_VERSIONS_V3 sets it to 1 (libm math).
Core DistributionFunction::evaluate with versioned math
packages/rs-dpp/Cargo.toml, packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate.rs
Add libm 0.2 dependency and update evaluate signature to accept platform_version. Route Polynomial/Exponential/Logarithmic/InvertedLogarithmic variants through version-driven switch between powf/exp/ln (version 0) and libm::pow/exp/log (version 1), returning UnknownVersionMismatch for unsupported versions.
Thread platform_version through interval evaluation
packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate_interval.rs
Update evaluate_interval and evaluate_interval_with_explanation to accept and forward platform_version to self.evaluate calls.
Update reward distribution methods for platform_version
packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/reward_distribution_type/evaluate_interval.rs
Extend rewards_in_interval and rewards_in_interval_with_explanation to accept platform_version and forward to underlying evaluate_interval calls.
Update distribution validation to use platform_version
packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/validation.rs
Pass platform_version into internal evaluate calls for all distribution variants (Linear, Polynomial, Exponential, Logarithmic, InvertedLogarithmic) in DistributionFunction::validate.
Integrate platform_version into token claim reward calculation
packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_claim_transition_action/v0/transformer.rs
Pass platform_version into rewards_in_interval calls for ContractOwner, Identity, and EvonodesByParticipation distribution recipients.
Test updates for versioned evaluation
packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate.rs, packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate_interval.rs, packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/distribution/perpetual/block_based.rs
Update all test invocations to pass PlatformVersion::latest(); add deterministic behavior tests for libm path by forcing distribution_function_evaluate_version to 1.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Suggested labels

codex, aardvark

Suggested reviewers

  • QuantumExplorer
  • thepastaclaw

Poem

🐰 Math goes versioned, libm shines bright,
Deterministic paths for token flight,
Platform versions guide the way,
Transcendental functions, precise and astray,
From v0 to v1, precision takes flight!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: version-gating distribution function floating-point evaluation for deterministic consensus-critical token reward computation.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/version-gate-float-reward-evaluation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added this to the v3.1.0 milestone Apr 8, 2026
@QuantumExplorer QuantumExplorer modified the milestones: v4.0.0, v4.1.0 Jun 1, 2026
@QuantumExplorer QuantumExplorer self-assigned this Jun 1, 2026
@QuantumExplorer
Copy link
Copy Markdown
Member

Will review for 4.1

@QuantumExplorer QuantumExplorer marked this pull request as ready for review June 1, 2026 15:23
@QuantumExplorer QuantumExplorer self-requested a review as a code owner June 1, 2026 15:23
@thepastaclaw
Copy link
Copy Markdown
Collaborator

thepastaclaw commented Jun 1, 2026

✅ Review complete (commit 2e06247)

@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 1, 2026

Codecov Report

❌ Patch coverage is 92.46862% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.12%. Comparing base (46e037e) to head (2e06247).
⚠️ Report is 585 commits behind head on v3.1-dev.

Files with missing lines Patch % Lines
...ual_distribution/distribution_function/evaluate.rs 91.22% 15 Missing ⚠️
...ibution/distribution_function/evaluate_interval.rs 94.91% 3 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##           v3.1-dev    #3462      +/-   ##
============================================
+ Coverage     84.12%   87.12%   +2.99%     
============================================
  Files          2601     2625      +24     
  Lines        271457   321377   +49920     
============================================
+ Hits         228366   279987   +51621     
+ Misses        43091    41390    -1701     
Components Coverage Δ
dpp 87.73% <92.40%> (+8.37%) ⬆️
drive 86.05% <100.00%> (+1.86%) ⬆️
drive-abci 89.28% <ø> (+1.88%) ⬆️
sdk ∅ <ø> (∅)
dapi-client ∅ <ø> (∅)
platform-version ∅ <ø> (∅)
platform-value 92.17% <ø> (+0.06%) ⬆️
platform-wallet ∅ <ø> (∅)
drive-proof-verifier 47.85% <ø> (-7.82%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Collaborator

@thepastaclaw thepastaclaw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

PR correctly version-gates four f64 transcendental call sites in DistributionFunction::evaluate behind a new distribution_function_evaluate_version field, with the new libm path activated only by TOKEN_VERSIONS_V3 (which is intentionally not yet wired to any PlatformVersion). The change is consensus-safe (v0 path preserved bit-for-bit) and threaded cleanly through evaluate_interval/rewards_in_interval. Main feedback is that the new version dispatch uses a wildcard fallback instead of the codebase's explicit-arms + UnknownVersionMismatch convention; plus minor test-comment and orphan-constant nits.

🟡 1 suggestion(s) | 💬 2 nitpick(s)

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate.rs`:
- [SUGGESTION] packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate.rs:228-235: Wildcard `_ =>` dispatch diverges from the repo's fail-closed version pattern
  All four new version gates (lines 228-235, 339-346, 421-428, 566-573) match `0 => std` and `_ => libm`, so any future `distribution_function_evaluate_version` value (2, 3, …) silently executes the v1 libm semantics instead of failing closed. Elsewhere in `rs-dpp` (e.g. `document/extended_document/v0/serialize.rs:130-133`, `document/serialization_traits/cbor_conversion/mod.rs:40-43`, `document/v0/serialize.rs:1457`) the codebase consistently enumerates known versions and ends with `version => Err(ProtocolError::UnknownVersionMismatch { method: ..., known_versions, received: version })`. Since this is consensus-critical reward math, a future protocol version bump that intends a third algorithm (e.g. fixed-point) but forgets to update this site would silently pay rewards under v1 semantics on this code path rather than producing a clean version-mismatch error. Tightening to explicit `1 => libm` + `version => Err(UnknownVersionMismatch …)` makes any future version change a typechecked code edit. Apply to all four call sites in this file.

Comment on lines +228 to +235
let diff_exp = match platform_version
.dpp
.token_versions
.distribution_function_evaluate_version
{
0 => (diff as f64).powf(exponent),
_ => pow(diff as f64, exponent),
};
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Suggestion: Wildcard _ => dispatch diverges from the repo's fail-closed version pattern

All four new version gates (lines 228-235, 339-346, 421-428, 566-573) match 0 => std and _ => libm, so any future distribution_function_evaluate_version value (2, 3, …) silently executes the v1 libm semantics instead of failing closed. Elsewhere in rs-dpp (e.g. document/extended_document/v0/serialize.rs:130-133, document/serialization_traits/cbor_conversion/mod.rs:40-43, document/v0/serialize.rs:1457) the codebase consistently enumerates known versions and ends with version => Err(ProtocolError::UnknownVersionMismatch { method: ..., known_versions, received: version }). Since this is consensus-critical reward math, a future protocol version bump that intends a third algorithm (e.g. fixed-point) but forgets to update this site would silently pay rewards under v1 semantics on this code path rather than producing a clean version-mismatch error. Tightening to explicit 1 => libm + version => Err(UnknownVersionMismatch …) makes any future version change a typechecked code edit. Apply to all four call sites in this file.

source: ['claude', 'codex']

Comment on lines +1 to +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,
};
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💬 Nitpick: TOKEN_VERSIONS_V3 has no PlatformVersion consumer

TOKEN_VERSIONS_V3 is the only constant that sets distribution_function_evaluate_version = 1, but no PlatformVersion::PLATFORM_V* references it (V1–V12 still bind TOKEN_VERSIONS_V1 or _V2). The PR description states activation is deferred to a follow-up PLATFORM_V13 PR, which is fine, but the protective effect is entirely deferred. Recommend ensuring a tracking issue exists for the activation PR (so the orphaned constant isn't forgotten) and considering a brief module-level doc comment in v3.rs pointing readers to the follow-up so future maintainers don't think it's wired up.

source: ['claude', 'codex']

Comment on lines +1604 to +1606
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
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💬 Nitpick: Comment in inverted-log determinism test says x=1 but the call passes x=0

The comment reads At x=1 (with o=1, so arg = 100/1 = 100) but the test invokes distribution.evaluate(0, 0, &deterministic_version) (x=0). The numeric expectation 51 still holds because with start_moment=Some(0) and o=1, diff = 0 - 0 + 1 = 1 and argument = n/(m*diff) = 100/(1*1) = 100. Either update the comment to At x=0 or pass x=1 and recompute expected (which would give the same value here since start_moment=Some(0) is fixed and only diff depends on x). The assertion is correct; only the comment is misleading.

Suggested change
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
// f(x) = 10 * ln(100 / (1 * (x - s + o))) / 1 + 5
// At x=0 (with s=0, o=1, so arg = 100/(1*1) = 100): ln(100) ≈ 4.605, * 10 = 46.05 + 5 = 51

source: ['claude']

Replace wildcard libm dispatch with explicit version arms (0/1) ending in UnknownVersionMismatch across all four evaluate.rs call sites. Fix a misleading determinism-test comment and document that TOKEN_VERSIONS_V3 has no PlatformVersion consumer yet.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (4)
packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate.rs (1)

670-678: ⚡ Quick win

Pin the baseline assertions to an explicit evaluation version.

Most of this suite uses PlatformVersion::latest(), so once a future PR points latest() at TOKEN_VERSIONS_V3, these tests will silently stop exercising v0 semantics and some expectations may flip without any change in this file. A small helper that clones latest() and forces distribution_function_evaluate_version = 0 would keep the legacy-path coverage stable, while the version-1 determinism cases stay explicit.

♻️ Example helper
 mod tests {
     use super::*;
     use platform_version::version::PlatformVersion;
     use std::collections::BTreeMap;
+
+    fn legacy_distribution_math_version() -> PlatformVersion {
+        let mut version = PlatformVersion::latest().clone();
+        version
+            .dpp
+            .token_versions
+            .distribution_function_evaluate_version = 0;
+        version
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate.rs`
around lines 670 - 678, The tests call DistributionFunction::evaluate(...) with
PlatformVersion::latest(), which will change behavior when latest() advances;
update the tests (e.g., test_fixed_amount and other evaluate tests) to pin the
legacy evaluation path by cloning PlatformVersion::latest() into a mutable
variable and setting distribution_function_evaluate_version = 0 before passing
it to distribution.evaluate so the assertions remain stable; locate uses of
PlatformVersion::latest() in the evaluate tests and replace them with the
cloned-and-modified PlatformVersion instance referenced when calling
DistributionFunction::evaluate.
packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate_interval.rs (1)

1903-1920: ⚡ Quick win

Pin these explanation tests to a fixed math version too.

These assertions currently inherit whatever PlatformVersion::latest() means at the time the test runs. When latest() eventually switches to the deterministic token version, this suite will stop validating the legacy interval totals by default. Mirroring the explicit v0/v1 fixtures here would keep the call-chain coverage stable across future platform bumps.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate_interval.rs`
around lines 1903 - 1920, The test uses PlatformVersion::latest() which makes it
float as the platform evolves; change the call in
test_fixed_amount_explanation_first_claim (and sibling explanation tests) to use
an explicit legacy math platform version instead of latest() so the assertions
remain fixed — replace PlatformVersion::latest() with a pinned PlatformVersion
representing the legacy math (e.g., the v0/v1 fixture you use elsewhere such as
PlatformVersion::v0() or PlatformVersion::new(0), depending on your API) when
calling DistributionFunction::evaluate_interval_with_explanation to ensure
deterministic behavior.
packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/validation.rs (1)

1825-1825: ⚡ Quick win

Pin the platform version in this exact-value test.

evaluate() is version-gated now, so PlatformVersion::latest() will make this assertion drift when a later protocol version flips distribution_function_evaluate_version. Prefer a fixed platform version here, or explicitly override just the distribution-function evaluation version used by the test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/validation.rs`
at line 1825, The test calls dist.evaluate(0, 4, PlatformVersion::latest()),
which will drift as distribution_function_evaluate_version changes; replace
PlatformVersion::latest() with a pinned PlatformVersion instance (or construct a
PlatformVersion and explicitly set distribution_function_evaluate_version to the
expected version) so that evaluate() is invoked with a fixed protocol version;
update the call site (the evaluate invocation) to pass that pinned/overridden
PlatformVersion instead of PlatformVersion::latest().
packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/distribution/perpetual/block_based.rs (1)

2296-2335: ⚡ Quick win

Avoid PlatformVersion::latest() in exact numeric regression checks.

These assertions now depend on version-gated math behavior, so they will become brittle as soon as latest() starts consuming the deterministic evaluator. Pin the platform version used by the test, or construct a test-only version with the intended distribution_function_evaluate_version, so the expected constants stay stable.

Also applies to: 2413-2416

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/distribution/perpetual/block_based.rs`
around lines 2296 - 2335, The test uses PlatformVersion::latest() when calling
InvertedLogarithmic::evaluate (and in other nearby assertions), which makes
numeric expectations brittle; change those calls to a pinned PlatformVersion
that encodes the deterministic distribution evaluation you expect (or build a
test-only PlatformVersion with the intended
distribution_function_evaluate_version) instead of PlatformVersion::latest();
update all evaluate invocations in this test (and the similar calls at the other
assertions) to pass that pinned/versioned PlatformVersion so the
InvertedLogarithmic::evaluate results remain stable for the asserted constants.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate_interval.rs`:
- Around line 1903-1920: The test uses PlatformVersion::latest() which makes it
float as the platform evolves; change the call in
test_fixed_amount_explanation_first_claim (and sibling explanation tests) to use
an explicit legacy math platform version instead of latest() so the assertions
remain fixed — replace PlatformVersion::latest() with a pinned PlatformVersion
representing the legacy math (e.g., the v0/v1 fixture you use elsewhere such as
PlatformVersion::v0() or PlatformVersion::new(0), depending on your API) when
calling DistributionFunction::evaluate_interval_with_explanation to ensure
deterministic behavior.

In
`@packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate.rs`:
- Around line 670-678: The tests call DistributionFunction::evaluate(...) with
PlatformVersion::latest(), which will change behavior when latest() advances;
update the tests (e.g., test_fixed_amount and other evaluate tests) to pin the
legacy evaluation path by cloning PlatformVersion::latest() into a mutable
variable and setting distribution_function_evaluate_version = 0 before passing
it to distribution.evaluate so the assertions remain stable; locate uses of
PlatformVersion::latest() in the evaluate tests and replace them with the
cloned-and-modified PlatformVersion instance referenced when calling
DistributionFunction::evaluate.

In
`@packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/validation.rs`:
- Line 1825: The test calls dist.evaluate(0, 4, PlatformVersion::latest()),
which will drift as distribution_function_evaluate_version changes; replace
PlatformVersion::latest() with a pinned PlatformVersion instance (or construct a
PlatformVersion and explicitly set distribution_function_evaluate_version to the
expected version) so that evaluate() is invoked with a fixed protocol version;
update the call site (the evaluate invocation) to pass that pinned/overridden
PlatformVersion instead of PlatformVersion::latest().

In
`@packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/distribution/perpetual/block_based.rs`:
- Around line 2296-2335: The test uses PlatformVersion::latest() when calling
InvertedLogarithmic::evaluate (and in other nearby assertions), which makes
numeric expectations brittle; change those calls to a pinned PlatformVersion
that encodes the deterministic distribution evaluation you expect (or build a
test-only PlatformVersion with the intended
distribution_function_evaluate_version) instead of PlatformVersion::latest();
update all evaluate invocations in this test (and the similar calls at the other
assertions) to pass that pinned/versioned PlatformVersion so the
InvertedLogarithmic::evaluate results remain stable for the asserted constants.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b32316de-a0c3-4b69-b6a4-4cbc192dcab7

📥 Commits

Reviewing files that changed from the base of the PR and between 11d80f5 and 2e06247.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (11)
  • packages/rs-dpp/Cargo.toml
  • packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate.rs
  • packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate_interval.rs
  • packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/validation.rs
  • packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/reward_distribution_type/evaluate_interval.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/distribution/perpetual/block_based.rs
  • packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_claim_transition_action/v0/transformer.rs
  • packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/mod.rs
  • packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/v1.rs
  • packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/v2.rs
  • packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/v3.rs

Copy link
Copy Markdown
Collaborator

@thepastaclaw thepastaclaw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

Latest commit 2e06247 resolves all three prior findings: the four version-dispatch sites in evaluate.rs now fail closed with ProtocolError::UnknownVersionMismatch (explicit 0/1 arms), v3.rs has a doc comment documenting the deferred PLATFORM_V13 activation, and the inverted-log test comment matches the actual call. One in-scope suggestion remains: the new error path has no regression test. The TOKEN_VERSIONS_V3-unwired nitpicks are intentionally staged per the PR description and not actionable here.

🟡 1 suggestion(s)

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate.rs`:
- [SUGGESTION] packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate.rs:228-242: No regression test for the new UnknownVersionMismatch error path
  The four new version-dispatch sites (Polynomial 228-242, Exponential 346-360, Logarithmic 435-449, InvertedLogarithmic 587-602) correctly fail closed with `ProtocolError::UnknownVersionMismatch` for any value other than 0 or 1, but the test suite only exercises the happy paths (`test_*_deterministic_libm_path` at version 1, plus the existing version-0 tests). A grep for `UnknownVersionMismatch` in this file matches only the four production sites — zero tests. Since this is consensus-critical reward math and the new behavior is specifically about rejecting unknown protocol versions, a future edit could reintroduce a wildcard arm at any of the four sites without breaking any test. Add at least one unit test that constructs a `PlatformVersion` with `distribution_function_evaluate_version = 2` (or similar) and asserts `Err(ProtocolError::UnknownVersionMismatch { .. })` for each transcendental variant, or a table-driven test across all four branches.

Comment on lines +228 to +242
let diff_exp = match platform_version
.dpp
.token_versions
.distribution_function_evaluate_version
{
0 => (diff as f64).powf(exponent),
1 => pow(diff as f64, exponent),
version => {
return Err(ProtocolError::UnknownVersionMismatch {
method: "DistributionFunction::evaluate (Polynomial)".to_string(),
known_versions: vec![0, 1],
received: version,
})
}
};
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Suggestion: No regression test for the new UnknownVersionMismatch error path

The four new version-dispatch sites (Polynomial 228-242, Exponential 346-360, Logarithmic 435-449, InvertedLogarithmic 587-602) correctly fail closed with ProtocolError::UnknownVersionMismatch for any value other than 0 or 1, but the test suite only exercises the happy paths (test_*_deterministic_libm_path at version 1, plus the existing version-0 tests). A grep for UnknownVersionMismatch in this file matches only the four production sites — zero tests. Since this is consensus-critical reward math and the new behavior is specifically about rejecting unknown protocol versions, a future edit could reintroduce a wildcard arm at any of the four sites without breaking any test. Add at least one unit test that constructs a PlatformVersion with distribution_function_evaluate_version = 2 (or similar) and asserts Err(ProtocolError::UnknownVersionMismatch { .. }) for each transcendental variant, or a table-driven test across all four branches.

source: ['codex']

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants