Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,8 @@ members = [
"substrate/client/executor/polkavm",
"substrate/client/executor/runtime-test",
"substrate/client/executor/wasmtime",
"substrate/client/informant",
"substrate/client/hop",
"substrate/client/informant",
"substrate/client/keystore",
"substrate/client/merkle-mountain-range",
"substrate/client/merkle-mountain-range/rpc",
Expand Down Expand Up @@ -509,6 +509,7 @@ members = [
"substrate/primitives/ethereum-standards",
"substrate/primitives/externalities",
"substrate/primitives/genesis-builder",
"substrate/primitives/hop",
"substrate/primitives/inherents",
"substrate/primitives/io",
"substrate/primitives/keyring",
Expand Down Expand Up @@ -1363,6 +1364,7 @@ sp-database = { path = "substrate/primitives/database", default-features = false
sp-debug-derive = { path = "substrate/primitives/debug-derive", default-features = false }
sp-externalities = { path = "substrate/primitives/externalities", default-features = false }
sp-genesis-builder = { path = "substrate/primitives/genesis-builder", default-features = false }
sp-hop = { path = "substrate/primitives/hop", default-features = false }
sp-inherents = { path = "substrate/primitives/inherents", default-features = false }
sp-io = { path = "substrate/primitives/io", default-features = false }
sp-keyring = { path = "substrate/primitives/keyring", default-features = false }
Expand Down
1 change: 1 addition & 0 deletions cumulus/polkadot-omni-node/lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ sp-consensus = { workspace = true, default-features = true }
sp-consensus-aura = { workspace = true, default-features = true }
sp-core = { workspace = true, default-features = true }
sp-genesis-builder = { workspace = true }
sp-hop = { workspace = true, default-features = true }
sp-inherents = { workspace = true, default-features = true }
sp-keystore = { workspace = true, default-features = true }
sp-offchain = { workspace = true, default-features = true }
Expand Down
43 changes: 4 additions & 39 deletions cumulus/polkadot-omni-node/lib/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,40 +238,9 @@ pub struct Cli<Config: CliConfig> {
#[arg(long, default_value_t = 50_000)]
pub statement_rate_limit: u32,

/// Enable HOP (Hand-Off Protocol) data pool.
///
/// The HOP pool provides ephemeral in-memory storage for peer-to-peer data
/// sharing. Data is stored temporarily until it expires and can be promoted
/// to permanent on-chain storage.
#[arg(long)]
pub enable_hop: bool,

/// HOP maximum data pool size in MiB.
///
/// Only relevant when `--enable-hop` is used.
#[arg(long, default_value_t = 10240)]
pub hop_max_pool_size: u64,

/// HOP data retention period in blocks.
///
/// At 6 seconds per block, 14400 blocks equals approximately 24 hours.
/// Only relevant when `--enable-hop` is used.
#[arg(long, default_value_t = 14400)]
pub hop_retention_blocks: u32,

/// HOP promotion check interval in seconds.
///
/// How often to check for expired entries that should be promoted to chain storage.
/// Only relevant when `--enable-hop` is used.
#[arg(long, default_value_t = 60)]
pub hop_check_interval: u64,

/// Directory for HOP persistent data storage.
///
/// If not specified, defaults to `<chain-data-dir>/hop`.
/// Only relevant when `--enable-hop` is used.
#[arg(long)]
pub hop_data_dir: Option<PathBuf>,
/// HOP (Hand-Off Protocol) parameters.
#[command(flatten)]
pub hop: sc_hop::HopParams,

#[arg(skip)]
pub(crate) _phantom: PhantomData<Config>,
Expand Down Expand Up @@ -321,11 +290,7 @@ impl<Config: CliConfig> Cli<Config> {
statement_network_workers: self.statement_network_workers,
statement_rate_limit: self.statement_rate_limit,
storage_monitor: self.storage_monitor.clone(),
enable_hop: self.enable_hop,
hop_max_pool_size_mb: self.hop_max_pool_size,
hop_retention_blocks: self.hop_retention_blocks,
hop_check_interval: self.hop_check_interval,
hop_data_dir: self.hop_data_dir.clone(),
hop: self.hop.clone(),
}
}

Expand Down
8 changes: 4 additions & 4 deletions cumulus/polkadot-omni-node/lib/src/common/hop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ pub(crate) fn build_hop_pool(
node_extra_args: &NodeExtraArgs,
database_path: Option<PathBuf>,
) -> sc_service::error::Result<Option<Arc<HopDataPool>>> {
if !node_extra_args.enable_hop {
if !node_extra_args.hop.enable_hop {
return Ok(None);
}

let data_dir = match &node_extra_args.hop_data_dir {
let data_dir = match &node_extra_args.hop.hop_data_dir {
Some(dir) => dir.clone(),
None => database_path
.ok_or_else(|| {
Expand All @@ -39,8 +39,8 @@ pub(crate) fn build_hop_pool(
};

let pool = HopDataPool::new(
node_extra_args.hop_max_pool_size_mb * 1024 * 1024,
node_extra_args.hop_retention_blocks,
node_extra_args.hop.hop_max_pool_size * 1024 * 1024,
node_extra_args.hop.hop_retention_blocks,
data_dir,
)
.map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?;
Expand Down
19 changes: 5 additions & 14 deletions cumulus/polkadot-omni-node/lib/src/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ use sc_offchain::OffchainWorkerApi;
use serde::de::DeserializeOwned;
use sp_api::{ApiExt, CallApiAt, ConstructRuntimeApi, Metadata};
use sp_block_builder::BlockBuilder;
use sp_hop::HopPromotionApi;
use sp_runtime::{
traits::{Block as BlockT, BlockNumber, Header as HeaderT, NumberFor},
OpaqueExtrinsic,
Expand Down Expand Up @@ -76,6 +77,7 @@ pub trait NodeRuntimeApi<Block: BlockT>:
+ GetParachainInfo<Block>
+ TransactionStorageApi<Block>
+ RelayParentOffsetApi<Block>
+ HopPromotionApi<Block>
+ Sized
{
}
Expand All @@ -91,6 +93,7 @@ impl<T, Block: BlockT> NodeRuntimeApi<Block> for T where
+ CollectCollationInfo<Block>
+ GetParachainInfo<Block>
+ TransactionStorageApi<Block>
+ HopPromotionApi<Block>
{
}

Expand Down Expand Up @@ -137,18 +140,6 @@ pub struct NodeExtraArgs {
/// Parameters for storage monitoring.
pub storage_monitor: sc_storage_monitor::StorageMonitorParams,

/// If true then the HOP data pool will be enabled.
pub enable_hop: bool,

/// HOP maximum data pool size in MiB.
pub hop_max_pool_size_mb: u64,

/// HOP data retention period in blocks.
pub hop_retention_blocks: u32,

/// HOP promotion check interval in seconds.
pub hop_check_interval: u64,

/// Directory for HOP persistent data storage.
pub hop_data_dir: Option<PathBuf>,
/// HOP (Hand-Off Protocol) parameters.
pub hop: sc_hop::HopParams,
}
3 changes: 1 addition & 2 deletions cumulus/polkadot-omni-node/lib/src/common/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,7 @@ where
if let Some(hop_pool) = hop_pool {
use sc_hop::{HopApiServer, HopRpcServer, NoopVerifier};
module.merge(
HopRpcServer::new(hop_pool, client.clone(), Arc::new(NoopVerifier))
.into_rpc(),
HopRpcServer::new(hop_pool, client.clone(), Arc::new(NoopVerifier)).into_rpc(),
)?;
}
module.merge(Dev::new(client).into_rpc())?;
Expand Down
30 changes: 11 additions & 19 deletions cumulus/polkadot-omni-node/lib/src/common/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,26 +426,18 @@ pub(crate) trait NodeSpec: BaseNodeSpec {
parachain_config.database.path().map(|p| p.to_path_buf()),
)?;
if let Some(ref pool) = hop_pool {
let task_pool = pool.clone();
let promoter = sc_hop::try_build_promoter(&client, &transaction_pool);
let task_client = client.clone();
let check_interval = node_extra_args.hop_check_interval;
task_manager.spawn_handle().spawn("hop-promotion", None, async move {
loop {
futures_timer::Delay::new(Duration::from_secs(check_interval)).await;
let block = task_client
.info()
.best_number
.saturated_into::<u32>();
let freed = task_pool.cleanup_expired(block);
if freed > 0 {
log::info!(
target: "hop",
"Cleaned up expired HOP entries, freed {} bytes",
freed,
);
}
}
});
let best_block: Arc<dyn Fn() -> u32 + Send + Sync> =
Arc::new(move || task_client.info().best_number.saturated_into::<u32>());
let maintenance = sc_hop::HopMaintenanceTask::new(
pool.clone(),
promoter,
best_block,
node_extra_args.hop.hop_buffer_blocks,
node_extra_args.hop.hop_check_interval,
);
task_manager.spawn_handle().spawn("hop-maintenance", None, maintenance.run());
}

if parachain_config.offchain_worker.enabled {
Expand Down
10 changes: 10 additions & 0 deletions cumulus/polkadot-omni-node/lib/src/fake_runtime_api/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,16 @@ macro_rules! impl_node_runtime_apis {
unimplemented!()
}
}

impl sp_hop::HopPromotionApi<$block> for $runtime {
fn create_promotion_extrinsic(_: Vec<u8>) -> <$block as BlockT>::Extrinsic {
unimplemented!()
}

fn max_promotion_size() -> u32 {
unimplemented!()
}
}
}
};
}
Expand Down
17 changes: 12 additions & 5 deletions substrate/client/hop/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,31 @@ workspace = true
[dependencies]
# Core
codec = { workspace = true, features = ["derive"] }
hex = { workspace = true }
parking_lot = { workspace = true }
serde = { workspace = true, features = ["derive"] }
thiserror = { workspace = true }
hex = { workspace = true }
tracing = { workspace = true }
serde = { workspace = true, features = ["derive"] }

# CLI
clap = { workspace = true, features = ["derive"] }

# RPC
jsonrpsee = { workspace = true, features = ["server", "client", "macros"] }
jsonrpsee = { workspace = true, features = ["client", "macros", "server"] }

# Async
futures-timer = { workspace = true }

# Substrate primitives (client-side, always with std)
sp-core = { workspace = true, default-features = true }
polkadot-primitives = { workspace = true, default-features = true }
sp-api = { workspace = true, default-features = true }
sp-blockchain = { workspace = true, default-features = true }
sp-core = { workspace = true, default-features = true }
sp-hop = { workspace = true, default-features = true }
sp-runtime = { workspace = true, default-features = true }
polkadot-primitives = { workspace = true, default-features = true }

# Substrate client
sc-transaction-pool-api = { workspace = true, default-features = true }

[dev-dependencies]
tempfile = { workspace = true }
8 changes: 8 additions & 0 deletions substrate/client/hop/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ pub struct HopParams {
#[arg(long, default_value = "60")]
pub hop_check_interval: u64,

/// How many blocks before expiry to start promoting entries to chain storage.
///
/// At 6 seconds per block, 1200 blocks is approximately 2 hours.
/// Only relevant when `--enable-hop` is used.
#[arg(long, default_value = "1200")]
pub hop_buffer_blocks: u32,

/// Directory for HOP persistent data storage.
///
/// If not specified, defaults to `<chain-data-dir>/hop`.
Expand All @@ -68,6 +75,7 @@ impl Default for HopParams {
hop_max_pool_size: (DEFAULT_MAX_POOL_SIZE / (1024 * 1024)), // Convert to MiB
hop_retention_blocks: DEFAULT_RETENTION_BLOCKS, // 24 hours
hop_check_interval: 60, // 1 minute
hop_buffer_blocks: 1200, // ~2 hours
hop_data_dir: None,
}
}
Expand Down
8 changes: 6 additions & 2 deletions substrate/client/hop/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,10 @@
//!
//! ## RPC Methods
//!
//! - `hop_submit(data: Bytes, recipients: Vec<Bytes>, proof: Bytes) -> SubmitResult` - Submit data with SCALE-encoded MultiSigner recipient keys and personhood proof, returns hash + pool status
//! - `hop_claim(hash: Bytes, signature: Bytes) -> Bytes` - Claim data with SCALE-encoded MultiSignature
//! - `hop_submit(data: Bytes, recipients: Vec<Bytes>, proof: Bytes) -> SubmitResult` - Submit data
//! with SCALE-encoded MultiSigner recipient keys and personhood proof, returns hash + pool status
//! - `hop_claim(hash: Bytes, signature: Bytes) -> Bytes` - Claim data with SCALE-encoded
//! MultiSignature
//! - `hop_poolStatus() -> PoolStatus` - Get pool statistics
//!
//! ## CLI Flags
Expand All @@ -90,12 +92,14 @@
pub mod cli;
pub mod pool;
pub mod primitives;
pub mod promotion;
pub mod rpc;
pub mod types;

// Convenience re-exports for common use cases
pub use cli::HopParams;
pub use pool::HopDataPool;
pub use primitives::{HopBlockNumber, HopHash};
pub use promotion::{try_build_promoter, HopMaintenanceTask, HopPromoter, RuntimeApiPromoter};
pub use rpc::{HopApiServer, HopRpcServer, NoopVerifier, PersonhoodVerifier};
pub use types::{Alias, HopEntryMeta, HopError, HopPoolEntry, PoolStatus, SubmitResult};
Loading
Loading