From 0c0a4dd59dbb4b4881cbb18bb871ee562295955f Mon Sep 17 00:00:00 2001 From: ss-es <155648797+ss-es@users.noreply.github.com> Date: Thu, 27 Jun 2024 14:32:18 -0400 Subject: [PATCH] Move versioning out of constants and into `NodeType` (#3391) --- crates/example-types/src/node_types.rs | 7 +++++ crates/hotshot/src/lib.rs | 6 ++-- crates/hotshot/src/tasks/mod.rs | 15 +++++----- crates/hotshot/src/tasks/task_state.rs | 9 ++---- crates/hotshot/src/types/handle.rs | 3 +- crates/orchestrator/src/client.rs | 21 +++++++------ crates/orchestrator/src/lib.rs | 12 ++++---- crates/task-impls/src/transactions.rs | 17 +++-------- crates/task-impls/src/upgrade.rs | 13 ++++---- crates/testing/src/block_builder/mod.rs | 22 +++++++------- crates/testing/src/block_builder/simple.rs | 16 +++++----- crates/testing/tests/tests_1/block_builder.rs | 3 +- .../testing/tests/tests_3/memory_network.rs | 7 +++-- crates/types/src/constants.rs | 10 ------- crates/types/src/message.rs | 30 +++++++++---------- .../types/src/traits/node_implementation.rs | 10 +++++++ 16 files changed, 100 insertions(+), 101 deletions(-) diff --git a/crates/example-types/src/node_types.rs b/crates/example-types/src/node_types.rs index 4e196e4df8..57f708b84f 100644 --- a/crates/example-types/src/node_types.rs +++ b/crates/example-types/src/node_types.rs @@ -9,6 +9,7 @@ use hotshot_types::{ traits::node_implementation::NodeType, }; use serde::{Deserialize, Serialize}; +use vbs::version::StaticVersion; use crate::{ auction_results_provider_types::TestAuctionResultsProvider, @@ -34,6 +35,12 @@ use crate::{ /// to select our traits pub struct TestTypes; impl NodeType for TestTypes { + 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, + ]; type Time = ViewNumber; type BlockHeader = TestBlockHeader; type BlockPayload = TestBlockPayload; diff --git a/crates/hotshot/src/lib.rs b/crates/hotshot/src/lib.rs index 5d6ffa0fc3..9a01ebd956 100644 --- a/crates/hotshot/src/lib.rs +++ b/crates/hotshot/src/lib.rs @@ -35,7 +35,7 @@ use hotshot_task_impls::{events::HotShotEvent, helpers::broadcast_event, network pub use hotshot_types::error::HotShotError; use hotshot_types::{ consensus::{Consensus, ConsensusMetricsValue, View, ViewInner}, - constants::{Base, EVENT_CHANNEL_SIZE, EXTERNAL_EVENT_CHANNEL_SIZE}, + constants::{EVENT_CHANNEL_SIZE, EXTERNAL_EVENT_CHANNEL_SIZE}, data::{Leaf, QuorumProposal}, event::{EventType, LeafInfo}, message::{DataMessage, Message, MessageKind, Proposal, VersionedMessage}, @@ -258,7 +258,7 @@ impl> SystemContext { ); let consensus = Arc::new(RwLock::new(consensus)); - let version = Arc::new(RwLock::new(Base::VERSION)); + let version = Arc::new(RwLock::new(TYPES::Base::VERSION)); // This makes it so we won't block on broadcasting if there is not a receiver // Our own copy of the receiver is inactive so it doesn't count. @@ -613,7 +613,7 @@ impl> SystemContext { ) .await; add_network_event_task(&mut handle, network, vid_membership, network::vid_filter).await; - add_consensus_tasks::(&mut handle).await; + add_consensus_tasks::(&mut handle).await; handle } } diff --git a/crates/hotshot/src/tasks/mod.rs b/crates/hotshot/src/tasks/mod.rs index 165ca013e5..43509c23c0 100644 --- a/crates/hotshot/src/tasks/mod.rs +++ b/crates/hotshot/src/tasks/mod.rs @@ -165,18 +165,19 @@ pub async fn add_network_event_task< } /// Adds consensus-related tasks to a `SystemContextHandle`. -pub async fn add_consensus_tasks< - TYPES: NodeType, - I: NodeImplementation, - VERSION: StaticVersionType + 'static, ->( +pub async fn add_consensus_tasks>( handle: &mut SystemContextHandle, ) { handle.add_task(ViewSyncTaskState::::create_from(handle).await); handle.add_task(VidTaskState::::create_from(handle).await); handle.add_task(DaTaskState::::create_from(handle).await); - handle.add_task(TransactionTaskState::::create_from(handle).await); - handle.add_task(UpgradeTaskState::::create_from(handle).await); + handle.add_task(TransactionTaskState::::create_from(handle).await); + + // only spawn the upgrade task if we are actually configured to perform an upgrade. + if TYPES::Base::VERSION < TYPES::Upgrade::VERSION { + handle.add_task(UpgradeTaskState::::create_from(handle).await); + } + { #![cfg(not(feature = "dependency-tasks"))] handle.add_task(ConsensusTaskState::::create_from(handle).await); diff --git a/crates/hotshot/src/tasks/task_state.rs b/crates/hotshot/src/tasks/task_state.rs index b768b18ae7..0202689c60 100644 --- a/crates/hotshot/src/tasks/task_state.rs +++ b/crates/hotshot/src/tasks/task_state.rs @@ -18,7 +18,6 @@ use hotshot_types::traits::{ consensus_api::ConsensusApi, node_implementation::{ConsensusTime, NodeImplementation, NodeType}, }; -use vbs::version::StaticVersionType; use crate::types::SystemContextHandle; @@ -163,12 +162,10 @@ impl> CreateTaskState } #[async_trait] -impl, Ver: StaticVersionType> - CreateTaskState for TransactionTaskState +impl> CreateTaskState + for TransactionTaskState { - async fn create_from( - handle: &SystemContextHandle, - ) -> TransactionTaskState { + async fn create_from(handle: &SystemContextHandle) -> TransactionTaskState { TransactionTaskState { builder_timeout: handle.builder_timeout(), output_event_stream: handle.hotshot.external_event_stream.0.clone(), diff --git a/crates/hotshot/src/types/handle.rs b/crates/hotshot/src/types/handle.rs index c859bd070d..6ab61469f5 100644 --- a/crates/hotshot/src/types/handle.rs +++ b/crates/hotshot/src/types/handle.rs @@ -10,12 +10,11 @@ use async_std::task::JoinHandle; use futures::Stream; use hotshot_task::task::{ConsensusTaskRegistry, NetworkTaskRegistry, Task, TaskState}; use hotshot_task_impls::{events::HotShotEvent, helpers::broadcast_event}; -use hotshot_types::traits::network::ConnectedNetwork; use hotshot_types::{ consensus::Consensus, data::Leaf, error::HotShotError, - traits::{election::Membership, node_implementation::NodeType}, + traits::{election::Membership, network::ConnectedNetwork, node_implementation::NodeType}, }; #[cfg(async_executor_impl = "tokio")] use tokio::task::JoinHandle; diff --git a/crates/orchestrator/src/client.rs b/crates/orchestrator/src/client.rs index dc604b47ee..8b29580624 100644 --- a/crates/orchestrator/src/client.rs +++ b/crates/orchestrator/src/client.rs @@ -3,9 +3,7 @@ use std::{net::SocketAddr, time::Duration}; use async_compatibility_layer::art::async_sleep; use clap::Parser; use futures::{Future, FutureExt}; -use hotshot_types::{ - constants::Base, traits::signature_key::SignatureKey, PeerConfig, ValidatorConfig, -}; +use hotshot_types::{traits::signature_key::SignatureKey, PeerConfig, ValidatorConfig}; use libp2p::{Multiaddr, PeerId}; use surf_disco::{error::ClientError, Client}; use tide_disco::Url; @@ -223,8 +221,10 @@ impl OrchestratorClient { }); // Serialize our (possible) libp2p-specific data - let request_body = - vbs::Serializer::::serialize(&(libp2p_address, libp2p_public_key))?; + let request_body = vbs::Serializer::::serialize(&( + libp2p_address, + libp2p_public_key, + ))?; let identity = |client: Client| { // We need to clone here to move it into the closure @@ -316,7 +316,7 @@ impl OrchestratorClient { /// if unable to serialize `address` pub async fn post_builder_addresses(&self, addresses: Vec) { let send_builder_f = |client: Client| { - let request_body = vbs::Serializer::::serialize(&addresses) + let request_body = vbs::Serializer::::serialize(&addresses) .expect("Failed to serialize request"); async move { @@ -382,9 +382,12 @@ impl OrchestratorClient { let da_requested: bool = validator_config.is_da; // Serialize our (possible) libp2p-specific data - let request_body = - vbs::Serializer::::serialize(&(pubkey, libp2p_address, libp2p_public_key)) - .expect("failed to serialize request"); + let request_body = vbs::Serializer::::serialize(&( + pubkey, + libp2p_address, + libp2p_public_key, + )) + .expect("failed to serialize request"); // register our public key with the orchestrator let (node_index, is_da): (u64, bool) = loop { diff --git a/crates/orchestrator/src/lib.rs b/crates/orchestrator/src/lib.rs index 798923687e..922898019b 100644 --- a/crates/orchestrator/src/lib.rs +++ b/crates/orchestrator/src/lib.rs @@ -17,7 +17,7 @@ use client::{BenchResults, BenchResultsDownloadConfig}; use config::BuilderType; use csv::Writer; use futures::{stream::FuturesUnordered, FutureExt, StreamExt}; -use hotshot_types::{constants::Base, traits::signature_key::SignatureKey, PeerConfig}; +use hotshot_types::{traits::signature_key::SignatureKey, PeerConfig}; use libp2p::{ identity::{ ed25519::{Keypair as EdKeypair, SecretKey}, @@ -582,7 +582,7 @@ where // Decode the libp2p data so we can add to our bootstrap nodes (if supplied) let Ok((libp2p_address, libp2p_public_key)) = - vbs::Serializer::::deserialize(&body_bytes) + vbs::Serializer::::deserialize(&body_bytes) else { return Err(ServerError { status: tide_disco::StatusCode::BAD_REQUEST, @@ -614,7 +614,7 @@ where // Decode the libp2p data so we can add to our bootstrap nodes (if supplied) let Ok((mut pubkey, libp2p_address, libp2p_public_key)) = - vbs::Serializer::::deserialize(&body_bytes) + vbs::Serializer::::deserialize(&body_bytes) else { return Err(ServerError { status: tide_disco::StatusCode::BAD_REQUEST, @@ -662,7 +662,9 @@ where let mut body_bytes = req.body_bytes(); body_bytes.drain(..12); - let Ok(urls) = vbs::Serializer::::deserialize::>(&body_bytes) else { + let Ok(urls) = + vbs::Serializer::::deserialize::>(&body_bytes) + else { return Err(ServerError { status: tide_disco::StatusCode::BAD_REQUEST, message: "Malformed body".to_string(), @@ -672,7 +674,7 @@ where let mut futures = urls .into_iter() .map(|url| async { - let client: surf_disco::Client = + let client: surf_disco::Client = surf_disco::client::Client::builder(url.clone()).build(); if client.connect(Some(Duration::from_secs(2))).await { Some(url) diff --git a/crates/task-impls/src/transactions.rs b/crates/task-impls/src/transactions.rs index efa1f9b543..84fb9bcb09 100644 --- a/crates/task-impls/src/transactions.rs +++ b/crates/task-impls/src/transactions.rs @@ -29,7 +29,6 @@ use hotshot_types::{ vid::VidCommitment, }; use tracing::{debug, error, instrument, warn}; -use vbs::version::StaticVersionType; use crate::{ builder::BuilderClient, @@ -65,11 +64,7 @@ pub struct BuilderResponses { } /// Tracks state of a Transaction task -pub struct TransactionTaskState< - TYPES: NodeType, - I: NodeImplementation, - Ver: StaticVersionType, -> { +pub struct TransactionTaskState> { /// The state's api pub builder_timeout: Duration, @@ -89,7 +84,7 @@ pub struct TransactionTaskState< pub membership: Arc, /// Builder API client - pub builder_clients: Vec>, + pub builder_clients: Vec>, /// This Nodes Public Key pub public_key: TYPES::SignatureKey, @@ -103,9 +98,7 @@ pub struct TransactionTaskState< pub decided_upgrade_certificate: Option>, } -impl, Ver: StaticVersionType> - TransactionTaskState -{ +impl> TransactionTaskState { /// main task event handler #[instrument(skip_all, fields(id = self.id, view = *self.cur_view), name = "Transaction task", level = "error")] pub async fn handle( @@ -524,9 +517,7 @@ impl, Ver: StaticVersionType> #[async_trait] /// task state implementation for Transactions Task -impl, Ver: StaticVersionType + 'static> TaskState - for TransactionTaskState -{ +impl> TaskState for TransactionTaskState { type Event = HotShotEvent; async fn handle_event( diff --git a/crates/task-impls/src/upgrade.rs b/crates/task-impls/src/upgrade.rs index 75264cc0cd..cae449c795 100644 --- a/crates/task-impls/src/upgrade.rs +++ b/crates/task-impls/src/upgrade.rs @@ -7,7 +7,6 @@ use async_trait::async_trait; use committable::Committable; use hotshot_task::task::TaskState; use hotshot_types::{ - constants::{Base, Upgrade, UPGRADE_HASH}, data::UpgradeProposal, event::{Event, EventType}, message::Proposal, @@ -92,9 +91,9 @@ impl> UpgradeTaskState { } // If the proposal does not match our upgrade target, we immediately exit. - if proposal.data.upgrade_proposal.new_version_hash != UPGRADE_HASH - || proposal.data.upgrade_proposal.old_version != Base::VERSION - || proposal.data.upgrade_proposal.new_version != Upgrade::VERSION + if proposal.data.upgrade_proposal.new_version_hash != TYPES::UPGRADE_HASH + || proposal.data.upgrade_proposal.old_version != TYPES::Base::VERSION + || proposal.data.upgrade_proposal.new_version != TYPES::Upgrade::VERSION { return None; } @@ -228,9 +227,9 @@ impl> UpgradeTaskState { && self.quorum_membership.leader(view + 5) == self.public_key { let upgrade_proposal_data = UpgradeProposalData { - old_version: Base::VERSION, - new_version: Upgrade::VERSION, - new_version_hash: UPGRADE_HASH.to_vec(), + old_version: TYPES::Base::VERSION, + new_version: TYPES::Upgrade::VERSION, + new_version_hash: TYPES::UPGRADE_HASH.to_vec(), // We schedule the upgrade to begin 15 views in the future old_version_last_view: TYPES::Time::new(*view + 15), // and end 20 views in the future diff --git a/crates/testing/src/block_builder/mod.rs b/crates/testing/src/block_builder/mod.rs index cda850d855..e9b75f4edc 100644 --- a/crates/testing/src/block_builder/mod.rs +++ b/crates/testing/src/block_builder/mod.rs @@ -10,13 +10,10 @@ use hotshot_builder_api::{ builder::{Error, Options}, data_source::BuilderDataSource, }; -use hotshot_types::{ - constants::Base, - traits::{ - block_contents::{precompute_vid_commitment, EncodeBytes}, - node_implementation::NodeType, - signature_key::BuilderSignatureKey, - }, +use hotshot_types::traits::{ + block_contents::{precompute_vid_commitment, EncodeBytes}, + node_implementation::NodeType, + signature_key::BuilderSignatureKey, }; use tide_disco::{method::ReadState, App, Url}; use vbs::version::StaticVersionType; @@ -75,14 +72,15 @@ pub fn run_builder_source( { async_spawn(async move { let start_builder = |url: Url, source: Source| -> _ { - let builder_api = hotshot_builder_api::builder::define_api::( - &Options::default(), - ) - .expect("Failed to construct the builder API"); + let builder_api = + hotshot_builder_api::builder::define_api::( + &Options::default(), + ) + .expect("Failed to construct the builder API"); let mut app: App = App::with_state(source); app.register_module("block_info", builder_api) .expect("Failed to register the builder API"); - async_spawn(app.serve(url, Base::instance())) + async_spawn(app.serve(url, TYPES::Base::instance())) }; let mut handle = Some(start_builder(url.clone(), source.clone())); diff --git a/crates/testing/src/block_builder/simple.rs b/crates/testing/src/block_builder/simple.rs index 416002fe7d..f88f3a9044 100644 --- a/crates/testing/src/block_builder/simple.rs +++ b/crates/testing/src/block_builder/simple.rs @@ -24,7 +24,6 @@ use hotshot_builder_api::{ data_source::BuilderDataSource, }; use hotshot_types::{ - constants::Base, traits::{ block_contents::BlockHeader, node_implementation::NodeType, signature_key::BuilderSignatureKey, @@ -238,16 +237,17 @@ impl SimpleBuilderSource { where ::InstanceState: Default, { - let builder_api = - hotshot_builder_api::builder::define_api::, TYPES, Base>( - &Options::default(), - ) - .expect("Failed to construct the builder API"); + let builder_api = hotshot_builder_api::builder::define_api::< + SimpleBuilderSource, + TYPES, + TYPES::Base, + >(&Options::default()) + .expect("Failed to construct the builder API"); let mut app: App, Error> = App::with_state(self); - app.register_module::("block_info", builder_api) + app.register_module::("block_info", builder_api) .expect("Failed to register the builder API"); - async_spawn(app.serve(url, Base::instance())); + async_spawn(app.serve(url, TYPES::Base::instance())); } } diff --git a/crates/testing/tests/tests_1/block_builder.rs b/crates/testing/tests/tests_1/block_builder.rs index 7d76a6ac04..03f13f83de 100644 --- a/crates/testing/tests/tests_1/block_builder.rs +++ b/crates/testing/tests/tests_1/block_builder.rs @@ -15,7 +15,6 @@ use hotshot_testing::block_builder::{ BuilderTask, RandomBuilderImplementation, TestBuilderImplementation, }; use hotshot_types::{ - constants::Base, traits::{ block_contents::vid_commitment, node_implementation::NodeType, signature_key::SignatureKey, BlockPayload, @@ -46,7 +45,7 @@ async fn test_random_block_builder() { let builder_started = Instant::now(); - let client: BuilderClient = BuilderClient::new(api_url); + let client: BuilderClient::Base> = BuilderClient::new(api_url); assert!(client.connect(Duration::from_millis(100)).await); let (pub_key, private_key) = diff --git a/crates/testing/tests/tests_3/memory_network.rs b/crates/testing/tests/tests_3/memory_network.rs index 53bbec0fda..b3dff52722 100644 --- a/crates/testing/tests/tests_3/memory_network.rs +++ b/crates/testing/tests/tests_3/memory_network.rs @@ -16,19 +16,19 @@ use hotshot_example_types::{ storage_types::TestStorage, auction_results_provider_types::TestAuctionResultsProvider, }; -use hotshot_types::traits::network::BroadcastDelay; use hotshot_types::{ data::ViewNumber, message::{DataMessage, Message, MessageKind, VersionedMessage}, signature_key::{BLSPubKey, BuilderKey}, traits::{ - network::{ConnectedNetwork, TestableNetworkingImplementation}, + network::{BroadcastDelay, ConnectedNetwork, TestableNetworkingImplementation}, node_implementation::{ConsensusTime, NodeType}, }, }; use rand::{rngs::StdRng, RngCore, SeedableRng}; use serde::{Deserialize, Serialize}; use tracing::{instrument, trace}; +use vbs::version::StaticVersion; #[derive( Copy, @@ -46,6 +46,9 @@ use tracing::{instrument, trace}; pub struct Test; impl NodeType for Test { + 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,]; type Time = ViewNumber; type BlockHeader = TestBlockHeader; type BlockPayload = TestBlockPayload; diff --git a/crates/types/src/constants.rs b/crates/types/src/constants.rs index 36d4822c60..67faf3b268 100644 --- a/crates/types/src/constants.rs +++ b/crates/types/src/constants.rs @@ -17,16 +17,6 @@ pub const COMBINED_NETWORK_MIN_PRIMARY_FAILURES: u64 = 5; /// the number of messages to send over the secondary network without delay before re-attempting the (presumed down) primary network pub const COMBINED_NETWORK_PRIMARY_CHECK_INTERVAL: u64 = 50; -/// Base protocol version, set to 0.1 -pub type Base = StaticVersion<0, 1>; -/// Upgraded protocol version, set to 0.2 -pub type Upgrade = StaticVersion<0, 2>; - -/// Hash for the upgrade from version 0.1 to version 0.2. -pub 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, -]; - /// Default channel size for consensus event sharing pub const EVENT_CHANNEL_SIZE: usize = 100_000; diff --git a/crates/types/src/message.rs b/crates/types/src/message.rs index 64185a05d4..869c08a40e 100644 --- a/crates/types/src/message.rs +++ b/crates/types/src/message.rs @@ -16,7 +16,6 @@ use vbs::{ }; use crate::{ - constants::{Base, Upgrade}, data::{DaProposal, Leaf, QuorumProposal, UpgradeProposal, VidDisperseShare}, simple_certificate::{ DaCertificate, UpgradeCertificate, ViewSyncCommitCertificate2, @@ -66,23 +65,24 @@ where let version = match upgrade_certificate { Some(ref cert) => { if view >= cert.data.new_version_first_view - && cert.data.new_version == Upgrade::VERSION + && cert.data.new_version == TYPES::Upgrade::VERSION { - Upgrade::VERSION + TYPES::Upgrade::VERSION } else if view >= cert.data.new_version_first_view - && cert.data.new_version != Upgrade::VERSION + && cert.data.new_version != TYPES::Upgrade::VERSION { bail!("The network has upgraded to a new version that we do not support!"); } else { - Base::VERSION + TYPES::Base::VERSION } } - None => Base::VERSION, + None => TYPES::Base::VERSION, }; let serialized_message = match version { - Base::VERSION => Serializer::::serialize(&self), - Upgrade::VERSION => Serializer::::serialize(&self), + // Associated constants cannot be used in pattern matches, so we do this trick instead. + v if v == TYPES::Base::VERSION => Serializer::::serialize(&self), + v if v == TYPES::Upgrade::VERSION => Serializer::::serialize(&self), _ => { bail!("Attempted to serialize with an incompatible version. This should be impossible."); } @@ -105,8 +105,8 @@ where .0; let deserialized_message: Self = match version { - Base::VERSION => Serializer::::deserialize(message), - Upgrade::VERSION => Serializer::::deserialize(message), + v if v == TYPES::Base::VERSION => Serializer::::deserialize(message), + v if v == TYPES::Upgrade::VERSION => Serializer::::deserialize(message), _ => { bail!("Cannot deserialize message!"); } @@ -118,18 +118,18 @@ where let expected_version = match upgrade_certificate { Some(ref cert) => { if view >= cert.data.new_version_first_view - && cert.data.new_version == Upgrade::VERSION + && cert.data.new_version == TYPES::Upgrade::VERSION { - Upgrade::VERSION + TYPES::Upgrade::VERSION } else if view >= cert.data.new_version_first_view - && cert.data.new_version != Upgrade::VERSION + && cert.data.new_version != TYPES::Upgrade::VERSION { bail!("The network has upgraded to a new version that we do not support!"); } else { - Base::VERSION + TYPES::Base::VERSION } } - None => Base::VERSION, + None => TYPES::Base::VERSION, }; ensure!( diff --git a/crates/types/src/traits/node_implementation.rs b/crates/types/src/traits/node_implementation.rs index 479cccc659..4dba2104c1 100644 --- a/crates/types/src/traits/node_implementation.rs +++ b/crates/types/src/traits/node_implementation.rs @@ -14,6 +14,7 @@ use std::{ use async_trait::async_trait; use committable::Committable; use serde::{Deserialize, Serialize}; +use vbs::version::StaticVersionType; use super::{ auction_results_provider::AuctionResultsProvider, @@ -191,6 +192,15 @@ pub trait NodeType: + Sync + 'static { + /// The base version of HotShot this node is instantiated with. + type Base: StaticVersionType; + + /// The version of HotShot this node may be upgraded to. Set equal to `Base` to disable upgrades. + type Upgrade: StaticVersionType; + + /// The hash for the upgrade. + const UPGRADE_HASH: [u8; 32]; + /// The time type that this hotshot setup is using. /// /// This should be the same `Time` that `ValidatedState::Time` is using.