Skip to content

Commit

Permalink
Add --min-sync-peer-threshold flag (#80)
Browse files Browse the repository at this point in the history
* Add --min-peer-threshold flag to allow to disable the threshold check

* Refactor UtxoNotFound variant

* Add network_startBlockSync rpc

* Update Cargo.lock

* Fix test

* Docs

* Nits

* Rename to --min-sync-peer-threshold
  • Loading branch information
liuchengxu authored Dec 12, 2024
1 parent 2ff95da commit 8e88291
Show file tree
Hide file tree
Showing 11 changed files with 73 additions and 16 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

37 changes: 26 additions & 11 deletions crates/sc-consensus-nakamoto/src/verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,17 @@ pub enum BlockVerification {
HeaderOnly,
}

/// Represents the context of a transaction within a block.
#[derive(Debug)]
pub struct TransactionContext {
/// Block number containing the transaction.
pub block_number: u32,
/// Index of the transaction in the block.
pub tx_index: usize,
/// ID of the transaction.
pub txid: Txid,
}

/// Block verification error.
#[derive(Debug, thiserror::Error)]
pub enum Error {
Expand All @@ -94,12 +105,14 @@ pub enum Error {
#[error("Block height mismatches in coinbase (got: {got}, expected: {expected})")]
BadCoinbaseBlockHeight { got: u32, expected: u32 },
/// Referenced output does not exist or was spent before.
#[error("UTXO not found (#{block_number}:{txid}: {utxo:?})")]
UtxoNotFound {
block_number: u32,
tx_index: usize,
txid: Txid,
utxo: OutPoint,
#[error(
"Missing UTXO in state for transaction ({context:?}). Missing UTXO: {missing_outpoint:?}"
)]
MissingUtxoInState {
/// Context of the transaction being processed.
context: TransactionContext,
/// UTXO missing from the UTXO set.
missing_outpoint: OutPoint,
},
/// Referenced output has already been spent in this block.
#[error("UTXO already spent in current block (#{block_number}:{txid}: {utxo:?})")]
Expand Down Expand Up @@ -392,11 +405,13 @@ where

// Access coin.
let (spent_output, is_coinbase, coin_height) =
access_coin(coin).ok_or_else(|| Error::UtxoNotFound {
block_number,
tx_index,
txid: get_txid(tx_index),
utxo: coin,
access_coin(coin).ok_or_else(|| Error::MissingUtxoInState {
context: TransactionContext {
block_number,
tx_index,
txid: get_txid(tx_index),
},
missing_outpoint: coin,
})?;

// If coin is coinbase, check that it's matured.
Expand Down
4 changes: 4 additions & 0 deletions crates/subcoin-network/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,8 @@ pub struct Config {
pub max_outbound_peers: usize,
/// Maximum number of inbound peer connections.
pub max_inbound_peers: usize,
/// Minimum peer threshold to start the block sync.
pub min_sync_peer_threshold: usize,
/// Persistent peer latency threshold in milliseconds (ms).
pub persistent_peer_latency_threshold: u128,
/// Major sync strategy.
Expand Down Expand Up @@ -450,6 +452,7 @@ where
network,
max_inbound_peers,
max_outbound_peers,
min_sync_peer_threshold,
sync_strategy,
block_sync,
sync_target,
Expand Down Expand Up @@ -497,6 +500,7 @@ where
is_major_syncing,
connection_initiator,
max_outbound_peers,
min_sync_peer_threshold,
enable_block_sync,
peer_store: Arc::new(persistent_peer_store_handle),
sync_target,
Expand Down
4 changes: 4 additions & 0 deletions crates/subcoin-network/src/network_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ pub struct Params<Block, Client> {
pub is_major_syncing: Arc<AtomicBool>,
pub connection_initiator: ConnectionInitiator,
pub max_outbound_peers: usize,
pub min_sync_peer_threshold: usize,
/// Whether to enable block sync on start.
pub enable_block_sync: bool,
pub peer_store: Arc<dyn PeerStore>,
Expand Down Expand Up @@ -101,6 +102,7 @@ where
is_major_syncing,
connection_initiator,
max_outbound_peers,
min_sync_peer_threshold,
enable_block_sync,
peer_store,
sync_target,
Expand Down Expand Up @@ -132,6 +134,7 @@ where
enable_block_sync,
peer_store.clone(),
sync_target,
min_sync_peer_threshold,
);

Self {
Expand Down Expand Up @@ -306,6 +309,7 @@ where
let _ = result_sender.send(send_transaction_result);
}
NetworkProcessorMessage::StartBlockSync => {
tracing::debug!("StartBlockSync signal received");
let sync_action = self.chain_sync.start_block_sync();
self.do_sync_action(sync_action);
}
Expand Down
14 changes: 9 additions & 5 deletions crates/subcoin-network/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ const LOW_LATENCY_CUTOFF: Latency = 20;
/// Maximum number of syncing retries for a deprioritized peer.
const MAX_STALLS: usize = 5;

// Minimum peer threshold required to start sync
const MIN_PEER_THRESHOLD: usize = 3;

/// The state of syncing between a Peer and ourselves.
#[derive(Copy, Clone, Eq, PartialEq, Debug, Serialize, Deserialize, Hash)]
#[serde(rename_all = "camelCase")]
Expand Down Expand Up @@ -190,6 +187,7 @@ pub(crate) struct ChainSync<Block, Client> {
peer_store: Arc<dyn PeerStore>,
/// Target block of the syncing process.
sync_target: Option<u32>,
min_sync_peer_threshold: usize,
_phantom: PhantomData<Block>,
}

Expand All @@ -209,6 +207,7 @@ where
enable_block_sync: bool,
peer_store: Arc<dyn PeerStore>,
sync_target: Option<u32>,
min_sync_peer_threshold: usize,
) -> Self {
Self {
client,
Expand All @@ -222,6 +221,7 @@ where
rng: fastrand::Rng::new(),
peer_store,
sync_target,
min_sync_peer_threshold,
_phantom: Default::default(),
}
}
Expand Down Expand Up @@ -532,8 +532,12 @@ where
return SyncAction::None;
}

if self.peers.len() < MIN_PEER_THRESHOLD {
tracing::debug!("Waiting for more peers");
if self.peers.len() < self.min_sync_peer_threshold {
tracing::debug!(
"Waiting for more sync peers, discovered {} peers, require {} peers",
self.peers.len(),
self.min_sync_peer_threshold
);
return SyncAction::None;
}

Expand Down
1 change: 1 addition & 0 deletions crates/subcoin-network/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ impl TestNode {
sync_target: None,
max_outbound_peers: 10,
max_inbound_peers: 10,
min_sync_peer_threshold: 0,
persistent_peer_latency_threshold: 200,
sync_strategy,
block_sync: crate::BlockSyncOption::Off,
Expand Down
7 changes: 7 additions & 0 deletions crates/subcoin-node/src/cli/subcoin_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ pub struct NetworkParams {
/// Default value is 500 ms
#[clap(long, default_value_t = 500)]
pub persistent_peer_latency_threshold: u128,

/// Minimum peer threshold required to start block sync.
///
/// The chain sync won't be started until the number of sync peers reaches this threshold.
/// Set to `0` to disable the peer threshold limit. Default: 3
#[arg(long, default_value = "3")]
pub min_sync_peer_threshold: usize,
}

#[derive(Debug, Clone, Parser)]
Expand Down
1 change: 1 addition & 0 deletions crates/subcoin-node/src/commands/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ impl Run {
sync_target: self.sync_target,
max_outbound_peers: self.network_params.max_outbound_peers,
max_inbound_peers: self.network_params.max_inbound_peers,
min_sync_peer_threshold: self.network_params.min_sync_peer_threshold,
persistent_peer_latency_threshold: self
.network_params
.persistent_peer_latency_threshold,
Expand Down
1 change: 1 addition & 0 deletions crates/subcoin-rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ async-trait = { workspace = true }
bitcoin = { workspace = true, features = ["serde", "std"] }
jsonrpsee = { workspace = true, features = ["client-core", "macros", "server-core"] }
sc-client-api = { workspace = true }
sc-rpc-api = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
sp-blockchain = { workspace = true }
Expand Down
4 changes: 4 additions & 0 deletions crates/subcoin-rpc/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use bitcoin::consensus::encode::FromHexError;
use jsonrpsee::types::error::ErrorObject;
use jsonrpsee::types::ErrorObjectOwned;
use sc_rpc_api::UnsafeRpcError;

/// Chain RPC errors.
#[derive(Debug, thiserror::Error)]
Expand All @@ -19,6 +20,9 @@ pub enum Error {
DecodeHex(#[from] FromHexError),
#[error(transparent)]
SerdeJson(#[from] serde_json::Error),
/// Call to an unsafe RPC was denied.
#[error(transparent)]
UnsafeRpcCalled(#[from] UnsafeRpcError),
/// Client error.
#[error("Client error: {0}")]
Client(#[from] Box<dyn std::error::Error + Send + Sync>),
Expand Down
15 changes: 15 additions & 0 deletions crates/subcoin-rpc/src/network.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::error::Error;
use jsonrpsee::proc_macros::rpc;
use jsonrpsee::Extensions;
use sc_client_api::{AuxStore, BlockBackend, HeaderBackend};
use serde::{Deserialize, Serialize};
use sp_runtime::traits::Block as BlockT;
Expand Down Expand Up @@ -38,6 +39,12 @@ pub trait NetworkApi {
/// Get overall network status.
#[method(name = "network_status")]
async fn network_status(&self) -> Result<Option<NetworkStatus>, Error>;

/// Trigger the block sync manually.
///
/// This API is unsafe and primarily for the local development.
#[method(name = "network_startBlockSync", with_extensions)]
fn network_start_block_sync(&self) -> Result<(), Error>;
}

/// This struct provides the Network API.
Expand Down Expand Up @@ -106,4 +113,12 @@ where
async fn network_status(&self) -> Result<Option<NetworkStatus>, Error> {
Ok(self.network_api.status().await)
}

fn network_start_block_sync(&self, ext: &Extensions) -> Result<(), Error> {
sc_rpc_api::check_if_safe(ext)?;

self.network_api.start_block_sync();

Ok(())
}
}

0 comments on commit 8e88291

Please sign in to comment.