Skip to content

Commit 2b6b550

Browse files
authored
Add Metric for Proposal Latency (#3360)
* add timestamp() to BlockHeader trait * add latency metric * fix timestamp issue in tests * hoist time and lock out of loop * use helper for timestamp
1 parent eef3c60 commit 2b6b550

File tree

20 files changed

+122
-76
lines changed

20 files changed

+122
-76
lines changed

crates/hotshot/example-types/src/block_types.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,10 @@ impl<
396396
self.payload_commitment.as_ref(),
397397
)
398398
}
399+
400+
fn timestamp(&self) -> u64 {
401+
self.timestamp
402+
}
399403
}
400404

401405
impl Committable for TestBlockHeader {

crates/hotshot/task-impls/src/helpers.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ use hotshot_types::{
4444
vote::{Certificate, HasViewNumber},
4545
};
4646
use hotshot_utils::anytrace::*;
47+
use time::OffsetDateTime;
4748
use tokio::time::timeout;
4849
use tracing::instrument;
4950
use vbs::version::StaticVersionType;
@@ -316,6 +317,27 @@ impl<TYPES: NodeType + Default> Default for LeafChainTraversalOutcome<TYPES> {
316317
}
317318
}
318319

320+
async fn update_metrics<TYPES: NodeType>(
321+
consensus: &OuterConsensus<TYPES>,
322+
leaf_views: &[LeafInfo<TYPES>],
323+
) {
324+
let consensus_reader = consensus.read().await;
325+
let now = OffsetDateTime::now_utc().unix_timestamp() as u64;
326+
327+
for leaf_view in leaf_views {
328+
let proposal_timestamp = leaf_view.leaf.block_header().timestamp();
329+
330+
let Some(proposal_to_decide_time) = now.checked_sub(proposal_timestamp) else {
331+
tracing::error!("Failed to calculate proposal to decide time: {proposal_timestamp}");
332+
continue;
333+
};
334+
consensus_reader
335+
.metrics
336+
.proposal_to_decide_time
337+
.add_point(proposal_to_decide_time as f64);
338+
}
339+
}
340+
319341
/// calculate the new decided leaf chain based on the rules of HotStuff 2
320342
///
321343
/// # Panics
@@ -426,6 +448,7 @@ pub async fn decide_from_proposal_2<TYPES: NodeType, I: NodeImplementation<TYPES
426448
)
427449
.await;
428450
}
451+
update_metrics(&consensus, &res.leaf_views).await;
429452
}
430453

431454
res

crates/hotshot/types/src/consensus.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,12 @@ pub struct ConsensusMetricsValue {
394394
pub number_of_empty_blocks_proposed: Box<dyn Counter>,
395395
/// Number of events in the hotshot event queue
396396
pub internal_event_queue_len: Box<dyn Gauge>,
397+
/// Time from proposal creation to decide time
398+
pub proposal_to_decide_time: Box<dyn Histogram>,
399+
/// Time from proposal received to proposal creation
400+
pub previous_proposal_to_proposal_time: Box<dyn Histogram>,
401+
/// Finalized bytes per view
402+
pub finalized_bytes: Box<dyn Histogram>,
397403
}
398404

399405
impl ConsensusMetricsValue {
@@ -425,6 +431,11 @@ impl ConsensusMetricsValue {
425431
.create_counter(String::from("number_of_empty_blocks_proposed"), None),
426432
internal_event_queue_len: metrics
427433
.create_gauge(String::from("internal_event_queue_len"), None),
434+
proposal_to_decide_time: metrics
435+
.create_histogram(String::from("proposal_to_decide_time"), None),
436+
previous_proposal_to_proposal_time: metrics
437+
.create_histogram(String::from("previous_proposal_to_proposal_time"), None),
438+
finalized_bytes: metrics.create_histogram(String::from("finalized_bytes"), None),
428439
}
429440
}
430441
}

crates/hotshot/types/src/traits/block_contents.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,9 @@ pub trait BlockHeader<TYPES: NodeType>:
187187
/// Get the block number.
188188
fn block_number(&self) -> u64;
189189

190+
/// Get the timestamp.
191+
fn timestamp(&self) -> u64;
192+
190193
/// Get the payload commitment.
191194
fn payload_commitment(&self) -> VidCommitment;
192195

hotshot-query-service/src/availability/query_data.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ pub type TransactionInclusionProof<Types> =
4949
pub type Timestamp = time::OffsetDateTime;
5050

5151
pub trait QueryableHeader<Types: NodeType>: BlockHeader<Types> {
52-
fn timestamp(&self) -> u64;
5352
fn namespace_size(&self, id: u32, payload_size: usize) -> u64;
5453
}
5554

hotshot-query-service/src/data_source.rs

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -775,16 +775,17 @@ pub mod node_tests {
775775
};
776776
use hotshot_types::{
777777
data::{vid_commitment, VidCommitment, VidShare},
778-
traits::{block_contents::EncodeBytes, node_implementation::Versions},
778+
traits::{
779+
block_contents::{BlockHeader, EncodeBytes},
780+
node_implementation::Versions,
781+
},
779782
vid::advz::{advz_scheme, ADVZScheme},
780783
};
781784
use jf_vid::VidScheme;
782785
use vbs::version::StaticVersionType;
783786

784787
use crate::{
785-
availability::{
786-
BlockInfo, BlockQueryData, LeafQueryData, QueryableHeader, VidCommonQueryData,
787-
},
788+
availability::{BlockInfo, BlockQueryData, LeafQueryData, VidCommonQueryData},
788789
data_source::{
789790
storage::{NodeStorage, UpdateAvailabilityStorage},
790791
update::Transaction,
@@ -799,6 +800,10 @@ pub mod node_tests {
799800
Header, VidCommon,
800801
};
801802

803+
fn block_header_timestamp(header: &Header<MockTypes>) -> u64 {
804+
<TestBlockHeader as BlockHeader<MockTypes>>::timestamp(header)
805+
}
806+
802807
#[tokio::test(flavor = "multi_thread")]
803808
pub async fn test_sync_status<D: TestableDataSource>()
804809
where
@@ -1232,7 +1237,9 @@ pub mod node_tests {
12321237
let leaf = leaves.next().await.unwrap();
12331238
let header = leaf.header().clone();
12341239
if let Some(last_timestamp) = test_blocks.last_mut() {
1235-
if last_timestamp[0].timestamp() == header.timestamp() {
1240+
if <TestBlockHeader as BlockHeader<MockTypes>>::timestamp(&last_timestamp[0])
1241+
== <TestBlockHeader as BlockHeader<MockTypes>>::timestamp(&header)
1242+
{
12361243
last_timestamp.push(header);
12371244
} else {
12381245
test_blocks.push(vec![header]);
@@ -1249,26 +1256,29 @@ pub mod node_tests {
12491256
let mut prev = res.prev.as_ref();
12501257
if let Some(prev) = prev {
12511258
if check_prev {
1252-
assert!(prev.timestamp() < start);
1259+
assert!(block_header_timestamp(prev) < start);
12531260
}
12541261
} else {
12551262
// `prev` can only be `None` if the first block in the window is the genesis
12561263
// block.
12571264
assert_eq!(res.from().unwrap(), 0);
12581265
};
12591266
for header in &res.window {
1260-
assert!(start <= header.timestamp());
1261-
assert!(header.timestamp() < end);
1267+
assert!(start <= block_header_timestamp(header));
1268+
assert!(block_header_timestamp(header) < end);
12621269
if let Some(prev) = prev {
1263-
assert!(prev.timestamp() <= header.timestamp());
1270+
assert!(
1271+
<TestBlockHeader as BlockHeader<MockTypes>>::timestamp(prev)
1272+
<= <TestBlockHeader as BlockHeader<MockTypes>>::timestamp(header)
1273+
);
12641274
}
12651275
prev = Some(header);
12661276
}
12671277
if let Some(next) = &res.next {
1268-
assert!(next.timestamp() >= end);
1278+
assert!(<TestBlockHeader as BlockHeader<MockTypes>>::timestamp(next) >= end);
12691279
// If there is a `next`, there must be at least one previous block (either `prev`
12701280
// itself or the last block if the window is nonempty), so we can `unwrap` here.
1271-
assert!(next.timestamp() >= prev.unwrap().timestamp());
1281+
assert!(block_header_timestamp(next) >= block_header_timestamp(prev.unwrap()));
12721282
}
12731283
};
12741284

@@ -1286,7 +1296,7 @@ pub mod node_tests {
12861296
};
12871297

12881298
// Case 0: happy path. All blocks are available, including prev and next.
1289-
let start = test_blocks[1][0].timestamp();
1299+
let start = <TestBlockHeader as BlockHeader<MockTypes>>::timestamp(&test_blocks[1][0]);
12901300
let end = start + 1;
12911301
let res = get_window(start, end).await;
12921302
assert_eq!(res.prev.unwrap(), *test_blocks[0].last().unwrap());
@@ -1295,14 +1305,14 @@ pub mod node_tests {
12951305

12961306
// Case 1: no `prev`, start of window is before genesis.
12971307
let start = 0;
1298-
let end = test_blocks[0][0].timestamp() + 1;
1308+
let end = <TestBlockHeader as BlockHeader<MockTypes>>::timestamp(&test_blocks[0][0]) + 1;
12991309
let res = get_window(start, end).await;
13001310
assert_eq!(res.prev, None);
13011311
assert_eq!(res.window, test_blocks[0]);
13021312
assert_eq!(res.next.unwrap(), test_blocks[1][0]);
13031313

13041314
// Case 2: no `next`, end of window is after the most recently sequenced block.
1305-
let start = test_blocks[2][0].timestamp();
1315+
let start = <TestBlockHeader as BlockHeader<MockTypes>>::timestamp(&test_blocks[2][0]);
13061316
let end = i64::MAX as u64;
13071317
let res = get_window(start, end).await;
13081318
assert_eq!(res.prev.unwrap(), *test_blocks[1].last().unwrap());
@@ -1344,7 +1354,7 @@ pub mod node_tests {
13441354
assert_eq!(more2.window[..more.window.len()], more.window);
13451355

13461356
// Case 3: the window is empty.
1347-
let start = test_blocks[1][0].timestamp();
1357+
let start = <TestBlockHeader as BlockHeader<MockTypes>>::timestamp(&test_blocks[1][0]);
13481358
let end = start;
13491359
let res = get_window(start, end).await;
13501360
assert_eq!(res.prev.unwrap(), *test_blocks[0].last().unwrap());
@@ -1366,8 +1376,8 @@ pub mod node_tests {
13661376
.flatten()
13671377
.collect::<Vec<_>>();
13681378
// Make a query that would return everything, but gets limited.
1369-
let start = blocks[0].timestamp();
1370-
let end = test_blocks[2][0].timestamp();
1379+
let start = block_header_timestamp(&blocks[0]);
1380+
let end = block_header_timestamp(&test_blocks[2][0]);
13711381
let res = ds
13721382
.get_header_window(WindowStart::Time(start), end, 1)
13731383
.await

hotshot-query-service/src/data_source/extension.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,20 @@
1313
use std::ops::{Bound, RangeBounds};
1414

1515
use async_trait::async_trait;
16-
use hotshot_types::{data::VidShare, traits::node_implementation::NodeType};
16+
use hotshot_types::{
17+
data::VidShare,
18+
traits::{block_contents::BlockHeader, node_implementation::NodeType},
19+
};
1720
use jf_merkle_tree::prelude::MerkleProof;
1821
use tagged_base64::TaggedBase64;
1922

2023
use super::VersionedDataSource;
2124
use crate::{
2225
availability::{
2326
AvailabilityDataSource, BlockId, BlockInfo, BlockQueryData, Fetch, FetchStream, LeafId,
24-
LeafQueryData, PayloadMetadata, PayloadQueryData, QueryableHeader, QueryablePayload,
25-
StateCertQueryData, TransactionHash, TransactionQueryData, UpdateAvailabilityData,
26-
VidCommonMetadata, VidCommonQueryData,
27+
LeafQueryData, PayloadMetadata, PayloadQueryData, QueryablePayload, StateCertQueryData,
28+
TransactionHash, TransactionQueryData, UpdateAvailabilityData, VidCommonMetadata,
29+
VidCommonQueryData,
2730
},
2831
data_source::storage::pruning::PrunedHeightDataSource,
2932
explorer::{self, ExplorerDataSource, ExplorerHeader, ExplorerTransaction},
@@ -441,7 +444,7 @@ where
441444
U: Send + Sync,
442445
Types: NodeType,
443446
Payload<Types>: QueryablePayload<Types>,
444-
Header<Types>: ExplorerHeader<Types> + QueryableHeader<Types>,
447+
Header<Types>: ExplorerHeader<Types> + BlockHeader<Types>,
445448
Transaction<Types>: ExplorerTransaction,
446449
{
447450
async fn get_block_detail(

hotshot-query-service/src/data_source/storage.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,18 @@ use std::ops::RangeBounds;
6060

6161
use async_trait::async_trait;
6262
use futures::future::Future;
63-
use hotshot_types::{data::VidShare, traits::node_implementation::NodeType};
63+
use hotshot_types::{
64+
data::VidShare,
65+
traits::{block_contents::BlockHeader, node_implementation::NodeType},
66+
};
6467
use jf_merkle_tree::prelude::MerkleProof;
6568
use tagged_base64::TaggedBase64;
6669

6770
use crate::{
6871
availability::{
6972
BlockId, BlockQueryData, LeafId, LeafQueryData, PayloadMetadata, PayloadQueryData,
70-
QueryableHeader, QueryablePayload, StateCertQueryData, TransactionHash,
71-
TransactionQueryData, VidCommonMetadata, VidCommonQueryData,
73+
QueryablePayload, StateCertQueryData, TransactionHash, TransactionQueryData,
74+
VidCommonMetadata, VidCommonQueryData,
7275
},
7376
explorer::{
7477
query_data::{
@@ -287,7 +290,7 @@ where
287290
pub trait ExplorerStorage<Types>
288291
where
289292
Types: NodeType,
290-
Header<Types>: ExplorerHeader<Types> + QueryableHeader<Types>,
293+
Header<Types>: ExplorerHeader<Types> + BlockHeader<Types>,
291294
Transaction<Types>: ExplorerTransaction,
292295
Payload<Types>: QueryablePayload<Types>,
293296
{

hotshot-query-service/src/data_source/storage/fs.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ use crate::{
4848
availability::{
4949
data_source::{BlockId, LeafId},
5050
query_data::{
51-
BlockHash, BlockQueryData, LeafHash, LeafQueryData, PayloadQueryData, QueryableHeader,
52-
QueryablePayload, TransactionHash, TransactionQueryData, VidCommonQueryData,
51+
BlockHash, BlockQueryData, LeafHash, LeafQueryData, PayloadQueryData, QueryablePayload,
52+
TransactionHash, TransactionQueryData, VidCommonQueryData,
5353
},
5454
StateCertQueryData,
5555
},
@@ -158,7 +158,7 @@ where
158158
impl<Types: NodeType> FileSystemStorage<Types>
159159
where
160160
Payload<Types>: QueryablePayload<Types>,
161-
Header<Types>: QueryableHeader<Types>,
161+
Header<Types>: BlockHeader<Types>,
162162
{
163163
/// Create a new [FileSystemStorage] with storage at `path`.
164164
///
@@ -490,7 +490,7 @@ impl<Types, T> AvailabilityStorage<Types> for Transaction<T>
490490
where
491491
Types: NodeType,
492492
Payload<Types>: QueryablePayload<Types>,
493-
Header<Types>: QueryableHeader<Types>,
493+
Header<Types>: BlockHeader<Types>,
494494
T: Revert + Deref<Target = FileSystemStorageInner<Types>> + Send + Sync,
495495
{
496496
async fn get_leaf(&mut self, id: LeafId<Types>) -> QueryResult<LeafQueryData<Types>> {
@@ -656,7 +656,7 @@ impl<Types: NodeType> UpdateAvailabilityStorage<Types>
656656
for Transaction<RwLockWriteGuard<'_, FileSystemStorageInner<Types>>>
657657
where
658658
Payload<Types>: QueryablePayload<Types>,
659-
Header<Types>: QueryableHeader<Types>,
659+
Header<Types>: BlockHeader<Types>,
660660
{
661661
async fn insert_leaf(&mut self, leaf: LeafQueryData<Types>) -> anyhow::Result<()> {
662662
self.inner
@@ -749,7 +749,7 @@ impl<Types, T> NodeStorage<Types> for Transaction<T>
749749
where
750750
Types: NodeType,
751751
Payload<Types>: QueryablePayload<Types>,
752-
Header<Types>: QueryableHeader<Types>,
752+
Header<Types>: BlockHeader<Types>,
753753
T: Revert + Deref<Target = FileSystemStorageInner<Types>> + Send,
754754
{
755755
async fn block_height(&mut self) -> QueryResult<usize> {

hotshot-query-service/src/data_source/storage/sql.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,7 +1068,7 @@ pub mod testing {
10681068
use tokio::{net::TcpStream, time::timeout};
10691069

10701070
use super::Config;
1071-
use crate::{availability::query_data::QueryableHeader, testing::sleep};
1071+
use crate::testing::sleep;
10721072
#[derive(Debug)]
10731073
pub struct TmpDb {
10741074
#[cfg(not(feature = "embedded-db"))]
@@ -1383,7 +1383,7 @@ mod test {
13831383

13841384
use super::{testing::TmpDb, *};
13851385
use crate::{
1386-
availability::{LeafQueryData, QueryableHeader},
1386+
availability::LeafQueryData,
13871387
data_source::storage::{pruning::PrunedHeightStorage, UpdateAvailabilityStorage},
13881388
merklized_state::{MerklizedState, UpdateStateData},
13891389
testing::{
@@ -1849,7 +1849,7 @@ mod test {
18491849
leaf.block_header().commit().to_string(),
18501850
payload_commitment.to_string(),
18511851
header_json,
1852-
leaf.block_header().timestamp() as i64,
1852+
<MockHeader as BlockHeader<MockTypes>>::timestamp(leaf.block_header()) as i64,
18531853
)],
18541854
)
18551855
.await

0 commit comments

Comments
 (0)