1use std::{collections::HashMap, sync::Arc};
20
21use darkfi_sdk::crypto::MerkleTree;
22use num_bigint::BigUint;
23use sled_overlay::sled;
24use smol::lock::RwLock;
25use tracing::{debug, error, info, warn};
26
27use crate::{
28 blockchain::{
29 block_store::{BlockDifficulty, BlockInfo, BlockRanks},
30 Blockchain, BlockchainOverlay, HeaderHash,
31 },
32 error::TxVerifyFailed,
33 tx::Transaction,
34 zk::VerifyingKey,
35 Error, Result,
36};
37
38pub mod consensus;
40use consensus::{Consensus, Fork, Proposal};
41
42pub mod pow;
44use pow::PoWModule;
45
46pub mod randomx_factory;
48pub use randomx_factory::RandomXFactory;
49
50pub mod verification;
52use verification::{
53 verify_block, verify_checkpoint_block, verify_genesis_block, verify_producer_transaction,
54 verify_transaction, verify_transactions,
55};
56
57pub mod fees;
59use fees::compute_fee;
60
61pub mod utils;
63use utils::{best_fork_index, block_rank, deploy_native_contracts};
64
65#[derive(Clone)]
67pub struct ValidatorConfig {
68 pub confirmation_threshold: usize,
70 pub pow_target: u32,
72 pub pow_fixed_difficulty: Option<BigUint>,
74 pub genesis_block: BlockInfo,
76 pub verify_fees: bool,
78}
79
80pub type ValidatorPtr = Arc<Validator>;
82
83pub struct Validator {
85 pub blockchain: Blockchain,
87 pub consensus: Consensus,
89 pub synced: RwLock<bool>,
91 pub verify_fees: bool,
93}
94
95impl Validator {
96 pub async fn new(db: &sled::Db, config: &ValidatorConfig) -> Result<ValidatorPtr> {
97 info!(target: "validator::new", "Initializing Validator");
98
99 info!(target: "validator::new", "Initializing Blockchain");
100 let blockchain = Blockchain::new(db)?;
101
102 let overlay = BlockchainOverlay::new(&blockchain)?;
104
105 deploy_native_contracts(&overlay, config.pow_target).await?;
107
108 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&[])?;
111 overlay.lock().unwrap().contracts.update_state_monotree(&diff)?;
112
113 if blockchain.genesis().is_err() {
115 info!(target: "validator::new", "Appending genesis block");
116 verify_genesis_block(&overlay, &[diff], &config.genesis_block, config.pow_target)
117 .await?;
118 };
119
120 overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
122
123 info!(target: "validator::new", "Initializing Consensus");
124 let consensus = Consensus::new(
125 blockchain.clone(),
126 config.confirmation_threshold,
127 config.pow_target,
128 config.pow_fixed_difficulty.clone(),
129 )?;
130
131 let state = Arc::new(Self {
133 blockchain,
134 consensus,
135 synced: RwLock::new(false),
136 verify_fees: config.verify_fees,
137 });
138
139 info!(target: "validator::new", "Finished initializing validator");
140 Ok(state)
141 }
142
143 pub async fn calculate_fee(&self, tx: &Transaction, verify_fee: bool) -> Result<u64> {
151 let forks = self.consensus.forks.read().await;
153 let fork = forks[best_fork_index(&forks)?].full_clone()?;
154 drop(forks);
155
156 let mut vks: HashMap<[u8; 32], HashMap<String, VerifyingKey>> = HashMap::new();
158 for call in &tx.calls {
159 vks.insert(call.data.contract_id.to_bytes(), HashMap::new());
160 }
161
162 let next_block_height = fork.get_next_block_height()?;
164
165 let verify_result = verify_transaction(
167 &fork.overlay,
168 next_block_height,
169 self.consensus.module.read().await.target,
170 tx,
171 &mut MerkleTree::new(1),
172 &mut vks,
173 verify_fee,
174 )
175 .await?;
176
177 Ok(compute_fee(&verify_result.total_gas_used()))
178 }
179
180 pub async fn append_tx(&self, tx: &Transaction, write: bool) -> Result<()> {
186 let tx_hash = tx.hash();
187
188 let tx_in_txstore = self.blockchain.transactions.contains(&tx_hash)?;
190 let tx_in_pending_txs_store = self.blockchain.transactions.contains_pending(&tx_hash)?;
191
192 if tx_in_txstore || tx_in_pending_txs_store {
193 debug!(target: "validator::append_tx", "We have already seen tx: {tx_hash}");
194 return Err(TxVerifyFailed::AlreadySeenTx(tx_hash.as_string()).into())
195 }
196
197 info!(target: "validator::append_tx", "Starting state transition validation for tx: {tx_hash}");
199 let tx_vec = [tx.clone()];
200 let mut valid = false;
201
202 let mut forks = self.consensus.forks.write().await;
204
205 for fork in forks.iter_mut() {
207 let fork_clone = fork.full_clone()?;
209
210 let next_block_height = fork_clone.get_next_block_height()?;
212
213 let verify_result = verify_transactions(
215 &fork_clone.overlay,
216 next_block_height,
217 self.consensus.module.read().await.target,
218 &tx_vec,
219 &mut MerkleTree::new(1),
220 self.verify_fees,
221 )
222 .await;
223
224 match verify_result {
226 Ok(_) => {}
227 Err(Error::TxVerifyFailed(TxVerifyFailed::ErroneousTxs(_))) => continue,
228 Err(e) => return Err(e),
229 }
230
231 valid = true;
232
233 if write {
235 fork.mempool.push(tx_hash);
236 }
237 }
238
239 drop(forks);
241
242 if !valid {
244 return Err(TxVerifyFailed::ErroneousTxs(tx_vec.to_vec()).into())
245 }
246
247 if write {
249 self.blockchain.add_pending_txs(&tx_vec)?;
250 info!(target: "validator::append_tx", "Appended tx {tx_hash} to pending txs store");
251 }
252
253 Ok(())
254 }
255
256 pub async fn purge_pending_txs(&self) -> Result<()> {
262 info!(target: "validator::purge_pending_txs", "Removing invalid transactions from pending transactions store...");
263
264 let pending_txs = self.blockchain.get_pending_txs()?;
266 if pending_txs.is_empty() {
267 info!(target: "validator::purge_pending_txs", "No pending transactions found");
268 return Ok(())
269 }
270
271 let mut forks = self.consensus.forks.write().await;
273
274 let mut removed_txs = vec![];
275 for tx in pending_txs {
276 let tx_hash = tx.hash();
277 let tx_vec = [tx.clone()];
278 let mut valid = false;
279
280 for fork in forks.iter_mut() {
282 let fork_clone = fork.full_clone()?;
284
285 let next_block_height = fork_clone.get_next_block_height()?;
287
288 let verify_result = verify_transactions(
290 &fork_clone.overlay,
291 next_block_height,
292 self.consensus.module.read().await.target,
293 &tx_vec,
294 &mut MerkleTree::new(1),
295 self.verify_fees,
296 )
297 .await;
298
299 match verify_result {
301 Ok(_) => {
302 valid = true;
303 continue
304 }
305 Err(Error::TxVerifyFailed(TxVerifyFailed::ErroneousTxs(_))) => {}
306 Err(e) => return Err(e),
307 }
308
309 fork.mempool.retain(|x| *x != tx_hash);
311 }
312
313 if !valid {
315 removed_txs.push(tx)
316 }
317 }
318
319 drop(forks);
321
322 if removed_txs.is_empty() {
323 info!(target: "validator::purge_pending_txs", "No erroneous transactions found");
324 return Ok(())
325 }
326 info!(target: "validator::purge_pending_txs", "Removing {} erroneous transactions...", removed_txs.len());
327 self.blockchain.remove_pending_txs(&removed_txs)?;
328
329 Ok(())
330 }
331
332 pub async fn append_proposal(&self, proposal: &Proposal) -> Result<()> {
334 let append_lock = self.consensus.append_lock.write().await;
336
337 let result = self.consensus.append_proposal(proposal, self.verify_fees).await;
339
340 drop(append_lock);
342
343 result
344 }
345
346 pub async fn confirmation(&self) -> Result<Vec<BlockInfo>> {
350 let append_lock = self.consensus.append_lock.write().await;
353
354 info!(target: "validator::confirmation", "Performing confirmation check");
355
356 let confirmed_fork = match self.consensus.confirmation().await {
358 Ok(f) => f,
359 Err(e) => {
360 drop(append_lock);
361 return Err(e)
362 }
363 };
364 if confirmed_fork.is_none() {
365 info!(target: "validator::confirmation", "No proposals can be confirmed");
366 drop(append_lock);
367 return Ok(vec![])
368 }
369
370 let confirmed_fork = confirmed_fork.unwrap();
372 let mut forks = self.consensus.forks.write().await;
373 let fork = &mut forks[confirmed_fork];
374
375 let excess = (fork.proposals.len() - self.consensus.confirmation_threshold) + 1;
377
378 let rest_proposals = fork.proposals.split_off(excess);
380 let rest_diffs = fork.diffs.split_off(excess);
381 let confirmed_proposals = fork.proposals.clone();
382 let diffs = fork.diffs.clone();
383 fork.proposals = rest_proposals;
384 fork.diffs = rest_diffs;
385
386 let confirmed_blocks =
388 fork.overlay.lock().unwrap().get_blocks_by_hash(&confirmed_proposals)?;
389
390 let mut module = self.consensus.module.write().await;
392 let mut confirmed_txs = vec![];
393 let mut state_inverse_diffs_heights = vec![];
394 let mut state_inverse_diffs = vec![];
395 info!(target: "validator::confirmation", "Confirming proposals:");
396 for (index, proposal) in confirmed_proposals.iter().enumerate() {
397 info!(target: "validator::confirmation", "\t{proposal} ({}) - {}", confirmed_blocks[index].header.pow_data, confirmed_blocks[index].header.height);
398 fork.overlay.lock().unwrap().overlay.lock().unwrap().apply_diff(&diffs[index])?;
399 let next_difficulty = module.next_difficulty()?;
400 module.append(&confirmed_blocks[index].header, &next_difficulty)?;
401 confirmed_txs.extend_from_slice(&confirmed_blocks[index].txs);
402 state_inverse_diffs_heights.push(confirmed_blocks[index].header.height);
403 state_inverse_diffs.push(diffs[index].inverse());
404 }
405 drop(module);
406 drop(forks);
407
408 self.blockchain
410 .blocks
411 .insert_state_inverse_diff(&state_inverse_diffs_heights, &state_inverse_diffs)?;
412
413 self.consensus.reset_forks(&confirmed_proposals, &confirmed_fork, &confirmed_txs).await?;
415 info!(target: "validator::confirmation", "Confirmation completed!");
416
417 drop(append_lock);
419
420 Ok(confirmed_blocks)
421 }
422
423 pub async fn add_checkpoint_blocks(
435 &self,
436 blocks: &[BlockInfo],
437 headers: &[HeaderHash],
438 ) -> Result<()> {
439 if blocks.len() != headers.len() {
441 return Err(Error::InvalidInputLengths)
442 }
443
444 debug!(target: "validator::add_checkpoint_blocks", "Instantiating BlockchainOverlay");
445 let overlay = BlockchainOverlay::new(&self.blockchain)?;
446
447 let last_difficulty = self.blockchain.last_block_difficulty()?;
449 let mut current_targets_rank = last_difficulty.ranks.targets_rank;
450 let mut current_hashes_rank = last_difficulty.ranks.hashes_rank;
451
452 let mut module = self.consensus.module.read().await.clone();
454
455 let mut removed_txs = vec![];
457
458 let mut diffs_heights = vec![];
460 let mut diffs = vec![];
461 let mut inverse_diffs = vec![];
462
463 for (index, block) in blocks.iter().enumerate() {
465 match verify_checkpoint_block(&overlay, &diffs, block, &headers[index], module.target)
467 .await
468 {
469 Ok(()) => { }
470 Err(Error::BlockAlreadyExists(_)) => continue,
472 Err(e) => {
473 error!(target: "validator::add_checkpoint_blocks", "Erroneous block found in set: {e}");
474 return Err(Error::BlockIsInvalid(block.hash().as_string()))
475 }
476 };
477
478 let (next_target, next_difficulty) = module.next_mine_target_and_difficulty()?;
480
481 let (target_distance_sq, hash_distance_sq) = block_rank(block, &next_target)?;
483
484 current_targets_rank += target_distance_sq.clone();
486 current_hashes_rank += hash_distance_sq.clone();
487
488 let cumulative_difficulty =
490 module.cumulative_difficulty.clone() + next_difficulty.clone();
491 let ranks = BlockRanks::new(
492 target_distance_sq,
493 current_targets_rank.clone(),
494 hash_distance_sq,
495 current_hashes_rank.clone(),
496 );
497 let block_difficulty = BlockDifficulty::new(
498 block.header.height,
499 block.header.timestamp,
500 next_difficulty,
501 cumulative_difficulty,
502 ranks,
503 );
504 module.append_difficulty(&overlay, &block.header, block_difficulty)?;
505
506 for tx in &block.txs {
508 removed_txs.push(tx.clone());
509 }
510
511 diffs_heights.push(block.header.height);
513 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&diffs)?;
514 inverse_diffs.push(diff.inverse());
515 diffs.push(diff);
516 }
517
518 debug!(target: "validator::add_checkpoint_blocks", "Applying overlay changes");
519 overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
520
521 self.blockchain.blocks.insert_state_inverse_diff(&diffs_heights, &inverse_diffs)?;
523
524 self.blockchain.remove_pending_txs(&removed_txs)?;
526
527 *self.consensus.module.write().await = module.clone();
529
530 *self.consensus.forks.write().await =
532 vec![Fork::new(self.blockchain.clone(), module).await?];
533
534 Ok(())
535 }
536
537 pub async fn add_test_blocks(&self, blocks: &[BlockInfo]) -> Result<()> {
544 debug!(target: "validator::add_test_blocks", "Instantiating BlockchainOverlay");
545 let overlay = BlockchainOverlay::new(&self.blockchain)?;
546
547 let mut previous = &overlay.lock().unwrap().last_block()?;
549
550 let last_difficulty = self.blockchain.last_block_difficulty()?;
552 let mut current_targets_rank = last_difficulty.ranks.targets_rank;
553 let mut current_hashes_rank = last_difficulty.ranks.hashes_rank;
554
555 let mut module = self.consensus.module.read().await.clone();
557
558 let mut removed_txs = vec![];
560
561 let mut diffs_heights = vec![];
563 let mut diffs = vec![];
564 let mut inverse_diffs = vec![];
565
566 for block in blocks {
568 match verify_block(&overlay, &diffs, &module, block, previous, self.verify_fees).await {
570 Ok(()) => { }
571 Err(Error::BlockAlreadyExists(_)) => {
573 previous = block;
574 continue
575 }
576 Err(e) => {
577 error!(target: "validator::add_test_blocks", "Erroneous block found in set: {e}");
578 return Err(Error::BlockIsInvalid(block.hash().as_string()))
579 }
580 };
581
582 let (next_target, next_difficulty) = module.next_mine_target_and_difficulty()?;
584
585 let (target_distance_sq, hash_distance_sq) = block_rank(block, &next_target)?;
587
588 current_targets_rank += target_distance_sq.clone();
590 current_hashes_rank += hash_distance_sq.clone();
591
592 let cumulative_difficulty =
594 module.cumulative_difficulty.clone() + next_difficulty.clone();
595 let ranks = BlockRanks::new(
596 target_distance_sq,
597 current_targets_rank.clone(),
598 hash_distance_sq,
599 current_hashes_rank.clone(),
600 );
601 let block_difficulty = BlockDifficulty::new(
602 block.header.height,
603 block.header.timestamp,
604 next_difficulty,
605 cumulative_difficulty,
606 ranks,
607 );
608 module.append_difficulty(&overlay, &block.header, block_difficulty)?;
609
610 for tx in &block.txs {
612 removed_txs.push(tx.clone());
613 }
614
615 diffs_heights.push(block.header.height);
617 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&diffs)?;
618 inverse_diffs.push(diff.inverse());
619 diffs.push(diff);
620
621 previous = block;
623 }
624
625 debug!(target: "validator::add_test_blocks", "Applying overlay changes");
626 overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
627
628 self.blockchain.blocks.insert_state_inverse_diff(&diffs_heights, &inverse_diffs)?;
630
631 self.blockchain.remove_pending_txs(&removed_txs)?;
633 self.purge_pending_txs().await?;
634
635 *self.consensus.module.write().await = module;
637
638 Ok(())
639 }
640
641 pub async fn add_test_transactions(
654 &self,
655 txs: &[Transaction],
656 verifying_block_height: u32,
657 block_target: u32,
658 write: bool,
659 verify_fees: bool,
660 ) -> Result<(u64, u64)> {
661 debug!(target: "validator::add_transactions", "Instantiating BlockchainOverlay");
662 let overlay = BlockchainOverlay::new(&self.blockchain)?;
663
664 let verify_result = verify_transactions(
666 &overlay,
667 verifying_block_height,
668 block_target,
669 txs,
670 &mut MerkleTree::new(1),
671 verify_fees,
672 )
673 .await;
674
675 let lock = overlay.lock().unwrap();
676 let mut overlay = lock.overlay.lock().unwrap();
677
678 let gas_values = match verify_result {
679 Ok(v) => v,
680 Err(e) => return Err(e),
681 };
682
683 if !write {
684 debug!(target: "validator::add_transactions", "Skipping apply of state updates because write=false");
685 return Ok(gas_values)
686 }
687
688 debug!(target: "validator::add_transactions", "Applying overlay changes");
689 overlay.apply()?;
690 Ok(gas_values)
691 }
692
693 pub async fn add_test_producer_transaction(
701 &self,
702 tx: &Transaction,
703 verifying_block_height: u32,
704 block_target: u32,
705 write: bool,
706 ) -> Result<()> {
707 debug!(target: "validator::add_test_producer_transaction", "Instantiating BlockchainOverlay");
708 let overlay = BlockchainOverlay::new(&self.blockchain)?;
709
710 let mut erroneous_txs = vec![];
712 if let Err(e) = verify_producer_transaction(
713 &overlay,
714 verifying_block_height,
715 block_target,
716 tx,
717 &mut MerkleTree::new(1),
718 )
719 .await
720 {
721 warn!(target: "validator::add_test_producer_transaction", "Transaction verification failed: {e}");
722 erroneous_txs.push(tx.clone());
723 }
724
725 let lock = overlay.lock().unwrap();
726 let mut overlay = lock.overlay.lock().unwrap();
727 if !erroneous_txs.is_empty() {
728 warn!(target: "validator::add_test_producer_transaction", "Erroneous transactions found in set");
729 return Err(TxVerifyFailed::ErroneousTxs(erroneous_txs).into())
730 }
731
732 if !write {
733 debug!(target: "validator::add_test_producer_transaction", "Skipping apply of state updates because write=false");
734 return Ok(())
735 }
736
737 debug!(target: "validator::add_test_producer_transaction", "Applying overlay changes");
738 overlay.apply()?;
739 Ok(())
740 }
741
742 pub async fn validate_blockchain(
749 &self,
750 pow_target: u32,
751 pow_fixed_difficulty: Option<BigUint>,
752 ) -> Result<()> {
753 let mut blocks_count = self.blockchain.len() as u32;
755 info!(target: "validator::validate_blockchain", "Validating {blocks_count} blocks...");
756 if blocks_count == 0 {
757 info!(target: "validator::validate_blockchain", "Blockchain validated successfully!");
758 return Ok(())
759 }
760
761 let sled_db = sled::Config::new().temporary(true).open()?;
763 let blockchain = Blockchain::new(&sled_db)?;
764 let overlay = BlockchainOverlay::new(&blockchain)?;
765
766 let mut previous = self.blockchain.genesis_block()?;
768
769 deploy_native_contracts(&overlay, pow_target).await?;
771
772 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&[])?;
774 overlay.lock().unwrap().contracts.update_state_monotree(&diff)?;
775
776 verify_genesis_block(&overlay, &[diff], &previous, pow_target).await?;
778 info!(target: "validator::validate_blockchain", "Genesis block validated successfully!");
779
780 overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
782
783 let mut module = PoWModule::new(blockchain, pow_target, pow_fixed_difficulty, Some(0))?;
785
786 let mut diffs = vec![];
788
789 info!(target: "validator::validate_blockchain", "Validating rest blocks...");
791 blocks_count -= 1;
792 let mut index = 1;
793 while index <= blocks_count {
794 let block = self.blockchain.get_blocks_by_heights(&[index])?[0].clone();
796
797 if let Err(e) =
799 verify_block(&overlay, &diffs, &module, &block, &previous, self.verify_fees).await
800 {
801 error!(target: "validator::validate_blockchain", "Erroneous block found in set: {e}");
802 return Err(Error::BlockIsInvalid(block.hash().as_string()))
803 };
804
805 module.append(&block.header, &module.next_difficulty()?)?;
807
808 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&diffs)?;
810 diffs.push(diff);
811
812 previous = block;
814
815 info!(target: "validator::validate_blockchain", "Block {index}/{blocks_count} validated successfully!");
816 index += 1;
817 }
818
819 info!(target: "validator::validate_blockchain", "Blockchain validated successfully!");
820 Ok(())
821 }
822
823 pub async fn current_mining_randomx_key(&self) -> Result<HeaderHash> {
827 self.consensus.current_mining_randomx_key().await
828 }
829
830 pub async fn best_current_fork(&self) -> Result<Fork> {
832 self.consensus.best_current_fork().await
833 }
834
835 pub async fn best_fork_next_block_height(&self) -> Result<u32> {
837 let forks = self.consensus.forks.read().await;
838 let fork = &forks[best_fork_index(&forks)?];
839 let next_block_height = fork.get_next_block_height()?;
840 drop(forks);
841
842 Ok(next_block_height)
843 }
844
845 pub async fn reset_to_height(&self, height: u32) -> Result<()> {
848 info!(target: "validator::reset_to_height", "Resetting validator to height: {height}");
849 let append_lock = self.consensus.append_lock.write().await;
851
852 self.blockchain.reset_to_height(height)?;
854
855 self.consensus.reset_pow_module().await?;
857
858 self.consensus.purge_forks().await?;
860
861 drop(append_lock);
863
864 info!(target: "validator::reset_to_height", "Validator reset successfully!");
865
866 Ok(())
867 }
868
869 pub async fn rebuild_block_difficulties(
873 &self,
874 pow_target: u32,
875 pow_fixed_difficulty: Option<BigUint>,
876 ) -> Result<()> {
877 info!(target: "validator::rebuild_block_difficulties", "Rebuilding validator block difficulties...");
878 let append_lock = self.consensus.append_lock.write().await;
880
881 self.blockchain.blocks.difficulty.clear()?;
883
884 let mut blocks_count = self.blockchain.len() as u32;
886 info!(target: "validator::rebuild_block_difficulties", "Rebuilding {blocks_count} block difficulties...");
887 if blocks_count == 0 {
888 info!(target: "validator::rebuild_block_difficulties", "Validator block difficulties rebuilt successfully!");
889 return Ok(())
890 }
891
892 let mut module =
895 PoWModule::new(self.blockchain.clone(), pow_target, pow_fixed_difficulty, Some(0))?;
896
897 let genesis_block = self.blockchain.genesis_block()?;
899 let last_difficulty = BlockDifficulty::genesis(genesis_block.header.timestamp);
900 let mut targets_rank = last_difficulty.ranks.targets_rank;
901 let mut hashes_rank = last_difficulty.ranks.hashes_rank;
902
903 blocks_count -= 1;
905 let mut index = 1;
906 while index <= blocks_count {
907 let block = self.blockchain.get_blocks_by_heights(&[index])?[0].clone();
909
910 let (next_target, next_difficulty) = module.next_mine_target_and_difficulty()?;
912
913 let (target_distance_sq, hash_distance_sq) = block_rank(&block, &next_target)?;
915
916 targets_rank += target_distance_sq.clone();
918 hashes_rank += hash_distance_sq.clone();
919
920 let cumulative_difficulty =
922 module.cumulative_difficulty.clone() + next_difficulty.clone();
923 let ranks = BlockRanks::new(
924 target_distance_sq,
925 targets_rank.clone(),
926 hash_distance_sq,
927 hashes_rank.clone(),
928 );
929 let block_difficulty = BlockDifficulty::new(
930 block.header.height,
931 block.header.timestamp,
932 next_difficulty,
933 cumulative_difficulty,
934 ranks,
935 );
936 module.append(&block.header, &block_difficulty.difficulty)?;
937
938 self.blockchain.blocks.insert_difficulty(&[block_difficulty])?;
940
941 info!(target: "validator::rebuild_block_difficulties", "Block {index}/{blocks_count} difficulty added successfully!");
942 index += 1;
943 }
944
945 self.blockchain.sled_db.flush()?;
947
948 drop(append_lock);
950
951 info!(target: "validator::rebuild_block_difficulties", "Validator block difficulties rebuilt successfully!");
952
953 Ok(())
954 }
955}