1use std::{collections::HashMap, sync::Arc};
20
21use darkfi_sdk::{blockchain::compute_fee, 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;
59
60pub mod utils;
62use utils::{best_fork_index, block_rank, deploy_native_contracts};
63
64#[derive(Clone)]
66pub struct ValidatorConfig {
67 pub confirmation_threshold: usize,
69 pub max_forks: usize,
71 pub pow_target: u32,
73 pub pow_fixed_difficulty: Option<BigUint>,
75 pub genesis_block: BlockInfo,
77 pub verify_fees: bool,
79}
80
81pub type ValidatorPtr = Arc<RwLock<Validator>>;
83
84pub struct Validator {
86 pub blockchain: Blockchain,
88 pub consensus: Consensus,
90 pub synced: bool,
92 pub verify_fees: bool,
94}
95
96impl Validator {
97 pub async fn new(db: &sled::Db, config: &ValidatorConfig) -> Result<ValidatorPtr> {
98 info!(target: "validator::new", "Initializing Validator");
99
100 info!(target: "validator::new", "Initializing Blockchain");
101 let blockchain = Blockchain::new(db)?;
102
103 let overlay = BlockchainOverlay::new(&blockchain)?;
106
107 deploy_native_contracts(&overlay, config.pow_target).await?;
109
110 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&[])?;
113 overlay.lock().unwrap().contracts.update_state_monotree(&diff)?;
114
115 if blockchain.genesis().is_err() {
117 info!(target: "validator::new", "Appending genesis block");
118 verify_genesis_block(&overlay, &[diff], &config.genesis_block, config.pow_target)
119 .await?;
120 };
121
122 overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
124
125 info!(target: "validator::new", "Initializing Consensus");
126 let consensus = Consensus::new(
127 blockchain.clone(),
128 config.confirmation_threshold,
129 config.max_forks,
130 config.pow_target,
131 config.pow_fixed_difficulty.clone(),
132 )?;
133
134 let state = Arc::new(RwLock::new(Self {
136 blockchain,
137 consensus,
138 synced: false,
139 verify_fees: config.verify_fees,
140 }));
141
142 info!(target: "validator::new", "Finished initializing validator");
143 Ok(state)
144 }
145
146 pub async fn calculate_fee(&self, tx: &Transaction, verify_fee: bool) -> Result<u64> {
154 let index = best_fork_index(&self.consensus.forks)?;
156 let fork = self.consensus.forks[index].full_clone()?;
157
158 let mut vks: HashMap<[u8; 32], HashMap<String, VerifyingKey>> = HashMap::new();
160 for call in &tx.calls {
161 vks.insert(call.data.contract_id.to_bytes(), HashMap::new());
162 }
163
164 let next_block_height = fork.get_next_block_height()?;
166
167 let verify_result = verify_transaction(
169 &fork.overlay,
170 next_block_height,
171 self.consensus.module.target,
172 tx,
173 &mut MerkleTree::new(1),
174 &mut vks,
175 verify_fee,
176 )
177 .await?;
178
179 Ok(compute_fee(&verify_result.total_gas_used()))
180 }
181
182 pub async fn append_tx(&mut self, tx: &Transaction, write: bool) -> Result<()> {
188 let tx_hash = tx.hash();
189
190 let tx_in_txstore = self.blockchain.transactions.contains(&tx_hash)?;
192 let tx_in_pending_txs_store = self.blockchain.transactions.contains_pending(&tx_hash)?;
193
194 if tx_in_txstore || tx_in_pending_txs_store {
195 debug!(target: "validator::append_tx", "We have already seen tx: {tx_hash}");
196 return Err(TxVerifyFailed::AlreadySeenTx(tx_hash.as_string()).into())
197 }
198
199 info!(target: "validator::append_tx", "Starting state transition validation for tx: {tx_hash}");
201 let tx_vec = [tx.clone()];
202 let mut valid = false;
203
204 for fork in self.consensus.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.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 if !valid {
241 return Err(TxVerifyFailed::ErroneousTxs(tx_vec.to_vec()).into())
242 }
243
244 if write {
246 self.blockchain.add_pending_txs(&tx_vec)?;
247 info!(target: "validator::append_tx", "Appended tx {tx_hash} to pending txs store");
248 }
249
250 Ok(())
251 }
252
253 pub async fn purge_pending_txs(&mut self) -> Result<()> {
259 info!(target: "validator::purge_pending_txs", "Removing invalid transactions from pending transactions store...");
260
261 let pending_txs = self.blockchain.get_pending_txs()?;
263 if pending_txs.is_empty() {
264 info!(target: "validator::purge_pending_txs", "No pending transactions found");
265 return Ok(())
266 }
267
268 let mut removed_txs = vec![];
269 for tx in pending_txs {
270 let tx_hash = tx.hash();
271 let tx_vec = [tx.clone()];
272 let mut valid = false;
273
274 for fork in self.consensus.forks.iter_mut() {
277 let fork_clone = fork.full_clone()?;
279
280 let next_block_height = fork_clone.get_next_block_height()?;
282
283 let verify_result = verify_transactions(
285 &fork_clone.overlay,
286 next_block_height,
287 self.consensus.module.target,
288 &tx_vec,
289 &mut MerkleTree::new(1),
290 self.verify_fees,
291 )
292 .await;
293
294 match verify_result {
296 Ok(_) => {
297 valid = true;
298 continue
299 }
300 Err(Error::TxVerifyFailed(TxVerifyFailed::ErroneousTxs(_))) => {}
301 Err(e) => return Err(e),
302 }
303
304 fork.mempool.retain(|x| *x != tx_hash);
306 }
307
308 if !valid {
311 removed_txs.push(tx)
312 }
313 }
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(&mut self, proposal: &Proposal) -> Result<()> {
328 self.consensus.append_proposal(proposal, self.synced, self.verify_fees).await
329 }
330
331 pub async fn confirmation(&mut self) -> Result<Vec<BlockInfo>> {
335 info!(target: "validator::confirmation", "Performing confirmation check");
336
337 let confirmed_fork = self.consensus.confirmation().await?;
339 if confirmed_fork.is_none() {
340 info!(target: "validator::confirmation", "No proposals can be confirmed");
341 return Ok(vec![])
342 }
343
344 let confirmed_fork = confirmed_fork.unwrap();
346 let fork = &mut self.consensus.forks[confirmed_fork];
347
348 let excess = (fork.proposals.len() - self.consensus.confirmation_threshold) + 1;
350
351 let rest_proposals = fork.proposals.split_off(excess);
353 let rest_diffs = fork.diffs.split_off(excess);
354 let confirmed_proposals = fork.proposals.clone();
355 let diffs = fork.diffs.clone();
356 fork.proposals = rest_proposals;
357 fork.diffs = rest_diffs;
358
359 let confirmed_blocks =
361 fork.overlay.lock().unwrap().get_blocks_by_hash(&confirmed_proposals)?;
362
363 let mut module = self.consensus.module.clone();
365 let mut confirmed_txs = vec![];
366 let mut state_inverse_diffs_heights = vec![];
367 let mut state_inverse_diffs = vec![];
368 info!(target: "validator::confirmation", "Confirming proposals:");
369 for (index, proposal) in confirmed_proposals.iter().enumerate() {
370 info!(target: "validator::confirmation", "\t{proposal} ({}) - {}", confirmed_blocks[index].header.pow_data, confirmed_blocks[index].header.height);
371 fork.overlay.lock().unwrap().overlay.lock().unwrap().apply_diff(&diffs[index])?;
372 let next_difficulty = module.next_difficulty()?;
373 module.append(&confirmed_blocks[index].header, &next_difficulty)?;
374 confirmed_txs.extend_from_slice(&confirmed_blocks[index].txs);
375 state_inverse_diffs_heights.push(confirmed_blocks[index].header.height);
376 state_inverse_diffs.push(diffs[index].inverse());
377 }
378 self.consensus.module = module;
379
380 self.blockchain
382 .blocks
383 .insert_state_inverse_diff(&state_inverse_diffs_heights, &state_inverse_diffs)?;
384
385 self.consensus.reset_forks(&confirmed_proposals, &confirmed_fork, &confirmed_txs).await?;
387 info!(target: "validator::confirmation", "Confirmation completed!");
388
389 Ok(confirmed_blocks)
390 }
391
392 pub async fn add_checkpoint_blocks(
404 &mut self,
405 blocks: &[BlockInfo],
406 headers: &[HeaderHash],
407 ) -> Result<()> {
408 if blocks.len() != headers.len() {
410 return Err(Error::InvalidInputLengths)
411 }
412
413 debug!(target: "validator::add_checkpoint_blocks", "Instantiating BlockchainOverlay");
414 let overlay = BlockchainOverlay::new(&self.blockchain)?;
415
416 let last_difficulty = self.blockchain.last_block_difficulty()?;
418 let mut current_targets_rank = last_difficulty.ranks.targets_rank;
419 let mut current_hashes_rank = last_difficulty.ranks.hashes_rank;
420
421 let mut module = self.consensus.module.clone();
423
424 let mut removed_txs = vec![];
427
428 let mut diffs_heights = vec![];
431 let mut diffs = vec![];
432 let mut inverse_diffs = vec![];
433
434 for (index, block) in blocks.iter().enumerate() {
436 match verify_checkpoint_block(&overlay, &diffs, block, &headers[index], module.target)
438 .await
439 {
440 Ok(()) => { }
441 Err(Error::BlockAlreadyExists(_)) => continue,
443 Err(e) => {
444 error!(target: "validator::add_checkpoint_blocks", "Erroneous block found in set: {e}");
445 return Err(Error::BlockIsInvalid(block.hash().as_string()))
446 }
447 };
448
449 let (next_target, next_difficulty) = module.next_mine_target_and_difficulty()?;
451
452 let (target_distance_sq, hash_distance_sq) = block_rank(block, &next_target)?;
454
455 current_targets_rank += target_distance_sq.clone();
457 current_hashes_rank += hash_distance_sq.clone();
458
459 let cumulative_difficulty =
461 module.cumulative_difficulty.clone() + next_difficulty.clone();
462 let ranks = BlockRanks::new(
463 target_distance_sq,
464 current_targets_rank.clone(),
465 hash_distance_sq,
466 current_hashes_rank.clone(),
467 );
468 let block_difficulty = BlockDifficulty::new(
469 block.header.height,
470 block.header.timestamp,
471 next_difficulty,
472 cumulative_difficulty,
473 ranks,
474 );
475 module.append_difficulty(&overlay, &block.header, block_difficulty)?;
476
477 for tx in &block.txs {
479 removed_txs.push(tx.clone());
480 }
481
482 diffs_heights.push(block.header.height);
484 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&diffs)?;
485 inverse_diffs.push(diff.inverse());
486 diffs.push(diff);
487 }
488
489 debug!(target: "validator::add_checkpoint_blocks", "Applying overlay changes");
490 overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
491
492 self.blockchain.blocks.insert_state_inverse_diff(&diffs_heights, &inverse_diffs)?;
494
495 self.blockchain.remove_pending_txs(&removed_txs)?;
497
498 self.consensus.module = module.clone();
500
501 self.consensus.forks = vec![Fork::new(self.blockchain.clone(), module).await?];
503
504 Ok(())
505 }
506
507 pub async fn add_test_blocks(&mut self, blocks: &[BlockInfo]) -> Result<()> {
514 debug!(target: "validator::add_test_blocks", "Instantiating BlockchainOverlay");
515 let overlay = BlockchainOverlay::new(&self.blockchain)?;
516
517 let mut previous = &overlay.lock().unwrap().last_block()?;
519
520 let last_difficulty = self.blockchain.last_block_difficulty()?;
522 let mut current_targets_rank = last_difficulty.ranks.targets_rank;
523 let mut current_hashes_rank = last_difficulty.ranks.hashes_rank;
524
525 let mut module = self.consensus.module.clone();
527
528 let mut removed_txs = vec![];
531
532 let mut diffs_heights = vec![];
535 let mut diffs = vec![];
536 let mut inverse_diffs = vec![];
537
538 for block in blocks {
540 match verify_block(
542 &overlay,
543 &diffs,
544 &mut module,
545 block,
546 previous,
547 true,
548 self.verify_fees,
549 )
550 .await
551 {
552 Ok(()) => { }
553 Err(Error::BlockAlreadyExists(_)) => {
555 previous = block;
556 continue
557 }
558 Err(e) => {
559 error!(target: "validator::add_test_blocks", "Erroneous block found in set: {e}");
560 return Err(Error::BlockIsInvalid(block.hash().as_string()))
561 }
562 };
563
564 let (next_target, next_difficulty) = module.next_mine_target_and_difficulty()?;
566
567 let (target_distance_sq, hash_distance_sq) = block_rank(block, &next_target)?;
569
570 current_targets_rank += target_distance_sq.clone();
572 current_hashes_rank += hash_distance_sq.clone();
573
574 let cumulative_difficulty =
576 module.cumulative_difficulty.clone() + next_difficulty.clone();
577 let ranks = BlockRanks::new(
578 target_distance_sq,
579 current_targets_rank.clone(),
580 hash_distance_sq,
581 current_hashes_rank.clone(),
582 );
583 let block_difficulty = BlockDifficulty::new(
584 block.header.height,
585 block.header.timestamp,
586 next_difficulty,
587 cumulative_difficulty,
588 ranks,
589 );
590 module.append_difficulty(&overlay, &block.header, block_difficulty)?;
591
592 for tx in &block.txs {
594 removed_txs.push(tx.clone());
595 }
596
597 diffs_heights.push(block.header.height);
599 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&diffs)?;
600 inverse_diffs.push(diff.inverse());
601 diffs.push(diff);
602
603 previous = block;
605 }
606
607 debug!(target: "validator::add_test_blocks", "Applying overlay changes");
608 overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
609
610 self.blockchain.blocks.insert_state_inverse_diff(&diffs_heights, &inverse_diffs)?;
612
613 self.blockchain.remove_pending_txs(&removed_txs)?;
616 self.purge_pending_txs().await?;
617
618 self.consensus.module = module;
620
621 Ok(())
622 }
623
624 pub async fn add_test_transactions(
637 &self,
638 txs: &[Transaction],
639 verifying_block_height: u32,
640 block_target: u32,
641 write: bool,
642 verify_fees: bool,
643 ) -> Result<(u64, u64)> {
644 debug!(target: "validator::add_transactions", "Instantiating BlockchainOverlay");
645 let overlay = BlockchainOverlay::new(&self.blockchain)?;
646
647 let verify_result = verify_transactions(
649 &overlay,
650 verifying_block_height,
651 block_target,
652 txs,
653 &mut MerkleTree::new(1),
654 verify_fees,
655 )
656 .await;
657
658 let lock = overlay.lock().unwrap();
659 let mut overlay = lock.overlay.lock().unwrap();
660
661 let gas_values = verify_result?;
662
663 if !write {
664 debug!(target: "validator::add_transactions", "Skipping apply of state updates because write=false");
665 return Ok(gas_values)
666 }
667
668 debug!(target: "validator::add_transactions", "Applying overlay changes");
669 overlay.apply()?;
670 Ok(gas_values)
671 }
672
673 pub async fn add_test_producer_transaction(
681 &self,
682 tx: &Transaction,
683 verifying_block_height: u32,
684 block_target: u32,
685 write: bool,
686 ) -> Result<()> {
687 debug!(target: "validator::add_test_producer_transaction", "Instantiating BlockchainOverlay");
688 let overlay = BlockchainOverlay::new(&self.blockchain)?;
689
690 let mut erroneous_txs = vec![];
692 if let Err(e) = verify_producer_transaction(
693 &overlay,
694 verifying_block_height,
695 block_target,
696 tx,
697 &mut MerkleTree::new(1),
698 )
699 .await
700 {
701 warn!(target: "validator::add_test_producer_transaction", "Transaction verification failed: {e}");
702 erroneous_txs.push(tx.clone());
703 }
704
705 let lock = overlay.lock().unwrap();
706 let mut overlay = lock.overlay.lock().unwrap();
707 if !erroneous_txs.is_empty() {
708 warn!(target: "validator::add_test_producer_transaction", "Erroneous transactions found in set");
709 return Err(TxVerifyFailed::ErroneousTxs(erroneous_txs).into())
710 }
711
712 if !write {
713 debug!(target: "validator::add_test_producer_transaction", "Skipping apply of state updates because write=false");
714 return Ok(())
715 }
716
717 debug!(target: "validator::add_test_producer_transaction", "Applying overlay changes");
718 overlay.apply()?;
719 Ok(())
720 }
721
722 pub async fn validate_blockchain(
729 &self,
730 pow_target: u32,
731 pow_fixed_difficulty: Option<BigUint>,
732 ) -> Result<()> {
733 let mut blocks_count = self.blockchain.len() as u32;
735 info!(target: "validator::validate_blockchain", "Validating {blocks_count} blocks...");
736 if blocks_count == 0 {
737 info!(target: "validator::validate_blockchain", "Blockchain validated successfully!");
738 return Ok(())
739 }
740
741 let sled_db = sled::Config::new().temporary(true).open()?;
743 let blockchain = Blockchain::new(&sled_db)?;
744 let overlay = BlockchainOverlay::new(&blockchain)?;
745
746 let mut previous = self.blockchain.genesis_block()?;
748
749 deploy_native_contracts(&overlay, pow_target).await?;
751
752 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&[])?;
754 overlay.lock().unwrap().contracts.update_state_monotree(&diff)?;
755
756 verify_genesis_block(&overlay, &[diff], &previous, pow_target).await?;
758 info!(target: "validator::validate_blockchain", "Genesis block validated successfully!");
759
760 overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
762
763 let mut module = PoWModule::new(blockchain, pow_target, pow_fixed_difficulty, Some(0))?;
765
766 let mut diffs = vec![];
768
769 info!(target: "validator::validate_blockchain", "Validating rest blocks...");
771 blocks_count -= 1;
772 let mut index = 1;
773 while index <= blocks_count {
774 let block = self.blockchain.get_blocks_by_heights(&[index])?[0].clone();
776
777 if let Err(e) = verify_block(
779 &overlay,
780 &diffs,
781 &mut module,
782 &block,
783 &previous,
784 false,
785 self.verify_fees,
786 )
787 .await
788 {
789 error!(target: "validator::validate_blockchain", "Erroneous block found in set: {e}");
790 return Err(Error::BlockIsInvalid(block.hash().as_string()))
791 };
792
793 module.append(&block.header, &module.next_difficulty()?)?;
795
796 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&diffs)?;
798 diffs.push(diff);
799
800 previous = block;
802
803 info!(target: "validator::validate_blockchain", "Block {index}/{blocks_count} validated successfully!");
804 index += 1;
805 }
806
807 info!(target: "validator::validate_blockchain", "Blockchain validated successfully!");
808 Ok(())
809 }
810
811 pub async fn current_mining_randomx_key(&self) -> Result<HeaderHash> {
815 self.consensus.current_mining_randomx_key().await
816 }
817
818 pub async fn best_current_fork(&self) -> Result<Fork> {
820 self.consensus.best_current_fork().await
821 }
822
823 pub async fn best_fork_next_block_height(&self) -> Result<u32> {
826 let index = best_fork_index(&self.consensus.forks)?;
827 let fork = &self.consensus.forks[index];
828 let next_block_height = fork.get_next_block_height()?;
829
830 Ok(next_block_height)
831 }
832
833 pub async fn reset_to_height(&mut self, height: u32) -> Result<()> {
836 info!(target: "validator::reset_to_height", "Resetting validator to height: {height}");
837 self.blockchain.reset_to_height(height)?;
839
840 self.consensus.reset_pow_module().await?;
842
843 self.consensus.purge_forks().await?;
845
846 info!(target: "validator::reset_to_height", "Validator reset successfully!");
847
848 Ok(())
849 }
850
851 pub async fn rebuild_block_difficulties(
855 &self,
856 pow_target: u32,
857 pow_fixed_difficulty: Option<BigUint>,
858 ) -> Result<()> {
859 info!(target: "validator::rebuild_block_difficulties", "Rebuilding validator block difficulties...");
860 self.blockchain.blocks.difficulty.clear()?;
862
863 let mut blocks_count = self.blockchain.len() as u32;
865 info!(target: "validator::rebuild_block_difficulties", "Rebuilding {blocks_count} block difficulties...");
866 if blocks_count == 0 {
867 info!(target: "validator::rebuild_block_difficulties", "Validator block difficulties rebuilt successfully!");
868 return Ok(())
869 }
870
871 let mut module =
874 PoWModule::new(self.blockchain.clone(), pow_target, pow_fixed_difficulty, Some(0))?;
875
876 let genesis_block = self.blockchain.genesis_block()?;
878 let last_difficulty = BlockDifficulty::genesis(genesis_block.header.timestamp);
879 let mut targets_rank = last_difficulty.ranks.targets_rank;
880 let mut hashes_rank = last_difficulty.ranks.hashes_rank;
881
882 blocks_count -= 1;
884 let mut index = 1;
885 while index <= blocks_count {
886 let block = self.blockchain.get_blocks_by_heights(&[index])?[0].clone();
888
889 let (next_target, next_difficulty) = module.next_mine_target_and_difficulty()?;
891
892 let (target_distance_sq, hash_distance_sq) = block_rank(&block, &next_target)?;
894
895 targets_rank += target_distance_sq.clone();
897 hashes_rank += hash_distance_sq.clone();
898
899 let cumulative_difficulty =
901 module.cumulative_difficulty.clone() + next_difficulty.clone();
902 let ranks = BlockRanks::new(
903 target_distance_sq,
904 targets_rank.clone(),
905 hash_distance_sq,
906 hashes_rank.clone(),
907 );
908 let block_difficulty = BlockDifficulty::new(
909 block.header.height,
910 block.header.timestamp,
911 next_difficulty,
912 cumulative_difficulty,
913 ranks,
914 );
915 module.append(&block.header, &block_difficulty.difficulty)?;
916
917 self.blockchain.blocks.insert_difficulty(&[block_difficulty])?;
919
920 info!(target: "validator::rebuild_block_difficulties", "Block {index}/{blocks_count} difficulty added successfully!");
921 index += 1;
922 }
923
924 self.blockchain.sled_db.flush()?;
926
927 info!(target: "validator::rebuild_block_difficulties", "Validator block difficulties rebuilt successfully!");
928
929 Ok(())
930 }
931}