consensus_core/
context.rs1use std::{sync::Arc, time::SystemTime};
5
6use consensus_config::{AuthorityIndex, Committee, ConsensusProtocolConfig, Parameters};
7use consensus_config::{NetworkKeyPair, ProtocolKeyPair};
8use consensus_types::block::BlockTimestampMs;
9use tempfile::TempDir;
10use tokio::time::Instant;
11
12use crate::metrics::Metrics;
13use crate::metrics::test_metrics;
14
15#[derive(Clone)]
18pub struct Context {
19 pub epoch_start_timestamp_ms: u64,
21 pub own_index: AuthorityIndex,
23 pub committee: Committee,
25 pub parameters: Parameters,
27 pub protocol_config: ConsensusProtocolConfig,
29 pub metrics: Arc<Metrics>,
31 pub clock: Arc<Clock>,
33}
34
35impl Context {
36 pub(crate) fn new(
37 epoch_start_timestamp_ms: u64,
38 own_index: Option<AuthorityIndex>,
39 committee: Committee,
40 parameters: Parameters,
41 protocol_config: ConsensusProtocolConfig,
42 metrics: Arc<Metrics>,
43 clock: Arc<Clock>,
44 ) -> Self {
45 let own_index = if let Some(own_index) = own_index {
46 own_index
47 } else {
48 AuthorityIndex::MAX
50 };
51
52 Self {
53 epoch_start_timestamp_ms,
54 own_index,
55 committee,
56 parameters,
57 protocol_config,
58 metrics,
59 clock,
60 }
61 }
62
63 pub fn new_for_test(committee_size: usize) -> (Self, Vec<(NetworkKeyPair, ProtocolKeyPair)>) {
65 Self::new_with_test_options(committee_size, true)
66 }
67
68 pub fn new_with_test_options(
70 committee_size: usize,
71 unused_port: bool,
72 ) -> (Self, Vec<(NetworkKeyPair, ProtocolKeyPair)>) {
73 let (committee, keypairs) = consensus_config::local_committee_and_keys_with_test_options(
74 0,
75 vec![1; committee_size],
76 unused_port,
77 );
78 let metrics = test_metrics();
79 let temp_dir = TempDir::new().unwrap();
80 let clock = Arc::new(Clock::default());
81
82 let context = Context::new(
83 0,
84 Some(AuthorityIndex::new_for_test(0)),
85 committee,
86 Parameters {
87 db_path: temp_dir.keep(),
88 ..Default::default()
89 },
90 ConsensusProtocolConfig::for_testing(),
91 metrics,
92 clock,
93 );
94 (context, keypairs)
95 }
96
97 pub fn with_epoch_start_timestamp_ms(mut self, epoch_start_timestamp_ms: u64) -> Self {
98 self.epoch_start_timestamp_ms = epoch_start_timestamp_ms;
99 self
100 }
101
102 pub fn with_authority_index(mut self, authority: AuthorityIndex) -> Self {
103 self.own_index = authority;
104 self
105 }
106
107 pub fn with_committee(mut self, committee: Committee) -> Self {
108 self.committee = committee;
109 self
110 }
111
112 pub fn with_parameters(mut self, parameters: Parameters) -> Self {
113 self.parameters = parameters;
114 self
115 }
116
117 pub fn with_protocol_config(mut self, protocol_config: ConsensusProtocolConfig) -> Self {
118 self.protocol_config = protocol_config;
119 self
120 }
121
122 pub fn is_validator(&self) -> bool {
124 self.committee.is_valid_index(self.own_index)
125 }
126
127 pub fn is_observer(&self) -> bool {
129 !self.is_validator()
130 }
131}
132
133pub struct Clock {
139 initial_instant: Instant,
140 initial_system_time: SystemTime,
141 clock_drift: BlockTimestampMs,
143}
144
145impl Default for Clock {
146 fn default() -> Self {
147 Self {
148 initial_instant: Instant::now(),
149 initial_system_time: SystemTime::now(),
150 clock_drift: 0,
151 }
152 }
153}
154
155impl Clock {
156 pub fn new_for_test(clock_drift: BlockTimestampMs) -> Self {
157 Self {
158 initial_instant: Instant::now(),
159 initial_system_time: SystemTime::now(),
160 clock_drift,
161 }
162 }
163
164 pub(crate) fn timestamp_utc_ms(&self) -> BlockTimestampMs {
168 if cfg!(not(any(msim, test))) {
169 assert_eq!(
170 self.clock_drift, 0,
171 "Clock drift should not be set in non testing environments."
172 );
173 }
174
175 let now: Instant = Instant::now();
176 let monotonic_system_time = self
177 .initial_system_time
178 .checked_add(
179 now.checked_duration_since(self.initial_instant)
180 .unwrap_or_else(|| {
181 panic!(
182 "current instant ({:?}) < initial instant ({:?})",
183 now, self.initial_instant
184 )
185 }),
186 )
187 .expect("Computing system time should not overflow");
188 monotonic_system_time
189 .duration_since(SystemTime::UNIX_EPOCH)
190 .unwrap_or_else(|_| {
191 panic!(
192 "system time ({:?}) < UNIX_EPOCH ({:?})",
193 monotonic_system_time,
194 SystemTime::UNIX_EPOCH,
195 )
196 })
197 .as_millis() as BlockTimestampMs
198 + self.clock_drift
199 }
200}