diff --git a/Cargo.lock b/Cargo.lock index d85d16ad43..90bbd10bac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11326,7 +11326,6 @@ dependencies = [ "sc-executor", "sc-network", "sc-network-sync", - "sc-proof-of-time", "sc-service", "sc-storage-monitor", "sc-subspace-chain-specs", diff --git a/crates/sc-proof-of-time/src/lib.rs b/crates/sc-proof-of-time/src/lib.rs index e0c5e66b48..031651b31d 100644 --- a/crates/sc-proof-of-time/src/lib.rs +++ b/crates/sc-proof-of-time/src/lib.rs @@ -9,7 +9,7 @@ mod time_keeper; use crate::state_manager::{init_pot_state, PotProtocolState}; use core::num::{NonZeroU32, NonZeroU8}; use std::sync::Arc; -use subspace_core_primitives::{BlockNumber, PotKey, SlotNumber}; +use subspace_core_primitives::{BlockNumber, PotKey, PotSeed, SlotNumber}; use subspace_proof_of_time::ProofOfTime; pub use state_manager::{ @@ -18,10 +18,13 @@ pub use state_manager::{ pub use time_keeper::TimeKeeper; // TODO: change the fields that can't be zero to NonZero types. +// TODO: CLean up unused fields #[derive(Debug, Clone)] pub struct PotConfig { + /// PoT seed used initially when PoT chain starts. + pub initial_seed: PotSeed, + /// PoT key used initially when PoT chain starts. - // TODO: Also add seed field here pub initial_key: PotKey, /// Frequency of entropy injection from consensus. @@ -52,6 +55,10 @@ pub struct PotConfig { /// Components initialized during the new_partial() phase of set up. #[derive(Debug)] pub struct PotComponents { + /// PoT seed used initially when PoT chain starts. + // TODO: Remove this from here, shouldn't be necessary eventually + pub(crate) initial_seed: PotSeed, + /// PoT key used initially when PoT chain starts. // TODO: Remove this from here, shouldn't be necessary eventually pub(crate) initial_key: PotKey, @@ -75,10 +82,12 @@ impl PotComponents { let proof_of_time = ProofOfTime::new(config.pot_iterations, config.num_checkpoints) // TODO: Proper error handling or proof .expect("Failed to initialize proof of time"); + let initial_seed = config.initial_seed; let initial_key = config.initial_key; let (protocol_state, consensus_state) = init_pot_state(config, proof_of_time); Self { + initial_seed, initial_key, is_time_keeper, proof_of_time, diff --git a/crates/sc-proof-of-time/src/state_manager.rs b/crates/sc-proof-of-time/src/state_manager.rs index 777e3eed47..fc51a88bf0 100644 --- a/crates/sc-proof-of-time/src/state_manager.rs +++ b/crates/sc-proof-of-time/src/state_manager.rs @@ -337,13 +337,18 @@ impl InternalState { let tip = match self.chain.tip() { Some(tip) => tip.clone(), None => { + if proof.seed != self.config.initial_seed { + return Err(PotProtocolStateError::InvalidSeed { + expected: self.config.initial_seed, + actual: proof.seed, + }); + } if proof.key != self.config.initial_key { return Err(PotProtocolStateError::InvalidKey { expected: self.config.initial_key, actual: proof.key, }); } - // TODO: Check initial seed // Chain is empty, possible first proof. return Ok(()); } @@ -659,7 +664,17 @@ impl StateManager { } })?; } else { - // TODO: This is ugly, but we need initial key here right now + // TODO: This is ugly, but we need initial seed and key here right now + let initial_seed = self.state.lock().config.initial_seed; + if proof.seed != initial_seed { + return Err(PotVerifyBlockProofsError::UnexpectedSeed { + summary: summary.clone(), + block_number, + slot: slot_number, + parent_slot: parent_slot_number, + error_slot: proof.slot_number, + }); + } let initial_key = self.state.lock().config.initial_key; if proof.key != initial_key { return Err(PotVerifyBlockProofsError::UnexpectedKey { @@ -670,7 +685,6 @@ impl StateManager { error_slot: proof.slot_number, }); } - // TODO: Check initial seed } to_add.push(proof.clone()); prev_proof = Some(proof.clone()); diff --git a/crates/sc-proof-of-time/src/time_keeper.rs b/crates/sc-proof-of-time/src/time_keeper.rs index 1dd68b9fa7..5028a97b1f 100644 --- a/crates/sc-proof-of-time/src/time_keeper.rs +++ b/crates/sc-proof-of-time/src/time_keeper.rs @@ -25,6 +25,8 @@ const PROOFS_CHANNEL_SIZE: usize = 12; // 2 * reveal lag. /// The time keeper manages the protocol: periodic proof generation/verification, gossip. pub struct TimeKeeper { + // TODO: Remove this from here, shouldn't be necessary eventually + initial_seed: PotSeed, // TODO: Remove this from here, shouldn't be necessary eventually initial_key: PotKey, proof_of_time: ProofOfTime, @@ -51,6 +53,7 @@ where gossip_sender: mpsc::Sender, ) -> Self { Self { + initial_seed: components.initial_seed, initial_key: components.initial_key, proof_of_time: components.proof_of_time, pot_state: Arc::clone(&components.protocol_state), @@ -115,7 +118,7 @@ where // proofs to exist // No proof of time means genesis block, produce the very first proof let proof = self.proof_of_time.create( - PotSeed::from_genesis_block_hash(best_hash.into()), + self.initial_seed, self.initial_key, 0, best_hash.into(), diff --git a/crates/subspace-node/Cargo.toml b/crates/subspace-node/Cargo.toml index 93ab805290..ea2ac53c30 100644 --- a/crates/subspace-node/Cargo.toml +++ b/crates/subspace-node/Cargo.toml @@ -45,7 +45,6 @@ sc-consensus-slots = { version = "0.10.0-dev", git = "https://github.com/subspac sc-consensus-subspace = { version = "0.1.0", path = "../sc-consensus-subspace" } sc-subspace-chain-specs = { version = "0.1.0", path = "../sc-subspace-chain-specs" } sc-executor = { version = "0.10.0-dev", git = "https://github.com/subspace/substrate", rev = "55c157cff49b638a59d81a9f971f0f9a66829c71" } -sc-proof-of-time = { version = "0.1.0", path = "../sc-proof-of-time" } sc-service = { version = "0.10.0-dev", git = "https://github.com/subspace/substrate", rev = "55c157cff49b638a59d81a9f971f0f9a66829c71", default-features = false } sc-storage-monitor = { version = "0.1.0", git = "https://github.com/subspace/substrate", rev = "55c157cff49b638a59d81a9f971f0f9a66829c71", default-features = false } sc-telemetry = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "55c157cff49b638a59d81a9f971f0f9a66829c71" } @@ -79,9 +78,9 @@ substrate-build-script-utils = { version = "3.0.0", git = "https://github.com/su default = ["do-not-enforce-cost-of-storage"] pot = [ "sc-consensus-subspace/pot", - "sc-proof-of-time/pot", "sp-consensus-subspace/pot", "subspace-runtime/pot", + "subspace-service/pot", ] do-not-enforce-cost-of-storage = [ "subspace-runtime/do-not-enforce-cost-of-storage" diff --git a/crates/subspace-node/src/bin/subspace-node.rs b/crates/subspace-node/src/bin/subspace-node.rs index 1f02a46579..eab2ce30e9 100644 --- a/crates/subspace-node/src/bin/subspace-node.rs +++ b/crates/subspace-node/src/bin/subspace-node.rs @@ -23,13 +23,11 @@ use futures::future::TryFutureExt; use log::warn; use sc_cli::{ChainSpec, CliConfiguration, SubstrateCli}; use sc_consensus_slots::SlotProportion; -use sc_proof_of_time::{PotComponents, PotConfig}; use sc_service::PartialComponents; use sc_storage_monitor::StorageMonitorService; use sp_core::crypto::Ss58AddressFormat; use sp_core::traits::SpawnEssentialNamed; use sp_domains::GenerateGenesisStateRoot; -use std::num::{NonZeroU32, NonZeroU8}; use std::sync::Arc; use subspace_node::domain::{ AccountId32ToAccountId20Converter, DomainCli, DomainGenesisBlockBuilder, DomainInstanceStarter, @@ -38,7 +36,7 @@ use subspace_node::domain::{ use subspace_node::{Cli, ExecutorDispatch, Subcommand}; use subspace_proof_of_space::chia::ChiaTable; use subspace_runtime::{Block, RuntimeApi}; -use subspace_service::{DsnConfig, SubspaceConfiguration, SubspaceNetworking}; +use subspace_service::{DsnConfig, PotPartialConfig, SubspaceConfiguration, SubspaceNetworking}; type PosTable = ChiaTable; @@ -378,25 +376,13 @@ fn main() -> Result<(), Error> { different explicit value" ); } - let pot_components = if cli.pot_role.is_pot_enabled() { - Some(PotComponents::new( - cli.pot_role.is_time_keeper(), - // TODO: fill proper values. These are set to use less - // CPU and take less than 1 sec to produce per proof - // during the initial testing. - PotConfig { - initial_key: maybe_chain_spec_pot_initial_key - .or(cli.pot_initial_key) - .unwrap_or_default(), - randomness_update_interval_blocks: 18, - injection_depth_blocks: 90, - global_randomness_reveal_lag_slots: 6, - pot_injection_lag_slots: 6, - max_future_slots: 10, - pot_iterations: NonZeroU32::new(4 * 1_000).expect("Not zero; qed"), - num_checkpoints: NonZeroU8::new(4).expect("Not zero; qed"), - }, - )) + let pot_config = if cli.pot_role.is_pot_enabled() { + Some(PotPartialConfig { + is_timekeeper: cli.pot_role.is_time_keeper(), + initial_key: maybe_chain_spec_pot_initial_key + .or(cli.pot_initial_key) + .unwrap_or_default(), + }) } else { None }; @@ -486,7 +472,7 @@ fn main() -> Result<(), Error> { subspace_service::new_partial::( &consensus_chain_config, Some(&construct_domain_genesis_block_builder), - pot_components, + pot_config, ) .map_err(|error| { sc_service::Error::Other(format!( @@ -494,7 +480,7 @@ fn main() -> Result<(), Error> { )) })?; - subspace_service::new_full::( + subspace_service::new_full::( consensus_chain_config, partial_components, true, diff --git a/crates/subspace-service/src/lib.rs b/crates/subspace-service/src/lib.rs index 742df0646b..29328267ff 100644 --- a/crates/subspace-service/src/lib.rs +++ b/crates/subspace-service/src/lib.rs @@ -56,9 +56,9 @@ use sc_consensus_subspace::{ use sc_executor::{NativeElseWasmExecutor, NativeExecutionDispatch}; use sc_network::NetworkService; use sc_proof_of_time::gossip::{pot_gossip_peers_set_config, PotGossipWorker}; -use sc_proof_of_time::{PotComponents, TimeKeeper}; +use sc_proof_of_time::{PotComponents, PotConfig, TimeKeeper}; use sc_service::error::Error as ServiceError; -use sc_service::{Configuration, NetworkStarter, PartialComponents, SpawnTasksParams, TaskManager}; +use sc_service::{Configuration, NetworkStarter, SpawnTasksParams, TaskManager}; use sc_subspace_block_relay::{build_consensus_relay, NetworkWrapper}; use sc_telemetry::{Telemetry, TelemetryWorker}; use sp_api::{ApiExt, ConstructRuntimeApi, Metadata, ProvideRuntimeApi, TransactionFor}; @@ -79,8 +79,10 @@ use sp_session::SessionKeys; use sp_transaction_pool::runtime_api::TaggedTransactionQueue; use static_assertions::const_assert; use std::marker::PhantomData; +use std::num::{NonZeroU32, NonZeroU8}; use std::sync::Arc; use subspace_core_primitives::crypto::kzg::{embedded_kzg_settings, Kzg}; +use subspace_core_primitives::{PotKey, PotSeed}; use subspace_fraud_proof::verifier_api::VerifierClient; use subspace_networking::libp2p::multiaddr::Protocol; use subspace_networking::libp2p::Multiaddr; @@ -227,6 +229,60 @@ where } } +/// PoT configuration used in in [`new_partial()`] +// TODO: Better name +pub struct PotPartialConfig { + /// Is this node a Timekeeper + pub is_timekeeper: bool, + /// Initial PoT key + pub initial_key: PotKey, +} + +/// Other partial components returned by [`new_partial()`] +pub struct OtherPartialComponents +where + RuntimeApi: ConstructRuntimeApi> + + Send + + Sync + + 'static, + ExecutorDispatch: NativeExecutionDispatch + 'static, +{ + /// Subspace block import + pub block_import: Box< + dyn BlockImport< + Block, + Error = ConsensusError, + Transaction = TransactionFor, Block>, + > + Send + + Sync, + >, + /// Subspace link + pub subspace_link: SubspaceLink, + /// Segment headers store + pub segment_headers_store: SegmentHeadersStore>, + /// Telemetry + pub telemetry: Option, + /// PoT components + pub pot_components: Option, +} + +type PartialComponents = sc_service::PartialComponents< + FullClient, + FullBackend, + FullSelectChain, + DefaultImportQueue>, + FullPool< + Block, + FullClient, + ConsensusChainTxPreValidator< + Block, + FullClient, + FraudProofVerifier, + >, + >, + OtherPartialComponents, +>; + /// Creates `PartialComponents` for Subspace client. #[allow(clippy::type_complexity)] pub fn new_partial( @@ -237,36 +293,8 @@ pub fn new_partial( NativeElseWasmExecutor, ) -> Arc, >, - pot_components: Option, -) -> Result< - PartialComponents< - FullClient, - FullBackend, - FullSelectChain, - DefaultImportQueue>, - FullPool< - Block, - FullClient, - ConsensusChainTxPreValidator< - Block, - FullClient, - FraudProofVerifier, - >, - >, - ( - impl BlockImport< - Block, - Error = ConsensusError, - Transaction = TransactionFor, Block>, - >, - SubspaceLink, - SegmentHeadersStore>, - Option, - Option, - ), - >, - ServiceError, -> + maybe_pot_config: Option, +) -> Result, ServiceError> where PosTable: Table, RuntimeApi: ConstructRuntimeApi> @@ -363,6 +391,26 @@ where let fraud_proof_block_import = sc_consensus_fraud_proof::block_import(client.clone(), client.clone(), proof_verifier); + let pot_components = maybe_pot_config.map(|pot_config| { + PotComponents::new( + pot_config.is_timekeeper, + // TODO: fill proper values. These are set to use less + // CPU and take less than 1 sec to produce per proof + // during the initial testing. + PotConfig { + initial_seed: PotSeed::from_genesis_block_hash(client.info().genesis_hash.into()), + initial_key: pot_config.initial_key, + randomness_update_interval_blocks: 18, + injection_depth_blocks: 90, + global_randomness_reveal_lag_slots: 6, + pot_injection_lag_slots: 6, + max_future_slots: 10, + pot_iterations: NonZeroU32::new(4 * 1_000).expect("Not zero; qed"), + num_checkpoints: NonZeroU8::new(4).expect("Not zero; qed"), + }, + ) + }); + let (block_import, subspace_link) = sc_consensus_subspace::block_import::< PosTable, _, @@ -425,6 +473,14 @@ where config.role.is_authority(), )?; + let other = OtherPartialComponents { + block_import: Box::new(block_import), + subspace_link, + segment_headers_store, + telemetry, + pot_components, + }; + Ok(PartialComponents { client, backend, @@ -433,13 +489,7 @@ where keystore_container, select_chain, transaction_pool, - other: ( - block_import, - subspace_link, - segment_headers_store, - telemetry, - pot_components, - ), + other, }) } @@ -497,31 +547,9 @@ type FullNode = NewFull< >; /// Builds a new service for a full client. -#[allow(clippy::type_complexity)] -pub async fn new_full( +pub async fn new_full( config: SubspaceConfiguration, - partial_components: PartialComponents< - FullClient, - FullBackend, - FullSelectChain, - DefaultImportQueue>, - FullPool< - Block, - FullClient, - ConsensusChainTxPreValidator< - Block, - FullClient, - FraudProofVerifier, - >, - >, - ( - I, - SubspaceLink, - SegmentHeadersStore>, - Option, - Option, - ), - >, + partial_components: PartialComponents, enable_rpc_extensions: bool, block_proposal_slot_portion: SlotProportion, ) -> Result, Error> @@ -544,13 +572,6 @@ where + ObjectsApi + PreValidationObjectApi, ExecutorDispatch: NativeExecutionDispatch + 'static, - I: BlockImport< - Block, - Error = ConsensusError, - Transaction = TransactionFor, Block>, - > + Send - + Sync - + 'static, { let PartialComponents { client, @@ -560,8 +581,15 @@ where keystore_container, select_chain, transaction_pool, - other: (block_import, subspace_link, segment_headers_store, mut telemetry, pot_components), + other, } = partial_components; + let OtherPartialComponents { + block_import, + subspace_link, + segment_headers_store, + mut telemetry, + pot_components, + } = other; let (node, bootstrap_nodes) = match config.subspace_networking.clone() { SubspaceNetworking::Reuse {