pub enum FeatureManagementInstruction {
Enable {
names: Vec<String>,
},
ScheduleEnable {
names: Vec<String>,
fire_at_ms: u64,
request_id: u64,
},
FireScheduledEnable {
request_id: u64,
},
Cancel {
request_id: u64,
},
UpdateAuthority {
new_authority: Pubkey,
},
ProposeAuthorityTransfer {
new_authority: Pubkey,
},
AcceptAuthorityTransfer,
CancelAuthorityTransfer,
}Expand description
Instructions supported by the Feature Management Program
Wire-stable from this commit forward. Borsh assigns each variant a
discriminant equal to its declaration index (the first byte on the wire),
so reordering variants or inserting one in the middle silently shifts the
discriminants of every following variant and breaks already-deployed
clients. From now on, add new variants only at the tail with the next
unused discriminant. The committed wire discriminants are pinned by the
discriminants_are_stable test below.
Variants§
Enable
Enable one or more features by name.
Idempotent: re-submitting an existing name is a no-op. Activation is
presence-based — a feature is active iff its name is in
FeaturesState.entries.
Per-batch cap: names.len() MUST be <= MAX_NAMES_PER_BATCH and each
name MUST satisfy validate_feature_name (which enforces
<= MAX_FEATURE_NAME_LENGTH and the allowed character set). The
MAX_NAMES_PER_BATCH × MAX_FEATURE_NAME_LENGTH payload is sized to
fit inside the ~64 KB transaction limit alongside headers and
signatures.
Accounts expected:
0. [writable] Storage account (PDA)
[signer]The authority account
Fields
ScheduleEnable
Schedule one or more features to be enabled at a future wall-clock time, rather than immediately.
The caller supplies request_id: it is the subscription nonce and the
Cancel handle. Because the subscription data account is a PDA derived
from the authority + request_id, the client must know the id ahead of
time to derive (and pass in) that account — so the id is chosen by the
caller rather than allocated on-chain. The program rejects a
request_id that already has a pending entry (with
RequestAlreadyExists).
Records a pending request in FeaturesState.pending keyed by
request_id, and registers a one-shot subscription (via the subscriber
program) with a fire_at_ms..u64::MAX timestamp_range predicate — it
fires on the first commit whose clock is at or after fire_at_ms (the
Rialo clock advances in coarse subdag steps, so a narrow window could
never match). When it fires, the subscription invokes this program’s own
FeatureManagementInstruction::FireScheduledEnable for request_id,
signed by the authority that scheduled it; that handler activates the
names recorded in pending[request_id] and removes the pending entry,
and the one-shot subscription then self-destroys.
Same per-batch / per-name caps as Enable (MAX_NAMES_PER_BATCH +
validate_feature_name), except MAX_FEATURE_COUNT is enforced at fire
time (in FireScheduledEnable), not at schedule time. fire_at_ms must
be in the future (rejected with ScheduleInPast) and within
MAX_SCHEDULE_HORIZON_MS of the current block time (rejected with
ScheduleTooFarOut). The pending set is bounded by MAX_PENDING_REQUESTS
(count) and by MAX_FEATURES_STATE_SIZE (bytes) — the byte cap is the
binding one for non-trivial batches and is rejected explicitly with
PendingStateTooLarge.
Stable across authority transfers. The subscription is created
under, and fires signed by, a program-derived scheduler authority
(get_scheduler_authority_address) — not the live human authority.
The subscription data account is a PDA of (scheduler_authority, request_id), so an UpdateAuthority / two-step accept between
schedule and cancel/fire does not orphan the pending entry: the
program can still derive the same subscription account, and the
matcher’s fired tx still satisfies FireScheduledEnable’s authority
check (signer == scheduler PDA, independent of the human authority).
Accounts expected:
0. [writable] Storage account (PDA)
[writable, signer]The authority account (pays rent for the subscription data account; the program top-ups the scheduler PDA just-in-time from the authority before the inner subscribe)[writable]Subscription data account (PDA from scheduler authority- request_id)
[]Subscriber program[]System program[writable]Scheduler authority PDA (get_scheduler_authority_address) — funded by the authority and used as the subscription’s subscriber/signer
Fields
FireScheduledEnable
Program-internal: fire a previously-scheduled
FeatureManagementInstruction::ScheduleEnable.
Not meant to be submitted by clients directly: it is registered as the
handler instruction of the one-shot subscription created by
ScheduleEnable, and is invoked when that subscription’s
timestamp_range predicate fires. When it fires it activates the names
recorded in pending[request_id] and removes that pending entry (so a
fired schedule no longer lingers in FeaturesState.pending). Signed by
the scheduling authority.
Rejected with RequestNotFound if no pending request has that id.
Accounts expected:
0. [writable] Storage account (PDA)
[signer]The authority account
Fields
Cancel
Cancel a previously-scheduled
FeatureManagementInstruction::ScheduleEnable by its request_id.
Removes the pending entry from FeaturesState.pending and destroys the
one-shot subscription so it never fires. Rejected with RequestNotFound
if no pending request has that id. Signed by the authority.
A schedule that has already fired is gone from pending (the one-shot
self-destructs), so cancelling it returns RequestNotFound — activation
is append-only and cannot be undone.
Accounts expected:
0. [writable] Storage account (PDA)
[signer]The authority account[writable]Subscription data account (PDA from scheduler authority- request_id)
[]Subscriber program[writable]Scheduler authority PDA — receives the destroyed subscription’s kelvins back via the inner unsubscribe
UpdateAuthority
Update the authority. Single-step path.
This instruction requires a valid signature from the current authority.
Accounts expected:
0. [writable] Storage account (PDA)
[signer]The current authority account
Fields
The new authority that will control the feature management system.
ProposeAuthorityTransfer
Step 1 of the two-step authority handshake: propose a transfer.
Sets pending_authority = Some(new_authority). Rejected with
PendingTransferExists if a previous proposal is still outstanding;
rejected with InvalidTransferTarget if new_authority equals the
current authority.
Accounts expected:
0. [writable] Storage account (PDA)
[signer]The current authority
Fields
Pubkey that will become the next authority once it signs an
AcceptAuthorityTransfer against this pending value.
AcceptAuthorityTransfer
Step 2 of the two-step authority handshake: commit a previously proposed transfer.
Requires the pending authority’s signature. On success the
authority field moves to the pending value and pending_authority
clears. Rejected with NoPendingTransfer if nothing is pending,
Unauthorized if the signer is not the pending authority.
Accounts expected:
0. [writable] Storage account (PDA)
[signer]The pending authority
CancelAuthorityTransfer
Cancel a previously proposed authority transfer.
Requires the current authority’s signature. Clears
pending_authority. Rejected with NoPendingTransfer if nothing
is pending.
Accounts expected:
0. [writable] Storage account (PDA)
[signer]The current authority
Implementations§
Trait Implementations§
Source§impl BorshDeserialize for FeatureManagementInstruction
impl BorshDeserialize for FeatureManagementInstruction
fn deserialize_reader<__R: Read>(reader: &mut __R) -> Result<Self, Error>
Source§fn deserialize(buf: &mut &[u8]) -> Result<Self, Error>
fn deserialize(buf: &mut &[u8]) -> Result<Self, Error>
Source§fn try_from_slice(v: &[u8]) -> Result<Self, Error>
fn try_from_slice(v: &[u8]) -> Result<Self, Error>
fn try_from_reader<R>(reader: &mut R) -> Result<Self, Error>where
R: Read,
Source§impl Clone for FeatureManagementInstruction
impl Clone for FeatureManagementInstruction
Source§fn clone(&self) -> FeatureManagementInstruction
fn clone(&self) -> FeatureManagementInstruction
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for FeatureManagementInstruction
impl Debug for FeatureManagementInstruction
impl Eq for FeatureManagementInstruction
Source§impl PartialEq for FeatureManagementInstruction
impl PartialEq for FeatureManagementInstruction
Source§fn eq(&self, other: &FeatureManagementInstruction) -> bool
fn eq(&self, other: &FeatureManagementInstruction) -> bool
self and other values to be equal, and is used by ==.