Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation for upgrades and use upgrade version for enabling upgrade instead of current sequencer version #1694

Merged
merged 9 commits into from
Jul 11, 2024
Merged
2 changes: 1 addition & 1 deletion data/genesis/demo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ fee_contract = '0xa15bb66138824a1c7167f5e85b957d04dd34e468'
timestamp = "1970-01-01T00:00:00Z"

[[upgrade]]
version = "0.2"
version = "0.1"
view = 5
propose_window = 10

Expand Down
70 changes: 70 additions & 0 deletions doc/upgrades.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@

# Upgrades

Hotshot protocol supports upgrades through an Upgrade proposal mechanism. The Upgrade proposal is broadcast separately from the `QuorumProposal`, typically several views in advance of its attachment. The goal is to ensure ample time for nodes to receive and prepare for the upgrade process.

Voting for the `UpgradeProposal` begins before its proposal. Sufficient votes are gathered to form an upgrade certificate. Once obtained, the proposal is broadcasted, and any node that receives it accepts and attaches it to its own `QuorumProposal`.
imabdulbasit marked this conversation as resolved.
Show resolved Hide resolved

## Enabling an Upgrade

To enable an upgrade in Hotshot protocol, it is essential to define the base version, the upgrade version, and a upgrade hash:

- **Base Version:** Represents the current version of the protocol (`0.1` in this example).
- **Upgrade Version:** Specifies the version to which the protocol will upgrade once the process is successful (`0.2` in this example).
- **Upgrade Hash:** Acts as a unique identifier for the specific upgrade nodes are voting on. It distinguishes between different proposals of the same version upgrade, ensuring nodes vote and execute the correct one. It consists of a sequence of 32 bytes.

These are defined in [NodeType implementation](../types/src/v0/mod.rs) for the Types (`SeqTypes` in our case).
```rust
impl NodeType for SeqTypes {
type Base = StaticVersion<0, 1>;
type Upgrade = StaticVersion<0, 2>;
const UPGRADE_HASH: [u8; 32] = [
1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
],
..
}
```

These parameters are fetched from the genesis TOML file and set in Hotshot config:

- **start_voting_view:** view at which voting for the upgrade proposal starts. In our implementation, this is set to 1 so that voting begins as soon as the node is started.
imabdulbasit marked this conversation as resolved.
Show resolved Hide resolved
- **stop_voting_view:** view at which voting for the upgrade proposal stops. To disable an upgrade, set this parameter to 0 or ensure `stop_voting_view` is less than `start_voting_view`.
- **start_proposing_view:** view at which the node proposes an upgrade. This should be set to when an upgrade is intended. If the current view > `start_proposing_view`, the node proposes as soon as `UpgradeCertificate` is formed.
imabdulbasit marked this conversation as resolved.
Show resolved Hide resolved
- **stop_proposing_view:** The view after which the upgrade proposal is no longer valid. If the upgrade proposal fails and the current view > stop_proposing_view then the upgrade is never proposed again.
imabdulbasit marked this conversation as resolved.
Show resolved Hide resolved

The window between `start_proposing_view` and `stop_proposing_view` should provide sufficient time for nodes to continue proposing the upgrade until successful.

Ensure that the `ESPRESSO_SEQUENCER_GENESIS_FILE` environment variable is defined to point to the path of the genesis TOML file. For an example with upgrades enabled, refer to [`data/genesis/demo.toml`](../data/genesis/demo.toml).

Note: We currently support only chain config upgrade.
### Example TOML Configuration

```toml
[[upgrade]]
version = "0.1"
view = 5
propose_window = 10

[upgrade.chain_config]
chain_id = 999999999
base_fee = '2 wei'
max_block_size = '1mb'
fee_recipient = '0x0000000000000000000000000000000000000000'
fee_contract = '0xa15bb66138824a1c7167f5e85b957d04dd34e468'
```
In the TOML configuration example above, the `upgrade` section defines an array of tables, each specifying upgrade parameters:

- **Version:** the current version targeted for the upgrade.
- **View:** Represents the `start_proposing_view` value at which the upgrade is proposed.
- **Propose Window:** Refers to the view window between `start_proposing_view` and `stop_proposing_view`.

The `upgrade.chain_config` table contains the complete set of chain config parameters, which can be used, for example, to enable protocol fees or modify other parameters.


## Fee upgrade

A successful Hotshot upgrade results in a new version, which allows us to update the `ChainConfig` and execute the upgrade if there exists any. `Chainconfig` includes the fee parameters. The sequencer node has two states: `NodeState` and `ValidatedState`. `NodeState` is an immutable state that contains `ResolvableChainConfig` (Enum of `ChainConfig`'s commitment and full `ChainConfig`), whereas `ValidatedState` is a mutable state. To make updates to the chain config post-upgrade possible, `ResolvableChainConfig` is also added to `ValidatedState`.

`NodeState` also includes two additional fields: `upgrades` and `current_version`. Functions like `Header::new()` and `ValidatedState::apply_header()` include a version parameter, which is used to apply upgrades by comparing this version with `current_version` in NodeState and fetching the upgrade if available from the upgrades BTreeMap in NodeState.

In scenarios where nodes join the network or restart, missing the upgrade window may result in their validated_state having only a chain config commitment. In such cases, nodes need to catch up from their peers to get the updated full chain config.
8 changes: 4 additions & 4 deletions sequencer/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1447,12 +1447,12 @@ mod test {
..Default::default()
};
let mut map = std::collections::BTreeMap::new();
let view = 5;
let start_proposing_view = 5;
let propose_window = 10;
map.insert(
Version { major: 0, minor: 2 },
Upgrade {
view,
start_proposing_view,
propose_window,
upgrade_type: UpgradeType::ChainConfig {
chain_config: chain_config_upgrade,
Expand All @@ -1463,8 +1463,8 @@ mod test {
let stop_voting_view = 100;
let upgrades = TestNetworkUpgrades {
upgrades: map,
start_proposing_view: view,
stop_proposing_view: view + propose_window,
start_proposing_view,
stop_proposing_view: start_proposing_view + propose_window,
start_voting_view: 1,
stop_voting_view,
};
Expand Down
4 changes: 2 additions & 2 deletions sequencer/src/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ mod upgrade_serialization {
for (version, upgrade) in map {
seq.serialize_element(&(
version.to_string(),
upgrade.view,
upgrade.start_proposing_view,
upgrade.propose_window,
upgrade.upgrade_type.clone(),
))?;
Expand Down Expand Up @@ -115,7 +115,7 @@ mod upgrade_serialization {
map.insert(
version,
Upgrade {
view: fields.view,
start_proposing_view: fields.view,
propose_window: fields.propose_window,
upgrade_type: fields.upgrade_type,
},
Expand Down
2 changes: 1 addition & 1 deletion sequencer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ pub async fn init_node<P: PersistenceOptions, Ver: StaticVersionType + 'static>(

let version = Ver::version();
if let Some(upgrade) = genesis.upgrades.get(&version) {
let view = upgrade.view;
let view = upgrade.start_proposing_view;
config.config.start_proposing_view = view;
config.config.stop_proposing_view = view + upgrade.propose_window;
config.config.start_voting_view = 1;
Expand Down
37 changes: 36 additions & 1 deletion types/src/v0/v0_1/instance_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use vbs::version::Version;

use super::l1::L1Client;

/// Represents the specific type of upgrade.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(untagged)]
#[serde(rename_all = "snake_case")]
Expand All @@ -19,14 +20,33 @@ pub enum UpgradeType {
ChainConfig { chain_config: ChainConfig },
}

/// Represents the upgrade config including the type of upgrade and upgrade parameters for hotshot config.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Upgrade {
pub view: u64,
/// The view at which the upgrade is proposed.
///
/// Note: Voting for the proposal begins before the upgrade is formally proposed.
/// In our implementation, `start_proposing_view` is set to `1`` for all upgrades,
/// so if an upgrade is planned then the voting starts as soon as node is started.
#[serde(rename = "view")]
pub start_proposing_view: u64,

/// The time window during which the upgrade can be proposed.
///
/// This parameter is used for setting the `stop_propose_window_view`.
/// `stop_proposing_view` is calculated as `start_proposing_view + propose_window`.
pub propose_window: u64,

/// The specific type of upgrade configuration.
///
/// Currently, we only support chain configuration upgrades (`upgrade.chain_config` in genesis toml file).
#[serde(flatten)]
pub upgrade_type: UpgradeType,
}

/// Represents the immutable state of a node.
///
/// For mutable state, use `ValidatedState`.
#[derive(Debug, Clone)]
pub struct NodeState {
pub node_id: u64,
Expand All @@ -36,6 +56,21 @@ pub struct NodeState {
pub genesis_header: GenesisHeader,
pub genesis_state: ValidatedState,
pub l1_genesis: Option<L1BlockInfo>,

/// Map containing all planned and executed upgrades.
///
/// Currently, only one upgrade can be executed at a time.
/// For multiple upgrades, the node needs to be restarted after each upgrade.
///
/// This field serves as a record for planned and past upgrades,
/// listed in the genesis TOML file. It will be very useful if multiple upgrades
/// are supported in the future.
pub upgrades: BTreeMap<Version, Upgrade>,
/// Current version of the sequencer.
///
/// This version is checked to determine if an upgrade is planned,
/// and which version variant for versioned types
/// to use in functions such as genesis.
/// (example: genesis returns V2 Header if version is 0.2)
pub current_version: Version,
}
Loading