use std::sync::{
Arc,
atomic::{AtomicBool, Ordering},
};
use tari_common_types::{
chain_metadata::ChainMetadata,
types::{CompressedCommitment, FixedHash},
};
use tari_node_components::blocks::{Block, BlockHeader, ChainBlock};
use tari_transaction_components::{tari_proof_of_work::Difficulty, transaction_components::Transaction};
use tari_utilities::epoch_time::EpochTime;
use super::{
BlockBodyValidator,
HeaderChainLinkedValidator,
InternalConsistencyValidator,
TransactionValidator,
traits::CandidateBlockValidator,
};
use crate::{
chain_storage::BlockchainBackend,
proof_of_work::{AchievedTargetDifficulty, randomx_factory::RandomXFactory},
test_helpers::create_consensus_rules,
validation::{DifficultyCalculator, FinalHorizonStateValidation, error::ValidationError},
};
#[derive(Clone)]
pub struct MockValidator {
is_valid: Arc<AtomicBool>,
}
pub struct SharedFlag(Arc<AtomicBool>);
impl SharedFlag {
pub fn set(&self, v: bool) {
self.0.store(v, Ordering::SeqCst);
}
}
impl MockValidator {
pub fn new(is_valid: bool) -> Self {
Self {
is_valid: Arc::new(AtomicBool::new(is_valid)),
}
}
pub fn shared_flag(&self) -> SharedFlag {
SharedFlag(self.is_valid.clone())
}
}
impl<B: BlockchainBackend> BlockBodyValidator<B> for MockValidator {
fn validate_body(&self, _: &B, block: &Block) -> Result<Block, ValidationError> {
if self.is_valid.load(Ordering::SeqCst) {
Ok(block.clone())
} else {
Err(ValidationError::ConsensusError(
"This mock validator always returns an error".to_string(),
))
}
}
}
impl<B: BlockchainBackend> CandidateBlockValidator<B> for MockValidator {
fn validate_body_with_metadata(&self, _: &B, _: &ChainBlock, _: &ChainMetadata) -> Result<(), ValidationError> {
if self.is_valid.load(Ordering::SeqCst) {
Ok(())
} else {
Err(ValidationError::ConsensusError(
"This mock validator always returns an error".to_string(),
))
}
}
fn validate_body_at_height(&self, _: &B, _: &ChainBlock) -> Result<(), ValidationError> {
if self.is_valid.load(Ordering::SeqCst) {
Ok(())
} else {
Err(ValidationError::ConsensusError(
"This mock validator always returns an error".to_string(),
))
}
}
}
impl InternalConsistencyValidator for MockValidator {
fn validate_internal_consistency(&self, _item: &Block) -> Result<(), ValidationError> {
if self.is_valid.load(Ordering::SeqCst) {
Ok(())
} else {
Err(ValidationError::ConsensusError(
"This mock validator always returns an error".to_string(),
))
}
}
}
impl<B: BlockchainBackend> HeaderChainLinkedValidator<B> for MockValidator {
fn validate(
&self,
db: &B,
header: &BlockHeader,
_: &BlockHeader,
_: &[EpochTime],
_: Option<Difficulty>,
_: FixedHash,
) -> Result<AchievedTargetDifficulty, ValidationError> {
if self.is_valid.load(Ordering::SeqCst) {
let difficulty_calculator = DifficultyCalculator::new(create_consensus_rules(), RandomXFactory::default());
let achieved_target_diff = difficulty_calculator.check_achieved_and_target_difficulty(db, header)?;
Ok(achieved_target_diff)
} else {
Err(ValidationError::ConsensusError(
"This mock validator always returns an error".to_string(),
))
}
}
}
impl TransactionValidator for MockValidator {
fn validate(&self, _transaction: &Transaction) -> Result<(), ValidationError> {
if self.is_valid.load(Ordering::SeqCst) {
Ok(())
} else {
Err(ValidationError::ConsensusError(
"This mock validator always returns an error".to_string(),
))
}
}
}
impl<B: BlockchainBackend> FinalHorizonStateValidation<B> for MockValidator {
fn validate(
&self,
_backend: &B,
_height: u64,
_total_utxo_sum: &CompressedCommitment,
_total_kernel_sum: &CompressedCommitment,
_total_burned_sum: &CompressedCommitment,
) -> Result<(), ValidationError> {
if self.is_valid.load(Ordering::SeqCst) {
Ok(())
} else {
Err(ValidationError::ConsensusError(
"This mock validator always returns an error".to_string(),
))
}
}
}