Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pieces verification to farmers. #725

Merged
merged 19 commits into from Aug 4, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
926372a
subspace-rpc: Introduce `records_root` endpoint.
shamil-gadelshin Jul 27, 2022
1ea616b
farmer: Introduce pieces_verification module.
shamil-gadelshin Jul 27, 2022
7743d25
farmer: Implement rpc_client method.
shamil-gadelshin Jul 27, 2022
673fb47
farmer: Add pieces verification to DSN sync.
shamil-gadelshin Jul 27, 2022
3d901b5
farmer: Fix review comments.
shamil-gadelshin Jul 27, 2022
ef4f9cf
farmer: Refactor `verify_pieces_at_blockchain` method.
shamil-gadelshin Jul 27, 2022
22011d8
subspace-rpc: Add records_roots request batching.
shamil-gadelshin Jul 28, 2022
79b59b2
Merge branch 'main' into verify-pieces
shamil-gadelshin Jul 28, 2022
8ec51dc
farmer: Fix farmer side of the `records_root` call.
shamil-gadelshin Jul 28, 2022
fb1687f
farmer: Fix review comments (tracing errors).
shamil-gadelshin Jul 28, 2022
a34268a
farmer: Fix minor review comments.
shamil-gadelshin Jul 28, 2022
7ead01d
Modify FarmerProtocolInfo structure.
shamil-gadelshin Jul 29, 2022
25982e1
Add a limit for a RPC records_roots call.
shamil-gadelshin Jul 29, 2022
e4ae0ce
farmer: Fix pieces verifcation formula.
shamil-gadelshin Jul 29, 2022
7d1cc50
farmer: Move rpc_client_* files to a new folder.
shamil-gadelshin Jul 29, 2022
c866ea7
Merge branch 'main' into verify-pieces
shamil-gadelshin Jul 29, 2022
790f371
Fix review comments.
shamil-gadelshin Aug 1, 2022
8538361
Merge branch 'main' into verify-pieces
shamil-gadelshin Aug 1, 2022
7d54abb
Merge branch 'main' into verify-pieces
shamil-gadelshin Aug 4, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 13 additions & 0 deletions crates/sc-consensus-subspace-rpc/src/lib.rs
Expand Up @@ -54,6 +54,7 @@ use subspace_core_primitives::{
};
use subspace_rpc_primitives::{
FarmerProtocolInfo, RewardSignatureResponse, RewardSigningInfo, SlotInfo, SolutionResponse,
MAX_SEGMENT_INDEXES_PER_REQUEST,
};

const SOLUTION_TIMEOUT: Duration = Duration::from_secs(2);
Expand Down Expand Up @@ -527,6 +528,18 @@ where
}

async fn records_roots(&self, segment_indexes: Vec<u64>) -> RpcResult<Vec<Option<Sha256Hash>>> {
if segment_indexes.len() > MAX_SEGMENT_INDEXES_PER_REQUEST {
error!(
"segment_indexes length exceed the limit: {} ",
segment_indexes.len()
);

return Err(JsonRpseeError::Custom(
"Internal error during `records_root` call: segment_indexes length exceed the limit"
shamil-gadelshin marked this conversation as resolved.
Show resolved Hide resolved
.to_string()
));
};

let runtime_api = self.client.runtime_api();
let best_block_id = BlockId::Hash(self.client.info().best_hash);

Expand Down
4 changes: 2 additions & 2 deletions crates/subspace-farmer/src/bench_rpc_client.rs
@@ -1,9 +1,9 @@
use std::num::NonZeroU32;
use crate::rpc_client::{Error, RpcClient};
use crate::utils::AbortingJoinHandle;
use async_trait::async_trait;
use futures::channel::mpsc;
use futures::{stream, SinkExt, Stream, StreamExt};
use std::num::NonZeroU32;
use std::pin::Pin;
use std::sync::Arc;
use subspace_archiving::archiver::ArchivedSegment;
Expand Down Expand Up @@ -33,7 +33,7 @@ pub const BENCH_FARMER_PROTOCOL_INFO: FarmerProtocolInfo = FarmerProtocolInfo {
genesis_hash: [0; 32],
// PIECE_SIZE - WITNESS_SIZE
record_size: NonZeroU32::new(3840).expect("We must set non-zero integer here."),
recorded_history_segment_size: 491520, // RECORD_SIZE * MERKLE_NUM_LEAVES / 2
recorded_history_segment_size: 491520, // RECORD_SIZE * MERKLE_NUM_LEAVES / 2
max_plot_size: 100 * 1024 * 1024 * 1024, // 100G
// Doesn't matter, as we don't start sync
total_pieces: 0,
Expand Down
2 changes: 1 addition & 1 deletion crates/subspace-farmer/src/lib.rs
Expand Up @@ -5,7 +5,7 @@
io_error_other,
map_first_last,
trait_alias,
try_blocks,
try_blocks
)]

//! # `subspace-farmer` library implementation overview
Expand Down
29 changes: 20 additions & 9 deletions crates/subspace-farmer/src/single_plot_farm.rs
Expand Up @@ -16,7 +16,7 @@ use crate::ws_rpc_server::PieceGetter;
use anyhow::anyhow;
use async_trait::async_trait;
use derive_more::{Display, From};
use futures::future::try_join;
use futures::future::{try_join, try_join_all};
use num_traits::Zero;
use serde::{Deserialize, Serialize};
use std::future::Future;
Expand All @@ -34,7 +34,7 @@ use subspace_networking::{
Config, Node, NodeRunner, PiecesByRangeRequest, PiecesByRangeRequestHandler,
PiecesByRangeResponse, PiecesToPlot,
};
use subspace_rpc_primitives::FarmerProtocolInfo;
use subspace_rpc_primitives::{FarmerProtocolInfo, MAX_SEGMENT_INDEXES_PER_REQUEST};
use subspace_solving::{BatchEncodeError, SubspaceCodec};
use thiserror::Error;
use tokio::runtime::Handle;
Expand Down Expand Up @@ -752,19 +752,29 @@ impl<RC: RpcClient> VerifyingPlotter<RC> {
return Err(PiecesVerificationError::InvalidFarmerProtocolInfo);
}

// Calculate segment indexes collection
let segment_indexes = piece_indexes
.iter()
.map(|piece_index| piece_index / records_per_segment as u64)
.collect::<Vec<_>>();
i1i1 marked this conversation as resolved.
Show resolved Hide resolved

let roots = self
.verification_client
.records_roots(segment_indexes)
.await
.map_err(|err| PiecesVerificationError::RpcError(err))?;
// Split segment indexes collection into allowed max sized chunks
// and run a future records_roots RPC call for each chunk.
let roots_futures = segment_indexes
.chunks(MAX_SEGMENT_INDEXES_PER_REQUEST)
.map(|segment_indexes_chunk| {
self.verification_client
.records_roots(segment_indexes_chunk.to_vec())
})
.collect::<Vec<_>>();

let verified_roots = roots
// Wait for all the RPC calls, flatten the results collection
// and check for empty result for any of the records root call.
let roots = try_join_all(roots_futures)
.await
.map_err(|err| PiecesVerificationError::RpcError(err))?
.into_iter()
.flatten()
.zip(piece_indexes.iter())
.map(|(root, piece_index)| {
if let Some(root) = root {
Expand All @@ -777,8 +787,9 @@ impl<RC: RpcClient> VerifyingPlotter<RC> {
})
.collect::<Result<Vec<Sha256Hash>, PiecesVerificationError>>()?;

// Perform an actual piece validity check
for ((piece, piece_index), root) in
pieces.as_pieces().zip(piece_indexes).zip(verified_roots)
pieces.as_pieces().zip(piece_indexes).zip(roots)
{
let position: u64 = piece_index % records_per_segment as u64;

Expand Down
5 changes: 4 additions & 1 deletion crates/subspace-rpc-primitives/src/lib.rs
Expand Up @@ -15,12 +15,15 @@

//! Primitives for Subspace RPC.

use std::num::NonZeroU32;
use serde::{Deserialize, Serialize};
use std::num::NonZeroU32;
use subspace_core_primitives::{
PublicKey, RewardSignature, Salt, Sha256Hash, SlotNumber, Solution,
};

/// Defines a limit for segment indexes array. It affects storage access on the runtime side.
pub const MAX_SEGMENT_INDEXES_PER_REQUEST: usize = 300;

/// Information about the protocol necessary for farmer operation
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
Expand Down