diff --git a/Cargo.lock b/Cargo.lock index d387de2b25..8c402255fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9374,6 +9374,7 @@ dependencies = [ "jemallocator", "lazy_static 1.5.0", "log", + "metrics", "move-binary-format", "move-bytecode-utils", "move-core-types", @@ -9520,10 +9521,12 @@ dependencies = [ "clap 4.5.13", "coerce", "derive_builder 0.20.0", + "function_name", "futures", "itertools 0.13.0", "jsonrpsee 0.23.2", "log", + "metrics", "move-binary-format", "move-core-types", "move-resource-viewer", @@ -9533,6 +9536,7 @@ dependencies = [ "moveos-types", "moveos-verifier", "parking_lot 0.12.3", + "prometheus", "rooch-config", "rooch-framework", "rooch-genesis", @@ -9937,14 +9941,17 @@ dependencies = [ "clap 4.5.13", "coerce", "derive_builder 0.20.0", + "function_name", "futures", "jsonrpsee 0.23.2", "log", + "metrics", "move-core-types", "move-resource-viewer", "moveos", "moveos-store", "moveos-types", + "prometheus", "rooch-config", "rooch-da", "rooch-executor", @@ -9975,14 +9982,17 @@ dependencies = [ "clap 4.5.13", "coerce", "derive_builder 0.20.0", + "function_name", "futures", "jsonrpsee 0.23.2", "log", + "metrics", "move-core-types", "move-resource-viewer", "moveos", "moveos-store", "moveos-types", + "prometheus", "rooch-da", "rooch-types", "schemars", @@ -10012,15 +10022,18 @@ dependencies = [ "derive_builder 0.20.0", "ethers", "fastcrypto 0.1.8 (git+https://github.com/MystenLabs/fastcrypto?rev=56f6223b84ada922b6cb2c672c69db2ea3dc6a13)", + "function_name", "futures", "hex", "jsonrpsee 0.23.2", + "metrics", "move-core-types", "move-resource-viewer", "moveos", "moveos-store", "moveos-types", "parking_lot 0.12.3", + "prometheus", "rooch-config", "rooch-executor", "rooch-key", @@ -10194,6 +10207,7 @@ dependencies = [ "coerce", "derive_builder 0.20.0", "fastcrypto 0.1.8 (git+https://github.com/MystenLabs/fastcrypto?rev=56f6223b84ada922b6cb2c672c69db2ea3dc6a13)", + "function_name", "futures", "jsonrpsee 0.23.2", "log", diff --git a/crates/rooch-benchmarks/Cargo.toml b/crates/rooch-benchmarks/Cargo.toml index 9c7f012285..002c87c39d 100644 --- a/crates/rooch-benchmarks/Cargo.toml +++ b/crates/rooch-benchmarks/Cargo.toml @@ -70,6 +70,7 @@ move-bytecode-utils = { workspace = true } raw-store = { workspace = true } moveos-config = { workspace = true } smt = { workspace = true } +metrics = { workspace = true } rooch-config = { workspace = true } rooch-types = { workspace = true } diff --git a/crates/rooch-benchmarks/benches/bench_tx_sequence.rs b/crates/rooch-benchmarks/benches/bench_tx_sequence.rs index 3f09a0e684..35750a8fdd 100644 --- a/crates/rooch-benchmarks/benches/bench_tx_sequence.rs +++ b/crates/rooch-benchmarks/benches/bench_tx_sequence.rs @@ -17,8 +17,12 @@ pub fn tx_sequence_benchmark(c: &mut Criterion) { let rooch_key_pair = binding_test.sequencer_kp().copy(); let sequencer_keypair = rooch_key_pair.copy(); - let mut sequencer = - gen_sequencer(sequencer_keypair, binding_test.executor().get_rooch_store()).unwrap(); + let mut sequencer = gen_sequencer( + sequencer_keypair, + binding_test.executor().get_rooch_store(), + &binding_test.registry_service.default_registry(), + ) + .unwrap(); let tx_type = config.tx_type.unwrap().clone(); diff --git a/crates/rooch-benchmarks/src/tx.rs b/crates/rooch-benchmarks/src/tx.rs index 6d462b2ae7..455aaaa819 100644 --- a/crates/rooch-benchmarks/src/tx.rs +++ b/crates/rooch-benchmarks/src/tx.rs @@ -10,6 +10,7 @@ use bitcoin::hex::FromHex; use bitcoincore_rpc::RpcApi; use bitcoincore_rpc_json::bitcoin; use bitcoincore_rpc_json::bitcoin::Block; +use prometheus::Registry; use rooch_sequencer::actor::sequencer::SequencerActor; use rooch_store::RoochStore; use rooch_test_transaction_builder::TestTransactionBuilder; @@ -25,8 +26,17 @@ use tracing::info; pub const EXAMPLE_SIMPLE_BLOG_PACKAGE_NAME: &str = "simple_blog"; pub const EXAMPLE_SIMPLE_BLOG_NAMED_ADDRESS: &str = "simple_blog"; -pub fn gen_sequencer(keypair: RoochKeyPair, rooch_store: RoochStore) -> Result { - SequencerActor::new(keypair, rooch_store.clone(), ServiceStatus::Active) +pub fn gen_sequencer( + keypair: RoochKeyPair, + rooch_store: RoochStore, + registry: &Registry, +) -> Result { + SequencerActor::new( + keypair, + rooch_store.clone(), + ServiceStatus::Active, + registry, + ) } pub fn create_publish_transaction( diff --git a/crates/rooch-executor/Cargo.toml b/crates/rooch-executor/Cargo.toml index b42049ecf4..c53e79af2a 100644 --- a/crates/rooch-executor/Cargo.toml +++ b/crates/rooch-executor/Cargo.toml @@ -34,6 +34,8 @@ serde_with = { workspace = true } log = { workspace = true } itertools = { workspace = true } parking_lot = { workspace = true } +prometheus = { workspace = true } +function_name = { workspace = true } move-core-types = { workspace = true } move-resource-viewer = { workspace = true } @@ -44,6 +46,7 @@ moveos-store = { workspace = true } moveos-types = { workspace = true } moveos-common = { workspace = true } moveos-verifier = { workspace = true } +metrics = { workspace = true } rooch-types = { workspace = true } rooch-framework = { workspace = true } diff --git a/crates/rooch-executor/src/actor/executor.rs b/crates/rooch-executor/src/actor/executor.rs index 32f8049e1c..1163b1fa15 100644 --- a/crates/rooch-executor/src/actor/executor.rs +++ b/crates/rooch-executor/src/actor/executor.rs @@ -5,9 +5,11 @@ use super::messages::{ ExecuteTransactionMessage, ExecuteTransactionResult, GetRootMessage, ValidateL1BlockMessage, ValidateL1TxMessage, ValidateL2TxMessage, }; +use crate::metrics::ExecutorMetrics; use anyhow::Result; use async_trait::async_trait; use coerce::actor::{context::ActorContext, message::Handler, Actor}; +use function_name::named; use move_core_types::vm_status::VMStatus; use moveos::moveos::{MoveOS, MoveOSConfig}; use moveos::vm::vm_status_explainer::explain_vm_status; @@ -20,6 +22,7 @@ use moveos_types::state::ObjectState; use moveos_types::state_resolver::RootObjectResolver; use moveos_types::transaction::VerifiedMoveOSTransaction; use moveos_types::transaction::{FunctionCall, MoveOSTransaction, VerifiedMoveAction}; +use prometheus::Registry; use rooch_genesis::FrameworksGasParameters; use rooch_store::RoochStore; use rooch_types::bitcoin::BitcoinModule; @@ -31,6 +34,7 @@ use rooch_types::multichain_id::RoochMultiChainID; use rooch_types::transaction::{ AuthenticatorInfo, L1Block, L1BlockWithBody, L1Transaction, RoochTransaction, }; +use std::sync::Arc; use tracing::{debug, warn}; pub struct ExecutorActor { @@ -38,6 +42,7 @@ pub struct ExecutorActor { moveos: MoveOS, moveos_store: MoveOSStore, rooch_store: RoochStore, + metrics: Arc, } type ValidateAuthenticatorResult = Result; @@ -47,6 +52,7 @@ impl ExecutorActor { root: ObjectMeta, moveos_store: MoveOSStore, rooch_store: RoochStore, + registry: &Registry, ) -> Result { let resolver = RootObjectResolver::new(root.clone(), &moveos_store); let gas_parameters = FrameworksGasParameters::load_from_chain(&resolver)?; @@ -64,6 +70,7 @@ impl ExecutorActor { moveos, moveos_store, rooch_store, + metrics: Arc::new(ExecutorMetrics::new(registry)), }) } @@ -79,24 +86,43 @@ impl ExecutorActor { &self.moveos } + #[named] pub fn execute(&mut self, tx: VerifiedMoveOSTransaction) -> Result { + let fn_name = function_name!(); + let _timer = self + .metrics + .executor_execute_tx_latency_seconds + .with_label_values(&[fn_name]) + .start_timer(); let tx_hash = tx.ctx.tx_hash(); + let size = tx.ctx.tx_size; let output = self.moveos.execute_and_apply(tx)?; let execution_info = self .moveos_store .handle_tx_output(tx_hash, output.clone())?; self.root = execution_info.root_metadata(); + self.metrics + .executor_execute_tx_bytes + .with_label_values(&[fn_name]) + .observe(size as f64); Ok(ExecuteTransactionResult { output, transaction_info: execution_info, }) } + #[named] pub fn validate_l1_block( &self, l1_block: L1BlockWithBody, ) -> Result { + let fn_name = function_name!(); + let _timer = self + .metrics + .executor_validate_tx_latency_seconds + .with_label_values(&[fn_name]) + .start_timer(); let tx_hash = l1_block.block.tx_hash(); let tx_size = l1_block.block.tx_size(); let ctx = TxContext::new_system_call_ctx(tx_hash, tx_size); @@ -111,7 +137,7 @@ impl ExecutorActor { }, block_body, } = l1_block; - match RoochMultiChainID::try_from(chain_id.id())? { + let result = match RoochMultiChainID::try_from(chain_id.id())? { RoochMultiChainID::Bitcoin => { let action = VerifiedMoveAction::Function { call: BitcoinModule::create_execute_l1_block_call_bytes( @@ -139,15 +165,28 @@ impl ExecutorActor { )) } id => Err(anyhow::anyhow!("Chain {} not supported yet", id)), - } + }; + + self.metrics + .executor_validate_tx_bytes + .with_label_values(&[fn_name]) + .observe(tx_size as f64); + result } + #[named] pub fn validate_l1_tx(&self, l1_tx: L1Transaction) -> Result { + let fn_name = function_name!(); + let _timer = self + .metrics + .executor_validate_tx_latency_seconds + .with_label_values(&[fn_name]) + .start_timer(); let tx_hash = l1_tx.tx_hash(); let tx_size = l1_tx.tx_size(); let ctx = TxContext::new_system_call_ctx(tx_hash, tx_size); //TODO we should call the contract to validate the l1 tx has been executed - match RoochMultiChainID::try_from(l1_tx.chain_id.id())? { + let result = match RoochMultiChainID::try_from(l1_tx.chain_id.id())? { RoochMultiChainID::Bitcoin => { let action = VerifiedMoveAction::Function { call: BitcoinModule::create_execute_l1_tx_call(l1_tx.block_hash, l1_tx.txid)?, @@ -160,20 +199,32 @@ impl ExecutorActor { )) } id => Err(anyhow::anyhow!("Chain {} not supported yet", id)), - } + }; + + self.metrics + .executor_validate_tx_bytes + .with_label_values(&[fn_name]) + .observe(tx_size as f64); + result } + #[named] pub fn validate_l2_tx(&self, mut tx: RoochTransaction) -> Result { + let fn_name = function_name!(); + let _timer = self + .metrics + .executor_validate_tx_latency_seconds + .with_label_values(&[fn_name]) + .start_timer(); let sender = tx.sender(); let tx_hash = tx.tx_hash(); - debug!("executor validate_l2_tx: {:?}, sender: {}", tx_hash, sender); let authenticator = tx.authenticator_info(); - let mut moveos_tx: MoveOSTransaction = tx.into_moveos_transaction(self.root.clone()); - let result = self.validate_authenticator(&moveos_tx.ctx, authenticator); - match result { + let tx_size = moveos_tx.ctx.tx_size; + let tx_result = self.validate_authenticator(&moveos_tx.ctx, authenticator); + let result = match tx_result { Ok(vm_result) => match vm_result { Ok(tx_validate_result) => { // Add the tx_validate_result to the context @@ -214,14 +265,27 @@ impl ExecutorActor { ); Err(e) } - } + }; + + self.metrics + .executor_validate_tx_bytes + .with_label_values(&[fn_name]) + .observe(tx_size as f64); + result } + #[named] pub fn validate_authenticator( &self, ctx: &TxContext, authenticator: AuthenticatorInfo, ) -> Result { + let fn_name = function_name!(); + let _timer = self + .metrics + .executor_validate_tx_latency_seconds + .with_label_values(&[fn_name]) + .start_timer(); let tx_validator = self.as_module_binding::(); let tx_validate_function_result = tx_validator .validate(ctx, authenticator.clone())? @@ -246,6 +310,7 @@ impl ExecutorActor { } Err(vm_status) => Err(vm_status), }; + Ok(vm_result) } } diff --git a/crates/rooch-executor/src/lib.rs b/crates/rooch-executor/src/lib.rs index c6dbf6b1fd..cb395b0f66 100644 --- a/crates/rooch-executor/src/lib.rs +++ b/crates/rooch-executor/src/lib.rs @@ -2,4 +2,5 @@ // SPDX-License-Identifier: Apache-2.0 pub mod actor; +pub mod metrics; pub mod proxy; diff --git a/crates/rooch-executor/src/metrics.rs b/crates/rooch-executor/src/metrics.rs new file mode 100644 index 0000000000..c96d8ead6f --- /dev/null +++ b/crates/rooch-executor/src/metrics.rs @@ -0,0 +1,56 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +use metrics::metrics_util::LATENCY_SEC_BUCKETS; +use prometheus::{register_histogram_vec_with_registry, HistogramVec, Registry}; + +#[derive(Debug)] +pub struct ExecutorMetrics { + pub executor_execute_tx_latency_seconds: HistogramVec, + pub executor_execute_tx_bytes: HistogramVec, + pub executor_validate_tx_latency_seconds: HistogramVec, + pub executor_validate_tx_bytes: HistogramVec, +} + +impl ExecutorMetrics { + pub(crate) fn new(registry: &Registry) -> Self { + ExecutorMetrics { + executor_execute_tx_latency_seconds: register_histogram_vec_with_registry!( + "executor_execute_tx_latency_seconds", + "Executor execute tx latency in seconds", + &["fn_name"], + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + executor_execute_tx_bytes: register_histogram_vec_with_registry!( + "executor_execute_tx_bytes", + "Executor execute tx size in bytes", + &["fn_name"], + prometheus::exponential_buckets(1.0, 4.0, 15) + .unwrap() + .to_vec(), + registry, + ) + .unwrap(), + executor_validate_tx_latency_seconds: register_histogram_vec_with_registry!( + "executor_validate_tx_latency_seconds", + "Executor validate tx latency in seconds", + &["fn_name"], + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + executor_validate_tx_bytes: register_histogram_vec_with_registry!( + "executor_validate_tx_bytes", + "Executor validate tx size in bytes", + &["fn_name"], + prometheus::exponential_buckets(1.0, 4.0, 15) + .unwrap() + .to_vec(), + registry, + ) + .unwrap(), + } + } +} diff --git a/crates/rooch-framework-tests/src/binding_test.rs b/crates/rooch-framework-tests/src/binding_test.rs index d4e70acb82..eb8ceeb774 100644 --- a/crates/rooch-framework-tests/src/binding_test.rs +++ b/crates/rooch-framework-tests/src/binding_test.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use anyhow::{bail, Result}; +use metrics::RegistryService; use move_core_types::account_address::AccountAddress; use move_core_types::vm_status::KeptVMStatus; use moveos_config::DataDirPath; @@ -48,6 +49,7 @@ pub struct RustBindingTest { pub reader_executor: ReaderExecutorActor, root: ObjectMeta, rooch_db: RoochDB, + pub registry_service: RegistryService, } impl RustBindingTest { @@ -71,6 +73,7 @@ impl RustBindingTest { root.clone(), rooch_db.moveos_store.clone(), rooch_db.rooch_store.clone(), + ®istry_service.default_registry(), )?; let reader_executor = ReaderExecutorActor::new( @@ -87,6 +90,7 @@ impl RustBindingTest { executor, reader_executor, rooch_db, + registry_service, }) } diff --git a/crates/rooch-pipeline-processor/Cargo.toml b/crates/rooch-pipeline-processor/Cargo.toml index 692a7215c8..d5d8c7f00c 100644 --- a/crates/rooch-pipeline-processor/Cargo.toml +++ b/crates/rooch-pipeline-processor/Cargo.toml @@ -32,6 +32,8 @@ tokio = { features = ["full"], workspace = true } tonic = { workspace = true } tracing = { workspace = true } tracing-subscriber = { workspace = true } +prometheus = { workspace = true } +function_name = { workspace = true } move-core-types = { workspace = true } move-resource-viewer = { workspace = true } @@ -39,6 +41,7 @@ move-resource-viewer = { workspace = true } moveos = { workspace = true } moveos-store = { workspace = true } moveos-types = { workspace = true } +metrics = { workspace = true } rooch-types = { workspace = true } rooch-da = { workspace = true } diff --git a/crates/rooch-pipeline-processor/src/actor/processor.rs b/crates/rooch-pipeline-processor/src/actor/processor.rs index 7351e4ab24..a982cfe263 100644 --- a/crates/rooch-pipeline-processor/src/actor/processor.rs +++ b/crates/rooch-pipeline-processor/src/actor/processor.rs @@ -2,10 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 use super::messages::{ExecuteL1BlockMessage, ExecuteL1TxMessage, ExecuteL2TxMessage}; +use crate::metrics::PipelineProcessorMetrics; use anyhow::Result; use async_trait::async_trait; use coerce::actor::{context::ActorContext, message::Handler, Actor}; +use function_name::named; use moveos_types::transaction::VerifiedMoveOSTransaction; +use prometheus::Registry; use rooch_executor::proxy::ExecutorProxy; use rooch_indexer::proxy::IndexerProxy; use rooch_proposer::proxy::ProposerProxy; @@ -18,6 +21,7 @@ use rooch_types::{ LedgerTxData, RoochTransaction, }, }; +use std::sync::Arc; use tracing::{debug, info}; /// PipelineProcessor aggregates the executor, sequencer, proposer, and indexer to process transactions. @@ -27,6 +31,7 @@ pub struct PipelineProcessorActor { pub(crate) proposer: ProposerProxy, pub(crate) indexer: IndexerProxy, pub(crate) service_status: ServiceStatus, + pub(crate) metrics: Arc, } impl PipelineProcessorActor { @@ -36,6 +41,7 @@ impl PipelineProcessorActor { proposer: ProposerProxy, indexer: IndexerProxy, service_status: ServiceStatus, + registry: &Registry, ) -> Self { Self { executor, @@ -43,6 +49,7 @@ impl PipelineProcessorActor { proposer, indexer, service_status, + metrics: Arc::new(PipelineProcessorMetrics::new(registry)), } } @@ -108,48 +115,110 @@ impl PipelineProcessorActor { Ok(()) } + #[named] pub async fn execute_l1_block( &mut self, l1_block: L1BlockWithBody, ) -> Result { + let fn_name = function_name!(); + let _timer = self + .metrics + .pipeline_processor_execution_tx_latency_seconds + .with_label_values(&[fn_name]) + .start_timer(); let moveos_tx = self.executor.validate_l1_block(l1_block.clone()).await?; let ledger_tx = self .sequencer .sequence_transaction(LedgerTxData::L1Block(l1_block.block)) .await?; - self.execute_tx(ledger_tx, moveos_tx).await + let size = moveos_tx.ctx.tx_size; + let result = self.execute_tx(ledger_tx, moveos_tx).await?; + + let gas_used = result.output.gas_used; + self.metrics + .pipeline_processor_l1_block_gas_used + .inc_by(gas_used); + self.metrics + .pipeline_processor_execution_tx_bytes + .with_label_values(&[fn_name]) + .observe(size as f64); + Ok(result) } + #[named] pub async fn execute_l1_tx( &mut self, l1_tx: L1Transaction, ) -> Result { + let fn_name = function_name!(); + let _timer = self + .metrics + .pipeline_processor_execution_tx_latency_seconds + .with_label_values(&[fn_name]) + .start_timer(); let moveos_tx = self.executor.validate_l1_tx(l1_tx.clone()).await?; let ledger_tx = self .sequencer .sequence_transaction(LedgerTxData::L1Tx(l1_tx)) .await?; - self.execute_tx(ledger_tx, moveos_tx).await + let size = moveos_tx.ctx.tx_size; + let result = self.execute_tx(ledger_tx, moveos_tx).await?; + + let gas_used = result.output.gas_used; + self.metrics + .pipeline_processor_l1_tx_gas_used + .inc_by(gas_used); + self.metrics + .pipeline_processor_execution_tx_bytes + .with_label_values(&[fn_name]) + .observe(size as f64); + Ok(result) } + #[named] pub async fn execute_l2_tx( &mut self, mut tx: RoochTransaction, ) -> Result { debug!("pipeline execute_l2_tx: {:?}", tx.tx_hash()); + let fn_name = function_name!(); + let _timer = self + .metrics + .pipeline_processor_execution_tx_latency_seconds + .with_label_values(&[fn_name]) + .start_timer(); let moveos_tx = self.executor.validate_l2_tx(tx.clone()).await?; let ledger_tx = self .sequencer .sequence_transaction(LedgerTxData::L2Tx(tx)) .await?; - self.execute_tx(ledger_tx, moveos_tx).await + let size = moveos_tx.ctx.tx_size; + let result = self.execute_tx(ledger_tx, moveos_tx).await?; + + let gas_used = result.output.gas_used; + self.metrics + .pipeline_processor_l2_tx_gas_used + .inc_by(gas_used); + self.metrics + .pipeline_processor_execution_tx_bytes + .with_label_values(&[fn_name]) + .observe(size as f64); + + Ok(result) } + #[named] pub async fn execute_tx( &mut self, tx: LedgerTransaction, mut moveos_tx: VerifiedMoveOSTransaction, ) -> Result { + let fn_name = function_name!(); + let _timer = self + .metrics + .pipeline_processor_execution_tx_latency_seconds + .with_label_values(&[fn_name]) + .start_timer(); // Add sequence info to tx context, let the Move contract can get the sequence info moveos_tx.ctx.add(tx.sequence_info.clone())?; // We must add TransactionSequenceInfo and TransactionSequenceInfoV1 both to the tx_context because the rust code is upgraded first, then the framework is upgraded. @@ -158,6 +227,7 @@ impl PipelineProcessorActor { moveos_tx.ctx.add(tx_sequence_info_v1)?; // Then execute + let size = moveos_tx.ctx.tx_size; let (output, execution_info) = self.executor.execute_transaction(moveos_tx.clone()).await?; self.proposer .propose_transaction(tx.clone(), execution_info.clone()) @@ -191,6 +261,11 @@ impl PipelineProcessorActor { }; }; + self.metrics + .pipeline_processor_execution_tx_bytes + .with_label_values(&[fn_name]) + .observe(size as f64); + Ok(ExecuteTransactionResponse { sequence_info, execution_info, diff --git a/crates/rooch-pipeline-processor/src/lib.rs b/crates/rooch-pipeline-processor/src/lib.rs index c6dbf6b1fd..cb395b0f66 100644 --- a/crates/rooch-pipeline-processor/src/lib.rs +++ b/crates/rooch-pipeline-processor/src/lib.rs @@ -2,4 +2,5 @@ // SPDX-License-Identifier: Apache-2.0 pub mod actor; +pub mod metrics; pub mod proxy; diff --git a/crates/rooch-pipeline-processor/src/metrics.rs b/crates/rooch-pipeline-processor/src/metrics.rs new file mode 100644 index 0000000000..c663f8aae8 --- /dev/null +++ b/crates/rooch-pipeline-processor/src/metrics.rs @@ -0,0 +1,60 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +use metrics::metrics_util::LATENCY_SEC_BUCKETS; +use prometheus::{ + register_histogram_vec_with_registry, register_int_counter_with_registry, HistogramVec, + IntCounter, Registry, +}; + +#[derive(Debug)] +pub struct PipelineProcessorMetrics { + pub pipeline_processor_execution_tx_latency_seconds: HistogramVec, + pub pipeline_processor_execution_tx_bytes: HistogramVec, + pub pipeline_processor_l1_block_gas_used: IntCounter, + pub pipeline_processor_l1_tx_gas_used: IntCounter, + pub pipeline_processor_l2_tx_gas_used: IntCounter, +} + +impl PipelineProcessorMetrics { + pub(crate) fn new(registry: &Registry) -> Self { + PipelineProcessorMetrics { + pipeline_processor_execution_tx_latency_seconds: register_histogram_vec_with_registry!( + "pipeline_processor_execution_tx_latency_seconds", + "Pipeline processor execution tx latency in seconds", + &["fn_name"], + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + pipeline_processor_execution_tx_bytes: register_histogram_vec_with_registry!( + "pipeline_processor_execution_tx_bytes", + "Pipeline processor execution tx size in bytes", + &["fn_name"], + prometheus::exponential_buckets(1.0, 4.0, 15) + .unwrap() + .to_vec(), + registry, + ) + .unwrap(), + pipeline_processor_l1_block_gas_used: register_int_counter_with_registry!( + "pipeline_processor_l1_block_gas_used", + "Pipeline processor L1 block gas used total", + registry, + ) + .unwrap(), + pipeline_processor_l1_tx_gas_used: register_int_counter_with_registry!( + "pipeline_processor_l1_tx_gas_used", + "Pipeline processor L1 tx gas used total", + registry, + ) + .unwrap(), + pipeline_processor_l2_tx_gas_used: register_int_counter_with_registry!( + "pipeline_processor_l2_tx_gas_used", + "Pipeline processor L2 tx gas used total", + registry, + ) + .unwrap(), + } + } +} diff --git a/crates/rooch-proposer/Cargo.toml b/crates/rooch-proposer/Cargo.toml index 10f5dbd524..5ab67c1276 100644 --- a/crates/rooch-proposer/Cargo.toml +++ b/crates/rooch-proposer/Cargo.toml @@ -32,6 +32,8 @@ tokio = { features = ["full"], workspace = true } tonic = { workspace = true } tracing = { workspace = true } tracing-subscriber = { workspace = true } +prometheus = { workspace = true } +function_name = { workspace = true } move-core-types = { workspace = true } move-resource-viewer = { workspace = true } @@ -39,6 +41,7 @@ move-resource-viewer = { workspace = true } moveos = { workspace = true } moveos-store = { workspace = true } moveos-types = { workspace = true } +metrics = { workspace = true } rooch-types = { workspace = true } rooch-da = { workspace = true } \ No newline at end of file diff --git a/crates/rooch-proposer/src/actor/proposer.rs b/crates/rooch-proposer/src/actor/proposer.rs index 2d205e2a53..7128308d2c 100644 --- a/crates/rooch-proposer/src/actor/proposer.rs +++ b/crates/rooch-proposer/src/actor/proposer.rs @@ -4,7 +4,10 @@ use anyhow::Result; use async_trait::async_trait; use coerce::actor::{context::ActorContext, message::Handler, Actor}; +use prometheus::Registry; +use std::sync::Arc; +use crate::metrics::ProposerMetrics; use rooch_da::proxy::DAProxy; use rooch_types::crypto::RoochKeyPair; @@ -12,16 +15,21 @@ use crate::scc::StateCommitmentChain; use super::messages::{ProposeBlock, TransactionProposeMessage, TransactionProposeResult}; +const TRANSACTION_PROPOSE_FN_NAME: &str = "transaction_propose"; +const PROPOSE_BLOCK_FN_NAME: &str = "propose_block"; + pub struct ProposerActor { proposer_key: RoochKeyPair, scc: StateCommitmentChain, + metrics: Arc, } impl ProposerActor { - pub fn new(proposer_key: RoochKeyPair, da_proxy: DAProxy) -> Self { + pub fn new(proposer_key: RoochKeyPair, da_proxy: DAProxy, registry: &Registry) -> Self { Self { proposer_key, scc: StateCommitmentChain::new(da_proxy), + metrics: Arc::new(ProposerMetrics::new(registry)), } } } @@ -35,6 +43,12 @@ impl Handler for ProposerActor { msg: TransactionProposeMessage, _ctx: &mut ActorContext, ) -> Result { + let fn_name = TRANSACTION_PROPOSE_FN_NAME; + let _timer = self + .metrics + .proposer_transaction_propose_latency_seconds + .with_label_values(&[fn_name]) + .start_timer(); self.scc.append_transaction(msg); Ok(TransactionProposeResult {}) } @@ -43,6 +57,12 @@ impl Handler for ProposerActor { #[async_trait] impl Handler for ProposerActor { async fn handle(&mut self, _message: ProposeBlock, _ctx: &mut ActorContext) { + let fn_name = PROPOSE_BLOCK_FN_NAME; + let _timer = self + .metrics + .proposer_propose_block_latency_seconds + .with_label_values(&[fn_name]) + .start_timer(); let block = self.scc.propose_block().await; match block { Some(block) => { @@ -58,5 +78,9 @@ impl Handler for ProposerActor { }; //TODO submit to the on-chain SCC contract use the proposer key let _proposer_key = &self.proposer_key; + let batch_size = block.map(|v| v.batch_size).unwrap_or(0u64); + self.metrics + .proposer_propose_block_batch_size + .set(batch_size as i64); } } diff --git a/crates/rooch-proposer/src/lib.rs b/crates/rooch-proposer/src/lib.rs index a81778bbf0..ba6dbb3615 100644 --- a/crates/rooch-proposer/src/lib.rs +++ b/crates/rooch-proposer/src/lib.rs @@ -2,5 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 pub mod actor; +pub mod metrics; pub mod proxy; pub mod scc; diff --git a/crates/rooch-proposer/src/metrics.rs b/crates/rooch-proposer/src/metrics.rs new file mode 100644 index 0000000000..15442e3354 --- /dev/null +++ b/crates/rooch-proposer/src/metrics.rs @@ -0,0 +1,55 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +use metrics::metrics_util::LATENCY_SEC_BUCKETS; +use prometheus::{ + register_histogram_vec_with_registry, register_int_gauge_with_registry, HistogramVec, IntGauge, + Registry, +}; + +#[derive(Debug)] +pub struct ProposerMetrics { + pub proposer_transaction_propose_latency_seconds: HistogramVec, + pub proposer_transaction_propose_bytes: HistogramVec, + pub proposer_propose_block_latency_seconds: HistogramVec, + pub proposer_propose_block_batch_size: IntGauge, +} + +impl ProposerMetrics { + pub(crate) fn new(registry: &Registry) -> Self { + ProposerMetrics { + proposer_transaction_propose_latency_seconds: register_histogram_vec_with_registry!( + "proposer_transaction_propose_latency_seconds", + "Proposer transaction propose latency in seconds", + &["fn_name"], + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + proposer_transaction_propose_bytes: register_histogram_vec_with_registry!( + "proposer_transaction_propose_bytes", + "Proposer transaction propose size in bytes", + &["fn_name"], + prometheus::exponential_buckets(1.0, 4.0, 15) + .unwrap() + .to_vec(), + registry, + ) + .unwrap(), + proposer_propose_block_latency_seconds: register_histogram_vec_with_registry!( + "proposer_propose_block_latency_seconds", + "Proposer propose block latency in seconds", + &["fn_name"], + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + proposer_propose_block_batch_size: register_int_gauge_with_registry!( + "proposer_propose_block_batch_size", + "Proposer propose block contains how many transactions", + registry, + ) + .unwrap(), + } + } +} diff --git a/crates/rooch-relayer/Cargo.toml b/crates/rooch-relayer/Cargo.toml index 2f7df85252..1b97d00226 100644 --- a/crates/rooch-relayer/Cargo.toml +++ b/crates/rooch-relayer/Cargo.toml @@ -37,6 +37,8 @@ parking_lot = { workspace = true } bitcoin = { workspace = true } bitcoincore-rpc = { workspace = true } hex = { workspace = true } +prometheus = { workspace = true } +function_name = { workspace = true } move-core-types = { workspace = true } move-resource-viewer = { workspace = true } @@ -44,6 +46,7 @@ move-resource-viewer = { workspace = true } moveos = { workspace = true } moveos-store = { workspace = true } moveos-types = { workspace = true } +metrics = { workspace = true } rooch-types = { workspace = true } rooch-key = { workspace = true } diff --git a/crates/rooch-relayer/src/metrics.rs b/crates/rooch-relayer/src/metrics.rs new file mode 100644 index 0000000000..9ed041cf38 --- /dev/null +++ b/crates/rooch-relayer/src/metrics.rs @@ -0,0 +1,36 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +use metrics::metrics_util::LATENCY_SEC_BUCKETS; +use prometheus::{register_histogram_vec_with_registry, HistogramVec, Registry}; + +#[derive(Debug)] +pub struct TxMetrics { + pub tx_execution_latency_seconds: HistogramVec, + pub tx_execution_bytes: HistogramVec, +} + +impl TxMetrics { + pub(crate) fn new(registry: &Registry) -> Self { + TxMetrics { + tx_execution_latency_seconds: register_histogram_vec_with_registry!( + "tx_execution_latency_seconds", + "Tx execution latency in seconds", + &["fn_name"], + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + tx_execution_bytes: register_histogram_vec_with_registry!( + "tx_execution_bytes", + "Tx execution size in bytes", + &["fn_name"], + prometheus::exponential_buckets(1.0, 4.0, 15) + .unwrap() + .to_vec(), + registry, + ) + .unwrap(), + } + } +} diff --git a/crates/rooch-rpc-server/src/lib.rs b/crates/rooch-rpc-server/src/lib.rs index 665ca8dcc2..978ceb19c6 100644 --- a/crates/rooch-rpc-server/src/lib.rs +++ b/crates/rooch-rpc-server/src/lib.rs @@ -234,8 +234,12 @@ pub async fn run_start_server(opt: RoochOpt, server_opt: ServerOpt) -> Result Result Result Result, } impl SequencerActor { @@ -34,6 +39,7 @@ impl SequencerActor { sequencer_key: RoochKeyPair, rooch_store: RoochStore, service_status: ServiceStatus, + registry: &Registry, ) -> Result { // The sequencer info would be inited when genesis, so the sequencer info should not be None let last_sequencer_info = rooch_store @@ -60,6 +66,7 @@ impl SequencerActor { sequencer_key, rooch_store, service_status, + metrics: Arc::new(SequencerMetrics::new(registry)), }) } @@ -67,7 +74,15 @@ impl SequencerActor { self.last_sequencer_info.last_order } + #[named] pub fn sequence(&mut self, mut tx_data: LedgerTxData) -> Result { + let fn_name = function_name!(); + let _timer = self + .metrics + .sequencer_sequence_latency_seconds + .with_label_values(&[fn_name]) + .start_timer(); + match self.service_status { ServiceStatus::ReadOnlyMode => { return Err(anyhow::anyhow!("The service is in read-only mode")); @@ -124,6 +139,7 @@ impl SequencerActor { self.rooch_store.save_transaction(tx.clone())?; info!("sequencer tx: {} order: {:?}", hash, tx_order); self.last_sequencer_info = sequencer_info; + Ok(tx) } } diff --git a/crates/rooch-sequencer/src/lib.rs b/crates/rooch-sequencer/src/lib.rs index f674d48877..5081bba9e4 100644 --- a/crates/rooch-sequencer/src/lib.rs +++ b/crates/rooch-sequencer/src/lib.rs @@ -3,4 +3,5 @@ pub mod actor; pub mod messages; +pub mod metrics; pub mod proxy; diff --git a/crates/rooch-sequencer/src/metrics.rs b/crates/rooch-sequencer/src/metrics.rs new file mode 100644 index 0000000000..33cae5be48 --- /dev/null +++ b/crates/rooch-sequencer/src/metrics.rs @@ -0,0 +1,36 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +use metrics::metrics_util::LATENCY_SEC_BUCKETS; +use prometheus::{register_histogram_vec_with_registry, HistogramVec, Registry}; + +#[derive(Debug)] +pub struct SequencerMetrics { + pub sequencer_sequence_latency_seconds: HistogramVec, + pub sequencer_sequence_bytes: HistogramVec, +} + +impl SequencerMetrics { + pub(crate) fn new(registry: &Registry) -> Self { + SequencerMetrics { + sequencer_sequence_latency_seconds: register_histogram_vec_with_registry!( + "sequencer_sequence_latency_seconds", + "Sequencer sequence latency in seconds", + &["fn_name"], + LATENCY_SEC_BUCKETS.to_vec(), + registry, + ) + .unwrap(), + sequencer_sequence_bytes: register_histogram_vec_with_registry!( + "sequencer_sequence_bytes", + "Sequencer sequence size in bytes", + &["fn_name"], + prometheus::exponential_buckets(1.0, 4.0, 15) + .unwrap() + .to_vec(), + registry, + ) + .unwrap(), + } + } +} diff --git a/crates/rooch-sequencer/tests/test_sequencer.rs b/crates/rooch-sequencer/tests/test_sequencer.rs index 798d442372..e8ed76e90a 100644 --- a/crates/rooch-sequencer/tests/test_sequencer.rs +++ b/crates/rooch-sequencer/tests/test_sequencer.rs @@ -32,8 +32,12 @@ async fn test_sequencer() -> Result<()> { { let rooch_db = init_rooch_db(&opt, ®istry_service.default_registry())?; let sequencer_key = RoochKeyPair::generate_secp256k1(); - let mut sequencer = - SequencerActor::new(sequencer_key, rooch_db.rooch_store, ServiceStatus::Active)?; + let mut sequencer = SequencerActor::new( + sequencer_key, + rooch_db.rooch_store, + ServiceStatus::Active, + ®istry_service.default_registry(), + )?; assert_eq!(sequencer.last_order(), last_tx_order); for _ in 0..10 { let tx_data = LedgerTxData::L2Tx(RoochTransaction::mock()); @@ -49,8 +53,12 @@ async fn test_sequencer() -> Result<()> { let new_registry = prometheus::Registry::new(); let rooch_db = RoochDB::init(opt.store_config(), &new_registry)?; let sequencer_key = RoochKeyPair::generate_secp256k1(); - let mut sequencer = - SequencerActor::new(sequencer_key, rooch_db.rooch_store, ServiceStatus::Active)?; + let mut sequencer = SequencerActor::new( + sequencer_key, + rooch_db.rooch_store, + ServiceStatus::Active, + &new_registry, + )?; assert_eq!(sequencer.last_order(), last_tx_order); let tx_data = LedgerTxData::L2Tx(RoochTransaction::mock()); let ledger_tx = sequencer.sequence(tx_data)?; @@ -70,10 +78,14 @@ async fn test_sequencer_concurrent() -> Result<()> { let actor_system = ActorSystem::global_system(); - let sequencer = - SequencerActor::new(sequencer_key, rooch_db.rooch_store, ServiceStatus::Active)? - .into_actor(Some("Sequencer"), &actor_system) - .await?; + let sequencer = SequencerActor::new( + sequencer_key, + rooch_db.rooch_store, + ServiceStatus::Active, + ®istry_service.default_registry(), + )? + .into_actor(Some("Sequencer"), &actor_system) + .await?; let sequencer_proxy = SequencerProxy::new(sequencer.into()); // start n thread to sequence