From c3bfb6976cc3d5ed032a15ec15f4c15e32e5ef3c Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Fri, 22 Oct 2021 17:52:26 +0800 Subject: [PATCH 1/8] Introduce RpcClient for abstracting all rpc related functions This PR extracts all the RPC related functions to `rpc.rs` to understand the farmer more easily(at least for me). I think `rpc.rs` will be extended further in the future, e.g., `subspace_subscribeArchivedSegment`. --- crates/subspace-farmer/src/commands.rs | 4 +- crates/subspace-farmer/src/commands/farm.rs | 82 ++++++------------ crates/subspace-farmer/src/main.rs | 3 +- crates/subspace-farmer/src/rpc.rs | 92 +++++++++++++++++++++ 4 files changed, 120 insertions(+), 61 deletions(-) create mode 100644 crates/subspace-farmer/src/rpc.rs diff --git a/crates/subspace-farmer/src/commands.rs b/crates/subspace-farmer/src/commands.rs index fa667949e14e8..3a36a3e57f13c 100644 --- a/crates/subspace-farmer/src/commands.rs +++ b/crates/subspace-farmer/src/commands.rs @@ -1,3 +1,3 @@ -mod farm; +pub mod farm; -pub(crate) use farm::farm; +pub(crate) use farm::start_farm; diff --git a/crates/subspace-farmer/src/commands/farm.rs b/crates/subspace-farmer/src/commands/farm.rs index fc96c68b5f24a..4fde93fefce41 100644 --- a/crates/subspace-farmer/src/commands/farm.rs +++ b/crates/subspace-farmer/src/commands/farm.rs @@ -1,14 +1,12 @@ use crate::commitments::Commitments; use crate::object_mappings::ObjectMappings; use crate::plot::Plot; +use crate::rpc::RpcClient; use crate::{Salt, Tag}; use anyhow::{anyhow, Result}; use futures::future; use futures::future::Either; -use jsonrpsee::types::traits::{Client, SubscriptionClient}; -use jsonrpsee::types::v2::params::JsonRpcParams; use jsonrpsee::types::Subscription; -use jsonrpsee::ws_client::{WsClient, WsClientBuilder}; use log::{debug, error, info, trace}; use schnorrkel::context::SigningContext; use schnorrkel::{Keypair, PublicKey}; @@ -30,7 +28,7 @@ type SlotNumber = u64; /// Metadata necessary for farmer operation #[derive(Debug, Deserialize)] -struct FarmerMetadata { +pub struct FarmerMetadata { /// Depth `K` after which a block enters the recorded history (a global constant, as opposed /// to the client-dependent transaction confirmation depth `k`). confirmation_depth_k: u32, @@ -50,7 +48,7 @@ struct FarmerMetadata { /// Encoded block with mapping of objects that it contains #[derive(Debug, Clone, Serialize, Deserialize)] -struct EncodedBlockWithObjectMapping { +pub struct EncodedBlockWithObjectMapping { /// Encoded block block: Vec, /// Mapping of objects inside of the block @@ -59,7 +57,7 @@ struct EncodedBlockWithObjectMapping { // There are more fields in this struct, but we only care about one #[derive(Debug, Deserialize)] -struct NewHead { +pub struct NewHead { number: String, } @@ -74,7 +72,7 @@ struct Solution { /// Proposed proof of space consisting of solution and farmer's secret key for block signing #[derive(Debug, Serialize)] -struct ProposedProofOfReplicationResponse { +pub struct ProposedProofOfReplicationResponse { /// Slot number slot_number: SlotNumber, /// Solution (if present) from farmer's plot corresponding to slot number above @@ -85,7 +83,7 @@ struct ProposedProofOfReplicationResponse { /// Information about new slot that just arrived #[derive(Debug, Deserialize)] -struct SlotInfo { +pub struct SlotInfo { /// Slot number slot_number: SlotNumber, /// Slot challenge @@ -100,9 +98,9 @@ struct SlotInfo { /// Start farming by using plot in specified path and connecting to WebSocket server at specified /// address. -pub(crate) async fn farm(base_directory: PathBuf, ws_server: &str) -> Result<()> { +pub(crate) async fn start_farm(base_directory: PathBuf, ws_server: &str) -> Result<()> { info!("Connecting to RPC server"); - let client = Arc::new(WsClientBuilder::default().build(ws_server).await?); + let client = RpcClient::new(ws_server).await?; let identity_file = base_directory.join("identity.bin"); let keypair = if identity_file.exists() { @@ -133,7 +131,7 @@ pub(crate) async fn farm(base_directory: PathBuf, ws_server: &str) -> Result<()> match future::select( { - let client = Arc::clone(&client); + let client = client.clone(); let plot = plot.clone(); let commitments = commitments.clone(); let public_key = keypair.public; @@ -164,7 +162,7 @@ pub(crate) async fn farm(base_directory: PathBuf, ws_server: &str) -> Result<()> // don't want eventually /// Maintains plot in up to date state plotting new pieces as they are produced on the network. async fn background_plotting( - client: Arc, + client: RpcClient, plot: Plot, commitments: Commitments, object_mappings: ObjectMappings, @@ -178,9 +176,7 @@ async fn background_plotting( pre_genesis_object_size, pre_genesis_object_count, pre_genesis_object_seed, - } = client - .request("subspace_getFarmerMetadata", JsonRpcParams::NoParams) - .await?; + } = client.farmer_metadata().await?; // TODO: This assumes fixed size segments, which might not be the case let merkle_num_leaves = u64::from(recorded_history_segment_size / record_size * 2); @@ -198,12 +194,7 @@ async fn background_plotting( let last_archived_block_number = last_root_block.last_archived_block().number; info!("Last archived block {}", last_archived_block_number); - let maybe_last_archived_block = client - .request( - "subspace_getBlockByNumber", - JsonRpcParams::Array(vec![serde_json::to_value(last_archived_block_number)?]), - ) - .await?; + let maybe_last_archived_block = client.block_by_number(last_archived_block_number).await?; match maybe_last_archived_block { Some(EncodedBlockWithObjectMapping { @@ -321,9 +312,9 @@ async fn background_plotting( .map(|n| n + 1) .unwrap_or_default(); - // Erasure coding in archiver and piece encoding are a CPU-intensive operations + // Erasure coding in archiver and piece encoding are CPU-intensive operations. tokio::task::spawn_blocking({ - let client = Arc::clone(&client); + let client = client.clone(); let weak_plot = weak_plot.clone(); #[allow(clippy::mut_range_bound)] @@ -342,17 +333,10 @@ async fn background_plotting( let mut last_root_block = None; for block_to_archive in blocks_to_archive_from..=blocks_to_archive_to { - let block_fut = client - .request::<'_, '_, '_, Option>( - "subspace_getBlockByNumber", - JsonRpcParams::Array(vec![ - serde_json::to_value(block_to_archive).unwrap() - ]), - ); let EncodedBlockWithObjectMapping { block, object_mapping, - } = match runtime_handle.block_on(block_fut) { + } = match runtime_handle.block_on(client.block_by_number(block_to_archive)) { Ok(Some(block)) => block, Ok(None) => { error!( @@ -439,15 +423,8 @@ async fn background_plotting( } }); - info!("Subscribing to new heads notifications"); - - let mut subscription: Subscription = client - .subscribe( - "chain_subscribeNewHead", - JsonRpcParams::NoParams, - "chain_unsubscribeNewHead", - ) - .await?; + info!("Subscribing to new heads"); + let mut subscription: Subscription = client.subscribe_new_head().await?; let block_to_archive = Arc::new(AtomicU32::default()); // Listen for new blocks produced on the network @@ -491,7 +468,7 @@ fn create_global_object_mapping( } async fn subscribe_to_slot_info( - client: &WsClient, + client: &RpcClient, plot: &Plot, commitments: &Commitments, keypair: &Keypair, @@ -500,13 +477,7 @@ async fn subscribe_to_slot_info( let farmer_public_key_hash = crypto::sha256_hash(&keypair.public); info!("Subscribing to slot info notifications"); - let mut subscription: Subscription = client - .subscribe( - "subspace_subscribeSlotInfo", - JsonRpcParams::NoParams, - "subspace_unsubscribeSlotInfo", - ) - .await?; + let mut subscription: Subscription = client.subscribe_slot_info().await?; let mut salts = Salts::default(); @@ -544,16 +515,11 @@ async fn subscribe_to_slot_info( }; client - .request( - "subspace_proposeProofOfReplication", - JsonRpcParams::Array(vec![serde_json::to_value( - &ProposedProofOfReplicationResponse { - slot_number: slot_info.slot_number, - solution, - secret_key: keypair.secret.to_bytes().into(), - }, - )?]), - ) + .propose_proof_of_replication(ProposedProofOfReplicationResponse { + slot_number: slot_info.slot_number, + solution, + secret_key: keypair.secret.to_bytes().into(), + }) .await?; } diff --git a/crates/subspace-farmer/src/main.rs b/crates/subspace-farmer/src/main.rs index f2ef3f045d172..c620093dc4939 100644 --- a/crates/subspace-farmer/src/main.rs +++ b/crates/subspace-farmer/src/main.rs @@ -20,6 +20,7 @@ mod commands; mod commitments; mod object_mappings; mod plot; +mod rpc; mod utils; use anyhow::Result; @@ -94,7 +95,7 @@ async fn main() -> Result<()> { ws_server, } => { let path = utils::get_path(custom_path); - commands::farm(path, &ws_server).await?; + commands::start_farm(path, &ws_server).await?; } } Ok(()) diff --git a/crates/subspace-farmer/src/rpc.rs b/crates/subspace-farmer/src/rpc.rs new file mode 100644 index 0000000000000..4a1e6081961c2 --- /dev/null +++ b/crates/subspace-farmer/src/rpc.rs @@ -0,0 +1,92 @@ +use crate::commands::farm::{ + EncodedBlockWithObjectMapping, FarmerMetadata, NewHead, ProposedProofOfReplicationResponse, + SlotInfo, +}; +use anyhow::Result; +use jsonrpsee::types::traits::{Client, SubscriptionClient}; +use jsonrpsee::types::v2::params::JsonRpcParams; +use jsonrpsee::types::Subscription; +use jsonrpsee::ws_client::{WsClient, WsClientBuilder}; +use std::sync::Arc; + +/// `WsClient` wrapper. +#[derive(Clone, Debug)] +pub struct RpcClient { + client: Arc, +} + +impl From for RpcClient { + fn from(client: WsClient) -> Self { + Self { + client: Arc::new(client), + } + } +} + +impl RpcClient { + /// Create a new instance of [`RpcClient`]. + pub async fn new(url: &str) -> Result { + let client = Arc::new(WsClientBuilder::default().build(url).await?); + Ok(Self { client }) + } + + /// Get farmer metadata. + pub async fn farmer_metadata(&self) -> Result { + self.client + .request("subspace_getFarmerMetadata", JsonRpcParams::NoParams) + .await + .map_err(Into::into) + } + + /// Get a block by number. + pub async fn block_by_number( + &self, + block_number: u32, + ) -> Result> { + self.client + .request( + "subspace_getBlockByNumber", + JsonRpcParams::Array(vec![serde_json::to_value(block_number)?]), + ) + .await + .map_err(Into::into) + } + + /// Subscribe to chain head. + pub async fn subscribe_new_head(&self) -> Result> { + self.client + .subscribe( + "chain_subscribeNewHead", + JsonRpcParams::NoParams, + "chain_unsubscribeNewHead", + ) + .await + .map_err(Into::into) + } + + /// Subscribe to slot. + pub async fn subscribe_slot_info(&self) -> Result> { + self.client + .subscribe( + "subspace_subscribeSlotInfo", + JsonRpcParams::NoParams, + "subspace_unsubscribeSlotInfo", + ) + .await + .map_err(Into::into) + } + + /// Propose PoR. + pub async fn propose_proof_of_replication( + &self, + por: ProposedProofOfReplicationResponse, + ) -> Result<()> { + self.client + .request( + "subspace_proposeProofOfReplication", + JsonRpcParams::Array(vec![serde_json::to_value(&por)?]), + ) + .await + .map_err(Into::into) + } +} From 6fabc6710aed462d33ab0c1a60dc66ea05d91be1 Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Fri, 22 Oct 2021 20:21:40 +0800 Subject: [PATCH 2/8] Do not use `pub` for farmer module --- crates/subspace-farmer/src/commands.rs | 7 +++++-- crates/subspace-farmer/src/rpc.rs | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/subspace-farmer/src/commands.rs b/crates/subspace-farmer/src/commands.rs index 3a36a3e57f13c..6488bb4d61fcd 100644 --- a/crates/subspace-farmer/src/commands.rs +++ b/crates/subspace-farmer/src/commands.rs @@ -1,3 +1,6 @@ -pub mod farm; +mod farm; -pub(crate) use farm::start_farm; +pub(crate) use farm::{ + start_farm, EncodedBlockWithObjectMapping, FarmerMetadata, NewHead, + ProposedProofOfReplicationResponse, SlotInfo, +}; diff --git a/crates/subspace-farmer/src/rpc.rs b/crates/subspace-farmer/src/rpc.rs index 4a1e6081961c2..5ce61928bb7a2 100644 --- a/crates/subspace-farmer/src/rpc.rs +++ b/crates/subspace-farmer/src/rpc.rs @@ -1,4 +1,4 @@ -use crate::commands::farm::{ +use crate::commands::{ EncodedBlockWithObjectMapping, FarmerMetadata, NewHead, ProposedProofOfReplicationResponse, SlotInfo, }; From 1fc2b876f009cbbb138decefb5845af2a3431a8f Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Fri, 22 Oct 2021 20:27:45 +0800 Subject: [PATCH 3/8] Do not use `anyhow::Result` in rpc --- crates/subspace-farmer/src/rpc.rs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/crates/subspace-farmer/src/rpc.rs b/crates/subspace-farmer/src/rpc.rs index 5ce61928bb7a2..a339fbe30c2fb 100644 --- a/crates/subspace-farmer/src/rpc.rs +++ b/crates/subspace-farmer/src/rpc.rs @@ -2,10 +2,9 @@ use crate::commands::{ EncodedBlockWithObjectMapping, FarmerMetadata, NewHead, ProposedProofOfReplicationResponse, SlotInfo, }; -use anyhow::Result; use jsonrpsee::types::traits::{Client, SubscriptionClient}; use jsonrpsee::types::v2::params::JsonRpcParams; -use jsonrpsee::types::Subscription; +use jsonrpsee::types::{Error, Subscription}; use jsonrpsee::ws_client::{WsClient, WsClientBuilder}; use std::sync::Arc; @@ -25,35 +24,33 @@ impl From for RpcClient { impl RpcClient { /// Create a new instance of [`RpcClient`]. - pub async fn new(url: &str) -> Result { + pub async fn new(url: &str) -> Result { let client = Arc::new(WsClientBuilder::default().build(url).await?); Ok(Self { client }) } /// Get farmer metadata. - pub async fn farmer_metadata(&self) -> Result { + pub async fn farmer_metadata(&self) -> Result { self.client .request("subspace_getFarmerMetadata", JsonRpcParams::NoParams) .await - .map_err(Into::into) } /// Get a block by number. pub async fn block_by_number( &self, block_number: u32, - ) -> Result> { + ) -> Result, Error> { self.client .request( "subspace_getBlockByNumber", JsonRpcParams::Array(vec![serde_json::to_value(block_number)?]), ) .await - .map_err(Into::into) } /// Subscribe to chain head. - pub async fn subscribe_new_head(&self) -> Result> { + pub async fn subscribe_new_head(&self) -> Result, Error> { self.client .subscribe( "chain_subscribeNewHead", @@ -61,11 +58,10 @@ impl RpcClient { "chain_unsubscribeNewHead", ) .await - .map_err(Into::into) } /// Subscribe to slot. - pub async fn subscribe_slot_info(&self) -> Result> { + pub async fn subscribe_slot_info(&self) -> Result, Error> { self.client .subscribe( "subspace_subscribeSlotInfo", @@ -73,20 +69,18 @@ impl RpcClient { "subspace_unsubscribeSlotInfo", ) .await - .map_err(Into::into) } /// Propose PoR. pub async fn propose_proof_of_replication( &self, por: ProposedProofOfReplicationResponse, - ) -> Result<()> { + ) -> Result<(), Error> { self.client .request( "subspace_proposeProofOfReplication", JsonRpcParams::Array(vec![serde_json::to_value(&por)?]), ) .await - .map_err(Into::into) } } From 461e7265ad8f2f9a6c7f4cd89857b08d5dcacb5f Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Fri, 22 Oct 2021 20:29:52 +0800 Subject: [PATCH 4/8] Remove currently unused From impl --- crates/subspace-farmer/src/rpc.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/crates/subspace-farmer/src/rpc.rs b/crates/subspace-farmer/src/rpc.rs index a339fbe30c2fb..6de99360f2407 100644 --- a/crates/subspace-farmer/src/rpc.rs +++ b/crates/subspace-farmer/src/rpc.rs @@ -14,14 +14,6 @@ pub struct RpcClient { client: Arc, } -impl From for RpcClient { - fn from(client: WsClient) -> Self { - Self { - client: Arc::new(client), - } - } -} - impl RpcClient { /// Create a new instance of [`RpcClient`]. pub async fn new(url: &str) -> Result { From fa522b28dca4088b6191a4904b5239f8a68f5e9f Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Fri, 22 Oct 2021 21:08:58 +0800 Subject: [PATCH 5/8] Move types to rpc --- crates/subspace-farmer/src/commands.rs | 5 +- crates/subspace-farmer/src/commands/farm.rs | 95 ++--------------- crates/subspace-farmer/src/rpc.rs | 109 ++++++++++++++++++-- 3 files changed, 111 insertions(+), 98 deletions(-) diff --git a/crates/subspace-farmer/src/commands.rs b/crates/subspace-farmer/src/commands.rs index 6488bb4d61fcd..e3822588dc9ce 100644 --- a/crates/subspace-farmer/src/commands.rs +++ b/crates/subspace-farmer/src/commands.rs @@ -1,6 +1,3 @@ mod farm; -pub(crate) use farm::{ - start_farm, EncodedBlockWithObjectMapping, FarmerMetadata, NewHead, - ProposedProofOfReplicationResponse, SlotInfo, -}; +pub(crate) use farm::start_farm; diff --git a/crates/subspace-farmer/src/commands/farm.rs b/crates/subspace-farmer/src/commands/farm.rs index 4fde93fefce41..afbb7516788ef 100644 --- a/crates/subspace-farmer/src/commands/farm.rs +++ b/crates/subspace-farmer/src/commands/farm.rs @@ -1,8 +1,11 @@ use crate::commitments::Commitments; use crate::object_mappings::ObjectMappings; use crate::plot::Plot; -use crate::rpc::RpcClient; -use crate::{Salt, Tag}; +use crate::rpc::{ + EncodedBlockWithObjectMapping, FarmerMetadata, NewHead, ProposedProofOfReplicationResponse, + RpcClient, SlotInfo, Solution, +}; +use crate::Salt; use anyhow::{anyhow, Result}; use futures::future; use futures::future::Either; @@ -10,7 +13,6 @@ use jsonrpsee::types::Subscription; use log::{debug, error, info, trace}; use schnorrkel::context::SigningContext; use schnorrkel::{Keypair, PublicKey}; -use serde::{Deserialize, Serialize}; use std::fs; use std::path::PathBuf; use std::sync::atomic::{AtomicU32, Ordering}; @@ -18,84 +20,10 @@ use std::sync::Arc; use std::time::Instant; use subspace_archiving::archiver::{ArchivedSegment, BlockArchiver, ObjectArchiver}; use subspace_archiving::pre_genesis_data; -use subspace_core_primitives::objects::{ - BlockObjectMapping, GlobalObject, PieceObject, PieceObjectMapping, -}; +use subspace_core_primitives::objects::{GlobalObject, PieceObject, PieceObjectMapping}; use subspace_core_primitives::{crypto, Sha256Hash}; use subspace_solving::{SubspaceCodec, SOLUTION_SIGNING_CONTEXT}; -type SlotNumber = u64; - -/// Metadata necessary for farmer operation -#[derive(Debug, Deserialize)] -pub struct FarmerMetadata { - /// Depth `K` after which a block enters the recorded history (a global constant, as opposed - /// to the client-dependent transaction confirmation depth `k`). - confirmation_depth_k: u32, - /// The size of data in one piece (in bytes). - record_size: u32, - /// Recorded history is encoded and plotted in segments of this size (in bytes). - recorded_history_segment_size: u32, - /// This constant defines the size (in bytes) of one pre-genesis object. - pre_genesis_object_size: u32, - /// This constant defines the number of a pre-genesis objects that will bootstrap the - /// history. - pre_genesis_object_count: u32, - /// This constant defines the seed used for deriving pre-genesis objects that will bootstrap - /// the history. - pre_genesis_object_seed: Vec, -} - -/// Encoded block with mapping of objects that it contains -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct EncodedBlockWithObjectMapping { - /// Encoded block - block: Vec, - /// Mapping of objects inside of the block - object_mapping: BlockObjectMapping, -} - -// There are more fields in this struct, but we only care about one -#[derive(Debug, Deserialize)] -pub struct NewHead { - number: String, -} - -#[derive(Debug, Serialize)] -struct Solution { - public_key: [u8; 32], - piece_index: u64, - encoding: Vec, - signature: Vec, - tag: Tag, -} - -/// Proposed proof of space consisting of solution and farmer's secret key for block signing -#[derive(Debug, Serialize)] -pub struct ProposedProofOfReplicationResponse { - /// Slot number - slot_number: SlotNumber, - /// Solution (if present) from farmer's plot corresponding to slot number above - solution: Option, - // Secret key, used for signing blocks on the client node - secret_key: Vec, -} - -/// Information about new slot that just arrived -#[derive(Debug, Deserialize)] -pub struct SlotInfo { - /// Slot number - slot_number: SlotNumber, - /// Slot challenge - challenge: [u8; 8], - /// Salt - salt: Salt, - /// Salt for the next eon - next_salt: Option, - /// Acceptable solution range - solution_range: u64, -} - /// Start farming by using plot in specified path and connecting to WebSocket server at specified /// address. pub(crate) async fn start_farm(base_directory: PathBuf, ws_server: &str) -> Result<()> { @@ -495,14 +423,13 @@ async fn subscribe_to_slot_info( { Some((tag, piece_index)) => { let encoding = plot.read(piece_index).await?; - let solution = Solution { - public_key: keypair.public.to_bytes(), + let solution = Solution::new( + keypair.public.to_bytes(), piece_index, - encoding: encoding.to_vec(), - signature: keypair.sign(ctx.bytes(&tag)).to_bytes().to_vec(), + encoding.to_vec(), + keypair.sign(ctx.bytes(&tag)).to_bytes().to_vec(), tag, - }; - + ); debug!("Solution found"); trace!("Solution found: {:?}", solution); diff --git a/crates/subspace-farmer/src/rpc.rs b/crates/subspace-farmer/src/rpc.rs index 6de99360f2407..ee35bf87c3906 100644 --- a/crates/subspace-farmer/src/rpc.rs +++ b/crates/subspace-farmer/src/rpc.rs @@ -1,12 +1,101 @@ -use crate::commands::{ - EncodedBlockWithObjectMapping, FarmerMetadata, NewHead, ProposedProofOfReplicationResponse, - SlotInfo, -}; +use crate::{Salt, Tag}; use jsonrpsee::types::traits::{Client, SubscriptionClient}; use jsonrpsee::types::v2::params::JsonRpcParams; use jsonrpsee::types::{Error, Subscription}; use jsonrpsee::ws_client::{WsClient, WsClientBuilder}; +use serde::{Deserialize, Serialize}; use std::sync::Arc; +use subspace_core_primitives::objects::BlockObjectMapping; + +type SlotNumber = u64; + +/// Metadata necessary for farmer operation +#[derive(Debug, Deserialize)] +pub(super) struct FarmerMetadata { + /// Depth `K` after which a block enters the recorded history (a global constant, as opposed + /// to the client-dependent transaction confirmation depth `k`). + pub confirmation_depth_k: u32, + /// The size of data in one piece (in bytes). + pub record_size: u32, + /// Recorded history is encoded and plotted in segments of this size (in bytes). + pub recorded_history_segment_size: u32, + /// This constant defines the size (in bytes) of one pre-genesis object. + pub pre_genesis_object_size: u32, + /// This constant defines the number of a pre-genesis objects that will bootstrap the + /// history. + pub pre_genesis_object_count: u32, + /// This constant defines the seed used for deriving pre-genesis objects that will bootstrap + /// the history. + pub pre_genesis_object_seed: Vec, +} + +/// Encoded block with mapping of objects that it contains +#[derive(Debug, Clone, Serialize, Deserialize)] +pub(super) struct EncodedBlockWithObjectMapping { + /// Encoded block + pub block: Vec, + /// Mapping of objects inside of the block + pub object_mapping: BlockObjectMapping, +} + +// There are more fields in this struct, but we only care about one +#[derive(Debug, Deserialize)] +pub(super) struct NewHead { + pub number: String, +} + +/// Proposed proof of space consisting of solution and farmer's secret key for block signing +#[derive(Debug, Serialize)] +pub(super) struct ProposedProofOfReplicationResponse { + /// Slot number + pub slot_number: SlotNumber, + /// Solution (if present) from farmer's plot corresponding to slot number above + pub solution: Option, + /// Secret key, used for signing blocks on the client node + pub secret_key: Vec, +} + +/// Information about new slot that just arrived +#[derive(Debug, Deserialize)] +pub(super) struct SlotInfo { + /// Slot number + pub slot_number: SlotNumber, + /// Slot challenge + pub challenge: [u8; 8], + /// Salt + pub salt: Salt, + /// Salt for the next eon + pub next_salt: Option, + /// Acceptable solution range + pub solution_range: u64, +} + +#[derive(Debug, Serialize)] +pub(super) struct Solution { + public_key: [u8; 32], + piece_index: u64, + encoding: Vec, + signature: Vec, + tag: Tag, +} + +impl Solution { + pub(super) fn new( + public_key: [u8; 32], + piece_index: u64, + encoding: Vec, + signature: Vec, + tag: Tag, + ) -> Self { + Self { + public_key, + piece_index, + encoding, + signature, + tag, + } + } +} /// `WsClient` wrapper. #[derive(Clone, Debug)] @@ -16,20 +105,20 @@ pub struct RpcClient { impl RpcClient { /// Create a new instance of [`RpcClient`]. - pub async fn new(url: &str) -> Result { + pub(super) async fn new(url: &str) -> Result { let client = Arc::new(WsClientBuilder::default().build(url).await?); Ok(Self { client }) } /// Get farmer metadata. - pub async fn farmer_metadata(&self) -> Result { + pub(super) async fn farmer_metadata(&self) -> Result { self.client .request("subspace_getFarmerMetadata", JsonRpcParams::NoParams) .await } /// Get a block by number. - pub async fn block_by_number( + pub(super) async fn block_by_number( &self, block_number: u32, ) -> Result, Error> { @@ -42,7 +131,7 @@ impl RpcClient { } /// Subscribe to chain head. - pub async fn subscribe_new_head(&self) -> Result, Error> { + pub(super) async fn subscribe_new_head(&self) -> Result, Error> { self.client .subscribe( "chain_subscribeNewHead", @@ -53,7 +142,7 @@ impl RpcClient { } /// Subscribe to slot. - pub async fn subscribe_slot_info(&self) -> Result, Error> { + pub(super) async fn subscribe_slot_info(&self) -> Result, Error> { self.client .subscribe( "subspace_subscribeSlotInfo", @@ -64,7 +153,7 @@ impl RpcClient { } /// Propose PoR. - pub async fn propose_proof_of_replication( + pub(super) async fn propose_proof_of_replication( &self, por: ProposedProofOfReplicationResponse, ) -> Result<(), Error> { From 84e58b98c5625bf65003b29674d1d8808baeae95 Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Fri, 22 Oct 2021 21:11:38 +0800 Subject: [PATCH 6/8] Avoid unneccesary changes --- crates/subspace-farmer/src/commands.rs | 2 +- crates/subspace-farmer/src/commands/farm.rs | 2 +- crates/subspace-farmer/src/main.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/subspace-farmer/src/commands.rs b/crates/subspace-farmer/src/commands.rs index e3822588dc9ce..fa667949e14e8 100644 --- a/crates/subspace-farmer/src/commands.rs +++ b/crates/subspace-farmer/src/commands.rs @@ -1,3 +1,3 @@ mod farm; -pub(crate) use farm::start_farm; +pub(crate) use farm::farm; diff --git a/crates/subspace-farmer/src/commands/farm.rs b/crates/subspace-farmer/src/commands/farm.rs index afbb7516788ef..8b735ab1cc335 100644 --- a/crates/subspace-farmer/src/commands/farm.rs +++ b/crates/subspace-farmer/src/commands/farm.rs @@ -26,7 +26,7 @@ use subspace_solving::{SubspaceCodec, SOLUTION_SIGNING_CONTEXT}; /// Start farming by using plot in specified path and connecting to WebSocket server at specified /// address. -pub(crate) async fn start_farm(base_directory: PathBuf, ws_server: &str) -> Result<()> { +pub(crate) async fn farm(base_directory: PathBuf, ws_server: &str) -> Result<()> { info!("Connecting to RPC server"); let client = RpcClient::new(ws_server).await?; diff --git a/crates/subspace-farmer/src/main.rs b/crates/subspace-farmer/src/main.rs index c620093dc4939..465d48405ba17 100644 --- a/crates/subspace-farmer/src/main.rs +++ b/crates/subspace-farmer/src/main.rs @@ -95,7 +95,7 @@ async fn main() -> Result<()> { ws_server, } => { let path = utils::get_path(custom_path); - commands::start_farm(path, &ws_server).await?; + commands::farm(path, &ws_server).await?; } } Ok(()) From 29c07cc1a6625af6953487acf672ceea9163399d Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Sat, 23 Oct 2021 10:28:17 +0800 Subject: [PATCH 7/8] Use more meaningful name for the subscription --- crates/subspace-farmer/src/commands/farm.rs | 38 ++++++++++----------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/crates/subspace-farmer/src/commands/farm.rs b/crates/subspace-farmer/src/commands/farm.rs index 3c427a1007433..394f6a54e040e 100644 --- a/crates/subspace-farmer/src/commands/farm.rs +++ b/crates/subspace-farmer/src/commands/farm.rs @@ -4,13 +4,12 @@ use crate::identity::Identity; use crate::object_mappings::ObjectMappings; use crate::plot::Plot; use crate::rpc::{ - EncodedBlockWithObjectMapping, FarmerMetadata, NewHead, ProposedProofOfReplicationResponse, - RpcClient, SlotInfo, Solution, + EncodedBlockWithObjectMapping, FarmerMetadata, ProposedProofOfReplicationResponse, RpcClient, + SlotInfo, Solution, }; use anyhow::{anyhow, Result}; use futures::future; use futures::future::Either; -use jsonrpsee::types::Subscription; use log::{debug, error, info, trace}; use std::path::PathBuf; use std::sync::atomic::{AtomicU32, Ordering}; @@ -25,25 +24,25 @@ use subspace_solving::SubspaceCodec; /// Start farming by using plot in specified path and connecting to WebSocket server at specified /// address. pub(crate) async fn farm(base_directory: PathBuf, ws_server: &str) -> Result<()> { - info!("Connecting to RPC server"); - let client = RpcClient::new(ws_server).await?; - - let identity = Identity::open_or_create(&base_directory)?; - - // TODO: This doesn't account for the fact that node can have a completely different history to - // what farmer expects + // TODO: This doesn't account for the fact that node can + // have a completely different history to what farmer expects info!("Opening plot"); let plot = Plot::open_or_create(&base_directory.clone().into()).await?; + info!("Opening commitments"); let commitments = Commitments::new(base_directory.join("commitments").into()).await?; + info!("Opening object mapping"); let object_mappings = tokio::task::spawn_blocking({ let path = base_directory.join("object-mappings"); - move || ObjectMappings::new(&path) }) - .await - .unwrap()?; + .await??; + + info!("Connecting to RPC server: {}", ws_server); + let client = RpcClient::new(ws_server).await?; + + let identity = Identity::open_or_create(&base_directory)?; match future::select( { @@ -340,14 +339,15 @@ async fn background_plotting>( }); info!("Subscribing to new heads"); - let mut subscription: Subscription = client.subscribe_new_head().await?; + let mut new_head = client.subscribe_new_head().await?; let block_to_archive = Arc::new(AtomicU32::default()); + // Listen for new blocks produced on the network - while let Some(new_head) = subscription.next().await? { + while let Some(head) = new_head.next().await? { // Numbers are in the format `0xabcd`, so strip `0x` prefix and interpret the rest as an // integer in hex - let block_number = u32::from_str_radix(&new_head.number[2..], 16).unwrap(); + let block_number = u32::from_str_radix(&head.number[2..], 16).unwrap(); debug!("Last block number: {:#?}", block_number); if let Some(block) = block_number.checked_sub(confirmation_depth_k) { @@ -391,12 +391,12 @@ async fn subscribe_to_slot_info( ) -> Result<()> { let farmer_public_key_hash = crypto::sha256_hash(&identity.public_key()); - info!("Subscribing to slot info notifications"); - let mut subscription: Subscription = client.subscribe_slot_info().await?; + info!("Subscribing to slot info"); + let mut new_slots = client.subscribe_slot_info().await?; let mut salts = Salts::default(); - while let Some(slot_info) = subscription.next().await? { + while let Some(slot_info) = new_slots.next().await? { debug!("New slot: {:?}", slot_info); update_commitments(plot, commitments, &mut salts, &slot_info); From c2c6955ca3e4be34974a0db038f5805858845e45 Mon Sep 17 00:00:00 2001 From: Liu-Cheng Xu Date: Sat, 23 Oct 2021 11:26:07 +0800 Subject: [PATCH 8/8] Fix clippy --- crates/sc-consensus-subspace/src/verification.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/crates/sc-consensus-subspace/src/verification.rs b/crates/sc-consensus-subspace/src/verification.rs index 2058e5ec84399..d479dd1c70618 100644 --- a/crates/sc-consensus-subspace/src/verification.rs +++ b/crates/sc-consensus-subspace/src/verification.rs @@ -178,12 +178,11 @@ pub(crate) fn verify_solution( let subspace_solving = SubspaceCodec::new(&solution.public_key); let mut piece = solution.encoding.clone(); - if subspace_solving + + // Ensure piece is decodable. + subspace_solving .decode(solution.piece_index, &mut piece) - .is_err() - { - return Err(Error::InvalidEncoding(slot)); - } + .map_err(|_| Error::InvalidEncoding(slot))?; if !archiver::is_piece_valid( &piece,