Skip to content

Commit

Permalink
Initial metrics integration (#37)
Browse files Browse the repository at this point in the history
* refactoring: introduce Params in network worker

* Initial metrics in subcoin-network

* Initial metrics in sc-consensus-nakamoto

* Spawn prometheus service in import-blocks command

* Use GaugeVec for block_execution_time

* Rename --bootnode to --seednodes in subcoin networking params

* More subcoin network metrics

* Fix test

* FMT

* Add block transactions count metric

* Add docker

* Add dashboard.json

* Add README.md

* Update grafana README.md

* .

* Update dashboard.json

* Add block size metric

* Update readme (#38)

* Update README.md

* Update README.md

* Update README.md

* .

* .

* .

* Update README.md

* Update README.md

* Update README.md

* Rate limiting on metric report of block_execution
  • Loading branch information
liuchengxu authored Aug 10, 2024
1 parent 5531c21 commit 41535b4
Show file tree
Hide file tree
Showing 23 changed files with 1,206 additions and 84 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

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

6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
# Subcoin: Bitcoin Full Node in Substrate
<div align="center">

<p align="center"><img width="400" src="./docs/images/subcoin-high-resolution-logo.png" alt="Subcoin logo"></p>

[![Continuous integration](https://github.com/subcoin-project/subcoin/actions/workflows/ci.yml/badge.svg)](https://github.com/subcoin-project/subcoin/actions/workflows/ci.yml)
[![Docs](https://github.com/subcoin-project/subcoin/actions/workflows/docs.yml/badge.svg)](https://github.com/subcoin-project/subcoin/actions/workflows/docs.yml)
[![Static Badge](https://img.shields.io/badge/User%20Guide-blue?logo=mdBook&logoColor=%23292b2e&link=https%3A%2F%2Fsubcoin-project.github.io%2Fsubcoin%2Fbook)](https://subcoin-project.github.io/subcoin/book)

</div>

> [!WARNING]
>
> Subcoin is currently in its early development stages and is not yet ready for production use.
Expand Down
1 change: 1 addition & 0 deletions crates/sc-consensus-nakamoto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ sp-io = { workspace = true }
sp-runtime = { workspace = true }
sp-state-machine = { workspace = true }
subcoin-primitives = { workspace = true }
substrate-prometheus-endpoint = { workspace = true }
thiserror = { workspace = true }
tracing = { workspace = true }

Expand Down
52 changes: 49 additions & 3 deletions crates/sc-consensus-nakamoto/src/block_import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
//! An enum representing the result of an import operation, with variants for different import outcomes.

use crate::block_executor::{BlockExecutor, ExecuteBlockResult};
use crate::metrics::Metrics;
use crate::verification::{BlockVerification, BlockVerifier};
use bitcoin::hashes::Hash;
use bitcoin::{Block as BitcoinBlock, BlockHash, Network};
Expand All @@ -37,10 +38,12 @@ use sp_runtime::traits::{
use sp_runtime::{SaturatedConversion, Saturating};
use std::marker::PhantomData;
use std::sync::Arc;
use std::time::Instant;
use subcoin_primitives::runtime::Subcoin;
use subcoin_primitives::{
substrate_header_digest, BackendExt, BitcoinTransactionAdapter, CoinStorageKey,
};
use substrate_prometheus_endpoint::Registry;

pub(crate) fn clone_storage_changes<Block: BlockT>(
c: &sp_state_machine::StorageChanges<HashingFor<Block>>,
Expand Down Expand Up @@ -129,6 +132,8 @@ pub struct BitcoinBlockImporter<Block, Client, BE, BI, TransactionAdapter> {
config: ImportConfig,
verifier: BlockVerifier<Block, Client, BE>,
block_executor: Box<dyn BlockExecutor<Block>>,
metrics: Option<Metrics>,
last_block_execution_report: Instant,
_phantom: PhantomData<TransactionAdapter>,
}

Expand Down Expand Up @@ -156,6 +161,7 @@ where
config: ImportConfig,
coin_storage_key: Arc<dyn CoinStorageKey>,
block_executor: Box<dyn BlockExecutor<Block>>,
registry: Option<&Registry>,
) -> Self {
let verifier = BlockVerifier::new(
client.clone(),
Expand All @@ -164,13 +170,23 @@ where
coin_storage_key,
config.verify_script,
);
let metrics = match registry {
Some(registry) => Metrics::register(registry)
.map_err(|err| {
tracing::error!("Failed to registry metrics: {err:?}");
})
.ok(),
None => None,
};
Self {
client,
inner: block_import,
stats: Stats::default(),
config,
verifier,
block_executor,
metrics,
last_block_execution_report: Instant::now(),
_phantom: Default::default(),
}
}
Expand Down Expand Up @@ -209,19 +225,46 @@ where
}

fn execute_block_at(
&self,
&mut self,
block_number: NumberFor<Block>,
parent_hash: Block::Hash,
block: Block,
) -> sp_blockchain::Result<(
Block::Hash,
sp_state_machine::StorageChanges<HashingFor<Block>>,
)> {
let timer = std::time::Instant::now();

let transactions_count = block.extrinsics().len();
let block_size = block.encoded_size();

let ExecuteBlockResult {
state_root,
storage_changes,
exec_info: _,
} = self.block_executor.execute_block(parent_hash, block)?;

if let Some(metrics) = &self.metrics {
const BLOCK_EXECUTION_REPORT_INTERVAL: u128 = 50;

// Executing blocks before 200000 is pretty fast, it becomes
// increasingly slower beyond this point, we only cares about
// the slow block executions.
if self.last_block_execution_report.elapsed().as_millis()
> BLOCK_EXECUTION_REPORT_INTERVAL
{
let block_number: u32 = block_number.saturated_into();
let execution_time = timer.elapsed().as_millis();
metrics.report_block_execution(
block_number.saturated_into(),
transactions_count,
block_size,
execution_time,
);
self.last_block_execution_report = Instant::now();
}
}

Ok((state_root, storage_changes))
}

Expand Down Expand Up @@ -266,8 +309,11 @@ where

let tx_count = extrinsics.len();

let (state_root, storage_changes) =
self.execute_block_at(parent_hash, Block::new(header.clone(), extrinsics.clone()))?;
let (state_root, storage_changes) = self.execute_block_at(
block_number,
parent_hash,
Block::new(header.clone(), extrinsics.clone()),
)?;

let execution_time = now.elapsed().as_millis();

Expand Down
1 change: 1 addition & 0 deletions crates/sc-consensus-nakamoto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod block_executor;
mod block_import;
mod chain_params;
mod import_queue;
mod metrics;
mod verification;

pub use block_executor::{
Expand Down
60 changes: 60 additions & 0 deletions crates/sc-consensus-nakamoto/src/metrics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use substrate_prometheus_endpoint::{register, GaugeVec, Opts, PrometheusError, Registry, U64};

pub struct Metrics {
block_execution_time: GaugeVec<U64>,
block_transactions_count: GaugeVec<U64>,
block_size: GaugeVec<U64>,
}

impl Metrics {
pub fn register(registry: &Registry) -> Result<Self, PrometheusError> {
Ok(Self {
block_execution_time: register(
GaugeVec::new(
Opts::new(
"subcoin_block_execution_time_milliseconds",
"Time taken to execute a block in milliseconds",
),
&["block_height"],
)?,
registry,
)?,
block_transactions_count: register(
GaugeVec::new(
Opts::new(
"subcoin_block_transactions_count",
"Number of transactions in the block",
),
&["block_height"],
)?,
registry,
)?,
block_size: register(
GaugeVec::new(
Opts::new("subcoin_block_size", "Block size in bytes"),
&["block_height"],
)?,
registry,
)?,
})
}

pub fn report_block_execution(
&self,
block_height: u32,
transactions_count: usize,
block_size: usize,
execution_time: u128,
) {
let block_height = block_height.to_string();
self.block_transactions_count
.with_label_values(&[&block_height])
.set(transactions_count as u64);
self.block_size
.with_label_values(&[&block_height])
.set(block_size as u64);
self.block_execution_time
.with_label_values(&[&block_height])
.set(execution_time as u64);
}
}
1 change: 1 addition & 0 deletions crates/subcoin-network/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ sp-consensus = { workspace = true }
sp-core = { workspace = true }
sp-runtime = { workspace = true }
subcoin-primitives = { workspace = true }
substrate-prometheus-endpoint = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["full"] }
tracing = { workspace = true }
Expand Down
4 changes: 4 additions & 0 deletions crates/subcoin-network/src/address_book.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ impl AddressBook {
self.discovered_addresses.len() >= self.max_addresses
}

pub fn available_addresses_count(&self) -> usize {
self.discovered_addresses.len()
}

/// Pops a random address from the discovered addresses and marks it as active.
pub fn pop(&mut self) -> Option<PeerId> {
let maybe_peer = self.rng.choice(self.discovered_addresses.clone());
Expand Down
Loading

0 comments on commit 41535b4

Please sign in to comment.