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 max_forks: usize,
72 pub pow_target: u32,
74 pub pow_fixed_difficulty: Option<BigUint>,
76 pub genesis_block: BlockInfo,
78 pub verify_fees: bool,
80}
81
82pub type ValidatorPtr = Arc<RwLock<Validator>>;
84
85pub struct Validator {
87 pub blockchain: Blockchain,
89 pub consensus: Consensus,
91 pub synced: bool,
93 pub verify_fees: bool,
95}
96
97impl Validator {
98 pub async fn new(db: &sled::Db, config: &ValidatorConfig) -> Result<ValidatorPtr> {
99 info!(target: "validator::new", "Initializing Validator");
100
101 info!(target: "validator::new", "Initializing Blockchain");
102 let blockchain = Blockchain::new(db)?;
103
104 let overlay = BlockchainOverlay::new(&blockchain)?;
107
108 deploy_native_contracts(&overlay, config.pow_target).await?;
110
111 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&[])?;
114 overlay.lock().unwrap().contracts.update_state_monotree(&diff)?;
115
116 if blockchain.genesis().is_err() {
118 info!(target: "validator::new", "Appending genesis block");
119 verify_genesis_block(&overlay, &[diff], &config.genesis_block, config.pow_target)
120 .await?;
121 };
122
123 overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
125
126 info!(target: "validator::new", "Initializing Consensus");
127 let consensus = Consensus::new(
128 blockchain.clone(),
129 config.confirmation_threshold,
130 config.max_forks,
131 config.pow_target,
132 config.pow_fixed_difficulty.clone(),
133 )?;
134
135 let state = Arc::new(RwLock::new(Self {
137 blockchain,
138 consensus,
139 synced: false,
140 verify_fees: config.verify_fees,
141 }));
142
143 info!(target: "validator::new", "Finished initializing validator");
144 Ok(state)
145 }
146
147 pub async fn calculate_fee(&self, tx: &Transaction, verify_fee: bool) -> Result<u64> {
155 let index = best_fork_index(&self.consensus.forks)?;
157 let fork = self.consensus.forks[index].full_clone()?;
158
159 let mut vks: HashMap<[u8; 32], HashMap<String, VerifyingKey>> = HashMap::new();
161 for call in &tx.calls {
162 vks.insert(call.data.contract_id.to_bytes(), HashMap::new());
163 }
164
165 let next_block_height = fork.get_next_block_height()?;
167
168 let verify_result = verify_transaction(
170 &fork.overlay,
171 next_block_height,
172 self.consensus.module.target,
173 tx,
174 &mut MerkleTree::new(1),
175 &mut vks,
176 verify_fee,
177 )
178 .await?;
179
180 Ok(compute_fee(&verify_result.total_gas_used()))
181 }
182
183 pub async fn append_tx(&mut self, tx: &Transaction, write: bool) -> Result<()> {
189 let tx_hash = tx.hash();
190
191 let tx_in_txstore = self.blockchain.transactions.contains(&tx_hash)?;
193 let tx_in_pending_txs_store = self.blockchain.transactions.contains_pending(&tx_hash)?;
194
195 if tx_in_txstore || tx_in_pending_txs_store {
196 debug!(target: "validator::append_tx", "We have already seen tx: {tx_hash}");
197 return Err(TxVerifyFailed::AlreadySeenTx(tx_hash.as_string()).into())
198 }
199
200 info!(target: "validator::append_tx", "Starting state transition validation for tx: {tx_hash}");
202 let tx_vec = [tx.clone()];
203 let mut valid = false;
204
205 for fork in self.consensus.forks.iter_mut() {
208 let fork_clone = fork.full_clone()?;
210
211 let next_block_height = fork_clone.get_next_block_height()?;
213
214 let verify_result = verify_transactions(
216 &fork_clone.overlay,
217 next_block_height,
218 self.consensus.module.target,
219 &tx_vec,
220 &mut MerkleTree::new(1),
221 self.verify_fees,
222 )
223 .await;
224
225 match verify_result {
227 Ok(_) => {}
228 Err(Error::TxVerifyFailed(TxVerifyFailed::ErroneousTxs(_))) => continue,
229 Err(e) => return Err(e),
230 }
231
232 valid = true;
233
234 if write {
236 fork.mempool.push(tx_hash);
237 }
238 }
239
240 if !valid {
242 return Err(TxVerifyFailed::ErroneousTxs(tx_vec.to_vec()).into())
243 }
244
245 if write {
247 self.blockchain.add_pending_txs(&tx_vec)?;
248 info!(target: "validator::append_tx", "Appended tx {tx_hash} to pending txs store");
249 }
250
251 Ok(())
252 }
253
254 pub async fn purge_pending_txs(&mut self) -> Result<()> {
260 info!(target: "validator::purge_pending_txs", "Removing invalid transactions from pending transactions store...");
261
262 let pending_txs = self.blockchain.get_pending_txs()?;
264 if pending_txs.is_empty() {
265 info!(target: "validator::purge_pending_txs", "No pending transactions found");
266 return Ok(())
267 }
268
269 let mut removed_txs = vec![];
270 for tx in pending_txs {
271 let tx_hash = tx.hash();
272 let tx_vec = [tx.clone()];
273 let mut valid = false;
274
275 for fork in self.consensus.forks.iter_mut() {
278 let fork_clone = fork.full_clone()?;
280
281 let next_block_height = fork_clone.get_next_block_height()?;
283
284 let verify_result = verify_transactions(
286 &fork_clone.overlay,
287 next_block_height,
288 self.consensus.module.target,
289 &tx_vec,
290 &mut MerkleTree::new(1),
291 self.verify_fees,
292 )
293 .await;
294
295 match verify_result {
297 Ok(_) => {
298 valid = true;
299 continue
300 }
301 Err(Error::TxVerifyFailed(TxVerifyFailed::ErroneousTxs(_))) => {}
302 Err(e) => return Err(e),
303 }
304
305 fork.mempool.retain(|x| *x != tx_hash);
307 }
308
309 if !valid {
312 removed_txs.push(tx)
313 }
314 }
315
316 if removed_txs.is_empty() {
317 info!(target: "validator::purge_pending_txs", "No erroneous transactions found");
318 return Ok(())
319 }
320 info!(target: "validator::purge_pending_txs", "Removing {} erroneous transactions...", removed_txs.len());
321 self.blockchain.remove_pending_txs(&removed_txs)?;
322
323 Ok(())
324 }
325
326 pub async fn append_proposal(&mut self, proposal: &Proposal) -> Result<()> {
329 self.consensus.append_proposal(proposal, self.synced, self.verify_fees).await
330 }
331
332 pub async fn confirmation(&mut self) -> Result<Vec<BlockInfo>> {
336 info!(target: "validator::confirmation", "Performing confirmation check");
337
338 let confirmed_fork = self.consensus.confirmation().await?;
340 if confirmed_fork.is_none() {
341 info!(target: "validator::confirmation", "No proposals can be confirmed");
342 return Ok(vec![])
343 }
344
345 let confirmed_fork = confirmed_fork.unwrap();
347 let fork = &mut self.consensus.forks[confirmed_fork];
348
349 let excess = (fork.proposals.len() - self.consensus.confirmation_threshold) + 1;
351
352 let rest_proposals = fork.proposals.split_off(excess);
354 let rest_diffs = fork.diffs.split_off(excess);
355 let confirmed_proposals = fork.proposals.clone();
356 let diffs = fork.diffs.clone();
357 fork.proposals = rest_proposals;
358 fork.diffs = rest_diffs;
359
360 let confirmed_blocks =
362 fork.overlay.lock().unwrap().get_blocks_by_hash(&confirmed_proposals)?;
363
364 let mut module = self.consensus.module.clone();
366 let mut confirmed_txs = vec![];
367 let mut state_inverse_diffs_heights = vec![];
368 let mut state_inverse_diffs = vec![];
369 info!(target: "validator::confirmation", "Confirming proposals:");
370 for (index, proposal) in confirmed_proposals.iter().enumerate() {
371 info!(target: "validator::confirmation", "\t{proposal} ({}) - {}", confirmed_blocks[index].header.pow_data, confirmed_blocks[index].header.height);
372 fork.overlay.lock().unwrap().overlay.lock().unwrap().apply_diff(&diffs[index])?;
373 let next_difficulty = module.next_difficulty()?;
374 module.append(&confirmed_blocks[index].header, &next_difficulty)?;
375 confirmed_txs.extend_from_slice(&confirmed_blocks[index].txs);
376 state_inverse_diffs_heights.push(confirmed_blocks[index].header.height);
377 state_inverse_diffs.push(diffs[index].inverse());
378 }
379 self.consensus.module = module;
380
381 self.blockchain
383 .blocks
384 .insert_state_inverse_diff(&state_inverse_diffs_heights, &state_inverse_diffs)?;
385
386 self.consensus.reset_forks(&confirmed_proposals, &confirmed_fork, &confirmed_txs).await?;
388 info!(target: "validator::confirmation", "Confirmation completed!");
389
390 Ok(confirmed_blocks)
391 }
392
393 pub async fn add_checkpoint_blocks(
405 &mut self,
406 blocks: &[BlockInfo],
407 headers: &[HeaderHash],
408 ) -> Result<()> {
409 if blocks.len() != headers.len() {
411 return Err(Error::InvalidInputLengths)
412 }
413
414 debug!(target: "validator::add_checkpoint_blocks", "Instantiating BlockchainOverlay");
415 let overlay = BlockchainOverlay::new(&self.blockchain)?;
416
417 let last_difficulty = self.blockchain.last_block_difficulty()?;
419 let mut current_targets_rank = last_difficulty.ranks.targets_rank;
420 let mut current_hashes_rank = last_difficulty.ranks.hashes_rank;
421
422 let mut module = self.consensus.module.clone();
424
425 let mut removed_txs = vec![];
428
429 let mut diffs_heights = vec![];
432 let mut diffs = vec![];
433 let mut inverse_diffs = vec![];
434
435 for (index, block) in blocks.iter().enumerate() {
437 match verify_checkpoint_block(&overlay, &diffs, block, &headers[index], module.target)
439 .await
440 {
441 Ok(()) => { }
442 Err(Error::BlockAlreadyExists(_)) => continue,
444 Err(e) => {
445 error!(target: "validator::add_checkpoint_blocks", "Erroneous block found in set: {e}");
446 return Err(Error::BlockIsInvalid(block.hash().as_string()))
447 }
448 };
449
450 let (next_target, next_difficulty) = module.next_mine_target_and_difficulty()?;
452
453 let (target_distance_sq, hash_distance_sq) = block_rank(block, &next_target)?;
455
456 current_targets_rank += target_distance_sq.clone();
458 current_hashes_rank += hash_distance_sq.clone();
459
460 let cumulative_difficulty =
462 module.cumulative_difficulty.clone() + next_difficulty.clone();
463 let ranks = BlockRanks::new(
464 target_distance_sq,
465 current_targets_rank.clone(),
466 hash_distance_sq,
467 current_hashes_rank.clone(),
468 );
469 let block_difficulty = BlockDifficulty::new(
470 block.header.height,
471 block.header.timestamp,
472 next_difficulty,
473 cumulative_difficulty,
474 ranks,
475 );
476 module.append_difficulty(&overlay, &block.header, block_difficulty)?;
477
478 for tx in &block.txs {
480 removed_txs.push(tx.clone());
481 }
482
483 diffs_heights.push(block.header.height);
485 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&diffs)?;
486 inverse_diffs.push(diff.inverse());
487 diffs.push(diff);
488 }
489
490 debug!(target: "validator::add_checkpoint_blocks", "Applying overlay changes");
491 overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
492
493 self.blockchain.blocks.insert_state_inverse_diff(&diffs_heights, &inverse_diffs)?;
495
496 self.blockchain.remove_pending_txs(&removed_txs)?;
498
499 self.consensus.module = module.clone();
501
502 self.consensus.forks = vec![Fork::new(self.blockchain.clone(), module).await?];
504
505 Ok(())
506 }
507
508 pub async fn add_test_blocks(&mut self, blocks: &[BlockInfo]) -> Result<()> {
515 debug!(target: "validator::add_test_blocks", "Instantiating BlockchainOverlay");
516 let overlay = BlockchainOverlay::new(&self.blockchain)?;
517
518 let mut previous = &overlay.lock().unwrap().last_block()?;
520
521 let last_difficulty = self.blockchain.last_block_difficulty()?;
523 let mut current_targets_rank = last_difficulty.ranks.targets_rank;
524 let mut current_hashes_rank = last_difficulty.ranks.hashes_rank;
525
526 let mut module = self.consensus.module.clone();
528
529 let mut removed_txs = vec![];
532
533 let mut diffs_heights = vec![];
536 let mut diffs = vec![];
537 let mut inverse_diffs = vec![];
538
539 for block in blocks {
541 match verify_block(
543 &overlay,
544 &diffs,
545 &mut module,
546 block,
547 previous,
548 true,
549 self.verify_fees,
550 )
551 .await
552 {
553 Ok(()) => { }
554 Err(Error::BlockAlreadyExists(_)) => {
556 previous = block;
557 continue
558 }
559 Err(e) => {
560 error!(target: "validator::add_test_blocks", "Erroneous block found in set: {e}");
561 return Err(Error::BlockIsInvalid(block.hash().as_string()))
562 }
563 };
564
565 let (next_target, next_difficulty) = module.next_mine_target_and_difficulty()?;
567
568 let (target_distance_sq, hash_distance_sq) = block_rank(block, &next_target)?;
570
571 current_targets_rank += target_distance_sq.clone();
573 current_hashes_rank += hash_distance_sq.clone();
574
575 let cumulative_difficulty =
577 module.cumulative_difficulty.clone() + next_difficulty.clone();
578 let ranks = BlockRanks::new(
579 target_distance_sq,
580 current_targets_rank.clone(),
581 hash_distance_sq,
582 current_hashes_rank.clone(),
583 );
584 let block_difficulty = BlockDifficulty::new(
585 block.header.height,
586 block.header.timestamp,
587 next_difficulty,
588 cumulative_difficulty,
589 ranks,
590 );
591 module.append_difficulty(&overlay, &block.header, block_difficulty)?;
592
593 for tx in &block.txs {
595 removed_txs.push(tx.clone());
596 }
597
598 diffs_heights.push(block.header.height);
600 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&diffs)?;
601 inverse_diffs.push(diff.inverse());
602 diffs.push(diff);
603
604 previous = block;
606 }
607
608 debug!(target: "validator::add_test_blocks", "Applying overlay changes");
609 overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
610
611 self.blockchain.blocks.insert_state_inverse_diff(&diffs_heights, &inverse_diffs)?;
613
614 self.blockchain.remove_pending_txs(&removed_txs)?;
617 self.purge_pending_txs().await?;
618
619 self.consensus.module = module;
621
622 Ok(())
623 }
624
625 pub async fn add_test_transactions(
638 &self,
639 txs: &[Transaction],
640 verifying_block_height: u32,
641 block_target: u32,
642 write: bool,
643 verify_fees: bool,
644 ) -> Result<(u64, u64)> {
645 debug!(target: "validator::add_transactions", "Instantiating BlockchainOverlay");
646 let overlay = BlockchainOverlay::new(&self.blockchain)?;
647
648 let verify_result = verify_transactions(
650 &overlay,
651 verifying_block_height,
652 block_target,
653 txs,
654 &mut MerkleTree::new(1),
655 verify_fees,
656 )
657 .await;
658
659 let lock = overlay.lock().unwrap();
660 let mut overlay = lock.overlay.lock().unwrap();
661
662 let gas_values = verify_result?;
663
664 if !write {
665 debug!(target: "validator::add_transactions", "Skipping apply of state updates because write=false");
666 return Ok(gas_values)
667 }
668
669 debug!(target: "validator::add_transactions", "Applying overlay changes");
670 overlay.apply()?;
671 Ok(gas_values)
672 }
673
674 pub async fn add_test_producer_transaction(
682 &self,
683 tx: &Transaction,
684 verifying_block_height: u32,
685 block_target: u32,
686 write: bool,
687 ) -> Result<()> {
688 debug!(target: "validator::add_test_producer_transaction", "Instantiating BlockchainOverlay");
689 let overlay = BlockchainOverlay::new(&self.blockchain)?;
690
691 let mut erroneous_txs = vec![];
693 if let Err(e) = verify_producer_transaction(
694 &overlay,
695 verifying_block_height,
696 block_target,
697 tx,
698 &mut MerkleTree::new(1),
699 )
700 .await
701 {
702 warn!(target: "validator::add_test_producer_transaction", "Transaction verification failed: {e}");
703 erroneous_txs.push(tx.clone());
704 }
705
706 let lock = overlay.lock().unwrap();
707 let mut overlay = lock.overlay.lock().unwrap();
708 if !erroneous_txs.is_empty() {
709 warn!(target: "validator::add_test_producer_transaction", "Erroneous transactions found in set");
710 return Err(TxVerifyFailed::ErroneousTxs(erroneous_txs).into())
711 }
712
713 if !write {
714 debug!(target: "validator::add_test_producer_transaction", "Skipping apply of state updates because write=false");
715 return Ok(())
716 }
717
718 debug!(target: "validator::add_test_producer_transaction", "Applying overlay changes");
719 overlay.apply()?;
720 Ok(())
721 }
722
723 pub async fn validate_blockchain(
730 &self,
731 pow_target: u32,
732 pow_fixed_difficulty: Option<BigUint>,
733 ) -> Result<()> {
734 let mut blocks_count = self.blockchain.len() as u32;
736 info!(target: "validator::validate_blockchain", "Validating {blocks_count} blocks...");
737 if blocks_count == 0 {
738 info!(target: "validator::validate_blockchain", "Blockchain validated successfully!");
739 return Ok(())
740 }
741
742 let sled_db = sled::Config::new().temporary(true).open()?;
744 let blockchain = Blockchain::new(&sled_db)?;
745 let overlay = BlockchainOverlay::new(&blockchain)?;
746
747 let mut previous = self.blockchain.genesis_block()?;
749
750 deploy_native_contracts(&overlay, pow_target).await?;
752
753 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&[])?;
755 overlay.lock().unwrap().contracts.update_state_monotree(&diff)?;
756
757 verify_genesis_block(&overlay, &[diff], &previous, pow_target).await?;
759 info!(target: "validator::validate_blockchain", "Genesis block validated successfully!");
760
761 overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
763
764 let mut module = PoWModule::new(blockchain, pow_target, pow_fixed_difficulty, Some(0))?;
766
767 let mut diffs = vec![];
769
770 info!(target: "validator::validate_blockchain", "Validating rest blocks...");
772 blocks_count -= 1;
773 let mut index = 1;
774 while index <= blocks_count {
775 let block = self.blockchain.get_blocks_by_heights(&[index])?[0].clone();
777
778 if let Err(e) = verify_block(
780 &overlay,
781 &diffs,
782 &mut module,
783 &block,
784 &previous,
785 false,
786 self.verify_fees,
787 )
788 .await
789 {
790 error!(target: "validator::validate_blockchain", "Erroneous block found in set: {e}");
791 return Err(Error::BlockIsInvalid(block.hash().as_string()))
792 };
793
794 module.append(&block.header, &module.next_difficulty()?)?;
796
797 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&diffs)?;
799 diffs.push(diff);
800
801 previous = block;
803
804 info!(target: "validator::validate_blockchain", "Block {index}/{blocks_count} validated successfully!");
805 index += 1;
806 }
807
808 info!(target: "validator::validate_blockchain", "Blockchain validated successfully!");
809 Ok(())
810 }
811
812 pub async fn current_mining_randomx_key(&self) -> Result<HeaderHash> {
816 self.consensus.current_mining_randomx_key().await
817 }
818
819 pub async fn best_current_fork(&self) -> Result<Fork> {
821 self.consensus.best_current_fork().await
822 }
823
824 pub async fn best_fork_next_block_height(&self) -> Result<u32> {
827 let index = best_fork_index(&self.consensus.forks)?;
828 let fork = &self.consensus.forks[index];
829 let next_block_height = fork.get_next_block_height()?;
830
831 Ok(next_block_height)
832 }
833
834 pub async fn reset_to_height(&mut self, height: u32) -> Result<()> {
837 info!(target: "validator::reset_to_height", "Resetting validator to height: {height}");
838 self.blockchain.reset_to_height(height)?;
840
841 self.consensus.reset_pow_module().await?;
843
844 self.consensus.purge_forks().await?;
846
847 info!(target: "validator::reset_to_height", "Validator reset successfully!");
848
849 Ok(())
850 }
851
852 pub async fn rebuild_block_difficulties(
856 &self,
857 pow_target: u32,
858 pow_fixed_difficulty: Option<BigUint>,
859 ) -> Result<()> {
860 info!(target: "validator::rebuild_block_difficulties", "Rebuilding validator block difficulties...");
861 self.blockchain.blocks.difficulty.clear()?;
863
864 let mut blocks_count = self.blockchain.len() as u32;
866 info!(target: "validator::rebuild_block_difficulties", "Rebuilding {blocks_count} block difficulties...");
867 if blocks_count == 0 {
868 info!(target: "validator::rebuild_block_difficulties", "Validator block difficulties rebuilt successfully!");
869 return Ok(())
870 }
871
872 let mut module =
875 PoWModule::new(self.blockchain.clone(), pow_target, pow_fixed_difficulty, Some(0))?;
876
877 let genesis_block = self.blockchain.genesis_block()?;
879 let last_difficulty = BlockDifficulty::genesis(genesis_block.header.timestamp);
880 let mut targets_rank = last_difficulty.ranks.targets_rank;
881 let mut hashes_rank = last_difficulty.ranks.hashes_rank;
882
883 blocks_count -= 1;
885 let mut index = 1;
886 while index <= blocks_count {
887 let block = self.blockchain.get_blocks_by_heights(&[index])?[0].clone();
889
890 let (next_target, next_difficulty) = module.next_mine_target_and_difficulty()?;
892
893 let (target_distance_sq, hash_distance_sq) = block_rank(&block, &next_target)?;
895
896 targets_rank += target_distance_sq.clone();
898 hashes_rank += hash_distance_sq.clone();
899
900 let cumulative_difficulty =
902 module.cumulative_difficulty.clone() + next_difficulty.clone();
903 let ranks = BlockRanks::new(
904 target_distance_sq,
905 targets_rank.clone(),
906 hash_distance_sq,
907 hashes_rank.clone(),
908 );
909 let block_difficulty = BlockDifficulty::new(
910 block.header.height,
911 block.header.timestamp,
912 next_difficulty,
913 cumulative_difficulty,
914 ranks,
915 );
916 module.append(&block.header, &block_difficulty.difficulty)?;
917
918 self.blockchain.blocks.insert_difficulty(&[block_difficulty])?;
920
921 info!(target: "validator::rebuild_block_difficulties", "Block {index}/{blocks_count} difficulty added successfully!");
922 index += 1;
923 }
924
925 self.blockchain.sled_db.flush()?;
927
928 info!(target: "validator::rebuild_block_difficulties", "Validator block difficulties rebuilt successfully!");
929
930 Ok(())
931 }
932}