From 7cbdaabccddcd63881879fc48342c01aa4f42dda Mon Sep 17 00:00:00 2001 From: Abdul Basit Date: Fri, 12 Jul 2024 05:46:52 +0500 Subject: [PATCH] fix upgrade: set time parameters --- data/genesis/demo.toml | 5 +- sequencer/src/api.rs | 52 +++---- sequencer/src/genesis.rs | 204 ++++++++++++++++++++++------ sequencer/src/lib.rs | 45 +++--- types/src/v0/v0_1/instance_state.rs | 34 ++--- 5 files changed, 231 insertions(+), 109 deletions(-) diff --git a/data/genesis/demo.toml b/data/genesis/demo.toml index 5c52dc3861..ec85c2bf65 100644 --- a/data/genesis/demo.toml +++ b/data/genesis/demo.toml @@ -13,9 +13,8 @@ timestamp = "1970-01-01T00:00:00Z" [[upgrade]] version = "0.2" -view = 5 -propose_window = 10 - +start_proposing_view = 5 +stop_proposing_view = 15 [upgrade.chain_config] chain_id = 999999999 diff --git a/sequencer/src/api.rs b/sequencer/src/api.rs index 3674abf4fd..2408e007cc 100644 --- a/sequencer/src/api.rs +++ b/sequencer/src/api.rs @@ -351,7 +351,7 @@ impl, Ver: StaticVersionType + 'static, P: Sequencer #[cfg(any(test, feature = "testing"))] pub mod test_helpers { - use std::{collections::BTreeMap, time::Duration}; + use std::time::Duration; use async_compatibility_layer::logging::{setup_backtrace, setup_logging}; use async_std::task::sleep; @@ -360,7 +360,7 @@ pub mod test_helpers { use espresso_types::{ mock::MockStateCatchup, v0::traits::{PersistenceOptions, StateCatchup}, - NamespaceId, Upgrade, ValidatedState, + NamespaceId, ValidatedState, }; use ethers::{prelude::Address, utils::Anvil}; use futures::{ @@ -378,7 +378,6 @@ pub mod test_helpers { use portpicker::pick_unused_port; use surf_disco::Client; use tide_disco::error::ServerError; - use vbs::version::Version; use super::*; use crate::{ @@ -503,15 +502,6 @@ pub mod test_helpers { } } - #[derive(Clone, Debug)] - pub struct TestNetworkUpgrades { - pub upgrades: BTreeMap, - pub start_proposing_view: u64, - pub stop_proposing_view: u64, - pub start_voting_view: u64, - pub stop_voting_view: u64, - } - impl TestNetwork { pub async fn new( cfg: TestNetworkConfig<{ NUM_NODES }, P, C>, @@ -529,7 +519,7 @@ pub mod test_helpers { .map(|(i, (state, persistence, catchup))| { let opt = cfg.api_config.clone(); let cfg = &cfg.network_config; - let upgrades_map = cfg.upgrades().map(|e| e.upgrades).unwrap_or_default(); + let upgrades_map = cfg.upgrades(); async move { if i == 0 { opt.serve( @@ -1049,7 +1039,8 @@ mod test { use committable::{Commitment, Committable}; use es_version::{SequencerVersion, SEQUENCER_VERSION}; use espresso_types::{ - mock::MockStateCatchup, FeeAccount, FeeAmount, Header, Upgrade, UpgradeType, ValidatedState, + mock::MockStateCatchup, v0_1::UpgradeMode, FeeAccount, FeeAmount, Header, Upgrade, + UpgradeType, ValidatedState, }; use ethers::utils::Anvil; use futures::{ @@ -1063,14 +1054,14 @@ mod test { }; use hotshot_types::{ event::LeafInfo, - traits::{metrics::NoMetrics, node_implementation::ConsensusTime}, + traits::{metrics::NoMetrics, node_implementation::{ConsensusTime, NodeType}}, }; use jf_merkle_tree::prelude::{MerkleProof, Sha3Node}; use portpicker::pick_unused_port; use surf_disco::Client; use test_helpers::{ catchup_test_helper, state_signature_test_helper, status_test_helper, submit_test_helper, - TestNetwork, TestNetworkConfigBuilder, TestNetworkUpgrades, + TestNetwork, TestNetworkConfigBuilder, }; use tide_disco::{app::AppHealth, error::ServerError, healthcheck::HealthStatus}; use vbs::version::Version; @@ -1446,28 +1437,27 @@ mod test { base_fee: 1.into(), ..Default::default() }; - let mut map = std::collections::BTreeMap::new(); - let start_proposing_view = 5; - let propose_window = 10; - map.insert( - Version { major: 0, minor: 2 }, + let mut upgrades = std::collections::BTreeMap::new(); + + upgrades.insert( + ::Upgrade::VERSION, Upgrade { - start_proposing_view, - propose_window, + start_voting_time: None, + stop_voting_time: None, + start_proposing_time: 0, + stop_proposing_time: u64::MAX, + start_voting_view: None, + stop_voting_view: None, + start_proposing_view: 1, + stop_proposing_view: 10, + mode: UpgradeMode::View, upgrade_type: UpgradeType::ChainConfig { chain_config: chain_config_upgrade, }, }, ); - let stop_voting_view = 100; - let upgrades = TestNetworkUpgrades { - upgrades: map, - start_proposing_view, - stop_proposing_view: start_proposing_view + propose_window, - start_voting_view: 1, - stop_voting_view, - }; + let stop_voting_view = u64::MAX; const NUM_NODES: usize = 5; let config = TestNetworkConfigBuilder::::with_num_nodes() diff --git a/sequencer/src/genesis.rs b/sequencer/src/genesis.rs index 8ad111a66a..5d21622da1 100644 --- a/sequencer/src/genesis.rs +++ b/sequencer/src/genesis.rs @@ -51,26 +51,71 @@ mod upgrade_serialization { use std::{collections::BTreeMap, fmt}; - use espresso_types::{Upgrade, UpgradeType}; + use espresso_types::{v0_1::UpgradeMode, Upgrade, UpgradeType}; use serde::{ de::{SeqAccess, Visitor}, ser::SerializeSeq, - Deserialize, Deserializer, Serializer, + Deserialize, Deserializer, Serialize, Serializer, }; use vbs::version::Version; + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct UpgradeTimeParams { + pub start_proposing_time: u64, + pub stop_proposing_time: u64, + pub start_voting_time: Option, + pub stop_voting_time: Option, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct UpgradeViewParams { + pub start_proposing_view: u64, + pub stop_proposing_view: u64, + pub start_voting_view: Option, + pub stop_voting_view: Option, + } + + /// Represents the specific type of upgrade. + #[derive(Clone, Debug, Deserialize, Serialize)] + #[serde(untagged)] + pub enum UpgradeParameters { + Time(UpgradeTimeParams), + View(UpgradeViewParams), + } + + #[derive(Deserialize)] + struct UpgradeFields { + version: String, + #[serde(flatten)] + params: UpgradeParameters, + #[serde(flatten)] + upgrade_type: UpgradeType, + } + pub fn serialize(map: &BTreeMap, serializer: S) -> Result where S: Serializer, { let mut seq = serializer.serialize_seq(Some(map.len()))?; for (version, upgrade) in map { - seq.serialize_element(&( - version.to_string(), - upgrade.start_proposing_view, - upgrade.propose_window, - upgrade.upgrade_type.clone(), - ))?; + match upgrade.mode { + UpgradeMode::View => seq.serialize_element(&( + version.to_string(), + upgrade.start_proposing_view, + upgrade.stop_proposing_view, + upgrade.start_voting_view, + upgrade.stop_voting_view, + upgrade.upgrade_type.clone(), + ))?, + UpgradeMode::Time => seq.serialize_element(&( + version.to_string(), + upgrade.start_proposing_time, + upgrade.stop_proposing_time, + upgrade.start_voting_time, + upgrade.stop_voting_time, + upgrade.upgrade_type.clone(), + ))?, + } } seq.end() } @@ -94,15 +139,6 @@ mod upgrade_serialization { { let mut map = BTreeMap::new(); - #[derive(Deserialize)] - struct UpgradeFields { - version: String, - view: u64, - propose_window: u64, - #[serde(flatten)] - upgrade_type: UpgradeType, - } - while let Some(fields) = seq.next_element::()? { // add try_from in Version let version: Vec<_> = fields.version.split('.').collect(); @@ -112,14 +148,38 @@ mod upgrade_serialization { minor: version[1].parse().expect("invalid version"), }; - map.insert( - version, - Upgrade { - start_proposing_view: fields.view, - propose_window: fields.propose_window, - upgrade_type: fields.upgrade_type, - }, - ); + match fields.params { + UpgradeParameters::Time(t) => map.insert( + version, + Upgrade { + start_voting_time: t.start_voting_time, + stop_voting_time: t.stop_voting_time, + start_proposing_time: t.start_proposing_time, + stop_proposing_time: t.stop_proposing_time, + start_voting_view: None, + stop_voting_view: None, + start_proposing_view: 0, + stop_proposing_view: u64::MAX, + mode: UpgradeMode::Time, + upgrade_type: fields.upgrade_type, + }, + ), + UpgradeParameters::View(v) => map.insert( + version, + Upgrade { + start_voting_time: None, + stop_voting_time: None, + start_proposing_time: 0, + stop_proposing_time: u64::MAX, + start_voting_view: v.start_voting_view, + stop_voting_view: v.stop_voting_view, + start_proposing_view: v.start_proposing_view, + stop_proposing_view: v.stop_proposing_view, + mode: UpgradeMode::View, + upgrade_type: fields.upgrade_type, + }, + ), + }; } Ok(map) @@ -148,7 +208,7 @@ impl Genesis { #[cfg(test)] mod test { - use espresso_types::{L1BlockInfo, Timestamp}; + use espresso_types::{v0_1::UpgradeMode, L1BlockInfo, Timestamp, UpgradeType}; use ethers::prelude::{Address, H160, H256}; use sequencer_utils::ser::FromStringOrInteger; use toml::toml; @@ -179,18 +239,6 @@ mod test { number = 64 timestamp = "0x123def" hash = "0x80f5dd11f2bdda2814cb1ad94ef30a47de02cf28ad68c89e104c00c4e51bb7a5" - - [[upgrade]] - version = "1.0" - view = 1 - propose_window = 10 - - [upgrade.chain_config] - chain_id = 12345 - max_block_size = 30000 - base_fee = 1 - fee_recipient = "0x0000000000000000000000000000000000000000" - fee_contract = "0x0000000000000000000000000000000000000000" } .to_string(); @@ -335,4 +383,84 @@ mod test { } ) } + + #[test] + fn test_genesis_toml_upgrade() { + // without optional fields + // with view settings + let toml = toml! { + [stake_table] + capacity = 10 + + [chain_config] + chain_id = 12345 + max_block_size = 30000 + base_fee = 1 + fee_recipient = "0x0000000000000000000000000000000000000000" + fee_contract = "0x0000000000000000000000000000000000000000" + + [header] + timestamp = 123456 + + [accounts] + "0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f" = 100000 + "0x0000000000000000000000000000000000000000" = 42 + + [l1_finalized] + number = 64 + timestamp = "0x123def" + hash = "0x80f5dd11f2bdda2814cb1ad94ef30a47de02cf28ad68c89e104c00c4e51bb7a5" + + [[upgrade]] + version = "0.2" + start_proposing_view = 1 + stop_proposing_view = 10 + + [upgrade.chain_config] + chain_id = 12345 + max_block_size = 30000 + base_fee = 1 + fee_recipient = "0x0000000000000000000000000000000000000000" + fee_contract = "0x0000000000000000000000000000000000000000" + } + .to_string(); + + let genesis: Genesis = toml::from_str(&toml).unwrap_or_else(|err| panic!("{err:#}")); + + let (version, genesis_upgrade) = genesis.upgrades.last_key_value().unwrap(); + + assert_eq!(*version, Version { major: 0, minor: 2 }); + + let upgrade = Upgrade { + start_voting_time: None, + stop_voting_time: None, + start_proposing_time: 0, + stop_proposing_time: u64::MAX, + start_voting_view: None, + stop_voting_view: None, + start_proposing_view: 1, + stop_proposing_view: 10, + mode: UpgradeMode::View, + upgrade_type: UpgradeType::ChainConfig { + chain_config: genesis.chain_config, + }, + }; + + assert_eq!(*genesis_upgrade, upgrade); + + let mut upgrades = BTreeMap::new(); + upgrades.insert(Version { major: 0, minor: 2 }, upgrade); + + let genesis = Genesis { + chain_config: genesis.chain_config, + stake_table: genesis.stake_table, + accounts: genesis.accounts, + l1_finalized: genesis.l1_finalized, + header: genesis.header, + upgrades, + }; + + let toml_from_genesis = toml::to_string(&genesis).unwrap(); + assert_eq!(toml, toml_from_genesis); + } } diff --git a/sequencer/src/lib.rs b/sequencer/src/lib.rs index e9206cdd76..f50092bf20 100644 --- a/sequencer/src/lib.rs +++ b/sequencer/src/lib.rs @@ -204,11 +204,15 @@ pub async fn init_node( .upgrades .get(&::Upgrade::VERSION) { - 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; - config.config.stop_voting_view = u64::MAX; + config.config.start_proposing_view = upgrade.start_proposing_view; + config.config.stop_proposing_view = upgrade.stop_proposing_view; + config.config.start_voting_view = upgrade.start_voting_view.unwrap_or(0); + config.config.stop_voting_view = upgrade.stop_voting_view.unwrap_or(u64::MAX); + + config.config.start_proposing_time = upgrade.start_proposing_time; + config.config.stop_proposing_time = upgrade.stop_proposing_time; + config.config.start_voting_time = upgrade.start_voting_time.unwrap_or(0); + config.config.stop_voting_time = upgrade.stop_voting_time.unwrap_or(u64::MAX); } // If the `Libp2p` bootstrap nodes were supplied via the command line, override those @@ -356,7 +360,6 @@ pub fn empty_builder_commitment() -> BuilderCommitment { pub mod testing { use std::{collections::HashMap, time::Duration}; - use api::test_helpers::TestNetworkUpgrades; use committable::Committable; use espresso_types::{ eth_signature_key::EthKeyPair, @@ -423,7 +426,7 @@ pub mod testing { l1_url: Url, state_relay_url: Option, builder_port: Option, - upgrades: Option, + upgrades: BTreeMap, } impl TestConfigBuilder { @@ -442,21 +445,21 @@ pub mod testing { self } - pub fn upgrades(mut self, upgrades: TestNetworkUpgrades) -> Self { - self.upgrades = Some(upgrades); + pub fn upgrades(mut self, upgrades: BTreeMap) -> Self { + self.upgrades = upgrades; self } pub fn build(mut self) -> TestConfig { - if let Some(upgrades) = &self.upgrades { - self.config.start_proposing_view = upgrades.start_proposing_view; - self.config.stop_proposing_view = upgrades.stop_proposing_view; - self.config.start_voting_view = upgrades.start_voting_view; - self.config.stop_voting_view = upgrades.stop_voting_view; - self.config.start_proposing_time = 0; - self.config.stop_proposing_time = u64::MAX; - self.config.start_voting_time = 0; - self.config.stop_voting_time = u64::MAX; + if let Some(upgrade) = self.upgrades.get(&::Upgrade::VERSION) { + self.config.start_proposing_view = upgrade.start_proposing_view; + self.config.stop_proposing_view = upgrade.stop_proposing_view; + self.config.start_voting_view = upgrade.start_voting_view.unwrap_or(0); + self.config.stop_voting_view = upgrade.stop_voting_view.unwrap_or(u64::MAX); + self.config.start_proposing_time = upgrade.start_proposing_time; + self.config.stop_proposing_time = upgrade.stop_proposing_time; + self.config.start_voting_time = upgrade.start_voting_time.unwrap_or(0); + self.config.stop_voting_time = upgrade.stop_voting_time.unwrap_or(u64::MAX); } TestConfig { @@ -541,7 +544,7 @@ pub mod testing { l1_url: "http://localhost:8545".parse().unwrap(), state_relay_url: None, builder_port: None, - upgrades: None, + upgrades: Default::default(), } } } @@ -555,7 +558,7 @@ pub mod testing { l1_url: Url, state_relay_url: Option, builder_port: Option, - upgrades: Option, + upgrades: BTreeMap, } impl TestConfig { @@ -579,7 +582,7 @@ pub mod testing { self.l1_url.clone() } - pub fn upgrades(&self) -> Option { + pub fn upgrades(&self) -> BTreeMap { self.upgrades.clone() } diff --git a/types/src/v0/v0_1/instance_state.rs b/types/src/v0/v0_1/instance_state.rs index 82f75ba4a7..facf203721 100644 --- a/types/src/v0/v0_1/instance_state.rs +++ b/types/src/v0/v0_1/instance_state.rs @@ -11,7 +11,7 @@ use vbs::version::Version; use super::l1::L1Client; /// Represents the specific type of upgrade. -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] #[serde(untagged)] #[serde(rename_all = "snake_case")] pub enum UpgradeType { @@ -21,22 +21,18 @@ pub enum UpgradeType { } /// Represents the upgrade config including the type of upgrade and upgrade parameters for hotshot config. -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] pub struct Upgrade { - /// 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_voting_time: Option, + pub stop_voting_time: Option, + pub start_proposing_time: u64, + pub stop_proposing_time: u64, + pub start_voting_view: Option, + pub stop_voting_view: Option, 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, - + pub stop_proposing_view: u64, + // View or time based + pub mode: UpgradeMode, /// The specific type of upgrade configuration. /// /// Currently, we only support chain configuration upgrades (`upgrade.chain_config` in genesis toml file). @@ -44,6 +40,12 @@ pub struct Upgrade { pub upgrade_type: UpgradeType, } +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +pub enum UpgradeMode { + View, + Time, +} + /// Represents the immutable state of a node. /// /// For mutable state, use `ValidatedState`. @@ -71,6 +73,6 @@ pub struct NodeState { /// 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) + /// (example: genesis returns V2 Header if version is 0.2) pub current_version: Version, }