-
Notifications
You must be signed in to change notification settings - Fork 98
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a85a0da
commit ac13e7e
Showing
1 changed file
with
243 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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,243 @@ | ||
--- | ||
simd: '0077' | ||
title: Programify Feature Gate Program | ||
authors: | ||
- Joe Caulfield | ||
- Tyera Eulberg | ||
category: Standard | ||
type: Core | ||
status: Draft | ||
created: 2023-10-26 | ||
feature: #33547 | ||
supercedes: 0072 | ||
--- | ||
|
||
## Summary | ||
|
||
### Roadmap | ||
|
||
This is SIMD 1/3 required for **Multi-Client Feature Gates**. See | ||
<https://github.com/solana-foundation/solana-improvement-documents/issues/76> | ||
|
||
**Goals:** | ||
|
||
- Decentralized control over queuing new runtime features | ||
- Automatic feature activation selection based on stake weight with supporting | ||
software | ||
- Decentralized governance of the mechanism itself | ||
|
||
**Resulting Architecture:** | ||
|
||
1. 👉 **Feature Creation:** Features can be created by anyone. Each is owned by | ||
an upgradeable BPF program at `Feature111111111111111111111111111111111111` | ||
2. **Feature Queuing:** A governance process nominates features that should be | ||
queued for activation | ||
3. **Feature Recognition & Activation:** Features are activated based on stake | ||
support of nodes who recognize the feature in their software version | ||
|
||
### Proposal | ||
|
||
This SIMD outlines a proposal to replace the non-existent system account at | ||
address `Feature111111111111111111111111111111111111`, which is the owner of | ||
all feature accounts, with an upgradeable BPF program. | ||
|
||
It defines the program's initial functionality - which consists solely of the | ||
capability to revoke pending feature activations - and an accompanying | ||
governance system for managing upgrades of the program. | ||
|
||
Important note: the process by which core contributors *activate* features | ||
would remain completely unchanged by this SIMD. | ||
|
||
## Motivation | ||
|
||
Sometimes, a feature that has been queued for activation may need to be | ||
revoked. For numerous reasons, a pending feature could suddenly become unsafe | ||
or otherwise non-desirable. The ability to revoke these pending features is | ||
paramount to secure, frictionless engineering processes and protecting the | ||
network’s stability. | ||
|
||
The best way to manage such a capability is to ensure all feature accounts are | ||
owned by a program, which has the authority to clear a feature account’s data | ||
and remove its lamports, effectively revoking it from activation. | ||
|
||
Such a program surely presents a security risk if the upgrade authority is not | ||
carefully handled, so a proper governance process is required for this program | ||
to exist. | ||
|
||
## Alternatives Considered | ||
|
||
At this time, core contributors have not considered any viable alternative | ||
solutions for enabling the ability to revoke pending feature activations. An | ||
on-chain program was decided to be the optimally viable solution. Suggestions | ||
are welcome. | ||
|
||
## New Terminology | ||
|
||
- Feature Gate program: The BPF program that will own all feature accounts. | ||
- “Revoke” or “revoke pending activation”: The act of reallocating a feature | ||
account’s data to zero, assigning it to the system program, and defunding | ||
its lamports balance - effectively removing it from the runtime’s recognized | ||
set of features pending activation. | ||
|
||
## Detailed Design | ||
|
||
Currently, when a core contributor wishes to add a runtime feature to the | ||
Solana runtime codebase, they are instructed to generate a new key pair, as | ||
described in the instructions linked below. | ||
|
||
<https://github.com/solana-labs/solana/blob/f4287d70bb78307f16949509e013fb5e6f15a751/sdk/src/feature_set.rs#L3-L17> | ||
|
||
The contributor then places the code required for the runtime to activate the | ||
feature behind a “feature gate” using the public key of the key pair. The | ||
feature gate allows the runtime to check to make sure a specific account exists | ||
at the address provided for the Feature ID before activating the feature with | ||
the contributor’s code. | ||
An example can be found at the link below: | ||
|
||
<https://github.com/solana-labs/solana/blob/f4287d70bb78307f16949509e013fb5e6f15a751/runtime/src/bank.rs#L7885-L7889> | ||
|
||
When the network reaches 95% of stake running the particular version of the | ||
Solana runtime software containing the feature, and core contributors have | ||
authorized the activation, the feature can be activated using the keypair and | ||
the CLI command `solana feature activate`. | ||
|
||
This command will use the keypair to authorize a transaction that will allocate | ||
the necessary data and assign it under owner | ||
`Feature111111111111111111111111111111111111`. This account at | ||
`Feature111111111111111111111111111111111111` does not exist, but is instead | ||
used as a special address that is known to the Solana SDK. After this process | ||
completes, the feature is scheduled for activation and will be activated at the | ||
next epoch boundary. | ||
|
||
### Deploying the Program | ||
|
||
In order to deploy an upgradeable BPF program to the address at | ||
`Feature111111111111111111111111111111111111`, a runtime change is required. | ||
This change would allow the runtime, upon feature activation, to move an | ||
already deployed upgradeable BPF program in place of the non-existent | ||
`Feature111111111111111111111111111111111111`. | ||
|
||
For maximum security, the intial program that will be deployed and then moved | ||
in place of `Feature111111111111111111111111111111111111` will be a no-op | ||
program with an intentionally large allocation (to allow for larger programs | ||
in the future). | ||
|
||
Shortly after verifying this program was successfully moved into place, the | ||
program will be upgraded to contain Feature Gate Program v0.1.0 - which will | ||
include the "revoke functionality defined below. | ||
|
||
The specific no-op program that will be initially deployed and moved by the | ||
runtime has been verifiably built and deployed to devent, testnet, and | ||
mainnet-beta. It can be found in the repository linked below. | ||
|
||
<https://github.com/buffalojoec/noop-programs/tree/main/programs/feature-gate-noop> | ||
|
||
The runtime change to perform this account replacement can be found in the pull | ||
request linked below. | ||
|
||
<https://github.com/solana-labs/solana/pull/32783> | ||
|
||
The feature tracking issue for this change can be found here: | ||
|
||
<https://github.com/solana-labs/solana/issues/33547> | ||
|
||
### Revoking Pending Features | ||
|
||
As mentioned above under “New Terminology”, the act of revoking a pending | ||
feature activation consists of reallocating a feature account’s data to zero, | ||
assigning it to the system program, and defunding its lamports balance. This | ||
causes the feature account to be “revoked” since the runtime will no longer | ||
detect it as an account owned by `Feature11111`. | ||
|
||
When a core contributor executes the `solana feature activate` command, a | ||
signature from the feature key pair is required to activate it, since its state | ||
will change. Similarly, we can require the same feature key pair’s signature to | ||
revoke said feature. | ||
|
||
Consider the instruction as it would appear in the Feature Gate Program: | ||
|
||
```rust | ||
pub enum FeatureGateInstruction { | ||
/// Revoke a pending feature activation. | ||
/// | ||
/// A "pending" feature activation is a feature account that has been | ||
/// allocated and assigned, but hasn't yet been updated by the runtime | ||
/// with an `activation_slot`. | ||
/// | ||
/// Features that _have_ been activated by the runtime cannot be revoked. | ||
/// | ||
/// Accounts expected by this instruction: | ||
/// | ||
/// 0. `[w+s]` Feature account | ||
/// 1. `[w]` Destination (for rent lamports) | ||
RevokePendingActivation, | ||
} | ||
``` | ||
|
||
When this instruction is invoked with the proper signature, the feature account | ||
would be reallocated, defunded, and returned to the System Program, like so: | ||
|
||
```rust | ||
/* Checks */ | ||
|
||
let new_destination_lamports = feature_info | ||
.lamports() | ||
.checked_add(destination_info.lamports()) | ||
.ok_or::<ProgramError>(FeatureGateError::Overflow.into())?; | ||
|
||
**feature_info.try_borrow_mut_lamports()? = 0; | ||
**destination_info.try_borrow_mut_lamports()? = new_destination_lamports; | ||
|
||
feature_info.realloc(0, true)?; | ||
feature_info.assign(&system_program::id()); | ||
``` | ||
|
||
### Governing the Program Upgrades | ||
|
||
Upgrading the Feature Gate program will be controlled by a 2-of-3 | ||
multi-signature authority, consisting of key-holders distributed across network | ||
participants. | ||
|
||
- Solana Labs: 1 key-holder | ||
- Jump: 1 key-holder | ||
- Jito: 1 key-holder | ||
|
||
Only when 2 out of 3 key-holders have authorized an upgrade will the Feature | ||
Gate program be upgraded. | ||
|
||
**Note:** This includes the upgrade required to upgrade the initial no-op | ||
program to Feature Gate Program v0.1.0. | ||
|
||
## Impact | ||
|
||
Core contributors are positively impacted by this change, since the ability to | ||
revoke pending feature activations is a significant security advantage. | ||
|
||
However, anyone in the community - validators, developers, etc. - who *is not* | ||
satisfied with the governance system outlined in this proposal may be | ||
emotionally impacted and/or feel there is a risk of centralized authority | ||
around a piece of vital runtime functionality. | ||
|
||
## Security Considerations | ||
|
||
Currently the accounts used for feature-gating are owned by an account that | ||
does not exists. This means that there’s no on-chain authority that can modify | ||
feature accounts once they’ve been created. This allows the runtime to | ||
confidently update their state upon activation. | ||
|
||
With this proposal, a live BPF program - which can accept instructions from | ||
anyone and execute code - will be the owner of these accounts. Surely this | ||
provides significant risk if *both* the program’s processor code *and* its | ||
upgrade authority are not properly managed. | ||
|
||
With that being said, thoroughly reviewed and safe processor code, as well as | ||
a robust governance system for upgrading the program, will together mitigate | ||
these new risks as much as possible. | ||
|
||
## Backwards Compatibility | ||
|
||
As mentioned under "Summary", the process by which core contributors *activate* | ||
features would remain completely unchanged by this SIMD. | ||
|
||
This SIMD only *adds* the capability to revoke pending activations, so it's | ||
completely backwards compatible. |