diff --git a/Cargo.lock b/Cargo.lock index 3ef8fcdb61..b0c2f64ffa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9611,6 +9611,8 @@ dependencies = [ "sc-network-sync", "sc-service", "sc-transaction-pool-api", + "sp-api", + "sp-consensus-subspace", "sp-runtime", "thiserror", "tracing", diff --git a/crates/sc-subspace-block-relay/Cargo.toml b/crates/sc-subspace-block-relay/Cargo.toml index fa773158f8..98f95da33b 100644 --- a/crates/sc-subspace-block-relay/Cargo.toml +++ b/crates/sc-subspace-block-relay/Cargo.toml @@ -22,6 +22,8 @@ sc-network = { version = "0.10.0-dev", git = "https://github.com/subspace/substr sc-network-common = { version = "0.10.0-dev", git = "https://github.com/subspace/substrate", rev = "55c157cff49b638a59d81a9f971f0f9a66829c71" } sc-network-sync = { version = "0.10.0-dev", git = "https://github.com/subspace/substrate", rev = "55c157cff49b638a59d81a9f971f0f9a66829c71" } sc-service = { version = "0.10.0-dev", git = "https://github.com/subspace/substrate", rev = "55c157cff49b638a59d81a9f971f0f9a66829c71", default-features = false } +sp-api = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "55c157cff49b638a59d81a9f971f0f9a66829c71" } +sp-consensus-subspace = { version = "0.1.0", path = "../sp-consensus-subspace" } sc-transaction-pool-api = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "55c157cff49b638a59d81a9f971f0f9a66829c71" } sp-runtime = { version = "24.0.0", git = "https://github.com/subspace/substrate", rev = "55c157cff49b638a59d81a9f971f0f9a66829c71" } thiserror = "1.0.38" diff --git a/crates/sc-subspace-block-relay/src/consensus.rs b/crates/sc-subspace-block-relay/src/consensus.rs index 2c94bc18e0..fb70d549ca 100644 --- a/crates/sc-subspace-block-relay/src/consensus.rs +++ b/crates/sc-subspace-block-relay/src/consensus.rs @@ -2,7 +2,9 @@ use crate::protocol::compact_block::{CompactBlockClient, CompactBlockServer}; use crate::utils::{NetworkPeerHandle, NetworkWrapper, RequestResponseErr}; -use crate::{ProtocolBackend, ProtocolClient, ProtocolServer, RelayError, LOG_TARGET}; +use crate::{ + ProtocolBackend, ProtocolClient, ProtocolServer, ProtocolUnitInfo, RelayError, LOG_TARGET, +}; use async_trait::async_trait; use codec::{Compact, CompactLen, Decode, Encode}; use futures::channel::oneshot; @@ -21,6 +23,8 @@ use sc_network_sync::block_relay_protocol::{ }; use sc_service::SpawnTaskHandle; use sc_transaction_pool_api::{InPoolTransaction, TransactionPool, TxHash}; +use sp_api::ProvideRuntimeApi; +use sp_consensus_subspace::{FarmerPublicKey, SubspaceApi}; use sp_runtime::generic::BlockId; use sp_runtime::traits::{Block as BlockT, Header, NumberFor, One, Zero}; use sp_runtime::Justifications; @@ -45,6 +49,10 @@ const MAX_RESPONSE_SIZE: NonZeroUsize = NonZeroUsize::new(8 * 1024 * 1024).expec /// Maximum blocks in the response. const MAX_RESPONSE_BLOCKS: NonZeroU32 = NonZeroU32::new(128).expect("Not zero; qed"); +/// If the encoded size of the extrinsic is less than the threshold, +/// return the full extrinsic along with the tx hash. +const TX_SIZE_THRESHOLD: NonZeroUsize = NonZeroUsize::new(32).expect("Not zero; qed"); + /// Initial request for a single block. #[derive(Encode, Decode)] struct InitialRequest { @@ -603,7 +611,8 @@ struct ConsensusBackend { impl ConsensusBackend where Block: BlockT, - Client: HeaderBackend + BlockBackend, + Client: HeaderBackend + BlockBackend + ProvideRuntimeApi, + Client::Api: SubspaceApi, Pool: TransactionPool + 'static, { fn new( @@ -645,17 +654,29 @@ impl ProtocolBackend, TxHash, Extrin for ConsensusBackend where Block: BlockT, - Client: HeaderBackend + BlockBackend, + Client: HeaderBackend + BlockBackend + ProvideRuntimeApi, + Client::Api: SubspaceApi, Pool: TransactionPool + 'static, { fn download_unit_members( &self, block_hash: &BlockHash, - ) -> Result, Extrinsic)>, RelayError> { - let tx = block_transactions(block_hash, self.client.as_ref())?; - Ok(tx + ) -> Result, Extrinsic>>, RelayError> { + let txns = block_transactions(block_hash, self.client.as_ref())?; + Ok(txns .into_iter() - .map(|extrinsic| (self.transaction_pool.hash_of(&extrinsic), extrinsic)) + .map(|extrinsic| { + let send_tx = extrinsic.encoded_size() <= TX_SIZE_THRESHOLD.get() + || self + .client + .runtime_api() + .is_inherent(*block_hash, &extrinsic) + .unwrap_or(false); + ProtocolUnitInfo { + id: self.transaction_pool.hash_of(&extrinsic), + unit: if send_tx { Some(extrinsic) } else { None }, + } + }) .collect()) } @@ -728,7 +749,8 @@ pub fn build_consensus_relay( ) -> BlockRelayParams where Block: BlockT, - Client: HeaderBackend + BlockBackend + 'static, + Client: HeaderBackend + BlockBackend + ProvideRuntimeApi + 'static, + Client::Api: SubspaceApi, Pool: TransactionPool + 'static, { let (tx, request_receiver) = async_channel::bounded(NUM_PEER_HINT.get()); diff --git a/crates/sc-subspace-block-relay/src/lib.rs b/crates/sc-subspace-block-relay/src/lib.rs index 0d00f62691..43feaa2feb 100644 --- a/crates/sc-subspace-block-relay/src/lib.rs +++ b/crates/sc-subspace-block-relay/src/lib.rs @@ -106,11 +106,16 @@ pub(crate) trait ProtocolServer { /// The relay user specific backend interface pub(crate) trait ProtocolBackend { - /// Returns all the protocol units for the given download unit + /// Returns the protocol units for the given download unit, to be returned + /// with the initial response. Some of the items may have the full entry + /// along with the Id (e.g) consensus may choose to return the full + /// transaction for inherents/small transactions in the block. And return + /// only the Tx hash for the remaining extrinsics. Further protocol + /// handshake would be used only for resolving these remaining items. fn download_unit_members( &self, id: &DownloadUnitId, - ) -> Result, RelayError>; + ) -> Result>, RelayError>; /// Returns the protocol unit for the given download/protocol unit fn protocol_unit( @@ -119,3 +124,15 @@ pub(crate) trait ProtocolBackend { protocol_unit_id: &ProtocolUnitId, ) -> Result, RelayError>; } + +/// The protocol unit info carried in the initial response +#[derive(Encode, Decode)] +struct ProtocolUnitInfo { + /// The protocol unit Id + id: ProtocolUnitId, + + /// The server can optionally return the protocol unit + /// as part of the initial response. No further + /// action is needed on client side to resolve it + unit: Option, +} diff --git a/crates/sc-subspace-block-relay/src/protocol/compact_block.rs b/crates/sc-subspace-block-relay/src/protocol/compact_block.rs index 8c6f8b6977..97ac5c1c32 100644 --- a/crates/sc-subspace-block-relay/src/protocol/compact_block.rs +++ b/crates/sc-subspace-block-relay/src/protocol/compact_block.rs @@ -1,22 +1,16 @@ //! Compact block implementation. use crate::utils::NetworkPeerHandle; -use crate::{ProtocolBackend, ProtocolClient, ProtocolServer, RelayError, Resolved, LOG_TARGET}; +use crate::{ + ProtocolBackend, ProtocolClient, ProtocolServer, ProtocolUnitInfo, RelayError, Resolved, + LOG_TARGET, +}; use async_trait::async_trait; use codec::{Decode, Encode}; use std::collections::BTreeMap; -use std::num::NonZeroUsize; use std::sync::Arc; use tracing::{trace, warn}; -/// If the encoded size of the protocol unit is less than the threshold, -/// return the full protocol unit along with the protocol unit Id in the -/// compact response. This catches the common cases like inherents with -/// no segment headers. Since inherents are not gossiped, this causes -/// a local miss/extra round trip. This threshold based scheme could be -/// replaced by using the is_inherent() API if needed -const PROTOCOL_UNIT_SIZE_THRESHOLD: NonZeroUsize = NonZeroUsize::new(32).expect("Not zero; qed"); - /// Request messages #[derive(Encode, Decode)] pub(crate) enum CompactBlockRequest { @@ -37,18 +31,6 @@ pub(crate) enum CompactBlockResponse), } -/// The protocol unit info carried in the compact response -#[derive(Encode, Decode)] -struct ProtocolUnitInfo { - /// The protocol unit Id - id: ProtocolUnitId, - - /// The server can optionally return the protocol unit - /// as part of the initial response. No further - /// action is needed on client side to resolve it - unit: Option, -} - /// The compact response #[derive(Encode, Decode)] pub(crate) struct InitialResponse { @@ -288,21 +270,10 @@ where return Err(RelayError::UnexpectedInitialRequest); } - // Return the hash of the members in the download unit. - let members = self.backend.download_unit_members(download_unit_id)?; + // Return the info of the members in the download unit. let response = InitialResponse { download_unit_id: download_unit_id.clone(), - protocol_units: members - .into_iter() - .map(|(id, unit)| { - let unit = if unit.encoded_size() <= PROTOCOL_UNIT_SIZE_THRESHOLD.get() { - Some(unit) - } else { - None - }; - ProtocolUnitInfo { id, unit } - }) - .collect(), + protocol_units: self.backend.download_unit_members(download_unit_id)?, }; Ok(CompactBlockResponse::Initial(response)) }