Skip to content

Feature/sma 55 add cli commands for adaptive staking parameters#128

Merged
mrnkslv merged 15 commits into
release/nodectl/v0.5.0from
feature/sma-55-add-cli-commands-for-adaptive-staking-parameters
May 15, 2026
Merged

Feature/sma 55 add cli commands for adaptive staking parameters#128
mrnkslv merged 15 commits into
release/nodectl/v0.5.0from
feature/sma-55-add-cli-commands-for-adaptive-staking-parameters

Conversation

@mrnkslv
Copy link
Copy Markdown
Contributor

@mrnkslv mrnkslv commented Apr 30, 2026

Summary

  • Adaptive staking CLI — extend nodectl config elections and related service wiring so adaptive staking parameters can be managed from the CLI, with README updates and small app_config adjustments.
  • Validator deposit amount — align TONCore deposit-validator with the pool’s fixed 1 TON processing fee (outbound message value = stake + fee), document it, and centralize the fee constant in contract message helpers.
  • Undeployed TONCore pools — treat uninitialized / missing contracts as not deployed instead of a generic error, merge slot init params from local config into pool list DTOs when chain data is absent, add --validator-share-percent (human-friendly percents vs basis points), refresh table/JSON display and tests, and document config pool ls behavior.

Changes

  • commands: config_elections_cmd (adaptive staking), service_api_cmd, config_pool_cmd (deposit math, --validator-share-percent, pool list state styling, serde defaults where needed).
  • service: config_handlers / config_handlers_tests (TONCore pool slots: RPC + config merge, not deployed state), http_server_task (routes/handlers for adaptive elections API).
  • contracts: nominator/messages.rs — fee constant and deposit message value semantics.
  • common: app_config.rs — minor tweak tied to elections/config flow.
  • README: elections adaptive usage, deposit-validator fee note, TONCore pool add (validator-share-percent) and pool ls (not deployed + config fallbacks).

Copilot AI review requested due to automatic review settings April 30, 2026 08:42
@linear
Copy link
Copy Markdown

linear Bot commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Extends node-control’s CLI and service API to manage adaptive staking/elections timing parameters, improves TONCore pool slot status handling when chain/RPC data is missing, and aligns TONCore validator deposit behavior with the pool’s fixed 1 TON processing fee while documenting the semantics.

Changes:

  • Add sleep_period_pct / waiting_period_pct support to elections settings API + CLI commands, including validation and tests.
  • Improve TONCore pool slot listing to treat uninitialized accounts as “not deployed” and merge deploy params from local config when on-chain reads fail.
  • Centralize TONCore deposit_validator fixed fee constant and update CLI deposit message value calculation + documentation.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/node-control/service/src/http/http_server_task.rs Adds HTTP route tests for adaptive elections timing validation and updates.
src/node-control/service/src/http/config_handlers_tests.rs Updates pool slot tests to expect config fallback deploy params in responses.
src/node-control/service/src/http/config_handlers.rs Implements TONCore slot state improvements + config fallback merge; adds elections timing fields to settings DTO/update flow.
src/node-control/contracts/src/nominator/messages.rs Introduces a shared constant for TONCore validator deposit fixed fee and documents message value semantics.
src/node-control/common/src/app_config.rs Makes elections timing validation callable across crates for API-side validation.
src/node-control/commands/src/commands/nodectl/service_api_cmd.rs Extends client-side elections settings update payload to include adaptive timing fields.
src/node-control/commands/src/commands/nodectl/config_pool_cmd.rs Adds --validator-share-percent, adjusts TONCore slot state display, and fixes validator deposit message value to include the fixed fee.
src/node-control/commands/src/commands/nodectl/config_elections_cmd.rs Adds CLI commands to set adaptive sleep/wait timing fractions and displays them in show.
src/node-control/README.md Documents new elections CLI flags and TONCore deposit fee semantics; updates pool add/ls behavior docs.
Comments suppressed due to low confidence (1)

src/node-control/commands/src/commands/nodectl/config_pool_cmd.rs:532

  • display_toncore_slot_row() can return the literal "not deployed" which is longer than the {:<10} width used for the "State" column in the TONCore table. This will misalign the table output once undeployed slots are shown. Consider either widening the State column formatting, or shortening the displayed label (e.g. "not-deployed") so the table stays aligned.
        for s in slots {
            let display_addr = display_ton_address(s.address.as_deref());
            let display_state = display_toncore_slot_row(s);
            let display_balance =
                s.balance.map(|b| display_tons(b).white()).unwrap_or_else(|| "-".red());
            let noms = match (s.nominators_count, s.max_nominators) {
                (Some(n), Some(m)) => format!("{n}/{m}"),

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@mrnkslv mrnkslv requested a review from Keshoid May 1, 2026 11:37
Copy link
Copy Markdown
Contributor

@Keshoid Keshoid left a comment

Choose a reason for hiding this comment

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

PR review — 6 issues found (details in inline comments).

Comment thread src/node-control/commands/src/commands/nodectl/config_elections_cmd.rs Outdated
Comment thread src/node-control/service/src/http/config_handlers.rs
Comment thread src/node-control/commands/src/commands/nodectl/config_elections_cmd.rs Outdated
Comment thread src/node-control/commands/src/commands/nodectl/config_elections_cmd.rs Outdated
Comment thread src/node-control/commands/src/commands/nodectl/config_pool_cmd.rs Outdated
Comment thread src/node-control/commands/src/commands/nodectl/config_elections_cmd.rs Outdated
Copy link
Copy Markdown
Contributor

@Keshoid Keshoid left a comment

Choose a reason for hiding this comment

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

Review of code quality / Rust idiom. Most are cleanup; (1) and (3) are the two I'd want addressed before merge.

Comment thread src/node-control/commands/src/commands/nodectl/config_elections_cmd.rs Outdated
Comment thread src/node-control/commands/src/commands/nodectl/config_elections_cmd.rs Outdated
Comment thread src/node-control/service/src/http/config_handlers.rs Outdated
Comment thread src/node-control/service/src/http/config_handlers.rs Outdated
Comment thread src/node-control/service/src/http/config_handlers.rs
Comment thread src/node-control/commands/src/commands/nodectl/config_pool_cmd.rs
Comment thread src/node-control/commands/src/commands/nodectl/config_pool_cmd.rs Outdated
Comment thread src/node-control/service/src/http/config_handlers_tests.rs
Comment thread src/node-control/common/src/app_config.rs Outdated
Comment thread src/node-control/commands/src/commands/nodectl/config_pool_cmd.rs
Comment thread src/node-control/commands/src/commands/nodectl/config_elections_cmd.rs Outdated
Copy link
Copy Markdown
Contributor

@Keshoid Keshoid left a comment

Choose a reason for hiding this comment

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

Second pass — three issues plus two minor wording nits. (1) is a real display bug Copilot flagged in the first round but never got addressed.

Comment thread src/node-control/commands/src/commands/nodectl/config_pool_cmd.rs
Comment thread src/node-control/commands/src/commands/nodectl/config_pool_cmd.rs
Comment thread src/node-control/commands/src/commands/nodectl/config_elections_cmd.rs Outdated
Comment thread src/node-control/commands/src/commands/nodectl/config_pool_cmd.rs Outdated
Comment thread src/node-control/commands/src/commands/nodectl/config_pool_cmd.rs Outdated
mrnkslv and others added 2 commits May 14, 2026 15:39
Resolve conflicts: combine elections adaptive settings with automation/voting
handlers and REST docs; merge HTTP integration tests in order.

Co-authored-by: Cursor <cursoragent@cursor.com>
@mrnkslv mrnkslv added run-e2e and removed run-e2e labels May 14, 2026
Copy link
Copy Markdown
Contributor

@Keshoid Keshoid left a comment

Choose a reason for hiding this comment

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

Rust idiom pass — three narrow API/style nits on the new code, all easy fixes.

}
}

fn from_wire(s: &str) -> Result<Self, ()> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Result<Self, ()>Option<Self>.

() as the error variant is meaningless — there's no information to convey beyond "it failed". The sole caller (deserialize_toncore_pool_slot_wire_state) immediately discards it with .map_err(|_| de::Error::custom(...)), which is the standard tell that the unit error is dead weight.

The idiomatic shape is Option<Self>:

fn from_wire(s: &str) -> Option<Self> {
    Some(match s {
        "" | "not deployed" => Self::NotDeployed,
        "active" => Self::Active,
        "frozen" => Self::Frozen,
        "error" => Self::Error,
        _ => return None,
    })
}

Caller becomes:

TonCorePoolSlotWireState::from_wire(&s)
    .ok_or_else(|| de::Error::custom(format!("unknown TONCore pool slot state: {s:?}")))

Drops one Result layer for no information loss.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Error,
}

impl Default for TonCorePoolSlotWireState {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The whole Default + Serialize + custom deserializer block (~40 lines) collapses to a 6-line derive.

Since Rust 1.62, #[derive(Default)] works on enums via #[default] on a variant. And serde handles "not deployed" (with the space) via #[serde(rename = ...)]:

#[derive(
    Clone, Copy, Debug, Default, PartialEq, Eq,
    serde::Serialize, serde::Deserialize,
)]
#[serde(rename_all = "lowercase")]
enum TonCorePoolSlotWireState {
    #[serde(rename = "not deployed")]
    #[default]
    NotDeployed,
    Active,
    Frozen,
    Error,
}

Then on the field:

#[serde(default)]
state: TonCorePoolSlotWireState,

Drops impl Default, the custom Serialize impl, as_wire / from_wire helpers, and deserialize_toncore_pool_slot_wire_state. The only behavior you lose is the "" → NotDeployed fallback, which is defensive coding for a case the server never produces (it always serializes one of the four wire strings). If you want to keep that, #[serde(alias = "")] on NotDeployed brings it back in one line.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

/// to **`< 10_000`**: a 100 % validator share would leave nominators with no
/// pool rewards, which is almost always operator error rather than intent.
fn validate_validator_share_bp(bp: u16) -> anyhow::Result<u16> {
anyhow::ensure!(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

First ensure! is subsumed by the second.

bp != 10_000 accepts everything in 0..10_000 ∪ 10_001..=u16::MAX, then bp < 10_000 accepts only 0..10_000. Anything the first rejects (bp == 10_000) the second also rejects — so the first guard only exists for a friendlier error message at that specific value, which is fine intent but reads as dead validation on first scan.

A single match makes the intent obvious and drops one branch:

fn validate_validator_share_bp(bp: u16) -> anyhow::Result<u16> {
    match bp {
        10_000 => anyhow::bail!(
            "--validator-share 10000 bp is 100%: nominators would receive no pool rewards — use a value below 10000 bp"
        ),
        bp if bp > 10_000 => anyhow::bail!(
            "validator_share must be in 0..10000 basis points (<100%; got {bp})"
        ),
        bp => Ok(bp),
    }
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

@mrnkslv mrnkslv added run-e2e and removed run-e2e labels May 15, 2026
@mrnkslv mrnkslv merged commit 72c32e2 into release/nodectl/v0.5.0 May 15, 2026
6 of 8 checks passed
@mrnkslv mrnkslv deleted the feature/sma-55-add-cli-commands-for-adaptive-staking-parameters branch May 15, 2026 11:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants