diff --git a/Cargo.lock b/Cargo.lock index 9c1b87997a..a5bbb9923e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -161,9 +161,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.7" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd2405b3ac1faab2990b74d728624cd9fd115651fcecc7c2d8daf01376275ba" +checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" dependencies = [ "anstyle", "anstyle-parse", @@ -621,7 +621,7 @@ checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.1.1", "async-executor", - "async-io 2.2.2", + "async-io 2.3.0", "async-lock 3.3.0", "blocking", "futures-lite 2.2.0", @@ -667,9 +667,9 @@ dependencies = [ [[package]] name = "async-io" -version = "2.2.2" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6afaa937395a620e33dc6a742c593c01aced20aa376ffb0f628121198578ccc7" +checksum = "fb41eb19024a91746eba0773aa5e16036045bbf45733766661099e182ea6a744" dependencies = [ "async-lock 3.3.0", "cfg-if", @@ -677,8 +677,8 @@ dependencies = [ "futures-io", "futures-lite 2.2.0", "parking", - "polling 3.3.1", - "rustix 0.38.28", + "polling 3.3.2", + "rustix 0.38.30", "slab", "tracing", "windows-sys 0.52.0", @@ -740,7 +740,7 @@ dependencies = [ "cfg-if", "event-listener 3.1.0", "futures-lite 1.13.0", - "rustix 0.38.28", + "rustix 0.38.30", "windows-sys 0.48.0", ] @@ -750,13 +750,13 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e47d90f65a225c4527103a8d747001fc56e375203592b25ad103e1ca13124c5" dependencies = [ - "async-io 2.2.2", + "async-io 2.3.0", "async-lock 2.8.0", "atomic-waker", "cfg-if", "futures-core", "futures-io", - "rustix 0.38.28", + "rustix 0.38.30", "signal-hook-registry", "slab", "windows-sys 0.48.0", @@ -1038,9 +1038,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "bitvec" @@ -1204,15 +1204,15 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "41daef31d7a747c5c847246f36de49ced6f7403b4cdabc807a97b5cc184cda7a" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", "serde", - "windows-targets 0.48.5", + "windows-targets 0.52.0", ] [[package]] @@ -2577,9 +2577,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" [[package]] name = "hex" @@ -3121,7 +3121,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6b0422c86d7ce0e97169cc42e04ae643caf278874a7a3c87b8150a220dc7e1e" dependencies = [ - "async-io 2.2.2", + "async-io 2.3.0", "core-foundation", "fnv", "futures", @@ -4189,7 +4189,7 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "libc", "redox_syscall", ] @@ -4268,9 +4268,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "local-ip-address" @@ -4736,11 +4736,11 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.62" +version = "0.10.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671" +checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "cfg-if", "foreign-types", "libc", @@ -4768,9 +4768,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.98" +version = "0.9.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7" +checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae" dependencies = [ "cc", "libc", @@ -5000,9 +5000,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" +checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" [[package]] name = "platforms" @@ -5028,14 +5028,14 @@ dependencies = [ [[package]] name = "polling" -version = "3.3.1" +version = "3.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf63fa624ab313c11656b4cda960bfc46c410187ad493c41f6ba2d8c1e991c9e" +checksum = "545c980a3880efd47b2e262f6a4bb6daad6555cf3367aa9c4e52895f69537a41" dependencies = [ "cfg-if", "concurrent-queue", "pin-project-lite 0.2.13", - "rustix 0.38.28", + "rustix 0.38.30", "tracing", "windows-sys 0.52.0", ] @@ -5420,9 +5420,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" dependencies = [ "either", "rayon-core", @@ -5430,9 +5430,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -5472,13 +5472,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.2" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.3", + "regex-automata 0.4.4", "regex-syntax 0.8.2", ] @@ -5493,9 +5493,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a" dependencies = [ "aho-corasick", "memchr", @@ -5541,9 +5541,9 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.5" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", "getrandom 0.2.12", @@ -5677,14 +5677,14 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.28" +version = "0.38.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "errno", "libc", - "linux-raw-sys 0.4.12", + "linux-raw-sys 0.4.13", "windows-sys 0.52.0", ] @@ -5708,7 +5708,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", - "ring 0.17.5", + "ring 0.17.7", "rustls-webpki", "sct 0.7.1", ] @@ -5719,7 +5719,7 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.5", + "ring 0.17.7", "untrusted 0.9.0", ] @@ -5786,7 +5786,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.17.5", + "ring 0.17.7", "untrusted 0.9.0", ] @@ -5925,9 +5925,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23" +checksum = "f58c3a1b3e418f61c25b2aeb43fc6c95eaa252b8cecdda67f401943e9e08d33f" dependencies = [ "base64 0.21.7", "chrono", @@ -5942,9 +5942,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788" +checksum = "d2068b437a31fc68f25dd7edc296b078f04b45145c199d8eed9866e45f1ff274" dependencies = [ "darling 0.20.3", "proc-macro2", @@ -6104,9 +6104,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.2" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "smartcow" @@ -6179,7 +6179,7 @@ dependencies = [ "chacha20poly1305", "curve25519-dalek", "rand_core 0.6.4", - "ring 0.17.5", + "ring 0.17.7", "rustc_version 0.4.0", "sha2 0.10.8", "subtle", @@ -6567,7 +6567,7 @@ dependencies = [ "cfg-if", "fastrand 2.0.1", "redox_syscall", - "rustix 0.38.28", + "rustix 0.38.30", "windows-sys 0.52.0", ] @@ -7221,9 +7221,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" diff --git a/crates/hotshot/examples/infra/mod.rs b/crates/hotshot/examples/infra/mod.rs index c709eaff8b..9763c0696f 100644 --- a/crates/hotshot/examples/infra/mod.rs +++ b/crates/hotshot/examples/infra/mod.rs @@ -24,7 +24,10 @@ use hotshot_orchestrator::{ config::{NetworkConfig, NetworkConfigFile, WebServerConfig}, }; use hotshot_task::task::FilterEvent; -use hotshot_testing::block_types::{TestBlockHeader, TestBlockPayload, TestTransaction}; +use hotshot_testing::{ + block_types::{TestBlockHeader, TestBlockPayload, TestTransaction}, + state_types::TestInstanceState, +}; use hotshot_types::message::Message; use hotshot_types::traits::network::ConnectedNetwork; use hotshot_types::ValidatorConfig; @@ -33,10 +36,11 @@ use hotshot_types::{ data::{Leaf, TestableLeaf}, event::{Event, EventType}, traits::{ + block_contents::TestableBlock, election::Membership, network::CommunicationChannel, - node_implementation::NodeType, - state::{ConsensusTime, TestableBlock, TestableState}, + node_implementation::{ConsensusTime, NodeType}, + states::TestableState, }, HotShotConfig, }; @@ -296,7 +300,7 @@ async fn libp2p_network_from_config( /// Defines the behavior of a "run" of the network with a given configuration #[async_trait] pub trait RunDA< - TYPES: NodeType, + TYPES: NodeType, DACHANNEL: CommunicationChannel + Debug, QUORUMCHANNEL: CommunicationChannel + Debug, VIEWSYNCCHANNEL: CommunicationChannel + Debug, @@ -308,7 +312,7 @@ pub trait RunDA< Storage = MemoryStorage, >, > where - ::StateType: TestableState, + ::ValidatedState: TestableState, ::BlockPayload: TestableBlock, TYPES: NodeType, Leaf: TestableLeaf, @@ -324,7 +328,7 @@ pub trait RunDA< /// get the anchored view /// Note: sequencing leaf does not have state, so does not return state async fn initialize_state_and_hotshot(&self) -> SystemContextHandle { - let initializer = hotshot::HotShotInitializer::::from_genesis() + let initializer = hotshot::HotShotInitializer::::from_genesis(&TestInstanceState {}) .expect("Couldn't generate genesis block"); let config = self.get_config(); @@ -519,6 +523,7 @@ impl< Transaction = TestTransaction, BlockPayload = TestBlockPayload, BlockHeader = TestBlockHeader, + InstanceState = TestInstanceState, >, NODE: NodeImplementation< TYPES, @@ -536,7 +541,7 @@ impl< NODE, > for WebServerDARun where - ::StateType: TestableState, + ::ValidatedState: TestableState, ::BlockPayload: TestableBlock, Leaf: TestableLeaf, Self: Sync, @@ -626,6 +631,7 @@ impl< Transaction = TestTransaction, BlockPayload = TestBlockPayload, BlockHeader = TestBlockHeader, + InstanceState = TestInstanceState, >, NODE: NodeImplementation< TYPES, @@ -643,7 +649,7 @@ impl< NODE, > for Libp2pDARun where - ::StateType: TestableState, + ::ValidatedState: TestableState, ::BlockPayload: TestableBlock, Leaf: TestableLeaf, Self: Sync, @@ -724,6 +730,7 @@ impl< Transaction = TestTransaction, BlockPayload = TestBlockPayload, BlockHeader = TestBlockHeader, + InstanceState = TestInstanceState, >, NODE: NodeImplementation< TYPES, @@ -741,7 +748,7 @@ impl< NODE, > for CombinedDARun where - ::StateType: TestableState, + ::ValidatedState: TestableState, ::BlockPayload: TestableBlock, Leaf: TestableLeaf, Self: Sync, @@ -837,6 +844,7 @@ pub async fn main_entry_point< Transaction = TestTransaction, BlockPayload = TestBlockPayload, BlockHeader = TestBlockHeader, + InstanceState = TestInstanceState, >, DACHANNEL: CommunicationChannel + Debug, QUORUMCHANNEL: CommunicationChannel + Debug, @@ -852,7 +860,7 @@ pub async fn main_entry_point< >( args: ValidatorArgs, ) where - ::StateType: TestableState, + ::ValidatedState: TestableState, ::BlockPayload: TestableBlock, Leaf: TestableLeaf, { @@ -907,7 +915,7 @@ pub async fn main_entry_point< for round in 0..rounds { for _ in 0..transactions_to_send_per_round { - let mut txn = ::create_random_transaction( + let mut txn = ::create_random_transaction( None, &mut txn_rng, transaction_size as u64, diff --git a/crates/hotshot/src/lib.rs b/crates/hotshot/src/lib.rs index 88ea0fcb40..f33289e65d 100644 --- a/crates/hotshot/src/lib.rs +++ b/crates/hotshot/src/lib.rs @@ -52,11 +52,11 @@ use hotshot_types::{ traits::{ consensus_api::ConsensusApi, network::{CommunicationChannel, NetworkError}, - node_implementation::{NodeType, SendToTasks}, + node_implementation::{ConsensusTime, NodeType, SendToTasks}, signature_key::SignatureKey, - state::ConsensusTime, + states::ValidatedState, storage::StoredView, - BlockPayload, State, + BlockPayload, }, HotShotConfig, }; @@ -173,8 +173,11 @@ pub struct SystemContext> { } impl> SystemContext { - /// Creates a new hotshot with the given configuration options and sets it up with the given + /// Creates a new [`SystemContext`] with the given configuration options and sets it up with the given /// genesis block + /// + /// To do a full initialization, use `fn init` instead, which will set up background tasks as + /// well. #[allow(clippy::too_many_arguments)] #[instrument(skip(private_key, storage, memberships, networks, initializer, metrics))] pub async fn new( @@ -192,6 +195,7 @@ impl> SystemContext { let consensus_metrics = Arc::new(metrics); let anchored_leaf = initializer.inner; + let instance_state = initializer.instance_state; // insert to storage storage @@ -200,13 +204,14 @@ impl> SystemContext { .context(StorageSnafu)?; // insert genesis (or latest block) to state map - let mut state_map = BTreeMap::default(); - state_map.insert( + let mut validated_state_map = BTreeMap::default(); + let validated_state = TYPES::ValidatedState::genesis(&instance_state); + validated_state_map.insert( anchored_leaf.get_view_number(), View { view_inner: ViewInner::Leaf { leaf: anchored_leaf.commit(), - state: TYPES::StateType::genesis(), + state: validated_state, }, }, ); @@ -230,7 +235,8 @@ impl> SystemContext { let start_view = anchored_leaf.get_view_number(); let consensus = Consensus { - state_map, + instance_state, + validated_state_map, cur_view: start_view, last_decided_view: anchored_leaf.get_view_number(), saved_leaves, @@ -391,7 +397,7 @@ impl> SystemContext { /// /// # Panics /// Panics if internal state for consensus is inconsistent - pub async fn get_decided_state(&self) -> TYPES::StateType { + pub async fn get_decided_state(&self) -> TYPES::ValidatedState { self.inner .consensus .read() @@ -400,7 +406,7 @@ impl> SystemContext { .clone() } - /// Initializes a new hotshot and does the work of setting up all the background tasks + /// Initializes a new [`SystemContext`] and does the work of setting up all the background tasks /// /// Assumes networking implementation is already primed. /// @@ -409,6 +415,8 @@ impl> SystemContext { /// Upon encountering an unrecoverable error, such as a failure to send to a broadcast channel, /// the `HotShot` instance will log the error and shut down. /// + /// To construct a [`SystemContext`] without setting up tasks, use `fn new` instead. + /// /// # Errors /// /// Will return an error when the storage failed to insert the first `QuorumCertificate` @@ -721,20 +729,29 @@ impl> ConsensusApi pub struct HotShotInitializer { /// the leaf specified initialization inner: Leaf, + + /// Instance-level state. + instance_state: TYPES::InstanceState, } impl HotShotInitializer { /// initialize from genesis /// # Errors /// If we are unable to apply the genesis block to the default state - pub fn from_genesis() -> Result> { + pub fn from_genesis( + instance_state: &TYPES::InstanceState, + ) -> Result> { Ok(Self { - inner: Leaf::genesis(), + inner: Leaf::genesis(instance_state), + instance_state: instance_state.clone(), }) } - /// reload previous state based on most recent leaf - pub fn from_reload(anchor_leaf: Leaf) -> Self { - Self { inner: anchor_leaf } + /// reload previous state based on most recent leaf and the instance-level state. + pub fn from_reload(anchor_leaf: Leaf, instance_state: TYPES::InstanceState) -> Self { + Self { + inner: anchor_leaf, + instance_state, + } } } diff --git a/crates/hotshot/src/tasks/mod.rs b/crates/hotshot/src/tasks/mod.rs index 231215dd2f..2805e77675 100644 --- a/crates/hotshot/src/tasks/mod.rs +++ b/crates/hotshot/src/tasks/mod.rs @@ -33,8 +33,7 @@ use hotshot_types::{ block_contents::vid_commitment, consensus_api::ConsensusApi, network::{CommunicationChannel, ConsensusIntentEvent, TransmitType}, - node_implementation::{NodeImplementation, NodeType}, - state::ConsensusTime, + node_implementation::{ConsensusTime, NodeImplementation, NodeType}, BlockPayload, }, }; diff --git a/crates/hotshot/src/traits.rs b/crates/hotshot/src/traits.rs index 9684bd61c7..203fa39705 100644 --- a/crates/hotshot/src/traits.rs +++ b/crates/hotshot/src/traits.rs @@ -4,7 +4,7 @@ mod networking; mod node_implementation; mod storage; -pub use hotshot_types::traits::{BlockPayload, State}; +pub use hotshot_types::traits::{BlockPayload, ValidatedState}; pub use networking::{NetworkError, NetworkReliability}; pub use node_implementation::{NodeImplementation, TestableNodeImplementation}; pub use storage::{Result as StorageResult, Storage}; diff --git a/crates/hotshot/src/traits/networking/libp2p_network.rs b/crates/hotshot/src/traits/networking/libp2p_network.rs index e837397c63..0da20d0738 100644 --- a/crates/hotshot/src/traits/networking/libp2p_network.rs +++ b/crates/hotshot/src/traits/networking/libp2p_network.rs @@ -25,9 +25,8 @@ use hotshot_types::{ CommunicationChannel, ConnectedNetwork, ConsensusIntentEvent, FailedToSerializeSnafu, NetworkError, NetworkMsg, TestableChannelImplementation, TransmitType, ViewMessage, }, - node_implementation::NodeType, + node_implementation::{ConsensusTime, NodeType}, signature_key::SignatureKey, - state::ConsensusTime, }, }; diff --git a/crates/hotshot/src/traits/storage/memory_storage.rs b/crates/hotshot/src/traits/storage/memory_storage.rs index ffbcf235de..adaff123f2 100644 --- a/crates/hotshot/src/traits/storage/memory_storage.rs +++ b/crates/hotshot/src/traits/storage/memory_storage.rs @@ -118,7 +118,8 @@ mod test { data::{fake_commitment, Leaf}, simple_certificate::QuorumCertificate, traits::{ - node_implementation::NodeType, signature_key::SignatureKey, state::ConsensusTime, + node_implementation::{ConsensusTime, NodeType}, + signature_key::SignatureKey, }, }; use std::marker::PhantomData; diff --git a/crates/hotshot/src/types/handle.rs b/crates/hotshot/src/types/handle.rs index 9577880031..bb6d32de33 100644 --- a/crates/hotshot/src/types/handle.rs +++ b/crates/hotshot/src/types/handle.rs @@ -26,7 +26,10 @@ use hotshot_types::{ error::HotShotError, event::EventType, simple_certificate::QuorumCertificate, - traits::{node_implementation::NodeType, state::ConsensusTime, storage::Storage}, + traits::{ + node_implementation::{ConsensusTime, NodeType}, + storage::Storage, + }, }; use std::sync::Arc; use tracing::error; @@ -101,7 +104,7 @@ impl + 'static> SystemContextHandl /// /// # Panics /// If the internal consensus is in an inconsistent state. - pub async fn get_decided_state(&self) -> TYPES::StateType { + pub async fn get_decided_state(&self) -> TYPES::ValidatedState { self.hotshot.get_decided_state().await } diff --git a/crates/task-impls/src/consensus.rs b/crates/task-impls/src/consensus.rs index 3d29c71674..9c35a62abe 100644 --- a/crates/task-impls/src/consensus.rs +++ b/crates/task-impls/src/consensus.rs @@ -28,10 +28,10 @@ use hotshot_types::{ consensus_api::ConsensusApi, election::Membership, network::{CommunicationChannel, ConsensusIntentEvent}, - node_implementation::{NodeImplementation, NodeType}, + node_implementation::{ConsensusTime, NodeImplementation, NodeType}, signature_key::SignatureKey, - state::ConsensusTime, - BlockPayload, State, + states::ValidatedState, + BlockPayload, }, utils::{Terminator, ViewInner}, vote::{Certificate, HasViewNumber}, @@ -154,7 +154,7 @@ impl, A: ConsensusApi + async fn genesis_leaf(&self) -> Option> { let consensus = self.consensus.read().await; - let Some(genesis_view) = consensus.state_map.get(&TYPES::Time::genesis()) else { + let Some(genesis_view) = consensus.validated_state_map.get(&TYPES::Time::genesis()) else { error!("Couldn't find genesis view in state map."); return None; }; @@ -538,10 +538,11 @@ impl, A: ConsensusApi + block_payload: None, proposer_id: sender, }; - let state = - ::from_header(&proposal.data.block_header); + let state = ::from_header( + &proposal.data.block_header, + ); - consensus.state_map.insert( + consensus.validated_state_map.insert( view, View { view_inner: ViewInner::Leaf { @@ -592,9 +593,9 @@ impl, A: ConsensusApi + return; }; let Ok(state) = parent_state.validate_and_apply_header( - &proposal.data.block_header.clone(), + &consensus.instance_state, &parent.block_header.clone(), - &view, + &proposal.data.block_header.clone(), ) else { error!("Block header doesn't extend the proposal",); return; @@ -749,7 +750,7 @@ impl, A: ConsensusApi + HashSet::new() }; - consensus.state_map.insert( + consensus.validated_state_map.insert( view, View { view_inner: ViewInner::Leaf { @@ -1164,7 +1165,7 @@ impl, A: ConsensusApi + let parent_view_number = &consensus.high_qc.get_view_number(); let mut reached_decided = false; - let Some(parent_view) = consensus.state_map.get(parent_view_number) else { + let Some(parent_view) = consensus.validated_state_map.get(parent_view_number) else { // This should have been added by the replica? error!("Couldn't find parent view in state map, waiting for replica to see proposal\n parent view number: {}", **parent_view_number); return false; @@ -1216,10 +1217,11 @@ impl, A: ConsensusApi + if let Some(commit_and_metadata) = &self.payload_commitment_and_metadata { let block_header = TYPES::BlockHeader::new( + state, + &consensus.instance_state, + &parent_header, commit_and_metadata.commitment, commit_and_metadata.metadata.clone(), - &parent_header, - state, ); let leaf = Leaf { view_number: view, diff --git a/crates/task-impls/src/da.rs b/crates/task-impls/src/da.rs index bab588d1dd..9f4ec122c6 100644 --- a/crates/task-impls/src/da.rs +++ b/crates/task-impls/src/da.rs @@ -22,9 +22,8 @@ use hotshot_types::{ consensus_api::ConsensusApi, election::Membership, network::{CommunicationChannel, ConsensusIntentEvent}, - node_implementation::{NodeImplementation, NodeType}, + node_implementation::{ConsensusTime, NodeImplementation, NodeType}, signature_key::SignatureKey, - state::ConsensusTime, }, utils::ViewInner, vote::HasViewNumber, @@ -185,7 +184,7 @@ impl, A: ConsensusApi + // Ensure this view is in the view map for garbage collection, but do not overwrite if // there is already a view there: the replica task may have inserted a `Leaf` view which // contains strictly more information. - consensus.state_map.entry(view).or_insert(View { + consensus.validated_state_map.entry(view).or_insert(View { view_inner: ViewInner::DA { payload_commitment }, }); diff --git a/crates/task-impls/src/transactions.rs b/crates/task-impls/src/transactions.rs index 3fe87ab312..4bb3d46091 100644 --- a/crates/task-impls/src/transactions.rs +++ b/crates/task-impls/src/transactions.rs @@ -204,7 +204,8 @@ impl, A: ConsensusApi + let consensus = self.consensus.read().await; let parent_view_number = &consensus.high_qc.view_number; - let Some(parent_view) = consensus.state_map.get(parent_view_number) else { + let Some(parent_view) = consensus.validated_state_map.get(parent_view_number) + else { error!( "Couldn't find high QC parent in state map. Parent view {:?}", parent_view_number diff --git a/crates/task-impls/src/view_sync.rs b/crates/task-impls/src/view_sync.rs index 56d046d6e7..a123cee52f 100644 --- a/crates/task-impls/src/view_sync.rs +++ b/crates/task-impls/src/view_sync.rs @@ -36,8 +36,7 @@ use hotshot_types::{ consensus_api::ConsensusApi, election::Membership, network::CommunicationChannel, - node_implementation::{NodeImplementation, NodeType}, - state::ConsensusTime, + node_implementation::{ConsensusTime, NodeImplementation, NodeType}, }, }; use snafu::Snafu; diff --git a/crates/testing/src/block_types.rs b/crates/testing/src/block_types.rs index 525a83378a..c581f7726a 100644 --- a/crates/testing/src/block_types.rs +++ b/crates/testing/src/block_types.rs @@ -7,15 +7,14 @@ use commit::{Commitment, Committable, RawCommitmentBuilder}; use hotshot_types::{ data::{BlockError, VidCommitment, VidScheme, VidSchemeTrait}, traits::{ - block_contents::{vid_commitment, BlockHeader, Transaction}, - state::TestableBlock, - BlockPayload, + block_contents::{vid_commitment, BlockHeader, TestableBlock, Transaction}, + BlockPayload, ValidatedState, }, }; use serde::{Deserialize, Serialize}; use sha3::{Digest, Keccak256}; -use crate::state_types::TestState; +use crate::state_types::TestValidatedState; /// The transaction in a [`TestBlockPayload`]. #[derive(Default, PartialEq, Eq, Hash, Serialize, Deserialize, Clone, Debug)] @@ -183,13 +182,14 @@ pub struct TestBlockHeader { impl BlockHeader for TestBlockHeader { type Payload = TestBlockPayload; - type State = TestState; + type State = TestValidatedState; fn new( + _parent_state: &Self::State, + _instance_state: &::Instance, + parent_header: &Self, payload_commitment: VidCommitment, _metadata: ::Metadata, - parent_header: &Self, - _parent_state: &Self::State, ) -> Self { Self { block_number: parent_header.block_number + 1, @@ -197,7 +197,9 @@ impl BlockHeader for TestBlockHeader { } } - fn genesis() -> ( + fn genesis( + _instance_state: &::Instance, + ) -> ( Self, Self::Payload, ::Metadata, diff --git a/crates/testing/src/node_types.rs b/crates/testing/src/node_types.rs index 92b1b3d010..4edb033443 100644 --- a/crates/testing/src/node_types.rs +++ b/crates/testing/src/node_types.rs @@ -2,7 +2,7 @@ use hotshot::traits::election::static_committee::GeneralStaticCommittee; use crate::{ block_types::{TestBlockHeader, TestBlockPayload, TestTransaction}, - state_types::TestState, + state_types::{TestInstanceState, TestValidatedState}, }; use hotshot::traits::{ @@ -42,7 +42,8 @@ impl NodeType for TestTypes { type SignatureKey = BLSPubKey; type Transaction = TestTransaction; type ElectionConfigType = StaticElectionConfig; - type StateType = TestState; + type ValidatedState = TestValidatedState; + type InstanceState = TestInstanceState; type Membership = GeneralStaticCommittee; } diff --git a/crates/testing/src/spinning_task.rs b/crates/testing/src/spinning_task.rs index 145f7d95a8..d3311a8a24 100644 --- a/crates/testing/src/spinning_task.rs +++ b/crates/testing/src/spinning_task.rs @@ -13,8 +13,10 @@ use hotshot_task::{ MergeN, }; use hotshot_types::traits::network::CommunicationChannel; -use hotshot_types::traits::state::ConsensusTime; -use hotshot_types::{event::Event, traits::node_implementation::NodeType}; +use hotshot_types::{ + event::Event, + traits::node_implementation::{ConsensusTime, NodeType}, +}; use snafu::Snafu; use crate::{ diff --git a/crates/testing/src/state_types.rs b/crates/testing/src/state_types.rs index aba587fce4..7d2c6794b5 100644 --- a/crates/testing/src/state_types.rs +++ b/crates/testing/src/state_types.rs @@ -4,8 +4,8 @@ use commit::{Commitment, Committable}; use hotshot_types::{ data::{fake_commitment, BlockError, ViewNumber}, traits::{ - state::{ConsensusTime, TestableState}, - BlockPayload, State, + states::{InstanceState, TestableState, ValidatedState}, + BlockPayload, }, }; @@ -16,22 +16,25 @@ use crate::block_types::TestTransaction; use crate::block_types::{TestBlockHeader, TestBlockPayload}; pub use crate::node_types::TestTypes; -/// sequencing demo entry state +/// Instance-level state implementation for testing purposes. +#[derive(Clone, Debug)] +pub struct TestInstanceState {} + +impl InstanceState for TestInstanceState {} + +/// Validated state implementation for testing purposes. #[derive(PartialEq, Eq, Hash, Serialize, Deserialize, Clone, Debug)] -pub struct TestState { +pub struct TestValidatedState { /// the block height block_height: u64, - /// the view number - view_number: ViewNumber, /// the previous state commitment prev_state_commitment: Commitment, } -impl Committable for TestState { +impl Committable for TestValidatedState { fn commit(&self) -> Commitment { commit::RawCommitmentBuilder::new("Test State Commit") .u64_field("block_height", self.block_height) - .u64_field("view_number", *self.view_number) .field("prev_state_commitment", self.prev_state_commitment) .finalize() } @@ -41,19 +44,20 @@ impl Committable for TestState { } } -impl Default for TestState { +impl Default for TestValidatedState { fn default() -> Self { Self { block_height: 0, - view_number: ViewNumber::genesis(), prev_state_commitment: fake_commitment(), } } } -impl State for TestState { +impl ValidatedState for TestValidatedState { type Error = BlockError; + type Instance = TestInstanceState; + type BlockHeader = TestBlockHeader; type BlockPayload = TestBlockPayload; @@ -62,20 +66,12 @@ impl State for TestState { fn validate_and_apply_header( &self, - _proposed_header: &Self::BlockHeader, + _instance: &Self::Instance, _parent_header: &Self::BlockHeader, - view_number: &Self::Time, + _proposed_header: &Self::BlockHeader, ) -> Result { - if view_number == &ViewNumber::genesis() { - if &self.view_number != view_number { - return Err(BlockError::InvalidBlockHeader); - } - } else if self.view_number >= *view_number { - return Err(BlockError::InvalidBlockHeader); - } - Ok(TestState { + Ok(TestValidatedState { block_height: self.block_height + 1, - view_number: *view_number, prev_state_commitment: self.commit(), }) } @@ -90,7 +86,7 @@ impl State for TestState { fn on_commit(&self) {} } -impl TestableState for TestState { +impl TestableState for TestValidatedState { fn create_random_transaction( _state: Option<&Self>, _rng: &mut dyn rand::RngCore, diff --git a/crates/testing/src/task_helpers.rs b/crates/testing/src/task_helpers.rs index 998497c46a..73068e94eb 100644 --- a/crates/testing/src/task_helpers.rs +++ b/crates/testing/src/task_helpers.rs @@ -4,7 +4,7 @@ use std::marker::PhantomData; use crate::{ block_types::{TestBlockHeader, TestBlockPayload}, node_types::{MemoryImpl, TestTypes}, - state_types::TestState, + state_types::{TestInstanceState, TestValidatedState}, test_builder::TestMetadata, }; use commit::Committable; @@ -22,13 +22,12 @@ use hotshot_types::{ simple_certificate::QuorumCertificate, simple_vote::SimpleVote, traits::{ - block_contents::vid_commitment, - block_contents::BlockHeader, + block_contents::{vid_commitment, BlockHeader, TestableBlock}, consensus_api::ConsensusApi, election::Membership, - node_implementation::NodeType, - state::{ConsensusTime, TestableBlock}, - BlockPayload, State, + node_implementation::{ConsensusTime, NodeType}, + states::ValidatedState, + BlockPayload, }, vote::HasViewNumber, }; @@ -62,7 +61,7 @@ pub async fn build_system_handle( let storage = (launcher.resource_generator.storage)(node_id); let config = launcher.resource_generator.config.clone(); - let initializer = HotShotInitializer::::from_genesis().unwrap(); + let initializer = HotShotInitializer::::from_genesis(&TestInstanceState {}).unwrap(); let known_nodes_with_stake = config.known_nodes_with_stake.clone(); let private_key = config.my_own_validator_config.private_key.clone(); @@ -217,7 +216,7 @@ async fn build_quorum_proposal_and_signature( // parent_view_number should be equal to 0 let parent_view_number = &consensus.high_qc.get_view_number(); assert_eq!(parent_view_number.get_u64(), 0); - let Some(parent_view) = consensus.state_map.get(parent_view_number) else { + let Some(parent_view) = consensus.validated_state_map.get(parent_view_number) else { panic!("Couldn't find high QC parent in state map."); }; let Some(leaf_view_0) = parent_view.get_leaf_commitment() else { @@ -239,12 +238,14 @@ async fn build_quorum_proposal_and_signature( .quorum_membership .total_nodes(), ); - let mut parent_state = ::from_header(&parent_leaf.block_header); + let mut parent_state = + ::from_header(&parent_leaf.block_header); let block_header = TestBlockHeader::new( + &parent_state, + &TestInstanceState {}, + &parent_leaf.block_header, payload_commitment, (), - &parent_leaf.block_header, - &parent_state, ); // current leaf that can be re-assigned everytime when entering a new view let mut leaf = Leaf { @@ -269,11 +270,11 @@ async fn build_quorum_proposal_and_signature( // Only view 2 is tested, higher views are not tested for cur_view in 2..=view { let state_new_view = parent_state - .validate_and_apply_header(&block_header, &block_header, &ViewNumber::new(cur_view - 1)) + .validate_and_apply_header(&TestInstanceState {}, &block_header, &block_header) .unwrap(); // save states for the previous view to pass all the qc checks // In the long term, we want to get rid of this, do not manually update consensus state - consensus.state_map.insert( + consensus.validated_state_map.insert( ViewNumber::new(cur_view - 1), View { view_inner: ViewInner::Leaf { diff --git a/crates/testing/src/test_runner.rs b/crates/testing/src/test_runner.rs index aadd6f1ffb..f1d4cf237b 100644 --- a/crates/testing/src/test_runner.rs +++ b/crates/testing/src/test_runner.rs @@ -6,6 +6,7 @@ use super::{ }; use crate::{ spinning_task::{ChangeNode, UpDown}, + state_types::TestInstanceState, test_launcher::{Networks, TestLauncher}, view_sync_task::ViewSyncTask, }; @@ -18,7 +19,10 @@ use hotshot_task::{ use hotshot_types::traits::network::CommunicationChannel; use hotshot_types::{ consensus::ConsensusMetricsValue, - traits::{election::Membership, node_implementation::NodeType, state::ConsensusTime}, + traits::{ + election::Membership, + node_implementation::{ConsensusTime, NodeType}, + }, HotShotConfig, ValidatorConfig, }; use std::{ @@ -64,7 +68,8 @@ pub struct TestRunner> { pub(crate) task_runner: TaskRunner, } -impl> TestRunner +impl, I: TestableNodeImplementation> + TestRunner where I: TestableNodeImplementation, { @@ -225,7 +230,8 @@ where let node_id = self.next_node_id; let storage = (self.launcher.resource_generator.storage)(node_id); let config = self.launcher.resource_generator.config.clone(); - let initializer = HotShotInitializer::::from_genesis().unwrap(); + let initializer = + HotShotInitializer::::from_genesis(&TestInstanceState {}).unwrap(); let networks = (self.launcher.resource_generator.channel_generator)(node_id); // We assign node's public key and stake value rather than read from config file since it's a test let validator_config = diff --git a/crates/testing/tests/atomic_storage.rs b/crates/testing/tests/atomic_storage.rs index a10bee76ed..0071621978 100644 --- a/crates/testing/tests/atomic_storage.rs +++ b/crates/testing/tests/atomic_storage.rs @@ -5,9 +5,9 @@ use hotshot::{ random_quorom_certificate, random_transaction, random_validating_leaf, VDemoBlock, VDemoState, }, - traits::{BlockPayload, State, Storage}, + traits::{BlockPayload, Storage, ValidatedState}, }; -use hotshot_types::{data::ViewNumber, traits::state::TestableState}; +use hotshot_types::{data::ViewNumber, traits::statesTestableState}; use rand::thread_rng; type AtomicStorage = hotshot::traits::implementations::AtomicStorage; @@ -94,7 +94,7 @@ async fn test_happy_path_leaves() { let mut store = AtomicStorage::open(path).expect("Could not open atomic store"); // Add some leaves - let mut leaves = Vec::>::new(); + let mut leaves = Vec::>::new(); for _ in 0..10 { let leaf = random_validating_leaf(DEntryBlock { previous_block: StateHash::random(), diff --git a/crates/testing/tests/consensus_task.rs b/crates/testing/tests/consensus_task.rs index 29468a1284..b5cdcc7887 100644 --- a/crates/testing/tests/consensus_task.rs +++ b/crates/testing/tests/consensus_task.rs @@ -12,7 +12,7 @@ use hotshot_types::vote::Certificate; use hotshot_types::{ data::{Leaf, QuorumProposal, ViewNumber}, message::GeneralConsensusMessage, - traits::state::ConsensusTime, + traits::node_implementation::ConsensusTime, }; use hotshot_types::{ simple_vote::QuorumData, @@ -35,7 +35,7 @@ async fn build_vote( let justify_qc = proposal.justify_qc.clone(); let view = ViewNumber::new(*proposal.view_number); let parent = if justify_qc.is_genesis { - let Some(genesis_view) = consensus.state_map.get(&ViewNumber::new(0)) else { + let Some(genesis_view) = consensus.validated_state_map.get(&ViewNumber::new(0)) else { panic!("Couldn't find genesis view in state map."); }; let Some(leaf) = genesis_view.get_leaf_commitment() else { @@ -194,6 +194,7 @@ async fn test_consensus_vote() { // issue: https://github.com/EspressoSystems/HotShot/issues/2236 #[ignore] async fn test_consensus_with_vid() { + use hotshot::traits::BlockPayload; use hotshot::types::SignatureKey; use hotshot_task_impls::harness::run_harness; use hotshot_testing::block_types::TestBlockPayload; @@ -205,9 +206,7 @@ async fn test_consensus_with_vid() { use hotshot_types::simple_certificate::DACertificate; use hotshot_types::simple_vote::DAData; use hotshot_types::simple_vote::DAVote; - use hotshot_types::traits::block_contents::vid_commitment; - use hotshot_types::traits::state::TestableBlock; - use hotshot_types::traits::BlockPayload; + use hotshot_types::traits::block_contents::{vid_commitment, TestableBlock}; use hotshot_types::{ data::VidDisperse, message::Proposal, traits::node_implementation::NodeType, }; diff --git a/crates/testing/tests/da_task.rs b/crates/testing/tests/da_task.rs index 3d532126b0..fa0e12eb43 100644 --- a/crates/testing/tests/da_task.rs +++ b/crates/testing/tests/da_task.rs @@ -8,8 +8,10 @@ use hotshot_types::{ data::{DAProposal, ViewNumber}, simple_vote::{DAData, DAVote}, traits::{ - block_contents::vid_commitment, consensus_api::ConsensusApi, election::Membership, - node_implementation::NodeType, state::ConsensusTime, + block_contents::vid_commitment, + consensus_api::ConsensusApi, + election::Membership, + node_implementation::{ConsensusTime, NodeType}, }, }; use sha2::{Digest, Sha256}; diff --git a/crates/testing/tests/memory_network.rs b/crates/testing/tests/memory_network.rs index b548a736e8..7648d30174 100644 --- a/crates/testing/tests/memory_network.rs +++ b/crates/testing/tests/memory_network.rs @@ -10,19 +10,19 @@ use hotshot::traits::implementations::{ use hotshot::traits::NodeImplementation; use hotshot::types::SignatureKey; use hotshot_constants::PROGRAM_PROTOCOL_VERSION; +use hotshot_testing::state_types::TestInstanceState; use hotshot_testing::{ block_types::{TestBlockHeader, TestBlockPayload, TestTransaction}, - state_types::TestState, + state_types::TestValidatedState, }; use hotshot_types::message::Message; use hotshot_types::signature_key::BLSPubKey; use hotshot_types::traits::network::TestableNetworkingImplementation; use hotshot_types::traits::network::{ConnectedNetwork, TransmitType}; -use hotshot_types::traits::node_implementation::{ChannelMaps, NodeType}; +use hotshot_types::traits::node_implementation::{ChannelMaps, ConsensusTime, NodeType}; use hotshot_types::{ data::ViewNumber, message::{DataMessage, MessageKind}, - traits::state::ConsensusTime, }; use rand::rngs::StdRng; use rand::{RngCore, SeedableRng}; @@ -52,7 +52,8 @@ impl NodeType for Test { type SignatureKey = BLSPubKey; type Transaction = TestTransaction; type ElectionConfigType = StaticElectionConfig; - type StateType = TestState; + type ValidatedState = TestValidatedState; + type InstanceState = TestInstanceState; type Membership = GeneralStaticCommittee; } diff --git a/crates/testing/tests/network_task.rs b/crates/testing/tests/network_task.rs index d47638506f..a3810fc21b 100644 --- a/crates/testing/tests/network_task.rs +++ b/crates/testing/tests/network_task.rs @@ -6,7 +6,7 @@ use hotshot_testing::{ }; use hotshot_types::{ data::{DAProposal, VidSchemeTrait, ViewNumber}, - traits::{consensus_api::ConsensusApi, state::ConsensusTime}, + traits::{consensus_api::ConsensusApi, node_implementation::ConsensusTime}, }; use sha2::{Digest, Sha256}; use std::{collections::HashMap, marker::PhantomData}; diff --git a/crates/testing/tests/unit/message.rs b/crates/testing/tests/unit/message.rs index 6e03fcc0ef..21f0ac4ac1 100644 --- a/crates/testing/tests/unit/message.rs +++ b/crates/testing/tests/unit/message.rs @@ -13,7 +13,7 @@ use hotshot_types::{ signature_key::BLSPubKey, simple_certificate::SimpleCertificate, simple_vote::ViewSyncCommitData, - traits::{signature_key::SignatureKey, state::ConsensusTime}, + traits::{node_implementation::ConsensusTime, signature_key::SignatureKey}, }; #[test] diff --git a/crates/testing/tests/vid_task.rs b/crates/testing/tests/vid_task.rs index 68d40f4d2c..85e1d27fb2 100644 --- a/crates/testing/tests/vid_task.rs +++ b/crates/testing/tests/vid_task.rs @@ -5,10 +5,10 @@ use hotshot_testing::{ node_types::{MemoryImpl, TestTypes}, task_helpers::vid_init, }; -use hotshot_types::traits::node_implementation::NodeType; +use hotshot_types::traits::node_implementation::{ConsensusTime, NodeType}; use hotshot_types::{ data::{DAProposal, VidDisperse, VidSchemeTrait, ViewNumber}, - traits::{consensus_api::ConsensusApi, state::ConsensusTime}, + traits::consensus_api::ConsensusApi, }; use std::collections::HashMap; use std::marker::PhantomData; diff --git a/crates/testing/tests/view_sync_task.rs b/crates/testing/tests/view_sync_task.rs index 2a0f5c94df..5dd956a145 100644 --- a/crates/testing/tests/view_sync_task.rs +++ b/crates/testing/tests/view_sync_task.rs @@ -1,7 +1,7 @@ use hotshot::HotShotConsensusApi; use hotshot_task_impls::events::HotShotEvent; use hotshot_testing::node_types::{MemoryImpl, TestTypes}; -use hotshot_types::{data::ViewNumber, traits::state::ConsensusTime}; +use hotshot_types::{data::ViewNumber, traits::node_implementation::ConsensusTime}; use std::collections::HashMap; #[cfg(test)] diff --git a/crates/types/src/consensus.rs b/crates/types/src/consensus.rs index 1773ca3a17..e379060458 100644 --- a/crates/types/src/consensus.rs +++ b/crates/types/src/consensus.rs @@ -32,9 +32,11 @@ type CommitmentMap = HashMap, T>; /// This will contain the state of all rounds. #[derive(custom_debug::Debug)] pub struct Consensus { - /// The phases that are currently loaded in memory - // TODO(https://github.com/EspressoSystems/hotshot/issues/153): Allow this to be loaded from `Storage`? - pub state_map: BTreeMap>, + /// Immutable instance-level state. + pub instance_state: TYPES::InstanceState, + + /// The validated states that are currently loaded in memory. + pub validated_state_map: BTreeMap>, /// All the DA certs we've received for current and future views. /// view -> DA cert @@ -253,7 +255,7 @@ impl Consensus { where F: FnMut(&Leaf) -> bool, { - let mut next_leaf = if let Some(view) = self.state_map.get(&start_from) { + let mut next_leaf = if let Some(view) = self.validated_state_map.get(&start_from) { view.get_leaf_commitment() .ok_or_else(|| HotShotError::InvalidState { context: format!( @@ -292,7 +294,7 @@ impl Consensus { } /// Garbage collects based on state change right now, this removes from both the - /// `saved_payloads` and `state_map` fields of `Consensus`. + /// `saved_payloads` and `validated_state_map` fields of `Consensus`. /// # Panics /// On inconsistent stored entries #[allow(clippy::unused_async)] // async for API compatibility reasons @@ -303,7 +305,7 @@ impl Consensus { ) { // state check let anchor_entry = self - .state_map + .validated_state_map .iter() .next() .expect("INCONSISTENT STATE: anchor leaf not in state map!"); @@ -315,13 +317,13 @@ impl Consensus { // perform gc self.saved_da_certs .retain(|view_number, _| *view_number >= old_anchor_view); - self.state_map + self.validated_state_map .range(old_anchor_view..new_anchor_view) .filter_map(|(_view_number, view)| view.get_leaf_commitment()) .for_each(|leaf| { self.saved_leaves.remove(&leaf); }); - self.state_map = self.state_map.split_off(&new_anchor_view); + self.validated_state_map = self.validated_state_map.split_off(&new_anchor_view); self.saved_payloads = self.saved_payloads.split_off(&new_anchor_view); } @@ -333,7 +335,7 @@ impl Consensus { #[must_use] pub fn get_decided_leaf(&self) -> Leaf { let decided_view_num = self.last_decided_view; - let view = self.state_map.get(&decided_view_num).unwrap(); + let view = self.validated_state_map.get(&decided_view_num).unwrap(); let leaf = view .get_leaf_commitment() .expect("Decided leaf not found! Consensus internally inconsistent"); @@ -342,8 +344,8 @@ impl Consensus { /// Gets the validated state with the given view number, if in the state map. #[must_use] - pub fn get_state(&self, view_number: TYPES::Time) -> Option<&TYPES::StateType> { - match self.state_map.get(&view_number) { + pub fn get_state(&self, view_number: TYPES::Time) -> Option<&TYPES::ValidatedState> { + match self.validated_state_map.get(&view_number) { Some(view) => view.get_state(), None => None, } @@ -355,7 +357,7 @@ impl Consensus { /// If the last decided view's state does not exist in the state map, which should never /// happen. #[must_use] - pub fn get_decided_state(&self) -> &TYPES::StateType { + pub fn get_decided_state(&self) -> &TYPES::ValidatedState { let decided_view_num = self.last_decided_view; self.get_state(decided_view_num) .expect("Decided state not found! Consensus internally inconsistent") diff --git a/crates/types/src/data.rs b/crates/types/src/data.rs index 9274ad8eb1..66537bdb73 100644 --- a/crates/types/src/data.rs +++ b/crates/types/src/data.rs @@ -7,14 +7,13 @@ use crate::{ simple_certificate::{QuorumCertificate, TimeoutCertificate}, simple_vote::UpgradeProposalData, traits::{ - block_contents::vid_commitment, - block_contents::BlockHeader, + block_contents::{vid_commitment, BlockHeader, TestableBlock}, election::Membership, - node_implementation::NodeType, + node_implementation::{ConsensusTime, NodeType}, signature_key::SignatureKey, - state::{ConsensusTime, TestableBlock, TestableState}, + states::{TestableState, ValidatedState}, storage::StoredView, - BlockPayload, State, + BlockPayload, }, vote::{Certificate, HasViewNumber}, }; @@ -106,9 +105,10 @@ impl std::ops::Sub for ViewNumber { } } -/// The `Transaction` type associated with a `State`, as a syntactic shortcut -pub type Transaction = <::BlockPayload as BlockPayload>::Transaction; -/// `Commitment` to the `Transaction` type associated with a `State`, as a syntactic shortcut +/// The `Transaction` type associated with a `ValidatedState`, as a syntactic shortcut +pub type Transaction = + <::BlockPayload as BlockPayload>::Transaction; +/// `Commitment` to the `Transaction` type associated with a `ValidatedState`, as a syntactic shortcut pub type TxnCommitment = Commitment>; /// A proposal to start providing data availability for a block. @@ -363,8 +363,8 @@ impl Display for Leaf { impl Leaf { /// Create a new leaf from its components. #[must_use] - pub fn genesis() -> Self { - let (block_header, block_payload, _) = TYPES::BlockHeader::genesis(); + pub fn genesis(instance_state: &TYPES::InstanceState) -> Self { + let (block_header, block_payload, _) = TYPES::BlockHeader::genesis(instance_state); Self { view_number: TYPES::Time::genesis(), justify_qc: QuorumCertificate::::genesis(), @@ -442,6 +442,7 @@ impl Leaf { pub fn get_proposer_id(&self) -> TYPES::SignatureKey { self.proposer_id.clone() } + /// Create a leaf from information stored about a view. pub fn from_stored_view(stored_view: StoredView) -> Self { Self { @@ -457,7 +458,7 @@ impl Leaf { impl TestableLeaf for Leaf where - TYPES::StateType: TestableState, + TYPES::ValidatedState: TestableState, TYPES::BlockPayload: TestableBlock, { type NodeType = TYPES; @@ -467,7 +468,7 @@ where rng: &mut dyn rand::RngCore, padding: u64, ) -> <::BlockPayload as BlockPayload>::Transaction { - TYPES::StateType::create_random_transaction(None, rng, padding) + TYPES::ValidatedState::create_random_transaction(None, rng, padding) } } /// Fake the thing a genesis block points to. Needed to avoid infinite recursion diff --git a/crates/types/src/simple_certificate.rs b/crates/types/src/simple_certificate.rs index cd609755e2..1592583e90 100644 --- a/crates/types/src/simple_certificate.rs +++ b/crates/types/src/simple_certificate.rs @@ -16,8 +16,8 @@ use crate::{ ViewSyncFinalizeData, ViewSyncPreCommitData, Voteable, }, traits::{ - election::Membership, node_implementation::NodeType, signature_key::SignatureKey, - state::ConsensusTime, + election::Membership, node_implementation::ConsensusTime, node_implementation::NodeType, + signature_key::SignatureKey, }, vote::{Certificate, HasViewNumber}, }; diff --git a/crates/types/src/traits.rs b/crates/types/src/traits.rs index 9c25e5fcb8..a698d2c158 100644 --- a/crates/types/src/traits.rs +++ b/crates/types/src/traits.rs @@ -8,8 +8,8 @@ pub mod node_implementation; pub mod qc; pub mod signature_key; pub mod stake_table; -pub mod state; +pub mod states; pub mod storage; pub use block_contents::BlockPayload; -pub use state::State; +pub use states::ValidatedState; diff --git a/crates/types/src/traits/block_contents.rs b/crates/types/src/traits/block_contents.rs index 00a7880c74..92785ed1b2 100644 --- a/crates/types/src/traits/block_contents.rs +++ b/crates/types/src/traits/block_contents.rs @@ -5,7 +5,7 @@ use crate::{ data::{test_srs, VidCommitment, VidScheme, VidSchemeTrait}, - traits::State, + traits::ValidatedState, }; use commit::{Commitment, Committable}; use serde::{de::DeserializeOwned, Serialize}; @@ -79,6 +79,15 @@ pub trait BlockPayload: ) -> Vec>; } +/// extra functions required on block to be usable by hotshot-testing +pub trait TestableBlock: BlockPayload + Debug { + /// generate a genesis block + fn genesis() -> Self; + + /// the number of transactions in this block + fn txn_count(&self) -> u64; +} + /// Compute the VID payload commitment. /// # Panics /// If the VID computation fails. @@ -104,18 +113,22 @@ pub trait BlockHeader: type Payload: BlockPayload; /// Validated state. - type State: State; + type State: ValidatedState; - /// Build a header with the payload commitment, metadata, parent header, and parent state. + /// Build a header with the payload commitment, metadata, instance-level state, parent header, + /// and parent state. fn new( + parent_state: &Self::State, + instance_state: &::Instance, + parent_header: &Self, payload_commitment: VidCommitment, metadata: ::Metadata, - parent_header: &Self, - parent_state: &Self::State, ) -> Self; /// Build the genesis header, payload, and metadata. - fn genesis() -> ( + fn genesis( + instance_state: &::Instance, + ) -> ( Self, Self::Payload, ::Metadata, diff --git a/crates/types/src/traits/node_implementation.rs b/crates/types/src/traits/node_implementation.rs index 10796f2275..df0dac8d0d 100644 --- a/crates/types/src/traits/node_implementation.rs +++ b/crates/types/src/traits/node_implementation.rs @@ -4,29 +4,32 @@ //! describing the overall behavior of a node, as a composition of implementations of the node trait. use super::{ - block_contents::{BlockHeader, Transaction}, + block_contents::{BlockHeader, TestableBlock, Transaction}, election::ElectionConfig, network::{CommunicationChannel, NetworkReliability, TestableNetworkingImplementation}, - state::{ConsensusTime, TestableBlock, TestableState}, + states::TestableState, storage::{StorageError, StorageState, TestableStorage}, - State, + ValidatedState, }; use crate::{ data::{Leaf, TestableLeaf}, message::ProcessedSequencingMessage, traits::{ election::Membership, network::TestableChannelImplementation, signature_key::SignatureKey, - storage::Storage, BlockPayload, + states::InstanceState, storage::Storage, BlockPayload, }, }; use async_compatibility_layer::channel::{unbounded, UnboundedReceiver, UnboundedSender}; use async_lock::{Mutex, RwLock}; use async_trait::async_trait; +use commit::Committable; use serde::{Deserialize, Serialize}; use std::{ collections::BTreeMap, fmt::Debug, hash::Hash, + ops, + ops::{Deref, Sub}, sync::{atomic::AtomicBool, Arc}, }; @@ -138,7 +141,7 @@ pub trait TestableNodeImplementation: NodeImplementation /// otherwise panics /// `padding` is the bytes of padding to add to the transaction fn state_create_random_transaction( - state: Option<&TYPES::StateType>, + state: Option<&TYPES::ValidatedState>, rng: &mut dyn rand::RngCore, padding: u64, ) -> ::Transaction; @@ -179,7 +182,7 @@ pub trait TestableNodeImplementation: NodeImplementation #[async_trait] impl> TestableNodeImplementation for I where - TYPES::StateType: TestableState, + TYPES::ValidatedState: TestableState, TYPES::BlockPayload: TestableBlock, I::Storage: TestableStorage, I::QuorumNetwork: TestableChannelImplementation, @@ -197,11 +200,11 @@ where } fn state_create_random_transaction( - state: Option<&TYPES::StateType>, + state: Option<&TYPES::ValidatedState>, rng: &mut dyn rand::RngCore, padding: u64, ) -> ::Transaction { - ::create_random_transaction(state, rng, padding) + ::create_random_transaction(state, rng, padding) } fn leaf_create_random_transaction( @@ -264,6 +267,36 @@ where } } +/// Trait for time compatibility needed for reward collection +pub trait ConsensusTime: + PartialOrd + + Ord + + Send + + Sync + + Debug + + Clone + + Copy + + Hash + + Deref + + serde::Serialize + + for<'de> serde::Deserialize<'de> + + ops::AddAssign + + ops::Add + + Sub + + 'static + + Committable +{ + /// Create a new instance of this time unit at time number 0 + #[must_use] + fn genesis() -> Self { + Self::new(0) + } + /// Create a new instance of this time unit + fn new(val: u64) -> Self; + /// Get the u64 format of time + fn get_u64(&self) -> u64; +} + /// Trait with all the type definitions that are used in the current hotshot setup. pub trait NodeType: Clone @@ -283,13 +316,13 @@ pub trait NodeType: { /// The time type that this hotshot setup is using. /// - /// This should be the same `Time` that `StateType::Time` is using. + /// This should be the same `Time` that `ValidatedState::Time` is using. type Time: ConsensusTime; /// The block header type that this hotshot setup is using. - type BlockHeader: BlockHeader; + type BlockHeader: BlockHeader; /// The block type that this hotshot setup is using. /// - /// This should be the same block that `StateType::BlockPayload` is using. + /// This should be the same block that `ValidatedState::BlockPayload` is using. type BlockPayload: BlockPayload; /// The signature key that this hotshot setup is using. type SignatureKey: SignatureKey; @@ -300,8 +333,12 @@ pub trait NodeType: /// The election config type that this hotshot setup is using. type ElectionConfigType: ElectionConfig; - /// The state type that this hotshot setup is using. - type StateType: State< + /// The instance-level state type that this hotshot setup is using. + type InstanceState: InstanceState; + + /// The validated state type that this hotshot setup is using. + type ValidatedState: ValidatedState< + Instance = Self::InstanceState, BlockHeader = Self::BlockHeader, BlockPayload = Self::BlockPayload, Time = Self::Time, diff --git a/crates/types/src/traits/state.rs b/crates/types/src/traits/state.rs deleted file mode 100644 index 0a10b58a9f..0000000000 --- a/crates/types/src/traits/state.rs +++ /dev/null @@ -1,132 +0,0 @@ -//! Abstraction over the global state that blocks modify -//! -//! This module provides the [`State`] trait, which serves as an compatibility over the current -//! network state, which is modified by the transactions contained within blocks. - -use crate::traits::BlockPayload; -use commit::Committable; -use serde::{de::DeserializeOwned, Serialize}; -use std::{ - error::Error, - fmt::Debug, - hash::Hash, - ops, - ops::{Deref, Sub}, -}; - -use super::block_contents::BlockHeader; - -/// Abstraction over the state that blocks modify -/// -/// This trait represents the behaviors that the 'global' ledger state must have: -/// * A defined error type ([`Error`](State::Error)) -/// * The type of block that modifies this type of state ([`BlockPayload`](State::BlockPayload)) -/// * The ability to validate that a block header is actually a valid extension of this state and -/// produce a new state, with the modifications from the block applied -/// ([`validate_and_apply_header`](State::validate_and_apply_header)) -pub trait State: - Serialize - + DeserializeOwned - + Clone - + Debug - + Default - + Hash - + PartialEq - + Eq - + Send - + Sync - + Committable -{ - /// The error type for this particular type of ledger state - type Error: Error + Debug + Send + Sync; - /// The type of block header this state is associated with - type BlockHeader: BlockHeader; - /// The type of block payload this state is associated with - type BlockPayload: BlockPayload; - /// Time compatibility needed for reward collection - type Time: ConsensusTime; - - /// Check if the proposed block header is valid and apply it to the state if so. - /// - /// Returns the new state. - /// - /// # Errors - /// - /// If the block header is invalid or appending it would lead to an invalid state. - fn validate_and_apply_header( - &self, - proposed_header: &Self::BlockHeader, - parent_header: &Self::BlockHeader, - view_number: &Self::Time, - ) -> Result; - - /// Construct the state with the given block header. - /// - /// This can also be used to rebuild the state for catchup. - fn from_header(block_header: &Self::BlockHeader) -> Self; - - /// Construct a genesis state. - #[must_use] - fn genesis() -> Self { - Self::from_header(&Self::BlockHeader::genesis().0) - } - - /// Gets called to notify the persistence backend that this state has been committed - fn on_commit(&self); -} - -// TODO Seuqnecing here means involving DA in consensus - -/// Trait for time compatibility needed for reward collection -pub trait ConsensusTime: - PartialOrd - + Ord - + Send - + Sync - + Debug - + Clone - + Copy - + Hash - + Deref - + serde::Serialize - + for<'de> serde::Deserialize<'de> - + ops::AddAssign - + ops::Add - + Sub - + 'static - + Committable -{ - /// Create a new instance of this time unit at time number 0 - #[must_use] - fn genesis() -> Self { - Self::new(0) - } - /// Create a new instance of this time unit - fn new(val: u64) -> Self; - /// Get the u64 format of time - fn get_u64(&self) -> u64; -} - -/// extra functions required on state to be usable by hotshot-testing -pub trait TestableState: State -where - ::BlockPayload: TestableBlock, -{ - /// Creates random transaction if possible - /// otherwise panics - /// `padding` is the bytes of padding to add to the transaction - fn create_random_transaction( - state: Option<&Self>, - rng: &mut dyn rand::RngCore, - padding: u64, - ) -> ::Transaction; -} - -/// extra functions required on block to be usable by hotshot-testing -pub trait TestableBlock: BlockPayload + Debug { - /// generate a genesis block - fn genesis() -> Self; - - /// the number of transactions in this block - fn txn_count(&self) -> u64; -} diff --git a/crates/types/src/traits/states.rs b/crates/types/src/traits/states.rs new file mode 100644 index 0000000000..0d7d5fe5ee --- /dev/null +++ b/crates/types/src/traits/states.rs @@ -0,0 +1,83 @@ +//! Abstractions over the immutable instance-level state and hte global state that blocks modify. +//! +//! This module provides the [`InstanceState`] and [`ValidatedState`] traits, which serve as +//! compatibilities over the current network state, which is modified by the transactions contained +//! within blocks. + +use super::block_contents::{BlockHeader, TestableBlock}; +use crate::traits::{node_implementation::ConsensusTime, BlockPayload}; +use serde::{de::DeserializeOwned, Serialize}; +use std::{error::Error, fmt::Debug, hash::Hash}; + +/// Instance-level state, which allows us to fetch missing validated state. +pub trait InstanceState: Clone + Debug + Send + Sync {} + +/// Abstraction over the state that blocks modify +/// +/// This trait represents the behaviors that the 'global' ledger state must have: +/// * A defined error type ([`Error`](ValidatedState::Error)) +/// * The type of block that modifies this type of state ([`BlockPayload`](`ValidatedStates:: +/// BlockPayload`)) +/// * The ability to validate that a block header is actually a valid extension of this state and +/// produce a new state, with the modifications from the block applied +/// ([`validate_and_apply_header`](`ValidatedState::validate_and_apply_header)) +pub trait ValidatedState: + Serialize + DeserializeOwned + Clone + Debug + Default + Hash + PartialEq + Eq + Send + Sync +{ + /// The error type for this particular type of ledger state + type Error: Error + Debug + Send + Sync; + /// The type of the instance-level state this state is assocaited with + type Instance: InstanceState; + /// The type of block header this state is associated with + type BlockHeader: BlockHeader; + /// The type of block payload this state is associated with + type BlockPayload: BlockPayload; + /// Time compatibility needed for reward collection + type Time: ConsensusTime; + + /// Check if the proposed block header is valid and apply it to the state if so. + /// + /// Returns the new state. + /// + /// # Arguments + /// * `instance` - Immutable instance-level state. + /// + /// # Errors + /// + /// If the block header is invalid or appending it would lead to an invalid state. + fn validate_and_apply_header( + &self, + instance: &Self::Instance, + parent_header: &Self::BlockHeader, + proposed_header: &Self::BlockHeader, + ) -> Result; + + /// Construct the state with the given block header. + /// + /// This can also be used to rebuild the state for catchup. + fn from_header(block_header: &Self::BlockHeader) -> Self; + + /// Construct a genesis validated state. + #[must_use] + fn genesis(instance: &Self::Instance) -> Self { + Self::from_header(&Self::BlockHeader::genesis(instance).0) + } + + /// Gets called to notify the persistence backend that this state has been committed + fn on_commit(&self); +} + +/// extra functions required on state to be usable by hotshot-testing +pub trait TestableState: ValidatedState +where + ::BlockPayload: TestableBlock, +{ + /// Creates random transaction if possible + /// otherwise panics + /// `padding` is the bytes of padding to add to the transaction + fn create_random_transaction( + state: Option<&Self>, + rng: &mut dyn rand::RngCore, + padding: u64, + ) -> ::Transaction; +} diff --git a/crates/types/src/utils.rs b/crates/types/src/utils.rs index c1b2ae3add..187996e360 100644 --- a/crates/types/src/utils.rs +++ b/crates/types/src/utils.rs @@ -24,7 +24,7 @@ pub enum ViewInner { /// Proposed leaf leaf: Commitment>, /// Validated state. - state: TYPES::StateType, + state: TYPES::ValidatedState, }, /// Leaf has failed Failed, @@ -32,7 +32,7 @@ pub enum ViewInner { impl ViewInner { /// Return the underlying undecide leaf view if it exists. - pub fn get_leaf(&self) -> Option<(Commitment>, &TYPES::StateType)> { + pub fn get_leaf(&self) -> Option<(Commitment>, &TYPES::ValidatedState)> { if let Self::Leaf { leaf, state } = self { Some((*leaf, state)) } else { @@ -52,7 +52,7 @@ impl ViewInner { /// return the underlying validated state if it exists #[must_use] - pub fn get_state(&self) -> Option<&TYPES::StateType> { + pub fn get_state(&self) -> Option<&TYPES::ValidatedState> { if let Self::Leaf { state, .. } = self { Some(state) } else {