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_difficulty, target_distance_sq, hash_distance_sq) =
451 block_rank(&mut module, block)?;
452
453 current_targets_rank += target_distance_sq.clone();
455 current_hashes_rank += hash_distance_sq.clone();
456
457 let cumulative_difficulty =
459 module.cumulative_difficulty.clone() + next_difficulty.clone();
460 let ranks = BlockRanks::new(
461 target_distance_sq,
462 current_targets_rank.clone(),
463 hash_distance_sq,
464 current_hashes_rank.clone(),
465 );
466 let block_difficulty = BlockDifficulty::new(
467 block.header.height,
468 block.header.timestamp,
469 next_difficulty,
470 cumulative_difficulty,
471 ranks,
472 );
473 module.append_difficulty(&overlay, &block.header, block_difficulty)?;
474
475 for tx in &block.txs {
477 removed_txs.push(tx.clone());
478 }
479
480 diffs_heights.push(block.header.height);
482 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&diffs)?;
483 inverse_diffs.push(diff.inverse());
484 diffs.push(diff);
485 }
486
487 debug!(target: "validator::add_checkpoint_blocks", "Applying overlay changes");
488 overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
489
490 self.blockchain.blocks.insert_state_inverse_diff(&diffs_heights, &inverse_diffs)?;
492
493 self.blockchain.remove_pending_txs(&removed_txs)?;
495
496 self.consensus.module = module.clone();
498
499 self.consensus.forks = vec![Fork::new(self.blockchain.clone(), module).await?];
501
502 Ok(())
503 }
504
505 pub async fn add_test_blocks(&mut self, blocks: &[BlockInfo]) -> Result<()> {
512 debug!(target: "validator::add_test_blocks", "Instantiating BlockchainOverlay");
513 let overlay = BlockchainOverlay::new(&self.blockchain)?;
514
515 let mut previous = &overlay.lock().unwrap().last_block()?;
517
518 let last_difficulty = self.blockchain.last_block_difficulty()?;
520 let mut current_targets_rank = last_difficulty.ranks.targets_rank;
521 let mut current_hashes_rank = last_difficulty.ranks.hashes_rank;
522
523 let mut module = self.consensus.module.clone();
525
526 let mut removed_txs = vec![];
529
530 let mut diffs_heights = vec![];
533 let mut diffs = vec![];
534 let mut inverse_diffs = vec![];
535
536 for block in blocks {
538 match verify_block(
540 &overlay,
541 &diffs,
542 &mut module,
543 block,
544 previous,
545 true,
546 self.verify_fees,
547 )
548 .await
549 {
550 Ok(()) => { }
551 Err(Error::BlockAlreadyExists(_)) => {
553 previous = block;
554 continue
555 }
556 Err(e) => {
557 error!(target: "validator::add_test_blocks", "Erroneous block found in set: {e}");
558 return Err(Error::BlockIsInvalid(block.hash().as_string()))
559 }
560 };
561
562 let (next_difficulty, target_distance_sq, hash_distance_sq) =
564 block_rank(&mut module, block)?;
565
566 current_targets_rank += target_distance_sq.clone();
568 current_hashes_rank += hash_distance_sq.clone();
569
570 let cumulative_difficulty =
572 module.cumulative_difficulty.clone() + next_difficulty.clone();
573 let ranks = BlockRanks::new(
574 target_distance_sq,
575 current_targets_rank.clone(),
576 hash_distance_sq,
577 current_hashes_rank.clone(),
578 );
579 let block_difficulty = BlockDifficulty::new(
580 block.header.height,
581 block.header.timestamp,
582 next_difficulty,
583 cumulative_difficulty,
584 ranks,
585 );
586 module.append_difficulty(&overlay, &block.header, block_difficulty)?;
587
588 for tx in &block.txs {
590 removed_txs.push(tx.clone());
591 }
592
593 diffs_heights.push(block.header.height);
595 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&diffs)?;
596 inverse_diffs.push(diff.inverse());
597 diffs.push(diff);
598
599 previous = block;
601 }
602
603 debug!(target: "validator::add_test_blocks", "Applying overlay changes");
604 overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
605
606 self.blockchain.blocks.insert_state_inverse_diff(&diffs_heights, &inverse_diffs)?;
608
609 self.blockchain.remove_pending_txs(&removed_txs)?;
612 self.purge_pending_txs().await?;
613
614 self.consensus.module = module;
616
617 Ok(())
618 }
619
620 pub async fn add_test_transactions(
633 &self,
634 txs: &[Transaction],
635 verifying_block_height: u32,
636 block_target: u32,
637 write: bool,
638 verify_fees: bool,
639 ) -> Result<(u64, u64)> {
640 debug!(target: "validator::add_transactions", "Instantiating BlockchainOverlay");
641 let overlay = BlockchainOverlay::new(&self.blockchain)?;
642
643 let verify_result = verify_transactions(
645 &overlay,
646 verifying_block_height,
647 block_target,
648 txs,
649 &mut MerkleTree::new(1),
650 verify_fees,
651 )
652 .await;
653
654 let lock = overlay.lock().unwrap();
655 let mut overlay = lock.overlay.lock().unwrap();
656
657 let gas_values = verify_result?;
658
659 if !write {
660 debug!(target: "validator::add_transactions", "Skipping apply of state updates because write=false");
661 return Ok(gas_values)
662 }
663
664 debug!(target: "validator::add_transactions", "Applying overlay changes");
665 overlay.apply()?;
666 Ok(gas_values)
667 }
668
669 pub async fn add_test_producer_transaction(
677 &self,
678 tx: &Transaction,
679 verifying_block_height: u32,
680 block_target: u32,
681 write: bool,
682 ) -> Result<()> {
683 debug!(target: "validator::add_test_producer_transaction", "Instantiating BlockchainOverlay");
684 let overlay = BlockchainOverlay::new(&self.blockchain)?;
685
686 let mut erroneous_txs = vec![];
688 if let Err(e) = verify_producer_transaction(
689 &overlay,
690 verifying_block_height,
691 block_target,
692 tx,
693 &mut MerkleTree::new(1),
694 )
695 .await
696 {
697 warn!(target: "validator::add_test_producer_transaction", "Transaction verification failed: {e}");
698 erroneous_txs.push(tx.clone());
699 }
700
701 let lock = overlay.lock().unwrap();
702 let mut overlay = lock.overlay.lock().unwrap();
703 if !erroneous_txs.is_empty() {
704 warn!(target: "validator::add_test_producer_transaction", "Erroneous transactions found in set");
705 return Err(TxVerifyFailed::ErroneousTxs(erroneous_txs).into())
706 }
707
708 if !write {
709 debug!(target: "validator::add_test_producer_transaction", "Skipping apply of state updates because write=false");
710 return Ok(())
711 }
712
713 debug!(target: "validator::add_test_producer_transaction", "Applying overlay changes");
714 overlay.apply()?;
715 Ok(())
716 }
717
718 pub async fn validate_blockchain(
725 &self,
726 pow_target: u32,
727 pow_fixed_difficulty: Option<BigUint>,
728 ) -> Result<()> {
729 let mut blocks_count = self.blockchain.len() as u32;
731 info!(target: "validator::validate_blockchain", "Validating {blocks_count} blocks...");
732 if blocks_count == 0 {
733 info!(target: "validator::validate_blockchain", "Blockchain validated successfully!");
734 return Ok(())
735 }
736
737 let sled_db = sled::Config::new().temporary(true).open()?;
739 let blockchain = Blockchain::new(&sled_db)?;
740 let overlay = BlockchainOverlay::new(&blockchain)?;
741
742 let mut previous = self.blockchain.genesis_block()?;
744
745 deploy_native_contracts(&overlay, pow_target).await?;
747
748 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&[])?;
750 overlay.lock().unwrap().contracts.update_state_monotree(&diff)?;
751
752 verify_genesis_block(&overlay, &[diff], &previous, pow_target).await?;
754 info!(target: "validator::validate_blockchain", "Genesis block validated successfully!");
755
756 overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
758
759 let mut module = PoWModule::new(blockchain, pow_target, pow_fixed_difficulty, Some(0))?;
761
762 let mut diffs = vec![];
764
765 info!(target: "validator::validate_blockchain", "Validating rest blocks...");
767 blocks_count -= 1;
768 let mut index = 1;
769 while index <= blocks_count {
770 let block = self.blockchain.get_blocks_by_heights(&[index])?[0].clone();
772
773 if let Err(e) = verify_block(
775 &overlay,
776 &diffs,
777 &mut module,
778 &block,
779 &previous,
780 false,
781 self.verify_fees,
782 )
783 .await
784 {
785 error!(target: "validator::validate_blockchain", "Erroneous block found in set: {e}");
786 return Err(Error::BlockIsInvalid(block.hash().as_string()))
787 };
788
789 module.append(&block.header, &module.next_difficulty()?)?;
791
792 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&diffs)?;
794 diffs.push(diff);
795
796 previous = block;
798
799 info!(target: "validator::validate_blockchain", "Block {index}/{blocks_count} validated successfully!");
800 index += 1;
801 }
802
803 info!(target: "validator::validate_blockchain", "Blockchain validated successfully!");
804 Ok(())
805 }
806
807 pub async fn current_mining_randomx_key(&self) -> Result<HeaderHash> {
811 self.consensus.current_mining_randomx_key().await
812 }
813
814 pub async fn best_current_fork(&self) -> Result<Fork> {
816 self.consensus.best_current_fork().await
817 }
818
819 pub async fn best_fork_next_block_height(&self) -> Result<u32> {
822 let index = best_fork_index(&self.consensus.forks)?;
823 let fork = &self.consensus.forks[index];
824 let next_block_height = fork.get_next_block_height()?;
825
826 Ok(next_block_height)
827 }
828
829 pub async fn reset_to_height(&mut self, height: u32) -> Result<()> {
832 info!(target: "validator::reset_to_height", "Resetting validator to height: {height}");
833 self.blockchain.reset_to_height(height)?;
835
836 self.consensus.reset_pow_module().await?;
838
839 self.consensus.purge_forks().await?;
841
842 info!(target: "validator::reset_to_height", "Validator reset successfully!");
843
844 Ok(())
845 }
846
847 pub async fn rebuild_block_difficulties(
851 &self,
852 pow_target: u32,
853 pow_fixed_difficulty: Option<BigUint>,
854 ) -> Result<()> {
855 info!(target: "validator::rebuild_block_difficulties", "Rebuilding validator block difficulties...");
856 self.blockchain.blocks.difficulty.clear()?;
858
859 let mut blocks_count = self.blockchain.len() as u32;
861 info!(target: "validator::rebuild_block_difficulties", "Rebuilding {blocks_count} block difficulties...");
862 if blocks_count == 0 {
863 info!(target: "validator::rebuild_block_difficulties", "Validator block difficulties rebuilt successfully!");
864 return Ok(())
865 }
866
867 let mut module =
870 PoWModule::new(self.blockchain.clone(), pow_target, pow_fixed_difficulty, Some(0))?;
871
872 let genesis_block = self.blockchain.genesis_block()?;
874 let last_difficulty = BlockDifficulty::genesis(genesis_block.header.timestamp);
875 let mut targets_rank = last_difficulty.ranks.targets_rank;
876 let mut hashes_rank = last_difficulty.ranks.hashes_rank;
877
878 blocks_count -= 1;
880 let mut index = 1;
881 while index <= blocks_count {
882 let block = self.blockchain.get_blocks_by_heights(&[index])?[0].clone();
884
885 let (next_difficulty, target_distance_sq, hash_distance_sq) =
887 block_rank(&mut module, &block)?;
888
889 targets_rank += target_distance_sq.clone();
891 hashes_rank += hash_distance_sq.clone();
892
893 let cumulative_difficulty =
895 module.cumulative_difficulty.clone() + next_difficulty.clone();
896 let ranks = BlockRanks::new(
897 target_distance_sq,
898 targets_rank.clone(),
899 hash_distance_sq,
900 hashes_rank.clone(),
901 );
902 let block_difficulty = BlockDifficulty::new(
903 block.header.height,
904 block.header.timestamp,
905 next_difficulty,
906 cumulative_difficulty,
907 ranks,
908 );
909 module.append(&block.header, &block_difficulty.difficulty)?;
910
911 self.blockchain.blocks.insert_difficulty(&[block_difficulty])?;
913
914 info!(target: "validator::rebuild_block_difficulties", "Block {index}/{blocks_count} difficulty added successfully!");
915 index += 1;
916 }
917
918 self.blockchain.sled_db.flush()?;
920
921 info!(target: "validator::rebuild_block_difficulties", "Validator block difficulties rebuilt successfully!");
922
923 Ok(())
924 }
925}