1use std::{collections::HashMap, sync::Arc};
20
21use darkfi_sdk::crypto::MerkleTree;
22use log::{debug, error, info, warn};
23use num_bigint::BigUint;
24use sled_overlay::sled;
25use smol::lock::RwLock;
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 verification;
48use verification::{
49 verify_block, verify_checkpoint_block, verify_genesis_block, verify_producer_transaction,
50 verify_transaction, verify_transactions,
51};
52
53pub mod fees;
55use fees::compute_fee;
56
57pub mod utils;
59use utils::{best_fork_index, block_rank, deploy_native_contracts};
60
61#[derive(Clone)]
63pub struct ValidatorConfig {
64 pub confirmation_threshold: usize,
66 pub pow_target: u32,
68 pub pow_fixed_difficulty: Option<BigUint>,
70 pub genesis_block: BlockInfo,
72 pub verify_fees: bool,
74}
75
76pub type ValidatorPtr = Arc<Validator>;
78
79pub struct Validator {
81 pub blockchain: Blockchain,
83 pub consensus: Consensus,
85 pub synced: RwLock<bool>,
87 pub verify_fees: bool,
89}
90
91impl Validator {
92 pub async fn new(db: &sled::Db, config: &ValidatorConfig) -> Result<ValidatorPtr> {
93 info!(target: "validator::new", "Initializing Validator");
94
95 info!(target: "validator::new", "Initializing Blockchain");
96 let blockchain = Blockchain::new(db)?;
97
98 let overlay = BlockchainOverlay::new(&blockchain)?;
100
101 deploy_native_contracts(&overlay, config.pow_target).await?;
103
104 if blockchain.genesis().is_err() {
106 info!(target: "validator::new", "Appending genesis block");
107 verify_genesis_block(&overlay, &config.genesis_block, config.pow_target).await?;
108 };
109
110 overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
112
113 info!(target: "validator::new", "Initializing Consensus");
114 let consensus = Consensus::new(
115 blockchain.clone(),
116 config.confirmation_threshold,
117 config.pow_target,
118 config.pow_fixed_difficulty.clone(),
119 )?;
120
121 let state = Arc::new(Self {
123 blockchain,
124 consensus,
125 synced: RwLock::new(false),
126 verify_fees: config.verify_fees,
127 });
128
129 info!(target: "validator::new", "Finished initializing validator");
130 Ok(state)
131 }
132
133 pub async fn calculate_fee(&self, tx: &Transaction, verify_fee: bool) -> Result<u64> {
138 let forks = self.consensus.forks.read().await;
140 let fork = forks[best_fork_index(&forks)?].full_clone()?;
141 drop(forks);
142
143 let mut vks: HashMap<[u8; 32], HashMap<String, VerifyingKey>> = HashMap::new();
145 for call in &tx.calls {
146 vks.insert(call.data.contract_id.to_bytes(), HashMap::new());
147 }
148
149 let next_block_height = fork.get_next_block_height()?;
151
152 let verify_result = verify_transaction(
154 &fork.overlay,
155 next_block_height,
156 self.consensus.module.read().await.target,
157 tx,
158 &mut MerkleTree::new(1),
159 &mut vks,
160 verify_fee,
161 )
162 .await?;
163
164 fork.overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
166
167 Ok(compute_fee(&verify_result.total_gas_used()))
168 }
169
170 pub async fn append_tx(&self, tx: &Transaction, write: bool) -> Result<()> {
173 let tx_hash = tx.hash();
174
175 let tx_in_txstore = self.blockchain.transactions.contains(&tx_hash)?;
177 let tx_in_pending_txs_store = self.blockchain.transactions.contains_pending(&tx_hash)?;
178
179 if tx_in_txstore || tx_in_pending_txs_store {
180 info!(target: "validator::append_tx", "We have already seen this tx");
181 return Err(TxVerifyFailed::AlreadySeenTx(tx_hash.as_string()).into())
182 }
183
184 info!(target: "validator::append_tx", "Starting state transition validation");
186 let tx_vec = [tx.clone()];
187 let mut valid = false;
188
189 let mut forks = self.consensus.forks.write().await;
191
192 for fork in forks.iter_mut() {
194 let fork_clone = fork.full_clone()?;
196
197 let next_block_height = fork_clone.get_next_block_height()?;
199
200 let verify_result = verify_transactions(
202 &fork_clone.overlay,
203 next_block_height,
204 self.consensus.module.read().await.target,
205 &tx_vec,
206 &mut MerkleTree::new(1),
207 self.verify_fees,
208 )
209 .await;
210
211 fork_clone.overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
213
214 match verify_result {
216 Ok(_) => {}
217 Err(Error::TxVerifyFailed(TxVerifyFailed::ErroneousTxs(_))) => continue,
218 Err(e) => return Err(e),
219 }
220
221 valid = true;
222
223 if write {
225 fork.mempool.push(tx_hash);
226 }
227 }
228
229 drop(forks);
231
232 if !valid {
234 return Err(TxVerifyFailed::ErroneousTxs(tx_vec.to_vec()).into())
235 }
236
237 if write {
239 self.blockchain.add_pending_txs(&tx_vec)?;
240 info!(target: "validator::append_tx", "Appended tx to pending txs store");
241 }
242
243 Ok(())
244 }
245
246 pub async fn purge_pending_txs(&self) -> Result<()> {
248 info!(target: "validator::purge_pending_txs", "Removing invalid transactions from pending transactions store...");
249
250 let pending_txs = self.blockchain.get_pending_txs()?;
252 if pending_txs.is_empty() {
253 info!(target: "validator::purge_pending_txs", "No pending transactions found");
254 return Ok(())
255 }
256
257 let mut forks = self.consensus.forks.write().await;
259
260 let mut removed_txs = vec![];
261 for tx in pending_txs {
262 let tx_hash = tx.hash();
263 let tx_vec = [tx.clone()];
264 let mut valid = false;
265
266 for fork in forks.iter_mut() {
268 let fork_clone = fork.full_clone()?;
270
271 let next_block_height = fork_clone.get_next_block_height()?;
273
274 let verify_result = verify_transactions(
276 &fork_clone.overlay,
277 next_block_height,
278 self.consensus.module.read().await.target,
279 &tx_vec,
280 &mut MerkleTree::new(1),
281 self.verify_fees,
282 )
283 .await;
284
285 fork_clone.overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
287
288 match verify_result {
290 Ok(_) => {
291 valid = true;
292 continue
293 }
294 Err(Error::TxVerifyFailed(TxVerifyFailed::ErroneousTxs(_))) => {}
295 Err(e) => return Err(e),
296 }
297
298 fork.mempool.retain(|x| *x != tx_hash);
300 }
301
302 if !valid {
304 removed_txs.push(tx)
305 }
306 }
307
308 drop(forks);
310
311 if removed_txs.is_empty() {
312 info!(target: "validator::purge_pending_txs", "No erroneous transactions found");
313 return Ok(())
314 }
315 info!(target: "validator::purge_pending_txs", "Removing {} erroneous transactions...", removed_txs.len());
316 self.blockchain.remove_pending_txs(&removed_txs)?;
317
318 Ok(())
319 }
320
321 pub async fn append_proposal(&self, proposal: &Proposal) -> Result<()> {
323 let append_lock = self.consensus.append_lock.write().await;
325
326 let result = self.consensus.append_proposal(proposal, self.verify_fees).await;
328
329 drop(append_lock);
331
332 result
333 }
334
335 pub async fn confirmation(&self) -> Result<Vec<BlockInfo>> {
339 let append_lock = self.consensus.append_lock.write().await;
342
343 info!(target: "validator::confirmation", "Performing confirmation check");
344
345 let confirmed_fork = match self.consensus.confirmation().await {
347 Ok(f) => f,
348 Err(e) => {
349 drop(append_lock);
350 return Err(e)
351 }
352 };
353 if confirmed_fork.is_none() {
354 info!(target: "validator::confirmation", "No proposals can be confirmed");
355 drop(append_lock);
356 return Ok(vec![])
357 }
358
359 let confirmed_fork = confirmed_fork.unwrap();
361 let mut forks = self.consensus.forks.write().await;
362 let fork = &mut forks[confirmed_fork];
363
364 let excess = (fork.proposals.len() - self.consensus.confirmation_threshold) + 1;
366
367 let rest_proposals = fork.proposals.split_off(excess);
369 let rest_diffs = fork.diffs.split_off(excess);
370 let confirmed_proposals = fork.proposals.clone();
371 let diffs = fork.diffs.clone();
372 fork.proposals = rest_proposals;
373 fork.diffs = rest_diffs;
374
375 let confirmed_blocks =
377 fork.overlay.lock().unwrap().get_blocks_by_hash(&confirmed_proposals)?;
378
379 let mut module = self.consensus.module.write().await;
381 let mut confirmed_txs = vec![];
382 let mut state_inverse_diffs_heights = vec![];
383 let mut state_inverse_diffs = vec![];
384 info!(target: "validator::confirmation", "Confirming proposals:");
385 for (index, proposal) in confirmed_proposals.iter().enumerate() {
386 info!(target: "validator::confirmation", "\t{} - {}", proposal, confirmed_blocks[index].header.height);
387 fork.overlay.lock().unwrap().overlay.lock().unwrap().apply_diff(&diffs[index])?;
388 let next_difficulty = module.next_difficulty()?;
389 module.append(confirmed_blocks[index].header.timestamp, &next_difficulty);
390 confirmed_txs.extend_from_slice(&confirmed_blocks[index].txs);
391 state_inverse_diffs_heights.push(confirmed_blocks[index].header.height);
392 state_inverse_diffs.push(diffs[index].inverse());
393 }
394 drop(module);
395 drop(forks);
396
397 self.blockchain
399 .blocks
400 .insert_state_inverse_diff(&state_inverse_diffs_heights, &state_inverse_diffs)?;
401
402 self.consensus.reset_forks(&confirmed_proposals, &confirmed_fork, &confirmed_txs).await?;
404 info!(target: "validator::confirmation", "Confirmation completed!");
405
406 drop(append_lock);
408
409 Ok(confirmed_blocks)
410 }
411
412 pub async fn add_checkpoint_blocks(
420 &self,
421 blocks: &[BlockInfo],
422 headers: &[HeaderHash],
423 ) -> Result<()> {
424 if blocks.len() != headers.len() {
426 return Err(Error::InvalidInputLengths)
427 }
428
429 debug!(target: "validator::add_checkpoint_blocks", "Instantiating BlockchainOverlay");
430 let overlay = BlockchainOverlay::new(&self.blockchain)?;
431
432 let last_difficulty = self.blockchain.last_block_difficulty()?;
434 let mut current_targets_rank = last_difficulty.ranks.targets_rank;
435 let mut current_hashes_rank = last_difficulty.ranks.hashes_rank;
436
437 let mut module = self.consensus.module.read().await.clone();
439
440 let mut state_monotree = overlay.lock().unwrap().get_state_monotree()?;
442
443 let mut removed_txs = vec![];
445
446 let mut diffs_heights = vec![];
448 let mut diffs = vec![];
449 let mut inverse_diffs = vec![];
450
451 for (index, block) in blocks.iter().enumerate() {
453 match verify_checkpoint_block(
455 &overlay,
456 &mut state_monotree,
457 block,
458 &headers[index],
459 module.target,
460 )
461 .await
462 {
463 Ok(()) => { }
464 Err(Error::BlockAlreadyExists(_)) => continue,
466 Err(e) => {
467 error!(target: "validator::add_checkpoint_blocks", "Erroneous block found in set: {}", e);
468 overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
469 return Err(Error::BlockIsInvalid(block.hash().as_string()))
470 }
471 };
472
473 let (next_target, next_difficulty) = module.next_mine_target_and_difficulty()?;
475
476 let (target_distance_sq, hash_distance_sq) = block_rank(block, &next_target);
478
479 current_targets_rank += target_distance_sq.clone();
481 current_hashes_rank += hash_distance_sq.clone();
482
483 let cumulative_difficulty =
485 module.cumulative_difficulty.clone() + next_difficulty.clone();
486 let ranks = BlockRanks::new(
487 target_distance_sq,
488 current_targets_rank.clone(),
489 hash_distance_sq,
490 current_hashes_rank.clone(),
491 );
492 let block_difficulty = BlockDifficulty::new(
493 block.header.height,
494 block.header.timestamp,
495 next_difficulty,
496 cumulative_difficulty,
497 ranks,
498 );
499 module.append_difficulty(&overlay, block_difficulty)?;
500
501 for tx in &block.txs {
503 removed_txs.push(tx.clone());
504 }
505
506 diffs_heights.push(block.header.height);
508 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&diffs)?;
509 inverse_diffs.push(diff.inverse());
510 diffs.push(diff);
511 }
512
513 debug!(target: "validator::add_checkpoint_blocks", "Applying overlay changes");
514 overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
515
516 self.blockchain.blocks.insert_state_inverse_diff(&diffs_heights, &inverse_diffs)?;
518
519 self.blockchain.remove_pending_txs(&removed_txs)?;
521
522 *self.consensus.module.write().await = module.clone();
524
525 *self.consensus.forks.write().await =
527 vec![Fork::new(self.blockchain.clone(), module).await?];
528
529 Ok(())
530 }
531
532 pub async fn add_test_blocks(&self, blocks: &[BlockInfo]) -> Result<()> {
536 debug!(target: "validator::add_test_blocks", "Instantiating BlockchainOverlay");
537 let overlay = BlockchainOverlay::new(&self.blockchain)?;
538
539 let mut previous = &overlay.lock().unwrap().last_block()?;
541
542 let last_difficulty = self.blockchain.last_block_difficulty()?;
544 let mut current_targets_rank = last_difficulty.ranks.targets_rank;
545 let mut current_hashes_rank = last_difficulty.ranks.hashes_rank;
546
547 let mut module = self.consensus.module.read().await.clone();
549
550 let mut state_monotree = overlay.lock().unwrap().get_state_monotree()?;
552
553 let mut removed_txs = vec![];
555
556 let mut diffs_heights = vec![];
558 let mut diffs = vec![];
559 let mut inverse_diffs = vec![];
560
561 for block in blocks {
563 match verify_block(
565 &overlay,
566 &module,
567 &mut state_monotree,
568 block,
569 previous,
570 self.verify_fees,
571 )
572 .await
573 {
574 Ok(()) => { }
575 Err(Error::BlockAlreadyExists(_)) => {
577 previous = block;
578 continue
579 }
580 Err(e) => {
581 error!(target: "validator::add_test_blocks", "Erroneous block found in set: {}", e);
582 overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
583 return Err(Error::BlockIsInvalid(block.hash().as_string()))
584 }
585 };
586
587 let (next_target, next_difficulty) = module.next_mine_target_and_difficulty()?;
589
590 let (target_distance_sq, hash_distance_sq) = block_rank(block, &next_target);
592
593 current_targets_rank += target_distance_sq.clone();
595 current_hashes_rank += hash_distance_sq.clone();
596
597 let cumulative_difficulty =
599 module.cumulative_difficulty.clone() + next_difficulty.clone();
600 let ranks = BlockRanks::new(
601 target_distance_sq,
602 current_targets_rank.clone(),
603 hash_distance_sq,
604 current_hashes_rank.clone(),
605 );
606 let block_difficulty = BlockDifficulty::new(
607 block.header.height,
608 block.header.timestamp,
609 next_difficulty,
610 cumulative_difficulty,
611 ranks,
612 );
613 module.append_difficulty(&overlay, block_difficulty)?;
614
615 for tx in &block.txs {
617 removed_txs.push(tx.clone());
618 }
619
620 diffs_heights.push(block.header.height);
622 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&diffs)?;
623 inverse_diffs.push(diff.inverse());
624 diffs.push(diff);
625
626 previous = block;
628 }
629
630 debug!(target: "validator::add_test_blocks", "Applying overlay changes");
631 overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
632
633 self.blockchain.blocks.insert_state_inverse_diff(&diffs_heights, &inverse_diffs)?;
635
636 self.blockchain.remove_pending_txs(&removed_txs)?;
638 self.purge_pending_txs().await?;
639
640 *self.consensus.module.write().await = module;
642
643 Ok(())
644 }
645
646 pub async fn add_test_transactions(
655 &self,
656 txs: &[Transaction],
657 verifying_block_height: u32,
658 block_target: u32,
659 write: bool,
660 verify_fees: bool,
661 ) -> Result<(u64, u64)> {
662 debug!(target: "validator::add_transactions", "Instantiating BlockchainOverlay");
663 let overlay = BlockchainOverlay::new(&self.blockchain)?;
664
665 let verify_result = verify_transactions(
667 &overlay,
668 verifying_block_height,
669 block_target,
670 txs,
671 &mut MerkleTree::new(1),
672 verify_fees,
673 )
674 .await;
675
676 let lock = overlay.lock().unwrap();
677 let mut overlay = lock.overlay.lock().unwrap();
678
679 if let Err(e) = verify_result {
680 overlay.purge_new_trees()?;
681 return Err(e)
682 }
683
684 let gas_values = verify_result.unwrap();
685
686 if !write {
687 debug!(target: "validator::add_transactions", "Skipping apply of state updates because write=false");
688 overlay.purge_new_trees()?;
689 return Ok(gas_values)
690 }
691
692 debug!(target: "validator::add_transactions", "Applying overlay changes");
693 overlay.apply()?;
694 Ok(gas_values)
695 }
696
697 pub async fn add_test_producer_transaction(
703 &self,
704 tx: &Transaction,
705 verifying_block_height: u32,
706 block_target: u32,
707 write: bool,
708 ) -> Result<()> {
709 debug!(target: "validator::add_test_producer_transaction", "Instantiating BlockchainOverlay");
710 let overlay = BlockchainOverlay::new(&self.blockchain)?;
711
712 let mut erroneous_txs = vec![];
714 if let Err(e) = verify_producer_transaction(
715 &overlay,
716 verifying_block_height,
717 block_target,
718 tx,
719 &mut MerkleTree::new(1),
720 )
721 .await
722 {
723 warn!(target: "validator::add_test_producer_transaction", "Transaction verification failed: {}", e);
724 erroneous_txs.push(tx.clone());
725 }
726
727 let lock = overlay.lock().unwrap();
728 let mut overlay = lock.overlay.lock().unwrap();
729 if !erroneous_txs.is_empty() {
730 warn!(target: "validator::add_test_producer_transaction", "Erroneous transactions found in set");
731 overlay.purge_new_trees()?;
732 return Err(TxVerifyFailed::ErroneousTxs(erroneous_txs).into())
733 }
734
735 if !write {
736 debug!(target: "validator::add_test_producer_transaction", "Skipping apply of state updates because write=false");
737 overlay.purge_new_trees()?;
738 return Ok(())
739 }
740
741 debug!(target: "validator::add_test_producer_transaction", "Applying overlay changes");
742 overlay.apply()?;
743 Ok(())
744 }
745
746 pub async fn validate_blockchain(
750 &self,
751 pow_target: u32,
752 pow_fixed_difficulty: Option<BigUint>,
753 ) -> Result<()> {
754 let blocks = self.blockchain.get_all()?;
755
756 if blocks.is_empty() {
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 = &blocks[0];
768
769 deploy_native_contracts(&overlay, pow_target).await?;
771
772 verify_genesis_block(&overlay, previous, pow_target).await?;
774
775 overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
777
778 let mut module = PoWModule::new(blockchain, pow_target, pow_fixed_difficulty, None)?;
780
781 let mut state_monotree = overlay.lock().unwrap().get_state_monotree()?;
783
784 for block in &blocks[1..] {
786 if verify_block(
788 &overlay,
789 &module,
790 &mut state_monotree,
791 block,
792 previous,
793 self.verify_fees,
794 )
795 .await
796 .is_err()
797 {
798 error!(target: "validator::validate_blockchain", "Erroneous block found in set");
799 overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
800 return Err(Error::BlockIsInvalid(block.hash().as_string()))
801 };
802
803 module.append(block.header.timestamp, &module.next_difficulty()?);
805
806 previous = block;
808 }
809
810 Ok(())
811 }
812
813 pub async fn best_fork_next_block_height(&self) -> Result<u32> {
815 let forks = self.consensus.forks.read().await;
816 let fork = &forks[best_fork_index(&forks)?];
817 let next_block_height = fork.get_next_block_height()?;
818 drop(forks);
819
820 Ok(next_block_height)
821 }
822
823 pub async fn reset_to_height(&self, height: u32) -> Result<()> {
826 info!(target: "validator::reset_to_height", "Resetting validator to height: {height}");
827 let append_lock = self.consensus.append_lock.write().await;
829
830 self.blockchain.reset_to_height(height)?;
832
833 self.consensus.reset_pow_module().await?;
835
836 self.consensus.purge_forks().await?;
838
839 drop(append_lock);
841
842 info!(target: "validator::reset_to_height", "Validator reset successfully!");
843
844 Ok(())
845 }
846}