SIMD-0391

Stake Program Float to Fixed-Point

Author: Gabe (Anza), Pete (Anza) · Category: Core Protocol GitHub →

TL;DR

This SIMD proposes replacing all IEEE-754 double-precision floating-point arithmetic within the Solana Stake Program & validator client's warmup/ cooldown logic with a fixed-point implementation using integer arithmetic. The new logic expresses the warmup/cooldown rate in basis points (bps) and performs stake calculations using unsigned 128-bit integers to maintain precision.

Summary

This SIMD proposes replacing all IEEE-754 double-precision floating-point arithmetic within the Solana Stake Program & validator client's warmup/ cooldown logic with a fixed-point implementation using integer arithmetic. The new logic expresses the warmup/cooldown rate in basis points (bps) and performs stake calculations using unsigned 128-bit integers to maintain precision.

Motivation

This change is a prerequisite to the Stake Program's migration to a `no_std` & upstream eBPF-toolchain friendly implementation. Standard eBPF strictly forbids floating-point operations. While the solana fork (SBF) allows for it via a deterministic (and inefficient) `soft-float` compiler built-in, aligning with upstream standards requires removing all floating-point usage from the program. The validator client shares the same warmup/cooldown calculation logic with the on-chain program, so it is also in need of a lock-step update to stay in sync.

Key Changes

  • Basis points (bps): An integer representation of a percentage where bps = percent × 100.
  • 1 bps = 0.01%
  • 1% = 100 bps
  • Formula variables
  • account_portion: The amount of stake (in lamports) for a single account that is eligible to warm up or cool down in a given epoch.
  • cluster_portion: The total amount of stake (in lamports) across the cluster that is in the same warmup/cooldown phase as account_portion for the previous epoch.
  • cluster_effective: The total effective stake in the cluster (in lamports) for the previous epoch.
  • Uint64 / Uint128: Unsigned 64-bit / 128-bit integer types
  • widen(x): Zero-extend a Uint64 to Uint128 (lossless)
  • narrow(x): Convert a Uint128 to Uint64 (caller must ensure x ≤ 2^64−1)
  • sat_mul(a, b): Saturating multiplication—returns a × b or 2^128−1 if the result would overflow
  • trunc_div(a, b): Truncating unsigned integer division (floor toward zero)
  • Saturate: All intermediate 128-bit multiplications in the computation (including both numerator and denominator multiplications) MUST use saturating arithmetic, capping at the maximum representable unsigned 128-bit value.
  • Divide: The division MUST use unsigned integer division and truncate (round down).
  • Clamp: The post-division result MUST be clamped to account_portion.
  • Narrow: The clamped value MUST be converted back to an unsigned 64-bit integer. Because the value is capped at account_portion, this conversion MUST be exact (lossless) and NOT truncate, wrap, or otherwise alter the clamped value.

Impact

- **Stake Interface**: - Export new integer-based stake activation and deactivation logic for rust consumers - Deprecate the floating-point rate field while preserving binary layout compatibility - **Stake Program**: Feature gate v2 interface helpers in: - **Stake Merging**: Stake calculations are used to determine if the account is in a transient state, ensuring that merges are rejected if the account is not effectively fully active or inactive. - **Stake Splitting**: Stake calculations are used to determine if the source stake is currently active (effective stake > 0). This status is required to correctly enforce rent-exempt reserve prefunding requirements for the destination account. - **Stake Redelegation**: The account's cooldown status is determined with stake calculations and confirms that effective stake is exactly zero before allowing redelegation. - **Stake Withdrawal**: When withdrawing from a deactivated account, stake calculations are used to determine the remaining effective stake. - **Validator Clients (Agave & Firedancer)**: Clients MUST feature gate the transition from floating-point to fixed-point arithmetic in all consensus-critical operations involving effective, activating, or deactivating stake. The following operations require updates: - **Stake Activation and Deactivation**: When querying a stake delegation's status for a given epoch, the validator _computes how much of the delegation's stake has completed warmup or cooldown_. This requires walking through epochs from the delegation's activation or deactivation point, computing the allowed stake change at each epoch boundary to determine the portion that transitioned. The result categorizes the delegation's lamports into effective, activating, and deactivating buckets. - **Epoch Boundary Stake History**: At each epoch boundary, the validator iterates over all stake delegations and _computes their activation status_ as of the concluding epoch. These per-delegation values are summed to produce the cluster-wide totals (effective/activating/deactivating) that form the new stake history entry. This entry is then used as input for subsequent epoch calculations. - **Stake Cache Updates**: The validator maintains a cache mapping vote accounts to their delegated stake. When a stake account is created/modified/closed, the cache entry for the associated vote account MUST be updated. This requires _computing the delegation's effective stake_ contribution before and after the change to correctly adjust the cached totals. - **Vote Account Stake Totals**: At epoch boundaries, the validator refreshes the stake distribution across vote accounts for the upcoming epoch. For each vote account, it _sums the effective stake_ of all delegations pointing to that account. T

Security Considerations

All implementations MUST adhere to the following standards: 1. **Unit tests:** Baseline of correctness by testing specific, known scenarios and edge cases. 2. **Differential Fuzzing:** maintains an oracle implementation that preserves the original logic, used only in tests. Those should then be run against the integer arithmetic to ensure a difference of no more than `4 x ULP` (units of last place). 3. **External Audit:** A comprehensive audit from an auditor with good skills in numerical audits to validate arithmetic equivalence or regressions.