-
Notifications
You must be signed in to change notification settings - Fork 259
SIMD-0391: Stake Program Float to Fixed-Point #391
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
grod220
wants to merge
8
commits into
solana-foundation:main
Choose a base branch
from
grod220:stake-float-to-fixed
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
b49c9f2
stake program float to fixed-point
grod220 1eff97a
Review updates
grod220 a73ecf7
Update to v2 methods
grod220 d446870
Implementation agnostic rework
grod220 785b0b0
More detail on validatior client reqs
grod220 4e67205
Signedness + clamp clarifications
grod220 d5faf74
Fix imperatives + sequence text improvement
grod220 cf98696
Update pseudocode conventions
grod220 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,138 @@ | ||
| --- | ||
| simd: "0391" | ||
| title: Stake Program Float to Fixed-Point | ||
| authors: | ||
| - Gabe (Anza) | ||
| - Pete (Anza) | ||
| category: Standard | ||
| type: Core | ||
| status: Idea | ||
| created: 2025-10-23 | ||
| feature: (to be assigned upon acceptance) | ||
| --- | ||
|
|
||
| ## Summary | ||
|
|
||
| Replace of all floating-point (`f64`) arithmetic within the Solana | ||
| Stake Program's warmup and cooldown logic with a deterministic | ||
| fixed-point implementation using integer arithmetic. This change is a | ||
| prerequisite to the Stake Program's migration to a `no_std` | ||
| Pinocchio-based implementation and ensures compatibility with upstream | ||
| eBPF toolchains, which do not support floating-point operations. | ||
|
|
||
| ## Motivation | ||
|
|
||
| The Stake Program's use of `f64` presents two blockers to the upcoming roadmap: | ||
|
|
||
| 1. **Upstream eBPF incompatibility:** Standard eBPF strictly forbids | ||
| floating-point operations. While the solana fork (SBF) currently | ||
| supports `f64` via a deterministic (and inefficient) `soft-float` | ||
| compiler built-in, aligning with upstream standards requires | ||
| removing all `f64` usage from the program. | ||
|
|
||
| 2. **Pinocchio migration inconsistency:** There is appetite for | ||
| converting the Stake Program to a highly efficient, `no_std` | ||
| Pinocchio implementation (reducing CU usage by +90%). These efforts | ||
| are undermined by the immense cost of soft-float operations. | ||
| [Benchmarking shows](https://solana.com/docs/programs/limitations#limited-float-support:~:text=Recent%20results%20show,Divide%20%20%20%20%20%209%20%20%20219) | ||
| a 22x performance penalty for a single multiplication of an `f32` | ||
| versus a `u64`. Using an `f64` with an operation | ||
| like division is even more complex. Further, doing the float | ||
| migration independently allows p-stake to enforce semantic | ||
| equivalence for its migration. | ||
|
|
||
| ## Requirements | ||
|
|
||
| The new implementation must be a replacement that precisely models the | ||
| intent of the original logic. Any resulting differences in output | ||
| should be minor and a direct result of improved numerical precision. | ||
|
|
||
| ## New Terminology | ||
|
|
||
| None | ||
|
|
||
| ## Detailed Design | ||
|
|
||
| ### Proposed Fixed-Point Implementation | ||
|
|
||
| This proposal replaces `f64` with _rational arithmetic_, expressing | ||
| the `warmup_cooldown_rate` as a fraction and reordering operations to | ||
| preserve precision while using integer arithmetic. | ||
|
|
||
| - The floating-point rates will be converted to their fractional | ||
| equivalents: | ||
| - `DEFAULT_WARMUP_COOLDOWN_RATE` (`0.25`) becomes a fraction of | ||
| **(numerator: 1, denominator: 4)**. | ||
| - `NEW_WARMUP_COOLDOWN_RATE` (`0.09`) becomes a fraction of | ||
| **(numerator: 9, denominator: 100)**. | ||
|
|
||
| - The current flow | ||
| `(account_portion / cluster_portion) * (cluster_effective * rate)` is | ||
| reordered to | ||
| `(account_portion * cluster_effective * rate_numerator) / (cluster_portion * rate_denominator)`. | ||
| Instead of performing divisions early in the process (which truncates | ||
| intermediate results), all multiplications are performed first. | ||
|
|
||
| - All intermediate multiplications are performed using `u128` to | ||
| prevent overflow. | ||
|
|
||
| ### State Compatibility | ||
|
|
||
| To maintain backwards compatibility with on-chain stake account data, | ||
| the `Delegation` struct will be modified: | ||
|
|
||
| ```diff | ||
| pub struct Delegation { | ||
| pub voter_pubkey: Pubkey, | ||
| pub stake: u64, | ||
| pub activation_epoch: Epoch, | ||
| pub deactivation_epoch: Epoch, | ||
| - pub warmup_cooldown_rate: f64, | ||
| + _reserved: [u8; 8], | ||
| } | ||
| ``` | ||
|
|
||
| This preserves the exact memory size and layout of existing accounts. | ||
| It is a legacy field anyway, with the actual rate being determined | ||
| dynamically in functions. | ||
|
|
||
| ## Alternatives Considered | ||
|
|
||
| Decimal scaling factor. Uses a uniform scaling factor represent rates | ||
| as integers like BPS (e.g 0.25 = 2500). Rejected as rational | ||
| arithmetic is more precise. It may be easier to use for external | ||
| consumers, but these values are really only used internally to the | ||
| stake interface crate. | ||
|
|
||
| ## Impact | ||
|
|
||
| - **Stake Program:** The program must be updated to use the new | ||
| integer-based calculation helpers from `solana-stake-interface`. It is | ||
| doing so mostly through its use of | ||
| `stake.delegation.stake_activating_and_deactivating()`. Also, the new | ||
| `Delegation` struct definition (with its private field), will likely | ||
| impact how its being instantiated in a few areas. | ||
|
|
||
| - **Agave:** Update the workspace dependency on | ||
| `solana-stake-interface`. Runtime stake processing already funnels | ||
| through Delegation::stake_activating_and_deactivating, so a dependency | ||
| bump automatically picks up the fixed-point math without touching | ||
| Agave code. | ||
grod220 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| - **Firedancer:** Will also need to update their stake interface | ||
| dependency in lockstep with Agave. | ||
grod220 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ## Security Considerations | ||
|
|
||
| 1. **Unit tests:** Baseline of correctness by testing specific, known | ||
| scenarios and edge cases. | ||
| 2. **Differential Fuzzing (`proptest`):** | ||
| - An oracle function preserving the original `f64` logic will be | ||
| maintained for testing purposes only. | ||
| - The test will run the new integer implementation against the oracle | ||
| with millions of random inputs. | ||
| - Assert that the results are within a relative tolerance to account | ||
| for the increased precision. | ||
grod220 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 3. **External Audit:** A comprehensive audit from an auditor with good | ||
| skills in numerical audits to validate arithmetic equivalence or | ||
| regressions. | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.