-
Notifications
You must be signed in to change notification settings - Fork 4
feat(elections): add adaptive staking strategy #41
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
Keshoid
wants to merge
11
commits into
release/nodectl/v0.4.0
Choose a base branch
from
feature/sma-35-add-adaptive-staking-strategy
base: release/nodectl/v0.4.0
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 all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
f2c9ecf
feat(nodectl): impl adaptive-split50 strategy
Keshoid d4c19a6
feat(election): add compute_min_effective_stake + tests
Keshoid 6c46471
refactor(elections): extract some stake funcs to a separate module
Keshoid 5ba952a
feat(elections): always use curr eff stake instead of min(curr, prev)
Keshoid 32849f2
refactor(elections): move common code to the beginning of `participat…
Keshoid 1d8f0e6
fmt: make fmt
Keshoid ef73f47
docs: rewrite adaptive staking strategy
Keshoid c4341dd
feat(elections): remove our stake for participants before emulation
Keshoid 77f30d7
fix: after review
Keshoid 4c6c1c3
refactor(elections): info logs for adaptive strategy
Keshoid 93956a3
fix(elections): restore participant from validator_config on restart
Keshoid 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
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
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
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
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
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
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,118 @@ | ||
| # Nodectl Staking Strategies | ||
|
|
||
| ## AdaptiveSplit50 | ||
|
|
||
| ### Overview | ||
|
|
||
| AdaptiveSplit50 splits your funds in half and stakes each half into alternating election rounds, so capital is always working. If half is not enough to be selected by the Elector, it stakes everything into the current round instead. | ||
|
|
||
| --- | ||
|
|
||
| ### Key Terms | ||
|
|
||
| | Term | Description | | ||
| |---|---| | ||
| | **Elector** | TON smart contract that runs validator elections. | | ||
| | **min_eff_stake** | Minimum stake the Elector would accept. Below this — no rewards. | | ||
| | **frozen_stake** | Stake locked in the previous validation round. | | ||
| | **free_pool_balance** | Funds available for staking on the pool balance. | | ||
| | **current_stake** | Stake already submitted to the current election (0 if none). | | ||
| | **available** | `frozen_stake + free_pool_balance + current_stake` | | ||
| | **half** | `available / 2` | | ||
| | **sleep_period** | Minimum wait time (fraction of election duration) before acting. | | ||
| | **waiting_period** | Maximum wait time for enough participants before using fallback data. Must be >= `sleep_period`. | | ||
|
|
||
| --- | ||
|
|
||
| ### How It Works | ||
|
|
||
| The strategy runs on every tick (periodic check) during an election. | ||
|
|
||
| #### 1. Wait for the right moment | ||
|
|
||
| Before doing anything, the strategy waits until: | ||
|
|
||
| - The **sleep_period** has passed since the election started, **and** | ||
| - At least `min_validators` participants have submitted stakes. | ||
|
|
||
| If the **waiting_period** expires and there still aren't enough participants, the strategy stops waiting and proceeds with whatever data is available. | ||
|
|
||
| #### 2. Estimate min_eff_stake | ||
|
|
||
| The strategy needs to know the minimum stake required to be selected. It uses two sources: | ||
|
|
||
| - **Current election estimate** — emulates the Elector's selection algorithm on the participants who have already submitted stakes. Available only when enough participants are present. | ||
| - **Previous election data** — takes the smallest frozen stake from the last completed election. Cached per election round. | ||
|
|
||
| **Priority:** use the current election estimate when available. Fall back to previous election data only when the current estimate cannot be computed (not enough participants). If neither is available, the strategy skips the election with an error. | ||
|
|
||
| #### 3. Decide how much to stake | ||
|
|
||
| ``` | ||
| available = frozen_stake + free_pool_balance + current_stake | ||
| half = available / 2 | ||
| ``` | ||
|
|
||
| - **half >= min_eff_stake** — stake half. The other half is reserved for the next round. | ||
| - **half < min_eff_stake** — stake all free funds. Splitting is pointless because the remaining half would also be below the threshold. | ||
|
|
||
| **Guards:** | ||
|
|
||
| - If `free_pool_balance` is too low to cover the required stake, the strategy skips the election and logs an error. | ||
| - If `current_stake` already meets or exceeds `min_eff_stake`, no action is taken. | ||
|
|
||
| #### 4. Top up on subsequent ticks | ||
|
|
||
| On every tick after the initial submission, the strategy re-evaluates: | ||
|
|
||
| - If `min_eff_stake` has risen above `current_stake` (e.g. larger stakes arrived), it tops up by the difference. | ||
| - The same half-vs-all logic applies: if the remaining funds can't cover the next round, everything goes into the current one. | ||
|
|
||
| --- | ||
|
|
||
| ### Configuration | ||
|
|
||
| | Parameter | Type | Description | | ||
| |---|---|---| | ||
| | `sleep_period` | float (0.0–1.0) | Fraction of election duration to wait before acting. | | ||
| | `waiting_period` | float (0.0–1.0) | Max fraction of election duration to wait for participants. | | ||
|
|
||
| --- | ||
|
|
||
| ### Decision Flowchart | ||
|
|
||
| ``` | ||
| Election starts | ||
| │ | ||
| ▼ | ||
| Wait for sleep_period AND min_validators participants | ||
| │ | ||
| ├─ Both met ──► Emulate election → curr_min_eff | ||
| │ | ||
| └─ Timeout ───► curr_min_eff = None | ||
| │ | ||
| ▼ | ||
| Fetch prev_min_stake from past elections (cached) | ||
| │ | ||
| ▼ | ||
| min_eff_stake = curr_min_eff ?? prev_min_stake | ||
| │ | ||
| ├─ Neither available ──► Skip election (error) | ||
| │ | ||
| ▼ | ||
| half = available / 2 | ||
| │ | ||
| ├─ half >= min_eff_stake ──► Stake half | ||
| │ | ||
| └─ half < min_eff_stake ──► Stake all | ||
| │ | ||
| ▼ | ||
| ┌─ On every tick: ──────────────────────────────┐ | ||
| │ │ | ||
| │ Re-estimate min_eff_stake │ | ||
| │ │ | ||
| │ If min_eff_stake > current_stake → top up │ | ||
| │ │ | ||
| │ Apply same half-vs-all logic │ | ||
| └────────────────────────────────────────────────┘ | ||
| ``` |
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Configuration parameter validation only applies when the full ElectionsConfig is validated, but
sleep_period_pctandwaiting_period_pctare added to the config regardless of the selected stake policy. These parameters should only be required/validated when AdaptiveSplit50 strategy is in use. Consider documenting this design choice or conditionally validating these parameters only for AdaptiveSplit50 policy.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Skipped. Validating always is simpler and catches misconfigs early.