diff --git a/Cargo.lock b/Cargo.lock index 19094d168a..8f4a5444ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2626,7 +2626,6 @@ dependencies = [ "sc-cli", "sc-client-api", "sc-consensus", - "sc-consensus-subspace", "sc-domains", "sc-network", "sc-network-common", diff --git a/crates/sc-consensus-subspace/src/archiver.rs b/crates/sc-consensus-subspace/src/archiver.rs index c767f795e1..3336b989a8 100644 --- a/crates/sc-consensus-subspace/src/archiver.rs +++ b/crates/sc-consensus-subspace/src/archiver.rs @@ -96,7 +96,7 @@ const ACKNOWLEDGEMENT_TIMEOUT: Duration = Duration::from_mins(2); /// Ideally, we'd decouple pruning from finalization, but it may require invasive changes in /// Substrate and is not worth it right now. /// https://github.com/paritytech/substrate/discussions/14359 -pub const FINALIZATION_DEPTH_IN_SEGMENTS: SegmentIndex = SegmentIndex::new(5); +const FINALIZATION_DEPTH_IN_SEGMENTS: SegmentIndex = SegmentIndex::new(5); #[derive(Debug)] struct SegmentHeadersStoreInner { diff --git a/crates/subspace-service/src/lib.rs b/crates/subspace-service/src/lib.rs index 24e320da17..bfc378a991 100644 --- a/crates/subspace-service/src/lib.rs +++ b/crates/subspace-service/src/lib.rs @@ -893,7 +893,7 @@ where if let Some(offchain_storage) = backend.offchain_storage() { // Allow both outgoing and incoming requests. let (handler, protocol_config) = - MmrRequestHandler::new::::Hash>, _>( + MmrRequestHandler::new::::Hash>>( &config.base.protocol_id(), fork_id.as_deref(), client.clone(), diff --git a/crates/subspace-service/src/mmr.rs b/crates/subspace-service/src/mmr.rs index 590f5e9d1f..42c85780d1 100644 --- a/crates/subspace-service/src/mmr.rs +++ b/crates/subspace-service/src/mmr.rs @@ -1,5 +1,7 @@ +use sp_core::H256; use sp_mmr_primitives::utils::NodesUtils; use sp_mmr_primitives::{NodeIndex, INDEXING_PREFIX}; +use subspace_runtime_primitives::opaque::Header; pub(crate) mod request_handler; pub(crate) mod sync; @@ -7,3 +9,7 @@ pub(crate) mod sync; pub(crate) fn get_offchain_key(index: NodeIndex) -> Vec { NodesUtils::node_canon_offchain_key(INDEXING_PREFIX, index) } + +pub(crate) fn get_temp_key(index: NodeIndex, hash: H256) -> Vec { + NodesUtils::node_temp_offchain_key::
(INDEXING_PREFIX, index, hash) +} diff --git a/crates/subspace-service/src/mmr/request_handler.rs b/crates/subspace-service/src/mmr/request_handler.rs index 0d774eac73..1bb019453d 100644 --- a/crates/subspace-service/src/mmr/request_handler.rs +++ b/crates/subspace-service/src/mmr/request_handler.rs @@ -14,7 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use crate::mmr::get_offchain_key; +use crate::mmr::sync::decode_mmr_data; +use crate::mmr::{get_offchain_key, get_temp_key}; use futures::channel::oneshot; use futures::stream::StreamExt; use parity_scale_codec::{Decode, Encode}; @@ -23,8 +24,10 @@ use sc_network::config::ProtocolId; use sc_network::request_responses::{IncomingRequest, OutgoingResponse}; use sc_network::{NetworkBackend, PeerId}; use schnellru::{ByLength, LruMap}; +use sp_blockchain::HeaderBackend; use sp_core::offchain::storage::OffchainDb; use sp_core::offchain::{DbExternalities, OffchainStorage, StorageKind}; +use sp_mmr_primitives::utils::NodesUtils; use sp_runtime::codec; use sp_runtime::traits::Block as BlockT; use std::collections::BTreeMap; @@ -115,7 +118,10 @@ enum SeenRequestsValue { } /// Handler for incoming block requests from a remote peer. -pub struct MmrRequestHandler { +pub struct MmrRequestHandler +where + Block: BlockT, +{ request_receiver: async_channel::Receiver, /// Maps from request to number of times we have seen this request. /// @@ -124,17 +130,20 @@ pub struct MmrRequestHandler { offchain_db: OffchainDb, + client: Arc, + _phantom: PhantomData, } -impl MmrRequestHandler +impl MmrRequestHandler where - Block: BlockT, - + Block: BlockT, + Client: + HeaderBackend + BlockBackend + ProofProvider + Send + Sync + 'static, OS: OffchainStorage, { /// Create a new [`MmrRequestHandler`]. - pub fn new( + pub fn new( protocol_id: &ProtocolId, fork_id: Option<&str>, client: Arc, @@ -143,7 +152,6 @@ where ) -> (Self, NB::RequestResponseProtocolConfig) where NB: NetworkBackend::Hash>, - Client: BlockBackend + ProofProvider + Send + Sync + 'static, { // Reserve enough request slots for one request per peer when we are at the maximum // number of peers. @@ -166,6 +174,7 @@ where ( Self { + client, request_receiver, seen_requests, offchain_db: OffchainDb::new(offchain_storage), @@ -232,17 +241,35 @@ where Err(()) } else { let mut mmr_data = BTreeMap::new(); - for block_number in - request.starting_position..(request.starting_position + request.limit) - { - let canon_key = get_offchain_key(block_number.into()); + for position in request.starting_position..(request.starting_position + request.limit) { + let canon_key = get_offchain_key(position.into()); let storage_value = self .offchain_db .local_storage_get(StorageKind::PERSISTENT, &canon_key); + let block_number = NodesUtils::leaf_index_that_added_node(position.into()); + trace!(%position, %block_number, "Storage data present: {}", storage_value.is_some()); + if let Some(storage_value) = storage_value { - mmr_data.insert(block_number, storage_value); + mmr_data.insert(position, storage_value); } else { + if let Ok(Some(hash)) = self.client.hash((block_number as u32).into()) { + let temp_key = get_temp_key(position.into(), hash); + let storage_value = self + .offchain_db + .local_storage_get(StorageKind::PERSISTENT, &temp_key); + + if let Some(storage_value) = storage_value { + let data = decode_mmr_data(&storage_value); + trace!(%position, %block_number,"MMR node: {data:?}"); + mmr_data.insert(position, storage_value); + continue; + } else { + debug!(%position, %block_number, ?hash, "Didn't find value in storage.") + } + } else { + debug!(%position, %block_number, "Didn't find hash.") + } break; // No more storage values } } diff --git a/crates/subspace-service/src/mmr/sync.rs b/crates/subspace-service/src/mmr/sync.rs index 4b90319d72..358ba33e86 100644 --- a/crates/subspace-service/src/mmr/sync.rs +++ b/crates/subspace-service/src/mmr/sync.rs @@ -28,7 +28,7 @@ type MmrLeafOf = MmrLeaf; type NodeOf = Node; type MmrOf = mmr_lib::MMR>; -fn decode_mmr_data(mut data: &[u8]) -> mmr_lib::Result { +pub(crate) fn decode_mmr_data(mut data: &[u8]) -> mmr_lib::Result { let node = match NodeOf::decode(&mut data) { Ok(node) => node, Err(err) => { @@ -203,35 +203,34 @@ where // Save the MMR-nodes from response to the local storage 'data: for (position, data) in response.mmr_data.iter() { - // Ensure continuous sync - if *position == starting_position { - let node = decode_mmr_data(data); + let node = decode_mmr_data(data); - let node = match node { - Ok(node) => node, - Err(err) => { - debug!(?peer_info, ?err, %position, "Can't decode MMR data received from the peer."); + let node = match node { + Ok(node) => node, + Err(err) => { + debug!(?peer_info, ?err, %position, "Can't decode MMR data received from the peer."); - continue 'peers; - } - }; - - if matches!(node, Node::Data(_)) { - if let Err(err) = mmr.push(node) { - debug!(?peer_info, ?err, %position, "Can't add MMR data received from the peer."); + continue 'peers; + } + }; - return Err(sp_blockchain::Error::Backend( - "Can't add MMR data to the MMR storage".to_string(), - )); - } + if matches!(node, Node::Data(_)) { + if let Err(err) = mmr.push(node) { + debug!(?peer_info, ?err, %position, "Can't add MMR data received from the peer."); - leaves_number += 1; + return Err(sp_blockchain::Error::Backend( + "Can't add MMR data to the MMR storage".to_string(), + )); } - starting_position += 1; - } else { - debug!("MMR-sync gap detected={peer_id}, position={position}",); - break 'data; // We don't support gaps in MMR data + leaves_number += 1; + } + + starting_position += 1; + + if u64::from(*position) >= target_position { + debug!(%target_position, "MMR-sync: target position reached."); + break 'data; } } } @@ -249,7 +248,7 @@ where if !verify_mmr_data(client, &mmr, leaves_number) { return Err(sp_blockchain::Error::Application( - "Can't get starting MMR position - data verification failed.".into(), + "MMR data verification failed.".into(), )); } diff --git a/domains/client/domain-operator/Cargo.toml b/domains/client/domain-operator/Cargo.toml index 3709221109..2339255822 100644 --- a/domains/client/domain-operator/Cargo.toml +++ b/domains/client/domain-operator/Cargo.toml @@ -14,7 +14,6 @@ futures-timer = "3.0.3" parking_lot = "0.12.2" sc-client-api = { git = "https://github.com/subspace/polkadot-sdk", rev = "5626154d0781ac9a6ffd5a6207ed237f425ae631" } sc-consensus = { git = "https://github.com/subspace/polkadot-sdk", rev = "5626154d0781ac9a6ffd5a6207ed237f425ae631" } -sc-consensus-subspace = { version = "0.1.0", default-features = false, path = "../../../crates/sc-consensus-subspace" } sc-domains = { version = "0.1.0", path = "../../../crates/sc-domains" } sc-network = { git = "https://github.com/subspace/polkadot-sdk", default-features = false, rev = "5626154d0781ac9a6ffd5a6207ed237f425ae631" } sc-network-common = { git = "https://github.com/subspace/polkadot-sdk", default-features = false, rev = "5626154d0781ac9a6ffd5a6207ed237f425ae631" } diff --git a/domains/client/domain-operator/src/snap_sync.rs b/domains/client/domain-operator/src/snap_sync.rs index 20642940de..39e6c6d880 100644 --- a/domains/client/domain-operator/src/snap_sync.rs +++ b/domains/client/domain-operator/src/snap_sync.rs @@ -5,7 +5,6 @@ use sc_client_api::{AuxStore, Backend, ProofProvider}; use sc_consensus::{ BlockImport, BlockImportParams, ForkChoiceStrategy, ImportedState, StateAction, StorageChanges, }; -use sc_consensus_subspace::archiver::FINALIZATION_DEPTH_IN_SEGMENTS; use sc_network::{NetworkRequest, PeerId}; use sc_network_common::sync::message::{ BlockAttributes, BlockData, BlockRequest, Direction, FromBlock, @@ -346,27 +345,7 @@ where .backend .offchain_storage() { - // let target_block = sync_params - // .consensus_chain_sync_params - // .segment_headers_store - // .last_segment_header() - // .map(|header| header.last_archived_block().number); - - let target_block = sync_params - .consensus_chain_sync_params - .segment_headers_store - .max_segment_index() - // Skip last `FINALIZATION_DEPTH_IN_SEGMENTS` archived segments - .and_then(|max_segment_index| { - max_segment_index.checked_sub(FINALIZATION_DEPTH_IN_SEGMENTS) - }) - .and_then(|segment_index| { - sync_params - .consensus_chain_sync_params - .segment_headers_store - .get_segment_header(segment_index) - }) - .map(|segment_header| segment_header.last_archived_block().number); + let target_block = Some(consensus_block_number); mmr_sync( sync_params.consensus_chain_sync_params.fork_id,