# SVM Series 02: SVM Feature Activation & Management

## What are features?

Feature activation refers to a community-governed process for enabling new non-controversial network primitives on the Solana network through validator voting based on **stake weight**. An example of this is [SIMD 220](https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0220-snapshots-use-accounts-lattice-hash.md) which improves validator performance by using Accounts Lattice Hash for snapshots instead of the Merkle-based account hash.

SPL tokens that represent the total active stake on the network are minted and distributed to all validtors based on their stake. Validators then transfer their vote tokens to a certain predetermined address, in the case of SIMD 220 address [LTsNA...3mSQ2](https://explorer.solana.com/address/LTsNAP8h1voEVVToMNBNqoiNQex4aqfUrbFhRH3mSQ2) on mainnet-beta. Once vote threshold is met the feature is activated at the beginning of a predetermined epoch. The built-in `Feature` program present in all validators is responsible for activating new features simultaneously to avoid hard forks that break consensus.

## Feature proposal

A feature proposal is added to the code base using a `feature id`. Feature IDs can be accessed using the [agave-feature-set](https://crates.io/crates/agave-feature-set) Rust crate. The feature ID is generated in the following steps:

1. Create a Solana keypair for the proposal
    
    ```sh
    solana-keygen new --outfile <feature-proposal-name>.json --silent --no-passphrase
    ```
    
2. Install the (note you need `libudev` installed) and then run
    
    ```sh
    # install spl-feature-proposal-cli
    $ cargo install spl-feature-proposal-cli --git https://github.com/solana-program/feature-proposal.git
    
    # Derive the feature ID
    $ spl-feature-proposal address feature-proposal.json
    ```
    
    Deriving the `feature ID` prints the details; example:
    
    ```sh
    Feature Id: AMJPdBjeCf1694FJcGsYNsGZaXogXuSVRVUVTAX28PEi
    Token Mint Address: 3vYBgFztMaEPByNsk8acEjfjLauswW46hm2ZuMkh3WFy
    Acceptance Token Address: EhfPUgpY4sKPqy8i488cXGxwKwMQ7YcMa5CMMHyzn6w9
    ```
    
    where: `Feature Id:` is the identifier added to the code base for that feature and is also retrieved by `solana feature status` subcommand of the `solana` command line tool. Note that only the `feature proposal program` can activate this feature since there is no private key for the address identified by the `Feature id`.
    
3. Initializing the feature - This is only possible after the feature is deployed to a Solana cluster (devnet, testnet or mainnet-beta). Note that features are first deployed to `testnet` cluster. Running `solana feature status` should show this feature's ID.
    
    ```bash
    # Example from Solana docs. Running this mints SPL tokens for the feature proposal and the 
    # `feature proposer` is required to finance creating all the 
    # SPL token accounts (about 0.00204 SOL per account) for all validators
    $ spl-feature-proposal propose feature-proposal.
    ```
    
    ```bash
    # The output of the above command example from Solana docs
    Feature Id: HQ3baDfNU7WKCyWvtMYZmi51YPs7vhSiLn1ESYp3jhiA
    Token Mint Address: ALvA7Lv9jbo8JFhxqnRpjWWuR3aD12uCb5KBJst4uc3d 
    Distributor Token Address: GK55hNft4TGc3Hg4KzbjEmju8VfaNuXK8jQNDTZKcsNF 
    Acceptance Token Address: AdqKm3mSJf8AtTWjfpA5ZbJszWQPcwyLA2XkRyLbf3Di 
    Number of validators: 376 
    Tokens to be minted: 134575791.53064314 
    Tokens required for acceptance: 90165780.3255309 (67%) 
    Token distribution file: feature-proposal.csv 
    JSON RPC URL: http://api.mainnet-beta.solana.com
    
    Distribute the proposal tokens to all validators by running: 
        $ solana-tokens distribute-spl-tokens --from GK55hNft4TGc3Hg4KzbjEmju8VfaNuXK8jQNDTZKcsNF --input-csv feature-proposal.csv --db-path db.8CyUVvio --fee-payer ~/.config/solana/id.json --owner <FEATURE_PROPOSAL_KEYPAIR> 
        $ solana-tokens spl-token-balances --mint ALvA7Lv9jbo8JFhxqnRpjWWuR3aD12uCb5KBJst4uc3d --input-csv feature-proposal.csv
    
    Once the distribution is complete, request validators vote for the proposal. To vote, validators should first look up their token account address: 
        $ spl-token --owner ~/validator-keypair.json accounts ALvA7Lv9jbo8JFhxqnRpjWWuR3aD12uCb5KBJst4uc3d 
    and then submit their vote by running: 
        $ spl-token --owner ~/validator-keypair.json transfer <TOKEN_ACCOUNT_ADDRESS> ALL AdqKm3mSJf8AtTWjfpA5ZbJszWQPcwyLA2XkRyLbf3Di
    
    Periodically the votes must be tallied by running: 
        $ spl-feature-proposal tally 8CyUVvio2oYAP28ZkMBPHq88ikhRgWet6i4NYsCW5Cxa
    Tallying is permissionless and may be run by anybody.
    Once this feature proposal is accepted, the HQ3baDfNU7WKCyWvtMYZmi51YPs7vhSiLn1ESYp3jhiA feature will be activated at the next epoch.
    
    Add --confirm flag to initiate the feature proposal
    ```
    
4. Tally the votes - anyone can tally the votes to enable the feature to be automatically activated at the start of the next epoch
    
    ```bash
     $ spl-feature-proposal tally
    ```
    

## Using features in SVM API

In this series we will use a mock `Bank` to coordinate the SVM execution pipeline. The [agave-feature-set](https://crates.io/crates/agave-feature-set) Rust crate will be used to activate features for transaction processing.

### FeatureSet struct

Feature set is defined by the struct `FeatureSet` which contains a list of activated features in the `active` field and deactivated features in the `inactive` field.

```rust
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct FeatureSet {
    active: AHashMap<Pubkey, u64>,
    inactive: AHashSet<Pubkey>,
}
```

### Default implementation for FeatureSet struct

Instantiating the `FeatureSet` struct using default method `FeatureSet::default()` makes all features inactive.

```rust

// Default implementation for `FeatureSet`
impl Default for FeatureSet {
    fn default() -> Self {
        Self {
            // All features disabled
            active: AHashMap::new(),
            inactive: AHashSet::from_iter((*FEATURE_NAMES).keys().cloned()),
        }
    }
}
```

The `*FEATURE_NAMES` is used to load all features since they are defined by [`agave_feature_set::FEATURE_NAMES`](https://docs.rs/agave-feature-set/latest/agave_feature_set/static.FEATURE_NAMES.html) constant which is a can be described as `HashMap<Public Key of the feature, the description of the feature>`.

Let’s explore this by creating a new Rust project and add the `agave-feature-set` crate

```bash
cargo new explore-feature-set
```

```bash
# Add agave-feature-set to Cargo.toml
cargo add agave-feature-set
```

### Looping through the available features for SVM API

In the `src/main.rs` folder loop through the feature names

```rust
use agave_feature_set::FEATURE_NAMES;

fn main() {
    // Loop through the available features for the SVM version
    for (feature_name: &solana_pubkey::Pubkey, feature_description: &&str) in FEATURE_NAMES.iter() {
        println!("{feature_name} - {feature_description",);
    }
}
```

### Instantiating the defaults for FeatureSet

```rust
use agave_feature_set::FeatureSet;

let feature_set_api = FeatureSet::default();
```

### Methods on FeatureSet

`FeatureSet` methods on can activate or deactivate a feature by providing it’s public key. An example is activating `SIMD 256` which raises the block limit to `60M` . `agave-feature-set` crate provides constant modules that have a method `id()` which contains the `Public Key` for the feature activation. For SIMD 256, the module is `agave_feature_set::raise_block_limits_to_60m` .

The `activate()` method requires the `feature public key` and the `slot` that the feature will be activated.

```rust
use agave_feature_set::FeatureSet;

fn main() {
    let mut feature_manager = FeatureSet::default();

    // Activate SIMD 256 from slot zero
    feature_manager.activate(&agave_feature_set::raise_block_limits_to_60m::id(), 0);

    // To deactivate a feature, example  SIMD 256
    feature_manager.deactivate(&agave_feature_set::raise_block_limits_to_60m::id());

    // Some more useful methods are
    //

    // To check whether a feature is active, example  SIMD 256
    feature_manager.is_active(&agave_feature_set::raise_block_limits_to_60m::id());

    // To check the slot when a certain feature was activated, example  SIMD 256
    feature_manager.activated_slot(&agave_feature_set::raise_block_limits_to_60m::id());

    // To get all active features
    feature_manager.active();

    // To get all inactive features
    feature_manager.inactive();

    // To get all enabled features that trigger full inflation
    feature_manager.full_inflation_features_enabled();

    // To instantiate a `FeatureSet` struct with all features enabled at once
    let feature_manager = FeatureSet::all_enabled();
}
```

These methods can be used to instantiate a `Bank` with the features required in your SVM application.

The source code for this article can be found at - [https://github.com/448-OG/SVM-Series/tree/master/svm-featues](https://github.com/448-OG/SVM-Series/tree/master/svm-featues)

[&lt; Previous Article - SVM Series 01: Introduction](https://448.africa/svm-series)

[Next Article - SVM Series 03: Compute Budget & Syscalls &gt;](https://448.africa/svm-series-03-compute-budget-and-syscalls)

## Resources

1. Feature Proposal Program’s source code - [https://github.com/solana-program/feature-proposal](https://github.com/solana-program/feature-proposal)
    
2. `solana-feature-gate-interface` - crate used within validator client to provide mechanism for features to be simultaneously activated across the network.  
    [https://crates.io/crates/solana-feature-gate-interface](https://crates.io/crates/solana-feature-gate-interface)
    
3. `solana feature activate` - subcommand part of the `solana` command line tool used to activate features. Run `solana feature --help` to show other arguments.
