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 if blockchain.genesis().is_err() {
110 info!(target: "validator::new", "Appending genesis block");
111 verify_genesis_block(&overlay, &config.genesis_block, config.pow_target).await?;
112 };
113
114 overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
116
117 info!(target: "validator::new", "Initializing Consensus");
118 let consensus = Consensus::new(
119 blockchain.clone(),
120 config.confirmation_threshold,
121 config.pow_target,
122 config.pow_fixed_difficulty.clone(),
123 )?;
124
125 let state = Arc::new(Self {
127 blockchain,
128 consensus,
129 synced: RwLock::new(false),
130 verify_fees: config.verify_fees,
131 });
132
133 info!(target: "validator::new", "Finished initializing validator");
134 Ok(state)
135 }
136
137 pub async fn calculate_fee(&self, tx: &Transaction, verify_fee: bool) -> Result<u64> {
142 let forks = self.consensus.forks.read().await;
144 let fork = forks[best_fork_index(&forks)?].full_clone()?;
145 drop(forks);
146
147 let mut vks: HashMap<[u8; 32], HashMap<String, VerifyingKey>> = HashMap::new();
149 for call in &tx.calls {
150 vks.insert(call.data.contract_id.to_bytes(), HashMap::new());
151 }
152
153 let next_block_height = fork.get_next_block_height()?;
155
156 let verify_result = verify_transaction(
158 &fork.overlay,
159 next_block_height,
160 self.consensus.module.read().await.target,
161 tx,
162 &mut MerkleTree::new(1),
163 &mut vks,
164 verify_fee,
165 )
166 .await?;
167
168 fork.overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
170
171 Ok(compute_fee(&verify_result.total_gas_used()))
172 }
173
174 pub async fn append_tx(&self, tx: &Transaction, write: bool) -> Result<()> {
177 let tx_hash = tx.hash();
178
179 let tx_in_txstore = self.blockchain.transactions.contains(&tx_hash)?;
181 let tx_in_pending_txs_store = self.blockchain.transactions.contains_pending(&tx_hash)?;
182
183 if tx_in_txstore || tx_in_pending_txs_store {
184 info!(target: "validator::append_tx", "We have already seen this tx");
185 return Err(TxVerifyFailed::AlreadySeenTx(tx_hash.as_string()).into())
186 }
187
188 info!(target: "validator::append_tx", "Starting state transition validation");
190 let tx_vec = [tx.clone()];
191 let mut valid = false;
192
193 let mut forks = self.consensus.forks.write().await;
195
196 for fork in forks.iter_mut() {
198 let fork_clone = fork.full_clone()?;
200
201 let next_block_height = fork_clone.get_next_block_height()?;
203
204 let verify_result = verify_transactions(
206 &fork_clone.overlay,
207 next_block_height,
208 self.consensus.module.read().await.target,
209 &tx_vec,
210 &mut MerkleTree::new(1),
211 self.verify_fees,
212 )
213 .await;
214
215 fork_clone.overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
217
218 match verify_result {
220 Ok(_) => {}
221 Err(Error::TxVerifyFailed(TxVerifyFailed::ErroneousTxs(_))) => continue,
222 Err(e) => return Err(e),
223 }
224
225 valid = true;
226
227 if write {
229 fork.mempool.push(tx_hash);
230 }
231 }
232
233 drop(forks);
235
236 if !valid {
238 return Err(TxVerifyFailed::ErroneousTxs(tx_vec.to_vec()).into())
239 }
240
241 if write {
243 self.blockchain.add_pending_txs(&tx_vec)?;
244 info!(target: "validator::append_tx", "Appended tx to pending txs store");
245 }
246
247 Ok(())
248 }
249
250 pub async fn purge_pending_txs(&self) -> Result<()> {
252 info!(target: "validator::purge_pending_txs", "Removing invalid transactions from pending transactions store...");
253
254 let pending_txs = self.blockchain.get_pending_txs()?;
256 if pending_txs.is_empty() {
257 info!(target: "validator::purge_pending_txs", "No pending transactions found");
258 return Ok(())
259 }
260
261 let mut forks = self.consensus.forks.write().await;
263
264 let mut removed_txs = vec![];
265 for tx in pending_txs {
266 let tx_hash = tx.hash();
267 let tx_vec = [tx.clone()];
268 let mut valid = false;
269
270 for fork in forks.iter_mut() {
272 let fork_clone = fork.full_clone()?;
274
275 let next_block_height = fork_clone.get_next_block_height()?;
277
278 let verify_result = verify_transactions(
280 &fork_clone.overlay,
281 next_block_height,
282 self.consensus.module.read().await.target,
283 &tx_vec,
284 &mut MerkleTree::new(1),
285 self.verify_fees,
286 )
287 .await;
288
289 fork_clone.overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
291
292 match verify_result {
294 Ok(_) => {
295 valid = true;
296 continue
297 }
298 Err(Error::TxVerifyFailed(TxVerifyFailed::ErroneousTxs(_))) => {}
299 Err(e) => return Err(e),
300 }
301
302 fork.mempool.retain(|x| *x != tx_hash);
304 }
305
306 if !valid {
308 removed_txs.push(tx)
309 }
310 }
311
312 drop(forks);
314
315 if removed_txs.is_empty() {
316 info!(target: "validator::purge_pending_txs", "No erroneous transactions found");
317 return Ok(())
318 }
319 info!(target: "validator::purge_pending_txs", "Removing {} erroneous transactions...", removed_txs.len());
320 self.blockchain.remove_pending_txs(&removed_txs)?;
321
322 Ok(())
323 }
324
325 pub async fn append_proposal(&self, proposal: &Proposal) -> Result<()> {
327 let append_lock = self.consensus.append_lock.write().await;
329
330 let result = self.consensus.append_proposal(proposal, self.verify_fees).await;
332
333 drop(append_lock);
335
336 result
337 }
338
339 pub async fn confirmation(&self) -> Result<Vec<BlockInfo>> {
343 let append_lock = self.consensus.append_lock.write().await;
346
347 info!(target: "validator::confirmation", "Performing confirmation check");
348
349 let confirmed_fork = match self.consensus.confirmation().await {
351 Ok(f) => f,
352 Err(e) => {
353 drop(append_lock);
354 return Err(e)
355 }
356 };
357 if confirmed_fork.is_none() {
358 info!(target: "validator::confirmation", "No proposals can be confirmed");
359 drop(append_lock);
360 return Ok(vec![])
361 }
362
363 let confirmed_fork = confirmed_fork.unwrap();
365 let mut forks = self.consensus.forks.write().await;
366 let fork = &mut forks[confirmed_fork];
367
368 let excess = (fork.proposals.len() - self.consensus.confirmation_threshold) + 1;
370
371 let rest_proposals = fork.proposals.split_off(excess);
373 let rest_diffs = fork.diffs.split_off(excess);
374 let confirmed_proposals = fork.proposals.clone();
375 let diffs = fork.diffs.clone();
376 fork.proposals = rest_proposals;
377 fork.diffs = rest_diffs;
378
379 let confirmed_blocks =
381 fork.overlay.lock().unwrap().get_blocks_by_hash(&confirmed_proposals)?;
382
383 let mut module = self.consensus.module.write().await;
385 let mut confirmed_txs = vec![];
386 let mut state_inverse_diffs_heights = vec![];
387 let mut state_inverse_diffs = vec![];
388 info!(target: "validator::confirmation", "Confirming proposals:");
389 for (index, proposal) in confirmed_proposals.iter().enumerate() {
390 info!(target: "validator::confirmation", "\t{proposal} ({}) - {}", confirmed_blocks[index].header.pow_data, confirmed_blocks[index].header.height);
391 fork.overlay.lock().unwrap().overlay.lock().unwrap().apply_diff(&diffs[index])?;
392 let next_difficulty = module.next_difficulty()?;
393 module.append(&confirmed_blocks[index].header, &next_difficulty)?;
394 confirmed_txs.extend_from_slice(&confirmed_blocks[index].txs);
395 state_inverse_diffs_heights.push(confirmed_blocks[index].header.height);
396 state_inverse_diffs.push(diffs[index].inverse());
397 }
398 drop(module);
399 drop(forks);
400
401 self.blockchain
403 .blocks
404 .insert_state_inverse_diff(&state_inverse_diffs_heights, &state_inverse_diffs)?;
405
406 self.consensus.reset_forks(&confirmed_proposals, &confirmed_fork, &confirmed_txs).await?;
408 info!(target: "validator::confirmation", "Confirmation completed!");
409
410 drop(append_lock);
412
413 Ok(confirmed_blocks)
414 }
415
416 pub async fn add_checkpoint_blocks(
424 &self,
425 blocks: &[BlockInfo],
426 headers: &[HeaderHash],
427 ) -> Result<()> {
428 if blocks.len() != headers.len() {
430 return Err(Error::InvalidInputLengths)
431 }
432
433 debug!(target: "validator::add_checkpoint_blocks", "Instantiating BlockchainOverlay");
434 let overlay = BlockchainOverlay::new(&self.blockchain)?;
435
436 let last_difficulty = self.blockchain.last_block_difficulty()?;
438 let mut current_targets_rank = last_difficulty.ranks.targets_rank;
439 let mut current_hashes_rank = last_difficulty.ranks.hashes_rank;
440
441 let mut module = self.consensus.module.read().await.clone();
443
444 let mut state_monotree = overlay.lock().unwrap().get_state_monotree()?;
446
447 let mut removed_txs = vec![];
449
450 let mut diffs_heights = vec![];
452 let mut diffs = vec![];
453 let mut inverse_diffs = vec![];
454
455 for (index, block) in blocks.iter().enumerate() {
457 match verify_checkpoint_block(
459 &overlay,
460 &diffs,
461 &mut state_monotree,
462 block,
463 &headers[index],
464 module.target,
465 )
466 .await
467 {
468 Ok(()) => { }
469 Err(Error::BlockAlreadyExists(_)) => continue,
471 Err(e) => {
472 error!(target: "validator::add_checkpoint_blocks", "Erroneous block found in set: {e}");
473 overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
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<()> {
541 debug!(target: "validator::add_test_blocks", "Instantiating BlockchainOverlay");
542 let overlay = BlockchainOverlay::new(&self.blockchain)?;
543
544 let mut previous = &overlay.lock().unwrap().last_block()?;
546
547 let last_difficulty = self.blockchain.last_block_difficulty()?;
549 let mut current_targets_rank = last_difficulty.ranks.targets_rank;
550 let mut current_hashes_rank = last_difficulty.ranks.hashes_rank;
551
552 let mut module = self.consensus.module.read().await.clone();
554
555 let mut state_monotree = overlay.lock().unwrap().get_state_monotree()?;
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(
570 &overlay,
571 &diffs,
572 &module,
573 &mut state_monotree,
574 block,
575 previous,
576 self.verify_fees,
577 )
578 .await
579 {
580 Ok(()) => { }
581 Err(Error::BlockAlreadyExists(_)) => {
583 previous = block;
584 continue
585 }
586 Err(e) => {
587 error!(target: "validator::add_test_blocks", "Erroneous block found in set: {e}");
588 overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
589 return Err(Error::BlockIsInvalid(block.hash().as_string()))
590 }
591 };
592
593 let (next_target, next_difficulty) = module.next_mine_target_and_difficulty()?;
595
596 let (target_distance_sq, hash_distance_sq) = block_rank(block, &next_target)?;
598
599 current_targets_rank += target_distance_sq.clone();
601 current_hashes_rank += hash_distance_sq.clone();
602
603 let cumulative_difficulty =
605 module.cumulative_difficulty.clone() + next_difficulty.clone();
606 let ranks = BlockRanks::new(
607 target_distance_sq,
608 current_targets_rank.clone(),
609 hash_distance_sq,
610 current_hashes_rank.clone(),
611 );
612 let block_difficulty = BlockDifficulty::new(
613 block.header.height,
614 block.header.timestamp,
615 next_difficulty,
616 cumulative_difficulty,
617 ranks,
618 );
619 module.append_difficulty(&overlay, &block.header, block_difficulty)?;
620
621 for tx in &block.txs {
623 removed_txs.push(tx.clone());
624 }
625
626 diffs_heights.push(block.header.height);
628 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&diffs)?;
629 inverse_diffs.push(diff.inverse());
630 diffs.push(diff);
631
632 previous = block;
634 }
635
636 debug!(target: "validator::add_test_blocks", "Applying overlay changes");
637 overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
638
639 self.blockchain.blocks.insert_state_inverse_diff(&diffs_heights, &inverse_diffs)?;
641
642 self.blockchain.remove_pending_txs(&removed_txs)?;
644 self.purge_pending_txs().await?;
645
646 *self.consensus.module.write().await = module;
648
649 Ok(())
650 }
651
652 pub async fn add_test_transactions(
661 &self,
662 txs: &[Transaction],
663 verifying_block_height: u32,
664 block_target: u32,
665 write: bool,
666 verify_fees: bool,
667 ) -> Result<(u64, u64)> {
668 debug!(target: "validator::add_transactions", "Instantiating BlockchainOverlay");
669 let overlay = BlockchainOverlay::new(&self.blockchain)?;
670
671 let verify_result = verify_transactions(
673 &overlay,
674 verifying_block_height,
675 block_target,
676 txs,
677 &mut MerkleTree::new(1),
678 verify_fees,
679 )
680 .await;
681
682 let lock = overlay.lock().unwrap();
683 let mut overlay = lock.overlay.lock().unwrap();
684
685 if let Err(e) = verify_result {
686 overlay.purge_new_trees()?;
687 return Err(e)
688 }
689
690 let gas_values = verify_result.unwrap();
691
692 if !write {
693 debug!(target: "validator::add_transactions", "Skipping apply of state updates because write=false");
694 overlay.purge_new_trees()?;
695 return Ok(gas_values)
696 }
697
698 debug!(target: "validator::add_transactions", "Applying overlay changes");
699 overlay.apply()?;
700 Ok(gas_values)
701 }
702
703 pub async fn add_test_producer_transaction(
709 &self,
710 tx: &Transaction,
711 verifying_block_height: u32,
712 block_target: u32,
713 write: bool,
714 ) -> Result<()> {
715 debug!(target: "validator::add_test_producer_transaction", "Instantiating BlockchainOverlay");
716 let overlay = BlockchainOverlay::new(&self.blockchain)?;
717
718 let mut erroneous_txs = vec![];
720 if let Err(e) = verify_producer_transaction(
721 &overlay,
722 verifying_block_height,
723 block_target,
724 tx,
725 &mut MerkleTree::new(1),
726 )
727 .await
728 {
729 warn!(target: "validator::add_test_producer_transaction", "Transaction verification failed: {e}");
730 erroneous_txs.push(tx.clone());
731 }
732
733 let lock = overlay.lock().unwrap();
734 let mut overlay = lock.overlay.lock().unwrap();
735 if !erroneous_txs.is_empty() {
736 warn!(target: "validator::add_test_producer_transaction", "Erroneous transactions found in set");
737 overlay.purge_new_trees()?;
738 return Err(TxVerifyFailed::ErroneousTxs(erroneous_txs).into())
739 }
740
741 if !write {
742 debug!(target: "validator::add_test_producer_transaction", "Skipping apply of state updates because write=false");
743 overlay.purge_new_trees()?;
744 return Ok(())
745 }
746
747 debug!(target: "validator::add_test_producer_transaction", "Applying overlay changes");
748 overlay.apply()?;
749 Ok(())
750 }
751
752 pub async fn validate_blockchain(
756 &self,
757 pow_target: u32,
758 pow_fixed_difficulty: Option<BigUint>,
759 ) -> Result<()> {
760 let mut blocks_count = self.blockchain.len() as u32;
762 info!(target: "validator::validate_blockchain", "Validating {blocks_count} blocks...");
763 if blocks_count == 0 {
764 info!(target: "validator::validate_blockchain", "Blockchain validated successfully!");
765 return Ok(())
766 }
767
768 let sled_db = sled::Config::new().temporary(true).open()?;
770 let blockchain = Blockchain::new(&sled_db)?;
771 let overlay = BlockchainOverlay::new(&blockchain)?;
772
773 let mut previous = self.blockchain.genesis_block()?;
775
776 deploy_native_contracts(&overlay, pow_target).await?;
778
779 verify_genesis_block(&overlay, &previous, pow_target).await?;
781 info!(target: "validator::validate_blockchain", "Genesis block validated successfully!");
782
783 overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
785
786 let mut module = PoWModule::new(blockchain, pow_target, pow_fixed_difficulty, Some(0))?;
788
789 let mut state_monotree = overlay.lock().unwrap().get_state_monotree()?;
791
792 let mut diffs = vec![];
794
795 info!(target: "validator::validate_blockchain", "Validating rest blocks...");
797 blocks_count -= 1;
798 let mut index = 1;
799 while index <= blocks_count {
800 let block = self.blockchain.get_blocks_by_heights(&[index])?[0].clone();
802
803 if let Err(e) = verify_block(
805 &overlay,
806 &diffs,
807 &module,
808 &mut state_monotree,
809 &block,
810 &previous,
811 self.verify_fees,
812 )
813 .await
814 {
815 error!(target: "validator::validate_blockchain", "Erroneous block found in set: {e}");
816 overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
817 return Err(Error::BlockIsInvalid(block.hash().as_string()))
818 };
819
820 module.append(&block.header, &module.next_difficulty()?)?;
822
823 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&diffs)?;
825 diffs.push(diff);
826
827 previous = block;
829
830 info!(target: "validator::validate_blockchain", "Block {index}/{blocks_count} validated successfully!");
831 index += 1;
832 }
833
834 info!(target: "validator::validate_blockchain", "Blockchain validated successfully!");
835 Ok(())
836 }
837
838 pub async fn current_mining_randomx_key(&self) -> Result<HeaderHash> {
842 self.consensus.current_mining_randomx_key().await
843 }
844
845 pub async fn best_current_fork(&self) -> Result<Fork> {
847 self.consensus.best_current_fork().await
848 }
849
850 pub async fn best_fork_next_block_height(&self) -> Result<u32> {
852 let forks = self.consensus.forks.read().await;
853 let fork = &forks[best_fork_index(&forks)?];
854 let next_block_height = fork.get_next_block_height()?;
855 drop(forks);
856
857 Ok(next_block_height)
858 }
859
860 pub async fn reset_to_height(&self, height: u32) -> Result<()> {
863 info!(target: "validator::reset_to_height", "Resetting validator to height: {height}");
864 let append_lock = self.consensus.append_lock.write().await;
866
867 self.blockchain.reset_to_height(height)?;
869
870 self.consensus.reset_pow_module().await?;
872
873 self.consensus.purge_forks().await?;
875
876 drop(append_lock);
878
879 info!(target: "validator::reset_to_height", "Validator reset successfully!");
880
881 Ok(())
882 }
883
884 pub async fn rebuild_block_difficulties(
888 &self,
889 pow_target: u32,
890 pow_fixed_difficulty: Option<BigUint>,
891 ) -> Result<()> {
892 info!(target: "validator::rebuild_block_difficulties", "Rebuilding validator block difficulties...");
893 let append_lock = self.consensus.append_lock.write().await;
895
896 self.blockchain.blocks.difficulty.clear()?;
898
899 let mut blocks_count = self.blockchain.len() as u32;
901 info!(target: "validator::rebuild_block_difficulties", "Rebuilding {blocks_count} block difficulties...");
902 if blocks_count == 0 {
903 info!(target: "validator::reset_to_height", "Validator block difficulties rebuilt successfully!");
904 return Ok(())
905 }
906
907 let mut module =
910 PoWModule::new(self.blockchain.clone(), pow_target, pow_fixed_difficulty, Some(0))?;
911
912 let genesis_block = self.blockchain.genesis_block()?;
914 let last_difficulty = BlockDifficulty::genesis(genesis_block.header.timestamp);
915 let mut targets_rank = last_difficulty.ranks.targets_rank;
916 let mut hashes_rank = last_difficulty.ranks.hashes_rank;
917
918 blocks_count -= 1;
920 let mut index = 1;
921 while index <= blocks_count {
922 let block = self.blockchain.get_blocks_by_heights(&[index])?[0].clone();
924
925 let (next_target, next_difficulty) = module.next_mine_target_and_difficulty()?;
927
928 let (target_distance_sq, hash_distance_sq) = block_rank(&block, &next_target)?;
930
931 targets_rank += target_distance_sq.clone();
933 hashes_rank += hash_distance_sq.clone();
934
935 let cumulative_difficulty =
937 module.cumulative_difficulty.clone() + next_difficulty.clone();
938 let ranks = BlockRanks::new(
939 target_distance_sq,
940 targets_rank.clone(),
941 hash_distance_sq,
942 hashes_rank.clone(),
943 );
944 let block_difficulty = BlockDifficulty::new(
945 block.header.height,
946 block.header.timestamp,
947 next_difficulty,
948 cumulative_difficulty,
949 ranks,
950 );
951 module.append(&block.header, &block_difficulty.difficulty)?;
952
953 self.blockchain.blocks.insert_difficulty(&[block_difficulty])?;
955
956 info!(target: "validator::validate_blockchain", "Block {index}/{blocks_count} difficulty added successfully!");
957 index += 1;
958 }
959
960 self.blockchain.sled_db.flush()?;
962
963 drop(append_lock);
965
966 info!(target: "validator::reset_to_height", "Validator block difficulties rebuilt successfully!");
967
968 Ok(())
969 }
970}