1use kaspa_consensus_core::{
6 acceptance_data::AcceptanceData,
7 api::{BlockCount, BlockValidationFutures, ConsensusApi, ConsensusStats, DynConsensus},
8 block::Block,
9 blockstatus::BlockStatus,
10 daa_score_timestamp::DaaScoreTimestamp,
11 errors::consensus::ConsensusResult,
12 header::Header,
13 pruning::{PruningPointProof, PruningPointTrustedData, PruningPointsList},
14 trusted::{ExternalGhostdagData, TrustedBlock},
15 tx::{MutableTransaction, Transaction, TransactionOutpoint, UtxoEntry},
16 BlockHashSet, BlueWorkType, ChainPath, Hash,
17};
18use kaspa_utils::sync::rwlock::*;
19use std::{ops::Deref, sync::Arc};
20
21pub use tokio::task::spawn_blocking;
22
23use crate::BlockProcessingBatch;
24
25#[allow(dead_code)]
26#[derive(Clone)]
27pub struct SessionOwnedReadGuard(Arc<RfRwLockOwnedReadGuard>);
28
29#[allow(dead_code)]
30pub struct SessionReadGuard<'a>(RfRwLockReadGuard<'a>);
31
32pub struct SessionWriteGuard<'a>(RfRwLockWriteGuard<'a>);
33
34impl SessionWriteGuard<'_> {
35 pub fn blocking_yield(&mut self) {
38 self.0.blocking_yield();
39 }
40}
41
42#[derive(Clone)]
43pub struct SessionLock(Arc<RfRwLock>);
44
45impl Default for SessionLock {
46 fn default() -> Self {
47 Self::new()
48 }
49}
50
51impl SessionLock {
52 pub fn new() -> SessionLock {
53 SessionLock(Arc::new(RfRwLock::new()))
54 }
55
56 pub async fn read_owned(&self) -> SessionOwnedReadGuard {
57 SessionOwnedReadGuard(Arc::new(self.0.clone().read_owned().await))
58 }
59
60 pub async fn read(&self) -> SessionReadGuard {
61 SessionReadGuard(self.0.read().await)
62 }
63
64 pub fn blocking_read(&self) -> SessionReadGuard {
65 SessionReadGuard(self.0.blocking_read())
66 }
67
68 pub fn blocking_write(&self) -> SessionWriteGuard<'_> {
69 SessionWriteGuard(self.0.blocking_write())
70 }
71}
72
73#[derive(Clone)]
74pub struct ConsensusInstance {
75 session_lock: SessionLock,
76 consensus: DynConsensus,
77}
78
79impl ConsensusInstance {
80 pub fn new(session_lock: SessionLock, consensus: DynConsensus) -> Self {
81 Self { session_lock, consensus }
82 }
83
84 pub async fn session_blocking(&self) -> ConsensusSessionBlocking {
88 let g = self.session_lock.read().await;
89 ConsensusSessionBlocking::new(g, self.consensus.clone())
90 }
91
92 pub fn unguarded_session_blocking(&self) -> ConsensusSessionBlocking<'static> {
96 ConsensusSessionBlocking::new_without_session_guard(self.consensus.clone())
97 }
98
99 pub async fn session(&self) -> ConsensusSessionOwned {
106 let g = self.session_lock.read_owned().await;
107 ConsensusSessionOwned::new(g, self.consensus.clone())
108 }
109
110 pub fn unguarded_session(&self) -> ConsensusSessionOwned {
114 ConsensusSessionOwned::new_without_session_guard(self.consensus.clone())
115 }
116}
117
118pub struct ConsensusSessionBlocking<'a> {
119 _session_guard: Option<SessionReadGuard<'a>>,
120 consensus: DynConsensus,
121}
122
123impl<'a> ConsensusSessionBlocking<'a> {
124 pub fn new(session_guard: SessionReadGuard<'a>, consensus: DynConsensus) -> Self {
125 Self { _session_guard: Some(session_guard), consensus }
126 }
127
128 pub fn new_without_session_guard(consensus: DynConsensus) -> Self {
129 Self { _session_guard: None, consensus }
130 }
131}
132
133impl Deref for ConsensusSessionBlocking<'_> {
134 type Target = dyn ConsensusApi; fn deref(&self) -> &Self::Target {
137 self.consensus.as_ref()
138 }
139}
140
141#[derive(Clone)]
145pub struct ConsensusSessionOwned {
146 _session_guard: Option<SessionOwnedReadGuard>,
147 consensus: DynConsensus,
148}
149
150impl ConsensusSessionOwned {
151 pub fn new(session_guard: SessionOwnedReadGuard, consensus: DynConsensus) -> Self {
152 Self { _session_guard: Some(session_guard), consensus }
153 }
154
155 pub fn new_without_session_guard(consensus: DynConsensus) -> Self {
156 Self { _session_guard: None, consensus }
157 }
158
159 pub async fn spawn_blocking<F, R>(self, f: F) -> R
163 where
164 F: FnOnce(&dyn ConsensusApi) -> R + Send + 'static,
165 R: Send + 'static,
166 {
167 spawn_blocking(move || f(self.consensus.as_ref())).await.unwrap()
168 }
169}
170
171impl ConsensusSessionOwned {
172 pub fn validate_and_insert_block(&self, block: Block) -> BlockValidationFutures {
173 self.consensus.validate_and_insert_block(block)
174 }
175
176 pub fn validate_and_insert_block_batch(&self, mut batch: Vec<Block>) -> BlockProcessingBatch {
177 batch.sort_by(|a, b| a.header.blue_work.partial_cmp(&b.header.blue_work).unwrap());
179 let (block_tasks, virtual_state_tasks) = batch
180 .iter()
181 .map(|b| {
182 let BlockValidationFutures { block_task, virtual_state_task } = self.consensus.validate_and_insert_block(b.clone());
183 (block_task, virtual_state_task)
184 })
185 .unzip();
186 BlockProcessingBatch::new(batch, block_tasks, virtual_state_tasks)
187 }
188
189 pub fn validate_and_insert_trusted_block(&self, tb: TrustedBlock) -> BlockValidationFutures {
190 self.consensus.validate_and_insert_trusted_block(tb)
191 }
192
193 pub fn calculate_transaction_compute_mass(&self, transaction: &Transaction) -> u64 {
194 self.consensus.calculate_transaction_compute_mass(transaction)
196 }
197
198 pub fn calculate_transaction_storage_mass(&self, transaction: &MutableTransaction) -> Option<u64> {
199 self.consensus.calculate_transaction_storage_mass(transaction)
201 }
202
203 pub fn get_virtual_daa_score(&self) -> u64 {
204 self.consensus.get_virtual_daa_score()
206 }
207
208 pub fn get_virtual_bits(&self) -> u32 {
209 self.consensus.get_virtual_bits()
211 }
212
213 pub fn get_virtual_past_median_time(&self) -> u64 {
214 self.consensus.get_virtual_past_median_time()
216 }
217
218 pub fn get_virtual_parents(&self) -> BlockHashSet {
219 self.consensus.get_virtual_parents()
221 }
222
223 pub fn get_virtual_parents_len(&self) -> usize {
224 self.consensus.get_virtual_parents_len()
226 }
227
228 pub async fn async_get_stats(&self) -> ConsensusStats {
229 self.clone().spawn_blocking(|c| c.get_stats()).await
230 }
231
232 pub async fn async_get_virtual_merge_depth_root(&self) -> Option<Hash> {
233 self.clone().spawn_blocking(|c| c.get_virtual_merge_depth_root()).await
234 }
235
236 pub async fn async_get_virtual_merge_depth_blue_work_threshold(&self) -> BlueWorkType {
240 self.clone().spawn_blocking(|c| c.get_virtual_merge_depth_blue_work_threshold()).await
241 }
242
243 pub async fn async_get_sink(&self) -> Hash {
244 self.clone().spawn_blocking(|c| c.get_sink()).await
245 }
246
247 pub async fn async_get_sink_timestamp(&self) -> u64 {
248 self.clone().spawn_blocking(|c| c.get_sink_timestamp()).await
249 }
250
251 pub async fn async_get_current_block_color(&self, hash: Hash) -> Option<bool> {
252 self.clone().spawn_blocking(move |c| c.get_current_block_color(hash)).await
253 }
254
255 pub async fn async_get_source(&self) -> Hash {
257 self.clone().spawn_blocking(|c| c.get_source()).await
258 }
259
260 pub async fn async_estimate_block_count(&self) -> BlockCount {
261 self.clone().spawn_blocking(|c| c.estimate_block_count()).await
262 }
263
264 pub async fn async_is_nearly_synced(&self) -> bool {
268 self.clone().spawn_blocking(|c| c.is_nearly_synced()).await
269 }
270
271 pub async fn async_get_virtual_chain_from_block(
272 &self,
273 low: Hash,
274 chain_path_added_limit: Option<usize>,
275 ) -> ConsensusResult<ChainPath> {
276 self.clone().spawn_blocking(move |c| c.get_virtual_chain_from_block(low, chain_path_added_limit)).await
277 }
278
279 pub async fn async_get_virtual_utxos(
280 &self,
281 from_outpoint: Option<TransactionOutpoint>,
282 chunk_size: usize,
283 skip_first: bool,
284 ) -> Vec<(TransactionOutpoint, UtxoEntry)> {
285 self.clone().spawn_blocking(move |c| c.get_virtual_utxos(from_outpoint, chunk_size, skip_first)).await
286 }
287
288 pub async fn async_get_tips(&self) -> Vec<Hash> {
289 self.clone().spawn_blocking(|c| c.get_tips()).await
290 }
291
292 pub async fn async_get_tips_len(&self) -> usize {
293 self.clone().spawn_blocking(|c| c.get_tips_len()).await
294 }
295
296 pub async fn async_is_chain_ancestor_of(&self, low: Hash, high: Hash) -> ConsensusResult<bool> {
297 self.clone().spawn_blocking(move |c| c.is_chain_ancestor_of(low, high)).await
298 }
299
300 pub async fn async_get_hashes_between(&self, low: Hash, high: Hash, max_blocks: usize) -> ConsensusResult<(Vec<Hash>, Hash)> {
301 self.clone().spawn_blocking(move |c| c.get_hashes_between(low, high, max_blocks)).await
302 }
303
304 pub async fn async_get_header(&self, hash: Hash) -> ConsensusResult<Arc<Header>> {
305 self.clone().spawn_blocking(move |c| c.get_header(hash)).await
306 }
307
308 pub async fn async_get_headers_selected_tip(&self) -> Hash {
309 self.clone().spawn_blocking(|c| c.get_headers_selected_tip()).await
310 }
311
312 pub async fn async_get_chain_block_samples(&self) -> Vec<DaaScoreTimestamp> {
313 self.clone().spawn_blocking(|c| c.get_chain_block_samples()).await
314 }
315
316 pub async fn async_get_antipast_from_pov(
320 &self,
321 hash: Hash,
322 context: Hash,
323 max_traversal_allowed: Option<u64>,
324 ) -> ConsensusResult<Vec<Hash>> {
325 self.clone().spawn_blocking(move |c| c.get_antipast_from_pov(hash, context, max_traversal_allowed)).await
326 }
327
328 pub async fn async_get_anticone(&self, hash: Hash) -> ConsensusResult<Vec<Hash>> {
330 self.clone().spawn_blocking(move |c| c.get_anticone(hash)).await
331 }
332
333 pub async fn async_get_pruning_point_proof(&self) -> Arc<PruningPointProof> {
334 self.clone().spawn_blocking(|c| c.get_pruning_point_proof()).await
335 }
336
337 pub async fn async_create_virtual_selected_chain_block_locator(
338 &self,
339 low: Option<Hash>,
340 high: Option<Hash>,
341 ) -> ConsensusResult<Vec<Hash>> {
342 self.clone().spawn_blocking(move |c| c.create_virtual_selected_chain_block_locator(low, high)).await
343 }
344
345 pub async fn async_create_block_locator_from_pruning_point(&self, high: Hash, limit: usize) -> ConsensusResult<Vec<Hash>> {
346 self.clone().spawn_blocking(move |c| c.create_block_locator_from_pruning_point(high, limit)).await
347 }
348
349 pub async fn async_pruning_point_headers(&self) -> Vec<Arc<Header>> {
350 self.clone().spawn_blocking(|c| c.pruning_point_headers()).await
351 }
352
353 pub async fn async_get_pruning_point_anticone_and_trusted_data(&self) -> ConsensusResult<Arc<PruningPointTrustedData>> {
354 self.clone().spawn_blocking(|c| c.get_pruning_point_anticone_and_trusted_data()).await
355 }
356
357 pub async fn async_get_block(&self, hash: Hash) -> ConsensusResult<Block> {
358 self.clone().spawn_blocking(move |c| c.get_block(hash)).await
359 }
360
361 pub async fn async_get_block_even_if_header_only(&self, hash: Hash) -> ConsensusResult<Block> {
362 self.clone().spawn_blocking(move |c| c.get_block_even_if_header_only(hash)).await
363 }
364
365 pub async fn async_get_ghostdag_data(&self, hash: Hash) -> ConsensusResult<ExternalGhostdagData> {
366 self.clone().spawn_blocking(move |c| c.get_ghostdag_data(hash)).await
367 }
368
369 pub async fn async_get_block_children(&self, hash: Hash) -> Option<Vec<Hash>> {
370 self.clone().spawn_blocking(move |c| c.get_block_children(hash)).await
371 }
372
373 pub async fn async_get_block_parents(&self, hash: Hash) -> Option<Arc<Vec<Hash>>> {
374 self.clone().spawn_blocking(move |c| c.get_block_parents(hash)).await
375 }
376
377 pub async fn async_get_block_status(&self, hash: Hash) -> Option<BlockStatus> {
378 self.clone().spawn_blocking(move |c| c.get_block_status(hash)).await
379 }
380
381 pub async fn async_get_block_acceptance_data(&self, hash: Hash) -> ConsensusResult<Arc<AcceptanceData>> {
382 self.clone().spawn_blocking(move |c| c.get_block_acceptance_data(hash)).await
383 }
384
385 pub async fn async_get_blocks_acceptance_data(
389 &self,
390 hashes: Vec<Hash>,
391 merged_blocks_limit: Option<usize>,
392 ) -> ConsensusResult<Vec<Arc<AcceptanceData>>> {
393 self.clone().spawn_blocking(move |c| c.get_blocks_acceptance_data(&hashes, merged_blocks_limit)).await
394 }
395
396 pub async fn async_is_chain_block(&self, hash: Hash) -> ConsensusResult<bool> {
397 self.clone().spawn_blocking(move |c| c.is_chain_block(hash)).await
398 }
399
400 pub async fn async_get_pruning_point_utxos(
401 &self,
402 expected_pruning_point: Hash,
403 from_outpoint: Option<TransactionOutpoint>,
404 chunk_size: usize,
405 skip_first: bool,
406 ) -> ConsensusResult<Vec<(TransactionOutpoint, UtxoEntry)>> {
407 self.clone()
408 .spawn_blocking(move |c| c.get_pruning_point_utxos(expected_pruning_point, from_outpoint, chunk_size, skip_first))
409 .await
410 }
411
412 pub async fn async_get_missing_block_body_hashes(&self, high: Hash) -> ConsensusResult<Vec<Hash>> {
413 self.clone().spawn_blocking(move |c| c.get_missing_block_body_hashes(high)).await
414 }
415
416 pub async fn async_pruning_point(&self) -> Hash {
417 self.clone().spawn_blocking(|c| c.pruning_point()).await
418 }
419
420 pub async fn async_get_daa_window(&self, hash: Hash) -> ConsensusResult<Vec<Hash>> {
421 self.clone().spawn_blocking(move |c| c.get_daa_window(hash)).await
422 }
423
424 pub async fn async_get_trusted_block_associated_ghostdag_data_block_hashes(&self, hash: Hash) -> ConsensusResult<Vec<Hash>> {
425 self.clone().spawn_blocking(move |c| c.get_trusted_block_associated_ghostdag_data_block_hashes(hash)).await
426 }
427
428 pub async fn async_estimate_network_hashes_per_second(
429 &self,
430 start_hash: Option<Hash>,
431 window_size: usize,
432 ) -> ConsensusResult<u64> {
433 self.clone().spawn_blocking(move |c| c.estimate_network_hashes_per_second(start_hash, window_size)).await
434 }
435
436 pub async fn async_validate_pruning_points(&self) -> ConsensusResult<()> {
437 self.clone().spawn_blocking(move |c| c.validate_pruning_points()).await
438 }
439
440 pub async fn async_are_pruning_points_violating_finality(&self, pp_list: PruningPointsList) -> bool {
441 self.clone().spawn_blocking(move |c| c.are_pruning_points_violating_finality(pp_list)).await
442 }
443
444 pub async fn async_creation_timestamp(&self) -> u64 {
445 self.clone().spawn_blocking(move |c| c.creation_timestamp()).await
446 }
447
448 pub async fn async_finality_point(&self) -> Hash {
449 self.clone().spawn_blocking(move |c| c.finality_point()).await
450 }
451}
452
453pub type ConsensusProxy = ConsensusSessionOwned;