Skip to content
This repository was archived by the owner on Feb 21, 2024. It is now read-only.

Commit dc117fd

Browse files
authored
Merge pull request paritytech#77 from subspace/extract-rpc-module
Introduce RpcClient for abstracting all rpc related functions
2 parents 38ae4c9 + c2c6955 commit dc117fd

File tree

4 files changed

+214
-154
lines changed

4 files changed

+214
-154
lines changed

crates/sc-consensus-subspace/src/verification.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -178,12 +178,11 @@ pub(crate) fn verify_solution<B: BlockT + Sized>(
178178
let subspace_solving = SubspaceCodec::new(&solution.public_key);
179179

180180
let mut piece = solution.encoding.clone();
181-
if subspace_solving
181+
182+
// Ensure piece is decodable.
183+
subspace_solving
182184
.decode(solution.piece_index, &mut piece)
183-
.is_err()
184-
{
185-
return Err(Error::InvalidEncoding(slot));
186-
}
185+
.map_err(|_| Error::InvalidEncoding(slot))?;
187186

188187
if !archiver::is_piece_valid(
189188
&piece,

crates/subspace-farmer/src/commands/farm.rs

Lines changed: 42 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -1,127 +1,52 @@
11
use crate::commitments::Commitments;
2-
use crate::common::{Salt, Tag};
2+
use crate::common::Salt;
33
use crate::identity::Identity;
44
use crate::object_mappings::ObjectMappings;
55
use crate::plot::Plot;
6+
use crate::rpc::{
7+
EncodedBlockWithObjectMapping, FarmerMetadata, ProposedProofOfReplicationResponse, RpcClient,
8+
SlotInfo, Solution,
9+
};
610
use anyhow::{anyhow, Result};
711
use futures::future;
812
use futures::future::Either;
9-
use jsonrpsee::types::traits::{Client, SubscriptionClient};
10-
use jsonrpsee::types::v2::params::JsonRpcParams;
11-
use jsonrpsee::types::Subscription;
12-
use jsonrpsee::ws_client::{WsClient, WsClientBuilder};
1313
use log::{debug, error, info, trace};
14-
use serde::{Deserialize, Serialize};
1514
use std::path::PathBuf;
1615
use std::sync::atomic::{AtomicU32, Ordering};
1716
use std::sync::Arc;
1817
use std::time::Instant;
1918
use subspace_archiving::archiver::{ArchivedSegment, BlockArchiver, ObjectArchiver};
2019
use subspace_archiving::pre_genesis_data;
21-
use subspace_core_primitives::objects::{
22-
BlockObjectMapping, GlobalObject, PieceObject, PieceObjectMapping,
23-
};
20+
use subspace_core_primitives::objects::{GlobalObject, PieceObject, PieceObjectMapping};
2421
use subspace_core_primitives::{crypto, Sha256Hash};
2522
use subspace_solving::SubspaceCodec;
2623

27-
type SlotNumber = u64;
28-
29-
/// Metadata necessary for farmer operation
30-
#[derive(Debug, Deserialize)]
31-
struct FarmerMetadata {
32-
/// Depth `K` after which a block enters the recorded history (a global constant, as opposed
33-
/// to the client-dependent transaction confirmation depth `k`).
34-
confirmation_depth_k: u32,
35-
/// The size of data in one piece (in bytes).
36-
record_size: u32,
37-
/// Recorded history is encoded and plotted in segments of this size (in bytes).
38-
recorded_history_segment_size: u32,
39-
/// This constant defines the size (in bytes) of one pre-genesis object.
40-
pre_genesis_object_size: u32,
41-
/// This constant defines the number of a pre-genesis objects that will bootstrap the
42-
/// history.
43-
pre_genesis_object_count: u32,
44-
/// This constant defines the seed used for deriving pre-genesis objects that will bootstrap
45-
/// the history.
46-
pre_genesis_object_seed: Vec<u8>,
47-
}
48-
49-
/// Encoded block with mapping of objects that it contains
50-
#[derive(Debug, Clone, Serialize, Deserialize)]
51-
struct EncodedBlockWithObjectMapping {
52-
/// Encoded block
53-
block: Vec<u8>,
54-
/// Mapping of objects inside of the block
55-
object_mapping: BlockObjectMapping,
56-
}
57-
58-
// There are more fields in this struct, but we only care about one
59-
#[derive(Debug, Deserialize)]
60-
struct NewHead {
61-
number: String,
62-
}
63-
64-
#[derive(Debug, Serialize)]
65-
struct Solution {
66-
public_key: [u8; 32],
67-
piece_index: u64,
68-
encoding: Vec<u8>,
69-
signature: Vec<u8>,
70-
tag: Tag,
71-
}
72-
73-
/// Proposed proof of space consisting of solution and farmer's secret key for block signing
74-
#[derive(Debug, Serialize)]
75-
struct ProposedProofOfReplicationResponse {
76-
/// Slot number
77-
slot_number: SlotNumber,
78-
/// Solution (if present) from farmer's plot corresponding to slot number above
79-
solution: Option<Solution>,
80-
// Secret key, used for signing blocks on the client node
81-
secret_key: Vec<u8>,
82-
}
83-
84-
/// Information about new slot that just arrived
85-
#[derive(Debug, Deserialize)]
86-
struct SlotInfo {
87-
/// Slot number
88-
slot_number: SlotNumber,
89-
/// Slot challenge
90-
challenge: [u8; 8],
91-
/// Salt
92-
salt: Salt,
93-
/// Salt for the next eon
94-
next_salt: Option<Salt>,
95-
/// Acceptable solution range
96-
solution_range: u64,
97-
}
98-
9924
/// Start farming by using plot in specified path and connecting to WebSocket server at specified
10025
/// address.
10126
pub(crate) async fn farm(base_directory: PathBuf, ws_server: &str) -> Result<()> {
102-
info!("Connecting to RPC server");
103-
let client = Arc::new(WsClientBuilder::default().build(ws_server).await?);
104-
105-
let identity = Identity::open_or_create(&base_directory)?;
106-
107-
// TODO: This doesn't account for the fact that node can have a completely different history to
108-
// what farmer expects
27+
// TODO: This doesn't account for the fact that node can
28+
// have a completely different history to what farmer expects
10929
info!("Opening plot");
11030
let plot = Plot::open_or_create(&base_directory.clone().into()).await?;
31+
11132
info!("Opening commitments");
11233
let commitments = Commitments::new(base_directory.join("commitments").into()).await?;
34+
11335
info!("Opening object mapping");
11436
let object_mappings = tokio::task::spawn_blocking({
11537
let path = base_directory.join("object-mappings");
116-
11738
move || ObjectMappings::new(&path)
11839
})
119-
.await
120-
.unwrap()?;
40+
.await??;
41+
42+
info!("Connecting to RPC server: {}", ws_server);
43+
let client = RpcClient::new(ws_server).await?;
44+
45+
let identity = Identity::open_or_create(&base_directory)?;
12146

12247
match future::select(
12348
{
124-
let client = Arc::clone(&client);
49+
let client = client.clone();
12550
let plot = plot.clone();
12651
let commitments = commitments.clone();
12752
let public_key = identity.public_key();
@@ -152,7 +77,7 @@ pub(crate) async fn farm(base_directory: PathBuf, ws_server: &str) -> Result<()>
15277
// don't want eventually
15378
/// Maintains plot in up to date state plotting new pieces as they are produced on the network.
15479
async fn background_plotting<P: AsRef<[u8]>>(
155-
client: Arc<WsClient>,
80+
client: RpcClient,
15681
plot: Plot,
15782
commitments: Commitments,
15883
object_mappings: ObjectMappings,
@@ -166,9 +91,7 @@ async fn background_plotting<P: AsRef<[u8]>>(
16691
pre_genesis_object_size,
16792
pre_genesis_object_count,
16893
pre_genesis_object_seed,
169-
} = client
170-
.request("subspace_getFarmerMetadata", JsonRpcParams::NoParams)
171-
.await?;
94+
} = client.farmer_metadata().await?;
17295

17396
// TODO: This assumes fixed size segments, which might not be the case
17497
let merkle_num_leaves = u64::from(recorded_history_segment_size / record_size * 2);
@@ -186,12 +109,7 @@ async fn background_plotting<P: AsRef<[u8]>>(
186109
let last_archived_block_number = last_root_block.last_archived_block().number;
187110
info!("Last archived block {}", last_archived_block_number);
188111

189-
let maybe_last_archived_block = client
190-
.request(
191-
"subspace_getBlockByNumber",
192-
JsonRpcParams::Array(vec![serde_json::to_value(last_archived_block_number)?]),
193-
)
194-
.await?;
112+
let maybe_last_archived_block = client.block_by_number(last_archived_block_number).await?;
195113

196114
match maybe_last_archived_block {
197115
Some(EncodedBlockWithObjectMapping {
@@ -309,9 +227,9 @@ async fn background_plotting<P: AsRef<[u8]>>(
309227
.map(|n| n + 1)
310228
.unwrap_or_default();
311229

312-
// Erasure coding in archiver and piece encoding are a CPU-intensive operations
230+
// Erasure coding in archiver and piece encoding are CPU-intensive operations.
313231
tokio::task::spawn_blocking({
314-
let client = Arc::clone(&client);
232+
let client = client.clone();
315233
let weak_plot = weak_plot.clone();
316234

317235
#[allow(clippy::mut_range_bound)]
@@ -330,17 +248,10 @@ async fn background_plotting<P: AsRef<[u8]>>(
330248

331249
let mut last_root_block = None;
332250
for block_to_archive in blocks_to_archive_from..=blocks_to_archive_to {
333-
let block_fut = client
334-
.request::<'_, '_, '_, Option<EncodedBlockWithObjectMapping>>(
335-
"subspace_getBlockByNumber",
336-
JsonRpcParams::Array(vec![
337-
serde_json::to_value(block_to_archive).unwrap()
338-
]),
339-
);
340251
let EncodedBlockWithObjectMapping {
341252
block,
342253
object_mapping,
343-
} = match runtime_handle.block_on(block_fut) {
254+
} = match runtime_handle.block_on(client.block_by_number(block_to_archive)) {
344255
Ok(Some(block)) => block,
345256
Ok(None) => {
346257
error!(
@@ -427,22 +338,16 @@ async fn background_plotting<P: AsRef<[u8]>>(
427338
}
428339
});
429340

430-
info!("Subscribing to new heads notifications");
431-
432-
let mut subscription: Subscription<NewHead> = client
433-
.subscribe(
434-
"chain_subscribeNewHead",
435-
JsonRpcParams::NoParams,
436-
"chain_unsubscribeNewHead",
437-
)
438-
.await?;
341+
info!("Subscribing to new heads");
342+
let mut new_head = client.subscribe_new_head().await?;
439343

440344
let block_to_archive = Arc::new(AtomicU32::default());
345+
441346
// Listen for new blocks produced on the network
442-
while let Some(new_head) = subscription.next().await? {
347+
while let Some(head) = new_head.next().await? {
443348
// Numbers are in the format `0xabcd`, so strip `0x` prefix and interpret the rest as an
444349
// integer in hex
445-
let block_number = u32::from_str_radix(&new_head.number[2..], 16).unwrap();
350+
let block_number = u32::from_str_radix(&head.number[2..], 16).unwrap();
446351
debug!("Last block number: {:#?}", block_number);
447352

448353
if let Some(block) = block_number.checked_sub(confirmation_depth_k) {
@@ -479,25 +384,19 @@ fn create_global_object_mapping(
479384
}
480385

481386
async fn subscribe_to_slot_info(
482-
client: &WsClient,
387+
client: &RpcClient,
483388
plot: &Plot,
484389
commitments: &Commitments,
485390
identity: &Identity,
486391
) -> Result<()> {
487392
let farmer_public_key_hash = crypto::sha256_hash(&identity.public_key());
488393

489-
info!("Subscribing to slot info notifications");
490-
let mut subscription: Subscription<SlotInfo> = client
491-
.subscribe(
492-
"subspace_subscribeSlotInfo",
493-
JsonRpcParams::NoParams,
494-
"subspace_unsubscribeSlotInfo",
495-
)
496-
.await?;
394+
info!("Subscribing to slot info");
395+
let mut new_slots = client.subscribe_slot_info().await?;
497396

498397
let mut salts = Salts::default();
499398

500-
while let Some(slot_info) = subscription.next().await? {
399+
while let Some(slot_info) = new_slots.next().await? {
501400
debug!("New slot: {:?}", slot_info);
502401

503402
update_commitments(plot, commitments, &mut salts, &slot_info);
@@ -511,14 +410,13 @@ async fn subscribe_to_slot_info(
511410
{
512411
Some((tag, piece_index)) => {
513412
let encoding = plot.read(piece_index).await?;
514-
let solution = Solution {
515-
public_key: identity.public_key().to_bytes(),
413+
let solution = Solution::new(
414+
identity.public_key().to_bytes(),
516415
piece_index,
517-
encoding: encoding.to_vec(),
518-
signature: identity.sign(&tag).to_bytes().to_vec(),
416+
encoding.to_vec(),
417+
identity.sign(&tag).to_bytes().to_vec(),
519418
tag,
520-
};
521-
419+
);
522420
debug!("Solution found");
523421
trace!("Solution found: {:?}", solution);
524422

@@ -531,16 +429,11 @@ async fn subscribe_to_slot_info(
531429
};
532430

533431
client
534-
.request(
535-
"subspace_proposeProofOfReplication",
536-
JsonRpcParams::Array(vec![serde_json::to_value(
537-
&ProposedProofOfReplicationResponse {
538-
slot_number: slot_info.slot_number,
539-
solution,
540-
secret_key: identity.secret_key().to_bytes().into(),
541-
},
542-
)?]),
543-
)
432+
.propose_proof_of_replication(ProposedProofOfReplicationResponse {
433+
slot_number: slot_info.slot_number,
434+
solution,
435+
secret_key: identity.secret_key().to_bytes().into(),
436+
})
544437
.await?;
545438
}
546439

crates/subspace-farmer/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ mod common;
2222
mod identity;
2323
mod object_mappings;
2424
mod plot;
25+
mod rpc;
2526
mod utils;
2627

2728
use anyhow::Result;

0 commit comments

Comments
 (0)