rialo-feature-management-program-interface 0.12.0

Rialo Feature Management Program Interface
Documentation
// Copyright (c) Subzero Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

//! Compile-time feature registry namespace.
//!
//! This module owns the `features` namespace: each feature name the runtime
//! understands is declared here as a `pub const &'static str` handle, and
//! `KNOWN_FEATURES` lists every one of them.
//!
//! Sibling tables (e.g. the builtin-upgrade registry, the compute-budget gating
//! table) carry their own compile-time assertions that every `feature_name`
//! they reference is a member of `KNOWN_FEATURES`.

/// Enables the `StakeInfo` schema version 2 on-disk layout.
///
/// While active, the bank-level `native-staking` writers — genesis self-bond
/// and epoch-reward compounding — emit the V2 stake-account format; before
/// activation they emit V1. The instruction-handler write path
/// (`write_stake_info`) runs inside the program runtime, which sees the Solana
/// `feature_set` rather than this runtime `ActiveFeatures` flag, so it keeps
/// emitting V1 for now; the versioned reader decodes both, so V1 and V2
/// records coexist. (The V2-only field `last_reward_slot` has no consumer yet,
/// so a handler rewriting a V2 record back to V1 is currently lossless in
/// practice; feature-aware handler emission lands with that consumer.)
/// Append-only: like all feature activation this cannot be reversed, and once
/// any account has been written in the new format the storage-format bump is
/// effectively permanent. This is the worked example for the writer-gated
/// storage-format migration template.
pub const ENABLE_STAKE_INFO_V2: &str = "ENABLE_STAKE_INFO_V2";

// ---------------------------------------------------------------------------
// Test-only protocol-upgrade demonstrators.
//
// The seven `TEST_*` handles below gate the end-to-end protocol-upgrade
// demonstrators (the `test-upgrade` builtin's V1/V2 lineage, the
// `rlo_test_gated` syscall, and a standalone scheduled-activation target).
// They are members of `KNOWN_FEATURES` so the runtime, deploy-time import
// check, and builtin-upgrade registry recognise them — but **nothing Upserts
// them in production**, so the gated handlers, builtin versions, and syscall
// binding ship as inert dead code. A managed test network opts in by
// `Enable`-ing them, which is how the `scripts/test/rialo-cli-tests`
// feature-upgrade suite drives every upgrade surface against a live node.
// ---------------------------------------------------------------------------

/// Enables version 1 (the baseline) of the `test-upgrade` demonstrator builtin.
///
/// Until active, the demonstrator program is unregistered and uncallable. Once
/// active, version 0 of the builtin (handling `Increment`) registers via the
/// `ACTIVE_FEATURE_BUILTINS` table in `svm-execution`.
pub const TEST_UPGRADE_BUILTIN_V1: &str = "TEST_UPGRADE_BUILTIN_V1";

/// Enables version 2 of the `test-upgrade` demonstrator builtin.
///
/// Activation swaps the builtin entrypoint to V2, which adds the `IncrementBy`
/// instruction, soft-deprecates `Increment`, and lazily migrates the storage
/// account from the V1 to the V2 on-disk layout on the next write.
pub const TEST_UPGRADE_BUILTIN_V2: &str = "TEST_UPGRADE_BUILTIN_V2";

/// Enables the `rlo_test_gated` system call at link time.
///
/// While inactive, a RISC-V program importing the syscall is rejected at deploy
/// (the import is known-but-gated-off) and would fail to link; once active the
/// import binds and the call succeeds. `rlo_test_gated` ships in the release
/// binary (it is the production-resident, `KNOWN_FEATURES`-registered gated
/// demonstrator), but nothing activates this feature in production.
pub const TEST_GATED_SYSCALL: &str = "TEST_GATED_SYSCALL";

/// Standalone target for the scheduled-activation demonstrator.
///
/// Gates no runtime behaviour; the scheduled-activation CLI test `ScheduleEnable`s
/// it and observes the timed `Scheduled` → `Active` transition (and the drained
/// pending entry) to confirm the one-shot scheduler fires.
pub const TEST_SCHEDULED: &str = "TEST_SCHEDULED";

/// Probe features for the authority-transfer demonstrator. Gate no runtime
/// behaviour; the authority-transfer CLI test enables them to prove that a
/// feature can be activated before/after an authority transfer (and that the
/// old authority can no longer activate features after the transfer).
pub const TEST_AUTHORITY_PROBE_1: &str = "TEST_AUTHORITY_PROBE_1";
/// See [`TEST_AUTHORITY_PROBE_1`].
pub const TEST_AUTHORITY_PROBE_2: &str = "TEST_AUTHORITY_PROBE_2";

/// Target for the schedule-cancellation demonstrator. Gates no runtime
/// behaviour; the test `ScheduleEnable`s it, then `Cancel`s the pending request
/// and confirms it never activates. Registered (like the others) so that, were
/// the cancel to fail and the schedule to fire, the resulting active set would
/// still be a subset of `KNOWN_FEATURES` and not halt the node.
pub const TEST_SCHEDULED_CANCEL: &str = "TEST_SCHEDULED_CANCEL";

/// Every feature name the runtime knows about.
///
/// Hot-path gating sites reference entries through the `pub const &'static str`
/// handles declared in this module. The slice itself exists so that:
///
/// * tooling can enumerate the registry,
/// * compile-time assertions on sibling tables (e.g. builtin upgrade registry,
///   compute-budget gating table) can verify that every referenced
///   `feature_name` is known.
pub const KNOWN_FEATURES: &[&str] = &[
    ENABLE_STAKE_INFO_V2,
    TEST_UPGRADE_BUILTIN_V1,
    TEST_UPGRADE_BUILTIN_V2,
    TEST_GATED_SYSCALL,
    TEST_SCHEDULED,
    TEST_AUTHORITY_PROBE_1,
    TEST_AUTHORITY_PROBE_2,
    TEST_SCHEDULED_CANCEL,
];

/// Const-evaluable string equality.
///
/// `==` on `&str` is not usable in `const fn` on stable, so sibling registry
/// tables in other crates (e.g. the builtin-upgrade and storage-format
/// writer-gate registries in `svm-execution`) compose this byte-compare into
/// their own compile-time assertions instead of each carrying a private copy.
pub const fn const_str_eq(a: &str, b: &str) -> bool {
    let a = a.as_bytes();
    let b = b.as_bytes();
    if a.len() != b.len() {
        return false;
    }
    let mut i = 0;
    while i < a.len() {
        if a[i] != b[i] {
            return false;
        }
        i += 1;
    }
    true
}

const fn const_slice_contains(haystack: &[&str], needle: &str) -> bool {
    let mut i = 0;
    while i < haystack.len() {
        if const_str_eq(haystack[i], needle) {
            return true;
        }
        i += 1;
    }
    false
}

/// Returns `true` if `name` appears in [`KNOWN_FEATURES`].
///
/// Const-evaluable so sibling tables in other crates (e.g. the compute-budget
/// gating table in `svm-execution`) can assert at compile time that every
/// feature name they reference is known to the runtime.
pub const fn is_known_feature(name: &str) -> bool {
    const_slice_contains(KNOWN_FEATURES, name)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn const_str_eq_matches() {
        assert!(const_str_eq("foo", "foo"));
        assert!(!const_str_eq("foo", "bar"));
        assert!(!const_str_eq("foo", "foobar"));
    }

    #[test]
    fn const_slice_contains_matches() {
        let s: &[&str] = &["a", "b", "c"];
        assert!(const_slice_contains(s, "b"));
        assert!(!const_slice_contains(s, "z"));
    }

    #[test]
    fn is_known_feature_matches() {
        assert!(is_known_feature(ENABLE_STAKE_INFO_V2));
        assert!(!is_known_feature("definitely_not_a_real_feature"));
    }

    #[test]
    fn test_upgrade_demonstrator_features_are_known() {
        for f in [
            TEST_UPGRADE_BUILTIN_V1,
            TEST_UPGRADE_BUILTIN_V2,
            TEST_GATED_SYSCALL,
            TEST_SCHEDULED,
            TEST_AUTHORITY_PROBE_1,
            TEST_AUTHORITY_PROBE_2,
            TEST_SCHEDULED_CANCEL,
        ] {
            assert!(is_known_feature(f), "{f} must be a known feature");
            assert!(
                crate::validate_feature_name(f),
                "{f} must be a valid feature name"
            );
        }
    }
}