diff --git a/src/lib.cairo b/src/lib.cairo index 7778f44f..ce41db81 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -1,4 +1,5 @@ -mod utils; +pub mod utils; pub mod validation; + mod state; mod main; diff --git a/src/validation.cairo b/src/validation.cairo index 368d4238..e190f596 100644 --- a/src/validation.cairo +++ b/src/validation.cairo @@ -1,5 +1,5 @@ -use super::utils::{shl, shr}; use super::state::{Block, ChainState, Transaction, UtreexoState}; +use super::utils::{shl, shr}; const MAX_TARGET: u256 = 0x00000000FFFF0000000000000000000000000000000000000000000000000000; pub const REWARD_INITIAL: u256 = 50; // 50 BTC in satoshis => 5000000000 SATS @@ -108,27 +108,38 @@ fn validate_merkle_root(self: @ChainState, block: @Block) -> Result<(), ByteArra Result::Ok(()) } -// Return BTC reward => pow to 8 to transform into Sats. Otherwise difficult to cast to u64 correctly after if needed -fn compute_block_reward(block_height: u32) -> Result { - let number_halvings = block_height / 210_000; - match number_halvings { - 0 => { return Result::Err("number_halvings equal 0"); }, - _ => {} +// Helper functions +pub fn bits_to_target(bits: u32) -> Result { + // Extract exponent and mantissa + let exponent: u32 = (bits / 0x1000000); + let mantissa: u32 = bits & 0x00FFFFFF; + + // Check if mantissa is valid (should be less than 0x1000000) + if mantissa > 0x7FFFFF && exponent != 0 { + return Result::Err('Invalid mantissa'); + } + + // Calculate the full target value + let mut target: u256 = mantissa.into(); + + if exponent == 0 { + // Special case: exponent 0 means we use the mantissa as-is + return Result::Ok(target); + } else if exponent <= 3 { + // For exponents 1, 2, and 3, divide by 256^(3 - exponent) i.e right shift + let shift = 8 * (3 - exponent); + target = shr(target, shift); + } else { + let shift = 8 * (exponent - 3); + target = shl(target, shift); } - // Simple way to do it, but breaking the final part of the test - // let subsidy_initial: u256 = REWARD_INITIAL; - // // let current_reward = subsidy_initial >> number_halvings; - // let current_reward = shr(subsidy_initial, number_halvings); - // Result::Ok((current_reward).try_into().unwrap()) - let cast_number_halvings: u256 = number_halvings.try_into().unwrap(); - let denominator = shr(cast_number_halvings, 2); - match denominator.try_into().unwrap() { - 0 => { return Result::Err("denominator = 0"); }, - _ => { } + + // Ensure the target doesn't exceed the maximum allowed value + if target > MAX_TARGET { + return Result::Err('Target exceeds maximum'); } - let subsidy_initial: u256 = REWARD_INITIAL; - let current_reward = subsidy_initial / denominator; - Result::Ok((current_reward).try_into().unwrap()) + + Result::Ok(target) } pub fn target_to_bits(target: u256) -> Result { diff --git a/tests/tests.cairo b/tests/tests.cairo index 0646d0a5..c7e52cb8 100644 --- a/tests/tests.cairo +++ b/tests/tests.cairo @@ -1,5 +1,81 @@ +use raito::validation::bits_to_target; use raito::validation::target_to_bits; +#[test] +fn test_bits_to_target_01003456() { + let result = bits_to_target(0x01003456); + assert!(result.is_ok(), "Should be valid"); + assert!(result.unwrap() == 0x00_u256, "Incorrect target for 0x01003456"); +} + +#[test] +fn test_bits_to_target_01123456() { + let result = bits_to_target(0x01123456); + assert!(result.is_ok(), "Should be valid"); + assert!(result.unwrap() == 0x12_u256, "Incorrect target for 0x01123456"); +} + +#[test] +fn test_bits_to_target_02008000() { + let result = bits_to_target(0x02008000); + assert!(result.is_ok(), "Should be valid"); + assert!(result.unwrap() == 0x80_u256, "Incorrect target for 0x02008000"); +} + +#[test] +fn test_bits_to_target_181bc330() { + let result = bits_to_target(0x181bc330); + assert!(result.is_ok(), "Should be valid"); + assert!( + result.unwrap() == 0x1bc330000000000000000000000000000000000000000000_u256, + "Incorrect target for 0x181bc330" + ); +} + +#[test] +fn test_bits_to_target_05009234() { + let result = bits_to_target(0x05009234); + assert!(result.is_ok(), "Should be valid"); + assert!(result.unwrap() == 0x92340000_u256, "Incorrect target for 0x05009234"); +} + +#[test] +fn test_bits_to_target_04123456() { + let result = bits_to_target(0x04123456); + assert!(result.is_ok(), "Should be valid"); + assert!(result.unwrap() == 0x12345600_u256, "Incorrect target for 0x04123456"); +} + +#[test] +fn test_bits_to_target_1d00ffff() { + let result = bits_to_target(0x1d00ffff); + assert!(result.is_ok(), "Should be valid"); + assert!( + result.unwrap() == 0x00000000ffff0000000000000000000000000000000000000000000000000000_u256, + "Incorrect target for 0x1d00ffff" + ); +} + +#[test] +fn test_bits_to_target_1c0d3142() { + let result = bits_to_target(0x1c0d3142); + assert!(result.is_ok(), "Should be valid"); + assert!( + result.unwrap() == 0x000000000d314200000000000000000000000000000000000000000000000000_u256, + "Incorrect target for 0x1c0d3142" + ); +} + +#[test] +fn test_bits_to_target_1707a429() { + let result = bits_to_target(0x1707a429); + assert!(result.is_ok(), "Should be valid"); + assert!( + result.unwrap() == 0x00000000000000000007a4290000000000000000000000000000000000000000_u256, + "Incorrect target for 0x1707a429" + ); +} + #[test] fn test_target_to_bits_large_target() { let target: u256 = 0x1bc330000000000000000000000000000000000000000000;