From 771359ad72b2b61c5e954966d12c05423a248254 Mon Sep 17 00:00:00 2001 From: Harsh Pratap Singh Date: Thu, 1 Aug 2024 06:35:28 +0530 Subject: [PATCH 01/37] add bits_to_target --- src/engine.cairo | 51 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/src/engine.cairo b/src/engine.cairo index 556fc702..c8e7013e 100644 --- a/src/engine.cairo +++ b/src/engine.cairo @@ -129,6 +129,10 @@ pub impl BlockHeaderEngineImpl of BlockHeaderEngineTrait { } fn validate_target(ref self: BlockHeaderEngine) -> Result<(), felt252> { + let target = bits_to_target(self.context.block_header.bits)?; + if self.context.target != target { + return Result::Err('Invalid target'); + } Result::Ok(()) } @@ -164,8 +168,30 @@ pub impl BlockHeaderEngineImpl of BlockHeaderEngineTrait { } // Helper functions -fn bits_to_target(bits: u32) -> u256 { - 0 +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 { + return Result::Err('Invalid mantissa'); + } + + // Calculate the full target value + let mut target: u256 = mantissa.into(); + if exponent <= 3 { + target = target / u256_pow(256, 3 - exponent); + } else { + target = target * u256_pow(256, exponent - 3); + } + + // Ensure the target doesn't exceed the maximum allowed value + if target > MAX_TARGET { + return Result::Err('Target exceeds maximum'); + } + + Result::Ok(target) } fn target_to_bits(target: u256) -> u32 { @@ -179,3 +205,24 @@ fn compute_work_from_target(target: u256) -> u256 { fn compute_timestamps_median(timestamps: Span) -> u32 { 0 } + +// Custom power function for u256 +fn u256_pow(base: u256, exp: u32) -> u256 { + if exp == 0 { + return 1.into(); + } + let mut result: u256 = 1.into(); + let mut base = base; + let mut exp = exp; + loop { + if exp & 1 != 0 { + result = result * base; + } + exp = exp / 2; + if exp == 0 { + break; + } + base = base * base; + }; + result +} From 40d9eb73ead952c4642f011db84c75b46919d24c Mon Sep 17 00:00:00 2001 From: Harsh Pratap Singh Date: Thu, 1 Aug 2024 06:45:28 +0530 Subject: [PATCH 02/37] add target_to_bits --- src/engine.cairo | 64 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/src/engine.cairo b/src/engine.cairo index 556fc702..c71ada32 100644 --- a/src/engine.cairo +++ b/src/engine.cairo @@ -168,8 +168,47 @@ fn bits_to_target(bits: u32) -> u256 { 0 } -fn target_to_bits(target: u256) -> u32 { - 0 +fn target_to_bits(target: u256) -> Result { + if target == 0 { + return Result::Err('Target is zero'); + } + + // Find the most significant byte + let mut size: u32 = 32; + let mut compact = target; + + while size > 3 { + compact = compact / 256; + if compact != 0 { + size -= 1; + } else { + break; + } + }; + + // The mantissa is the most significant 3 bytes + let mut mantissa: u32 = (target / u256_pow(256, size - 3)).try_into().unwrap(); + + // Normalize: ensure the most significant byte is non-zero + if mantissa < 0x800000 { + mantissa = mantissa * 256; + size -= 1; + } + + // Ensure the result is valid and normalized + if mantissa > 0x7fffff { + return Result::Err('Mantissa too large'); + } + + // Combine exponent and mantissa into the compact format + let result: u32 = (size * 0x1000000) + mantissa; + + // Check if the result is within the valid range + if result > MAX_BITS { + return Result::Err('Exceeds max value'); + } + + Result::Ok(result) } fn compute_work_from_target(target: u256) -> u256 { @@ -179,3 +218,24 @@ fn compute_work_from_target(target: u256) -> u256 { fn compute_timestamps_median(timestamps: Span) -> u32 { 0 } + +// Custom power function for u256 +fn u256_pow(base: u256, exp: u32) -> u256 { + if exp == 0 { + return 1.into(); + } + let mut result: u256 = 1.into(); + let mut base = base; + let mut exp = exp; + loop { + if exp & 1 != 0 { + result = result * base; + } + exp = exp / 2; + if exp == 0 { + break; + } + base = base * base; + }; + result +} \ No newline at end of file From 84c343e18994bf80ce290a683e57bf649f1f8753 Mon Sep 17 00:00:00 2001 From: Harsh Pratap Singh Date: Fri, 2 Aug 2024 11:47:33 +0530 Subject: [PATCH 03/37] bits_to_target edge cases --- src/engine.cairo | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/engine.cairo b/src/engine.cairo index c8e7013e..3e8027cb 100644 --- a/src/engine.cairo +++ b/src/engine.cairo @@ -168,22 +168,32 @@ pub impl BlockHeaderEngineImpl of BlockHeaderEngineTrait { } // Helper functions -fn bits_to_target(bits: u32) -> Result { +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 { + if mantissa > 0x7FFFFF && exponent != 0 { return Result::Err('Invalid mantissa'); } // Calculate the full target value let mut target: u256 = mantissa.into(); - if exponent <= 3 { - target = target / u256_pow(256, 3 - exponent); + + if exponent == 0 || exponent == 1 { + return Result::Ok(target); + } else if exponent <= 3 { + let shift = 8 * (3 - exponent); + let divisor = u256_pow(256, shift / 8); + target = target / divisor; } else { - target = target * u256_pow(256, exponent - 3); + // Check for potential overflow + let shift = 8 * (exponent - 3); + if shift >= 256 { + return Result::Err('Exponent too large'); + } + target = target * u256_pow(256, shift / 8); } // Ensure the target doesn't exceed the maximum allowed value @@ -211,6 +221,9 @@ fn u256_pow(base: u256, exp: u32) -> u256 { if exp == 0 { return 1.into(); } + if base == 2.into() { + return 1.into() * (2.into() * u256_pow(2, exp - 1)); + } let mut result: u256 = 1.into(); let mut base = base; let mut exp = exp; From 23a2e4f8e616864b09a527e019349ffaba5a8d2b Mon Sep 17 00:00:00 2001 From: Harsh Pratap Singh Date: Sat, 3 Aug 2024 07:55:53 +0530 Subject: [PATCH 04/37] adding unit tests and overflow checks --- src/engine.cairo | 58 ++++++++++++++++++++++++-------------- tests/tests.cairo | 72 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 21 deletions(-) create mode 100644 tests/tests.cairo diff --git a/src/engine.cairo b/src/engine.cairo index 3e8027cb..2f855bb2 100644 --- a/src/engine.cairo +++ b/src/engine.cairo @@ -181,19 +181,27 @@ pub fn bits_to_target(bits: u32) -> Result { // Calculate the full target value let mut target: u256 = mantissa.into(); - if exponent == 0 || exponent == 1 { + if exponent == 0 { + // Special case: exponent 0 means we use the mantissa as-is return Result::Ok(target); } else if exponent <= 3 { - let shift = 8 * (3 - exponent); - let divisor = u256_pow(256, shift / 8); + // For exponents 1, 2, and 3, divide by 256^(3 - exponent) i.e right shift + let divisor = u256_pow(256.into(), 3 - exponent); target = target / divisor; } else { // Check for potential overflow - let shift = 8 * (exponent - 3); - if shift >= 256 { + let shift = exponent - 3; + if shift >= 29 { return Result::Err('Exponent too large'); } - target = target * u256_pow(256, shift / 8); + // left shift + let mut multiplier: u256 = 256.into(); + let mut i: u32 = 3; + while i < exponent { + multiplier = checked_mul(multiplier, 256.into()).expect('u256_mul Overflow'); + i += 1; + }; + target = checked_mul(target, multiplier).expect('u256_mul Overflow'); } // Ensure the target doesn't exceed the maximum allowed value @@ -216,26 +224,34 @@ fn compute_timestamps_median(timestamps: Span) -> u32 { 0 } -// Custom power function for u256 +// Helper function to calculate power of 256 fn u256_pow(base: u256, exp: u32) -> u256 { if exp == 0 { return 1.into(); } - if base == 2.into() { - return 1.into() * (2.into() * u256_pow(2, exp - 1)); - } let mut result: u256 = 1.into(); - let mut base = base; - let mut exp = exp; - loop { - if exp & 1 != 0 { - result = result * base; - } - exp = exp / 2; - if exp == 0 { - break; - } - base = base * base; + let mut i = 0; + while i < exp { + result = checked_mul(result, base).expect('u256_mul Overflow'); + i += 1; }; result } + +fn checked_mul(a: u256, b: u256) -> Option { + // If either number is zero, return zero immediately + if a == 0.into() || b == 0.into() { + return Option::Some(0.into()); + } + + // Perform multiplication and check for overflow + let product = a * b; + + // Check if the product divided by either of the operands does not yield the other operand, + // which would indicate an overflow. + if product / a != b || product / b != a { + return Option::None; + } + + Option::Some(product) +} diff --git a/tests/tests.cairo b/tests/tests.cairo new file mode 100644 index 00000000..58684418 --- /dev/null +++ b/tests/tests.cairo @@ -0,0 +1,72 @@ +use raito::engine::bits_to_target; + +#[test] +fn test_bits_to_target_mantissa_zero() { + let result = bits_to_target(0x04000000); + assert!(result.is_ok(), "Should be valid"); + assert!(result.unwrap() == 0_u256, "Target should be zero"); +} + +#[test] +fn test_bits_to_target_invalid_mantissa() { + let result = bits_to_target(0x04800000); + assert!(result.is_err(), "Should be invalid due to mantissa"); +} + +#[test] +fn test_bits_to_target_exponent_equal_3() { + let result = bits_to_target(0x03123456); + assert!(result.is_ok(), "Should be valid"); + assert!( + result.unwrap() == 0x0000000000000000000000000000000000000000000000000000000000123456_u256, + "Incorrect target for exp = 3" + ); +} + +#[test] +fn test_bits_to_target_exponent_greater_than_3() { + let result = bits_to_target(0x05012345); + assert!(result.is_ok(), "Should be valid"); + assert!( + result.unwrap() == 0x0000000000000000000000000000000000000000000000000000012345000000_u256, + "Incorrect target for exp = 5" + ); +} + +#[test] +fn test_bits_to_target_exponent_too_large() { + let result = bits_to_target(0x20123456); + assert!(result.is_err(), "Should be invalid due to large exponent"); +} + +#[test] +fn test_bits_to_target_max_target() { + let result = bits_to_target(0x1d00ffff); + assert!(result.is_err(), "Should be invalid due to exceeding MAX_TARGET"); +} + +#[test] +fn test_bits_to_target_overflow_target() { + let result = bits_to_target(0x1e00ffff); + assert!(result.is_err(), "Should be invalid due to overflow"); +} + +#[test] +fn test_bits_to_target_exponent_zero() { + let result = bits_to_target(0x00012345); + assert!(result.is_ok(), "Should be valid for exponent zero"); + assert!( + result.unwrap() == 0x0000000000000000000000000000000000000000000000000000000000012345_u256, + "Incorrect target for exp = 0" + ); +} + +#[test] +fn test_bits_to_target_large_mantissa() { + let result = bits_to_target(0x050FFFFF); + assert!(result.is_ok(), "Should be valid for large mantissa"); + assert!( + result.unwrap() == 0x00000000000000000000000000000000000000000000000000000FFFFF000000_u256, + "Incorrect target for large mantissa" + ); +} \ No newline at end of file From 38bb86d421602693a5fb8d4e7329ddd8667142c4 Mon Sep 17 00:00:00 2001 From: Harsh Pratap Singh Date: Sun, 4 Aug 2024 11:09:35 +0530 Subject: [PATCH 05/37] add some tests --- src/engine.cairo | 81 ++++++++++++++++++++++++++--------------------- tests/tests.cairo | 24 ++++++++++++++ 2 files changed, 69 insertions(+), 36 deletions(-) create mode 100644 tests/tests.cairo diff --git a/src/engine.cairo b/src/engine.cairo index c71ada32..8a1fc602 100644 --- a/src/engine.cairo +++ b/src/engine.cairo @@ -168,45 +168,43 @@ fn bits_to_target(bits: u32) -> u256 { 0 } -fn target_to_bits(target: u256) -> Result { +pub fn target_to_bits(target: u256) -> Result { if target == 0 { return Result::Err('Target is zero'); } + if target > MAX_TARGET { + return Result::Err('Exceeds max value'); + } + // Find the most significant byte let mut size: u32 = 32; let mut compact = target; - while size > 3 { - compact = compact / 256; - if compact != 0 { - size -= 1; - } else { - break; - } + // Count leading zero bytes by finding the first non-zero byte + while size > 1 && (compact / u256_pow(256, size - 1)) == 0 { + size -= 1; }; - // The mantissa is the most significant 3 bytes - let mut mantissa: u32 = (target / u256_pow(256, size - 3)).try_into().unwrap(); + size += 1; - // Normalize: ensure the most significant byte is non-zero - if mantissa < 0x800000 { - mantissa = mantissa * 256; - size -= 1; - } + // Extract mantissa (most significant 3 bytes) + let mut mantissa: u32 = ((compact / u256_pow(256, size - 3))).try_into().unwrap(); - // Ensure the result is valid and normalized + // Normalize if mantissa > 0x7fffff { - return Result::Err('Mantissa too large'); + mantissa = (mantissa + 0x80) / 0x100; + size += 1; } - // Combine exponent and mantissa into the compact format - let result: u32 = (size * 0x1000000) + mantissa; + // Ensure the mantissa is only 3 bytes + mantissa = mantissa & 0xffffff; - // Check if the result is within the valid range - if result > MAX_BITS { - return Result::Err('Exceeds max value'); - } + // Simulate (size << 24) by multiplying size with 0x1000000 (256^3) + let size_component: u32 = (u256_pow(256.into(), 3) * size.into()).try_into().unwrap(); + + // Combine size and mantissa + let result: u32 = size_component + mantissa; Result::Ok(result) } @@ -219,23 +217,34 @@ fn compute_timestamps_median(timestamps: Span) -> u32 { 0 } -// Custom power function for u256 +// Helper function to calculate power of 256 fn u256_pow(base: u256, exp: u32) -> u256 { if exp == 0 { return 1.into(); } let mut result: u256 = 1.into(); - let mut base = base; - let mut exp = exp; - loop { - if exp & 1 != 0 { - result = result * base; - } - exp = exp / 2; - if exp == 0 { - break; - } - base = base * base; + let mut i = 0; + while i < exp { + result = checked_mul(result, base).expect('u256_mul Overflow'); + i += 1; }; result -} \ No newline at end of file +} + +fn checked_mul(a: u256, b: u256) -> Option { + // If either number is zero, return zero immediately + if a == 0.into() || b == 0.into() { + return Option::Some(0.into()); + } + + // Perform multiplication and check for overflow + let product = a * b; + + // Check if the product divided by either of the operands does not yield the other operand, + // which would indicate an overflow. + if product / a != b || product / b != a { + return Option::None; + } + + Option::Some(product) +} diff --git a/tests/tests.cairo b/tests/tests.cairo new file mode 100644 index 00000000..bb3e3250 --- /dev/null +++ b/tests/tests.cairo @@ -0,0 +1,24 @@ +use core::result::ResultTrait; +use core::option::OptionTrait; +use core::traits::Into; +use raito::engine::target_to_bits; + +#[test] +fn test_target_to_bits_zero() { + let result = target_to_bits(0.into()); + assert!(result.is_err(), "Should error on zero input"); +} + +#[test] +fn test_target_to_bits_overflow() { + let target: u256 = 0x01000000000000000000000000000000000000000000000000000000000000000; + let result = target_to_bits(target); + assert!(result.is_err(), "Should error on overflow"); +} + +#[test] +fn test_target_to_bits_medium_target() { + let medium_target: u256 = 0x00000000000FFFFF000000000000000000000000000000000000000000000000; + let result = target_to_bits(medium_target).unwrap(); + assert!(result == 0x1c000fff, "Incorrect bits for medium target"); +} \ No newline at end of file From 8572c057f96b2b2f29893c3ccbfd09e274418202 Mon Sep 17 00:00:00 2001 From: Harsh Pratap Singh Date: Mon, 5 Aug 2024 09:14:57 +0530 Subject: [PATCH 06/37] nit --- src/engine.cairo | 4 +--- tests/tests.cairo | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/engine.cairo b/src/engine.cairo index 8a1fc602..21cf340c 100644 --- a/src/engine.cairo +++ b/src/engine.cairo @@ -186,8 +186,6 @@ pub fn target_to_bits(target: u256) -> Result { size -= 1; }; - size += 1; - // Extract mantissa (most significant 3 bytes) let mut mantissa: u32 = ((compact / u256_pow(256, size - 3))).try_into().unwrap(); @@ -202,7 +200,7 @@ pub fn target_to_bits(target: u256) -> Result { // Simulate (size << 24) by multiplying size with 0x1000000 (256^3) let size_component: u32 = (u256_pow(256.into(), 3) * size.into()).try_into().unwrap(); - + // Combine size and mantissa let result: u32 = size_component + mantissa; diff --git a/tests/tests.cairo b/tests/tests.cairo index bb3e3250..a6b01546 100644 --- a/tests/tests.cairo +++ b/tests/tests.cairo @@ -20,5 +20,5 @@ fn test_target_to_bits_overflow() { fn test_target_to_bits_medium_target() { let medium_target: u256 = 0x00000000000FFFFF000000000000000000000000000000000000000000000000; let result = target_to_bits(medium_target).unwrap(); - assert!(result == 0x1c000fff, "Incorrect bits for medium target"); + assert!(result == 454033407, "Incorrect bits for medium target"); } \ No newline at end of file From 331ba78e9e7cfeac5b1f1295162ff1513d375f7d Mon Sep 17 00:00:00 2001 From: Harsh Pratap Singh Date: Mon, 5 Aug 2024 09:54:03 +0530 Subject: [PATCH 07/37] normalization test --- src/engine.cairo | 5 +++++ tests/tests.cairo | 9 ++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/engine.cairo b/src/engine.cairo index 21cf340c..c9b7ea26 100644 --- a/src/engine.cairo +++ b/src/engine.cairo @@ -198,6 +198,11 @@ pub fn target_to_bits(target: u256) -> Result { // Ensure the mantissa is only 3 bytes mantissa = mantissa & 0xffffff; + // Check size doesn't exceed maximum + if size > 34 { + return Result::Err('Overflow'); + } + // Simulate (size << 24) by multiplying size with 0x1000000 (256^3) let size_component: u32 = (u256_pow(256.into(), 3) * size.into()).try_into().unwrap(); diff --git a/tests/tests.cairo b/tests/tests.cairo index a6b01546..cf30dc30 100644 --- a/tests/tests.cairo +++ b/tests/tests.cairo @@ -21,4 +21,11 @@ fn test_target_to_bits_medium_target() { let medium_target: u256 = 0x00000000000FFFFF000000000000000000000000000000000000000000000000; let result = target_to_bits(medium_target).unwrap(); assert!(result == 454033407, "Incorrect bits for medium target"); -} \ No newline at end of file +} + +#[test] +fn test_target_to_bits_normalization() { + let target: u256 = 0x00000000007FFFFF800000000000000000000000000000000000000000000000; + let result = target_to_bits(target).unwrap(); + assert!(result == 0x1b7fffff, "Incorrect bits after normalization"); +} From 2d9bbd397eea946ad6cbcf60268f9a3531afeecb Mon Sep 17 00:00:00 2001 From: Harsh Pratap Singh Date: Mon, 5 Aug 2024 09:55:03 +0530 Subject: [PATCH 08/37] max target test --- tests/tests.cairo | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/tests.cairo b/tests/tests.cairo index cf30dc30..3b0ad9f0 100644 --- a/tests/tests.cairo +++ b/tests/tests.cairo @@ -29,3 +29,10 @@ fn test_target_to_bits_normalization() { let result = target_to_bits(target).unwrap(); assert!(result == 0x1b7fffff, "Incorrect bits after normalization"); } + +#[test] +fn test_target_to_bits_max_target() { + let max_target: u256 = 0x00000000FFFF0000000000000000000000000000000000000000000000000000; + let result = target_to_bits(max_target).unwrap(); + assert!(result == 0x1d00ffff, "Incorrect bits for max target"); +} \ No newline at end of file From 59316d0287aaea64e6d59b74e039267a82f9f7b2 Mon Sep 17 00:00:00 2001 From: Harsh Pratap Singh Date: Mon, 5 Aug 2024 11:40:56 +0530 Subject: [PATCH 09/37] exponent < 3 nit --- src/engine.cairo | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/engine.cairo b/src/engine.cairo index 2f855bb2..a2473f83 100644 --- a/src/engine.cairo +++ b/src/engine.cairo @@ -186,8 +186,14 @@ pub fn bits_to_target(bits: u32) -> Result { return Result::Ok(target); } else if exponent <= 3 { // For exponents 1, 2, and 3, divide by 256^(3 - exponent) i.e right shift - let divisor = u256_pow(256.into(), 3 - exponent); - target = target / divisor; + let shift = 8 * (3 - exponent); + let mut multiplier: u256 = 1.into(); + let mut i = 0; + while i < shift { + multiplier = checked_mul(multiplier, 256.into()).expect('u256_mul Overflow'); + i += 1; + }; + target = checked_mul(target, multiplier).expect('u256_mul Overflow'); } else { // Check for potential overflow let shift = exponent - 3; From 0f258c1bb9160a833bda8bd8578d9385446fda8d Mon Sep 17 00:00:00 2001 From: Xavek Date: Tue, 6 Aug 2024 21:32:35 +0545 Subject: [PATCH 10/37] impl proof of work validate func --- src/validation.cairo | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/validation.cairo b/src/validation.cairo index 68bf7eb8..363d48aa 100644 --- a/src/validation.cairo +++ b/src/validation.cairo @@ -30,8 +30,14 @@ fn validate_prev_block_hash(self: @ChainState, block: @Block) -> Result<(), Byte } fn validate_proof_of_work(self: @ChainState, block: @Block) -> Result<(), ByteArray> { - // TODO: implement - Result::Ok(()) + let target_u256: u256 = block.header.bits.clone().into(); + if block.header.prev_block_hash.clone() <= target_u256 { + Result::Ok(()) + } else { + Result::Err( + "Insufficient proof of work. Expected block hash {block.header.prev_block_hash} to be less than or equal to target {block.header.bits}." + ) + } } fn validate_target(self: @ChainState, block: @Block) -> Result<(), ByteArray> { From 6efdb0b5ca38367d49d8d5fe5b5fdf781859d903 Mon Sep 17 00:00:00 2001 From: Harsh Pratap Singh Date: Wed, 7 Aug 2024 06:37:18 +0530 Subject: [PATCH 11/37] major refactor --- src/engine.cairo | 57 ++++-------------------------------- src/lib.cairo | 1 + src/utils.cairo | 35 ++++++++++++++++++++++ tests/tests.cairo | 74 +++++++++++++++++++++++++---------------------- 4 files changed, 80 insertions(+), 87 deletions(-) create mode 100644 src/utils.cairo diff --git a/src/engine.cairo b/src/engine.cairo index a2473f83..1c2182bc 100644 --- a/src/engine.cairo +++ b/src/engine.cairo @@ -2,6 +2,8 @@ use core::result::Result; use core::option::OptionTrait; use core::traits::Into; use core::byte_array::ByteArray; +use raito::utils::shl; +use raito::utils::shr; // Constants const BLOCK_HEADER_SIZE: u32 = 80; @@ -187,27 +189,10 @@ pub fn bits_to_target(bits: u32) -> Result { } else if exponent <= 3 { // For exponents 1, 2, and 3, divide by 256^(3 - exponent) i.e right shift let shift = 8 * (3 - exponent); - let mut multiplier: u256 = 1.into(); - let mut i = 0; - while i < shift { - multiplier = checked_mul(multiplier, 256.into()).expect('u256_mul Overflow'); - i += 1; - }; - target = checked_mul(target, multiplier).expect('u256_mul Overflow'); + target = shr(target, shift); } else { - // Check for potential overflow - let shift = exponent - 3; - if shift >= 29 { - return Result::Err('Exponent too large'); - } - // left shift - let mut multiplier: u256 = 256.into(); - let mut i: u32 = 3; - while i < exponent { - multiplier = checked_mul(multiplier, 256.into()).expect('u256_mul Overflow'); - i += 1; - }; - target = checked_mul(target, multiplier).expect('u256_mul Overflow'); + let shift = 8 * (exponent - 3); + target = shl(target, shift); } // Ensure the target doesn't exceed the maximum allowed value @@ -229,35 +214,3 @@ fn compute_work_from_target(target: u256) -> u256 { fn compute_timestamps_median(timestamps: Span) -> u32 { 0 } - -// Helper function to calculate power of 256 -fn u256_pow(base: u256, exp: u32) -> u256 { - if exp == 0 { - return 1.into(); - } - let mut result: u256 = 1.into(); - let mut i = 0; - while i < exp { - result = checked_mul(result, base).expect('u256_mul Overflow'); - i += 1; - }; - result -} - -fn checked_mul(a: u256, b: u256) -> Option { - // If either number is zero, return zero immediately - if a == 0.into() || b == 0.into() { - return Option::Some(0.into()); - } - - // Perform multiplication and check for overflow - let product = a * b; - - // Check if the product divided by either of the operands does not yield the other operand, - // which would indicate an overflow. - if product / a != b || product / b != a { - return Option::None; - } - - Option::Some(product) -} diff --git a/src/lib.cairo b/src/lib.cairo index 829eb99c..985a50dd 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -1,3 +1,4 @@ pub mod engine; +pub mod utils; mod main; diff --git a/src/utils.cairo b/src/utils.cairo new file mode 100644 index 00000000..c525c415 --- /dev/null +++ b/src/utils.cairo @@ -0,0 +1,35 @@ +use core::traits::Into; +use core::traits::TryInto; + +// Bitwise shift left for u256 +pub fn shl(value: u256, shift: u32) -> u256 { + value * fast_pow(2.into(), shift.into()) +} + +// Bitwise shift right for u256 +pub fn shr(value: u256, shift: u32) -> u256 { + value / fast_pow(2.into(), shift.into()) +} + +// Fast exponentiation using the square-and-multiply algorithm +// Reference: https://github.com/keep-starknet-strange/alexandria/blob/bcdca70afdf59c9976148e95cebad5cf63d75a7f/packages/math/src/fast_power.cairo#L12 +pub fn fast_pow(base: u256, exp: u256) -> u256 { + if exp == 0.into() { + return 1.into(); + } + + let mut res: u256 = 1.into(); + let mut base: u256 = base; + let mut exp: u256 = exp; + + loop { + if exp % 2.into() == 1.into() { + res = res * base; + } + exp = exp / 2.into(); + if exp == 0.into() { + break res; + } + base = base * base; + } +} \ No newline at end of file diff --git a/tests/tests.cairo b/tests/tests.cairo index 58684418..52ab226e 100644 --- a/tests/tests.cairo +++ b/tests/tests.cairo @@ -1,72 +1,76 @@ use raito::engine::bits_to_target; #[test] -fn test_bits_to_target_mantissa_zero() { - let result = bits_to_target(0x04000000); +fn test_bits_to_target_01003456() { + let result = bits_to_target(0x01003456); assert!(result.is_ok(), "Should be valid"); - assert!(result.unwrap() == 0_u256, "Target should be zero"); + assert!(result.unwrap() == 0x00_u256, "Incorrect target for 0x01003456"); } #[test] -fn test_bits_to_target_invalid_mantissa() { - let result = bits_to_target(0x04800000); - assert!(result.is_err(), "Should be invalid due to mantissa"); +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_exponent_equal_3() { - let result = bits_to_target(0x03123456); +fn test_bits_to_target_02008000() { + let result = bits_to_target(0x02008000); assert!(result.is_ok(), "Should be valid"); - assert!( - result.unwrap() == 0x0000000000000000000000000000000000000000000000000000000000123456_u256, - "Incorrect target for exp = 3" - ); + assert!(result.unwrap() == 0x80_u256, "Incorrect target for 0x02008000"); } #[test] -fn test_bits_to_target_exponent_greater_than_3() { - let result = bits_to_target(0x05012345); +fn test_bits_to_target_181bc330() { + let result = bits_to_target(0x181bc330); assert!(result.is_ok(), "Should be valid"); assert!( - result.unwrap() == 0x0000000000000000000000000000000000000000000000000000012345000000_u256, - "Incorrect target for exp = 5" + result.unwrap() == 0x1bc330000000000000000000000000000000000000000000_u256, + "Incorrect target for 0x181bc330" ); } #[test] -fn test_bits_to_target_exponent_too_large() { - let result = bits_to_target(0x20123456); - assert!(result.is_err(), "Should be invalid due to large exponent"); +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_max_target() { - let result = bits_to_target(0x1d00ffff); - assert!(result.is_err(), "Should be invalid due to exceeding MAX_TARGET"); +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_overflow_target() { - let result = bits_to_target(0x1e00ffff); - assert!(result.is_err(), "Should be invalid due to overflow"); +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_exponent_zero() { - let result = bits_to_target(0x00012345); - assert!(result.is_ok(), "Should be valid for exponent zero"); +fn test_bits_to_target_1c0d3142() { + let result = bits_to_target(0x1c0d3142); + assert!(result.is_ok(), "Should be valid"); assert!( - result.unwrap() == 0x0000000000000000000000000000000000000000000000000000000000012345_u256, - "Incorrect target for exp = 0" + result.unwrap() == 0x000000000d314200000000000000000000000000000000000000000000000000_u256, + "Incorrect target for 0x1c0d3142" ); } #[test] -fn test_bits_to_target_large_mantissa() { - let result = bits_to_target(0x050FFFFF); - assert!(result.is_ok(), "Should be valid for large mantissa"); +fn test_bits_to_target_1707a429() { + let result = bits_to_target(0x1707a429); + assert!(result.is_ok(), "Should be valid"); assert!( - result.unwrap() == 0x00000000000000000000000000000000000000000000000000000FFFFF000000_u256, - "Incorrect target for large mantissa" + result.unwrap() == 0x00000000000000000007a4290000000000000000000000000000000000000000_u256, + "Incorrect target for 0x1707a429" ); } \ No newline at end of file From 1961cd3323d4f5c6ff53484ce103dc5cf59261a6 Mon Sep 17 00:00:00 2001 From: Harsh Pratap Singh Date: Wed, 7 Aug 2024 06:53:08 +0530 Subject: [PATCH 12/37] major refactor --- src/engine.cairo | 51 +++++++++----------------------------- src/lib.cairo | 1 + src/utils.cairo | 35 ++++++++++++++++++++++++++ tests/tests.cairo | 62 ++++++++++++++++++++++++++++++++++------------- 4 files changed, 92 insertions(+), 57 deletions(-) create mode 100644 src/utils.cairo diff --git a/src/engine.cairo b/src/engine.cairo index c9b7ea26..bd95cbef 100644 --- a/src/engine.cairo +++ b/src/engine.cairo @@ -2,6 +2,9 @@ use core::result::Result; use core::option::OptionTrait; use core::traits::Into; use core::byte_array::ByteArray; +use raito::utils::shl; +use raito::utils::shr; +use raito::utils::fast_pow; // Constants const BLOCK_HEADER_SIZE: u32 = 80; @@ -182,14 +185,14 @@ pub fn target_to_bits(target: u256) -> Result { let mut compact = target; // Count leading zero bytes by finding the first non-zero byte - while size > 1 && (compact / u256_pow(256, size - 1)) == 0 { + while size > 1 && shr(compact, (size - 1) * 8) == 0 { size -= 1; }; // Extract mantissa (most significant 3 bytes) - let mut mantissa: u32 = ((compact / u256_pow(256, size - 3))).try_into().unwrap(); + let mut mantissa: u32 = shr(compact, (size - 3) * 8).try_into().unwrap(); - // Normalize + // Normalize if mantissa > 0x7fffff { mantissa = (mantissa + 0x80) / 0x100; size += 1; @@ -203,11 +206,11 @@ pub fn target_to_bits(target: u256) -> Result { return Result::Err('Overflow'); } - // Simulate (size << 24) by multiplying size with 0x1000000 (256^3) - let size_component: u32 = (u256_pow(256.into(), 3) * size.into()).try_into().unwrap(); + // Convert size to u256 + let size_u256: u256 = size.into(); - // Combine size and mantissa - let result: u32 = size_component + mantissa; + // Combine size and mantissa + let result: u32 = (shl(size_u256, 24) + mantissa.into()).try_into().unwrap(); Result::Ok(result) } @@ -218,36 +221,4 @@ fn compute_work_from_target(target: u256) -> u256 { fn compute_timestamps_median(timestamps: Span) -> u32 { 0 -} - -// Helper function to calculate power of 256 -fn u256_pow(base: u256, exp: u32) -> u256 { - if exp == 0 { - return 1.into(); - } - let mut result: u256 = 1.into(); - let mut i = 0; - while i < exp { - result = checked_mul(result, base).expect('u256_mul Overflow'); - i += 1; - }; - result -} - -fn checked_mul(a: u256, b: u256) -> Option { - // If either number is zero, return zero immediately - if a == 0.into() || b == 0.into() { - return Option::Some(0.into()); - } - - // Perform multiplication and check for overflow - let product = a * b; - - // Check if the product divided by either of the operands does not yield the other operand, - // which would indicate an overflow. - if product / a != b || product / b != a { - return Option::None; - } - - Option::Some(product) -} +} \ No newline at end of file diff --git a/src/lib.cairo b/src/lib.cairo index 829eb99c..985a50dd 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -1,3 +1,4 @@ pub mod engine; +pub mod utils; mod main; diff --git a/src/utils.cairo b/src/utils.cairo new file mode 100644 index 00000000..c525c415 --- /dev/null +++ b/src/utils.cairo @@ -0,0 +1,35 @@ +use core::traits::Into; +use core::traits::TryInto; + +// Bitwise shift left for u256 +pub fn shl(value: u256, shift: u32) -> u256 { + value * fast_pow(2.into(), shift.into()) +} + +// Bitwise shift right for u256 +pub fn shr(value: u256, shift: u32) -> u256 { + value / fast_pow(2.into(), shift.into()) +} + +// Fast exponentiation using the square-and-multiply algorithm +// Reference: https://github.com/keep-starknet-strange/alexandria/blob/bcdca70afdf59c9976148e95cebad5cf63d75a7f/packages/math/src/fast_power.cairo#L12 +pub fn fast_pow(base: u256, exp: u256) -> u256 { + if exp == 0.into() { + return 1.into(); + } + + let mut res: u256 = 1.into(); + let mut base: u256 = base; + let mut exp: u256 = exp; + + loop { + if exp % 2.into() == 1.into() { + res = res * base; + } + exp = exp / 2.into(); + if exp == 0.into() { + break res; + } + base = base * base; + } +} \ No newline at end of file diff --git a/tests/tests.cairo b/tests/tests.cairo index 3b0ad9f0..2ee9eb93 100644 --- a/tests/tests.cairo +++ b/tests/tests.cairo @@ -4,35 +4,63 @@ use core::traits::Into; use raito::engine::target_to_bits; #[test] -fn test_target_to_bits_zero() { - let result = target_to_bits(0.into()); - assert!(result.is_err(), "Should error on zero input"); +fn test_target_to_bits_large_target() { + let target: u256 = 0x1bc330000000000000000000000000000000000000000000; + let result = target_to_bits(target).unwrap(); + assert!(result == 0x181bc330, "Incorrect bits for large target"); } #[test] -fn test_target_to_bits_overflow() { - let target: u256 = 0x01000000000000000000000000000000000000000000000000000000000000000; - let result = target_to_bits(target); - assert!(result.is_err(), "Should error on overflow"); +fn test_target_to_bits_small_target() { + let target: u256 = 0x92340000; + let result = target_to_bits(target).unwrap(); + assert!(result == 0x05009234, "Incorrect bits for small target"); } #[test] fn test_target_to_bits_medium_target() { - let medium_target: u256 = 0x00000000000FFFFF000000000000000000000000000000000000000000000000; - let result = target_to_bits(medium_target).unwrap(); - assert!(result == 454033407, "Incorrect bits for medium target"); -} - -#[test] -fn test_target_to_bits_normalization() { - let target: u256 = 0x00000000007FFFFF800000000000000000000000000000000000000000000000; + let target: u256 = 0x12345600; let result = target_to_bits(target).unwrap(); - assert!(result == 0x1b7fffff, "Incorrect bits after normalization"); + assert!(result == 0x04123456, "Incorrect bits for medium target"); } #[test] fn test_target_to_bits_max_target() { - let max_target: u256 = 0x00000000FFFF0000000000000000000000000000000000000000000000000000; + let max_target: u256 = 0x00000000ffff0000000000000000000000000000000000000000000000000000; let result = target_to_bits(max_target).unwrap(); assert!(result == 0x1d00ffff, "Incorrect bits for max target"); +} + +#[test] +fn test_target_to_bits_high_precision_target() { + let target: u256 = 0x000000000d314200000000000000000000000000000000000000000000000000; + let result = target_to_bits(target).unwrap(); + assert!(result == 0x1c0d3142, "Incorrect bits for high precision target"); +} + +#[test] +fn test_target_to_bits_low_precision_target() { + let target: u256 = 0x00000000000000000007a4290000000000000000000000000000000000000000; + let result = target_to_bits(target).unwrap(); + assert!(result == 0x1707a429, "Incorrect bits for low precision target"); +} + +#[test] +fn test_target_to_bits_full_mantissa() { + let target: u256 = 0xd86a528bc8bc8bc8bc8bc8bc8bc8bc8bc8bc8bc8bc8bc8bc8bc8bc8b; + let result = target_to_bits(target).unwrap(); + assert!(result == 0x1d00d86a, "Incorrect bits for full mantissa target"); +} + +#[test] +fn test_target_to_bits_zero_target() { + let result = target_to_bits(0.into()); + assert!(result.is_err(), "Should error on zero target"); +} + +#[test] +fn test_target_to_bits_overflow_target() { + let target: u256 = 0x01000000000000000000000000000000000000000000000000000000000000000; + let result = target_to_bits(target); + assert!(result.is_err(), "Should error on overflow target"); } \ No newline at end of file From e0bd6e2d5d8c49ee4122aba083cd3a38ba88af0a Mon Sep 17 00:00:00 2001 From: Harsh Pratap Singh Date: Wed, 7 Aug 2024 16:25:46 +0530 Subject: [PATCH 13/37] nits --- src/engine.cairo | 1 - src/utils.cairo | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/engine.cairo b/src/engine.cairo index bd95cbef..f0ef83f3 100644 --- a/src/engine.cairo +++ b/src/engine.cairo @@ -4,7 +4,6 @@ use core::traits::Into; use core::byte_array::ByteArray; use raito::utils::shl; use raito::utils::shr; -use raito::utils::fast_pow; // Constants const BLOCK_HEADER_SIZE: u32 = 80; diff --git a/src/utils.cairo b/src/utils.cairo index c525c415..e188b13f 100644 --- a/src/utils.cairo +++ b/src/utils.cairo @@ -13,21 +13,21 @@ pub fn shr(value: u256, shift: u32) -> u256 { // Fast exponentiation using the square-and-multiply algorithm // Reference: https://github.com/keep-starknet-strange/alexandria/blob/bcdca70afdf59c9976148e95cebad5cf63d75a7f/packages/math/src/fast_power.cairo#L12 -pub fn fast_pow(base: u256, exp: u256) -> u256 { - if exp == 0.into() { +pub fn fast_pow(base: u256, exp: u32) -> u256 { + if exp == 0 { return 1.into(); } let mut res: u256 = 1.into(); let mut base: u256 = base; - let mut exp: u256 = exp; + let mut exp: u32 = exp; loop { - if exp % 2.into() == 1.into() { + if exp % 2 == 1 { res = res * base; } - exp = exp / 2.into(); - if exp == 0.into() { + exp = exp / 2; + if exp == 0 { break res; } base = base * base; From 4bec57afd3aea6ee785ba78a4e04f0382cdd7eb5 Mon Sep 17 00:00:00 2001 From: Harsh Pratap Singh Date: Wed, 7 Aug 2024 16:26:33 +0530 Subject: [PATCH 14/37] nits --- src/utils.cairo | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/utils.cairo b/src/utils.cairo index c525c415..e188b13f 100644 --- a/src/utils.cairo +++ b/src/utils.cairo @@ -13,21 +13,21 @@ pub fn shr(value: u256, shift: u32) -> u256 { // Fast exponentiation using the square-and-multiply algorithm // Reference: https://github.com/keep-starknet-strange/alexandria/blob/bcdca70afdf59c9976148e95cebad5cf63d75a7f/packages/math/src/fast_power.cairo#L12 -pub fn fast_pow(base: u256, exp: u256) -> u256 { - if exp == 0.into() { +pub fn fast_pow(base: u256, exp: u32) -> u256 { + if exp == 0 { return 1.into(); } let mut res: u256 = 1.into(); let mut base: u256 = base; - let mut exp: u256 = exp; + let mut exp: u32 = exp; loop { - if exp % 2.into() == 1.into() { + if exp % 2 == 1 { res = res * base; } - exp = exp / 2.into(); - if exp == 0.into() { + exp = exp / 2; + if exp == 0 { break res; } base = base * base; From d598d209f00a3f7aafd197861d0c7802c328f4c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski?= Date: Wed, 7 Aug 2024 14:02:06 +0200 Subject: [PATCH 15/37] updated roadmap --- .github/CODEOWNERS | 2 +- README.md | 28 +++++++++++++++++++++++----- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 65ea647d..dc1830d5 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @b-j-roberts @m-kus @maciejka +* @m-kus @maciejka diff --git a/README.md b/README.md index 2df41baa..874d5053 100644 --- a/README.md +++ b/README.md @@ -49,11 +49,29 @@ Although this is a highly experimental project without immediate plans for deplo ## Roadmap -* [ ] verify block header (block hash, previous block hash, Merkle root, proof-of-work, median time, and difficulty adjustment) -* [ ] verify transactions -* [ ] integrate with Shinigami and verify scripts -* [ ] verify previous chain proofs -* [ ] add utreexo accumulator to the chain state +### Milestone 1 - Block Verification + * header verification + * [ ] block hash + * [ ] previous block hash + * [ ] tx merkle root, + * [ ] proof-of-work, + * [ ] median time, + * [ ] difficulty adjustment + * transaction verification + * [ ] verify inputs + * [ ] verify outputs + * [ ] verify coinbase tx + * [ ] use utreexo to verify tx inputs + * verify scripts(integrate with Shinigami) + * tbd + * integration testing + * [ ] test on individual historical blocks +### Milestone 2 - Real Data + * [ ] feed it with real data + * [ ] produce and verify proofs of verrification of individual blocks +### Milestone 3 - Recursive Verification + * verify chain proofs with cairo verifier, tbd + ## Name reference From 2f11c3cef1a2e3027d29d47b191468ecb2e8e833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski?= Date: Wed, 7 Aug 2024 14:07:42 +0200 Subject: [PATCH 16/37] fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 874d5053..27d6538f 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ Although this is a highly experimental project without immediate plans for deplo * [ ] test on individual historical blocks ### Milestone 2 - Real Data * [ ] feed it with real data - * [ ] produce and verify proofs of verrification of individual blocks + * [ ] produce and verify proofs of verification of individual blocks ### Milestone 3 - Recursive Verification * verify chain proofs with cairo verifier, tbd From 5a258d8cdde38d700811adde1f961b01049fbcc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski?= Date: Wed, 7 Aug 2024 14:08:37 +0200 Subject: [PATCH 17/37] fix 2 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 27d6538f..32a222f3 100644 --- a/README.md +++ b/README.md @@ -62,8 +62,8 @@ Although this is a highly experimental project without immediate plans for deplo * [ ] verify outputs * [ ] verify coinbase tx * [ ] use utreexo to verify tx inputs - * verify scripts(integrate with Shinigami) - * tbd + * verify scripts + * integrate with Shinigami, tbd * integration testing * [ ] test on individual historical blocks ### Milestone 2 - Real Data From d188296b3d8b636844b16499ef26cda3376e532c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski?= Date: Wed, 7 Aug 2024 14:10:11 +0200 Subject: [PATCH 18/37] fix 3 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 32a222f3..4f9a36fb 100644 --- a/README.md +++ b/README.md @@ -63,12 +63,12 @@ Although this is a highly experimental project without immediate plans for deplo * [ ] verify coinbase tx * [ ] use utreexo to verify tx inputs * verify scripts - * integrate with Shinigami, tbd + * integration with Shinigami, tbd * integration testing * [ ] test on individual historical blocks ### Milestone 2 - Real Data * [ ] feed it with real data - * [ ] produce and verify proofs of verification of individual blocks + * [ ] test that you can produce and verify proofs of individual blocks ### Milestone 3 - Recursive Verification * verify chain proofs with cairo verifier, tbd From bfa4521533d4cc205dd0f8821031185dc8028fa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski?= Date: Wed, 7 Aug 2024 14:26:11 +0200 Subject: [PATCH 19/37] fix 4 --- README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 4f9a36fb..2a66f8c2 100644 --- a/README.md +++ b/README.md @@ -53,17 +53,20 @@ Although this is a highly experimental project without immediate plans for deplo * header verification * [ ] block hash * [ ] previous block hash - * [ ] tx merkle root, - * [ ] proof-of-work, - * [ ] median time, + * [ ] proof-of-work + * [ ] median time * [ ] difficulty adjustment * transaction verification - * [ ] verify inputs - * [ ] verify outputs - * [ ] verify coinbase tx + * [ ] tx hash + * [ ] tx merkle root + * [ ] verify transaction fee + * utreexo + * [ ] fetch utreexo from some kind of bridge node, tbd * [ ] use utreexo to verify tx inputs * verify scripts * integration with Shinigami, tbd + * block verification + * [ ] verify coinbase tx * integration testing * [ ] test on individual historical blocks ### Milestone 2 - Real Data From 56e6ac4949db0fc7da50e75105ce375bea45ae9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski?= Date: Wed, 7 Aug 2024 14:30:09 +0200 Subject: [PATCH 20/37] fix markdown --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2a66f8c2..1f698af2 100644 --- a/README.md +++ b/README.md @@ -50,31 +50,40 @@ Although this is a highly experimental project without immediate plans for deplo ## Roadmap ### Milestone 1 - Block Verification + * header verification * [ ] block hash * [ ] previous block hash * [ ] proof-of-work * [ ] median time * [ ] difficulty adjustment + * transaction verification * [ ] tx hash * [ ] tx merkle root * [ ] verify transaction fee + * utreexo * [ ] fetch utreexo from some kind of bridge node, tbd * [ ] use utreexo to verify tx inputs + * verify scripts * integration with Shinigami, tbd + * block verification * [ ] verify coinbase tx + * integration testing * [ ] test on individual historical blocks + ### Milestone 2 - Real Data + * [ ] feed it with real data * [ ] test that you can produce and verify proofs of individual blocks + ### Milestone 3 - Recursive Verification - * verify chain proofs with cairo verifier, tbd + * verify chain proofs with cairo verifier, tbd ## Name reference From 9fafacd6840aba5d0e208349c82e2d1555380d34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski?= Date: Wed, 7 Aug 2024 14:31:53 +0200 Subject: [PATCH 21/37] fix markdown 2 --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 1f698af2..57dcfd31 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ Although this is a highly experimental project without immediate plans for deplo ### Milestone 1 - Block Verification * header verification + * [ ] block hash * [ ] previous block hash * [ ] proof-of-work @@ -59,21 +60,26 @@ Although this is a highly experimental project without immediate plans for deplo * [ ] difficulty adjustment * transaction verification + * [ ] tx hash * [ ] tx merkle root * [ ] verify transaction fee * utreexo + * [ ] fetch utreexo from some kind of bridge node, tbd * [ ] use utreexo to verify tx inputs * verify scripts + * integration with Shinigami, tbd * block verification + * [ ] verify coinbase tx * integration testing + * [ ] test on individual historical blocks ### Milestone 2 - Real Data From 3bf60fd2947309c3a76dd840627687953c988b03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski?= Date: Wed, 7 Aug 2024 14:35:37 +0200 Subject: [PATCH 22/37] fix markdown 3 --- README.md | 55 ++++++++++++++++++++++--------------------------------- 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 57dcfd31..005469b4 100644 --- a/README.md +++ b/README.md @@ -51,45 +51,34 @@ Although this is a highly experimental project without immediate plans for deplo ### Milestone 1 - Block Verification - * header verification - - * [ ] block hash - * [ ] previous block hash - * [ ] proof-of-work - * [ ] median time - * [ ] difficulty adjustment - - * transaction verification - - * [ ] tx hash - * [ ] tx merkle root - * [ ] verify transaction fee - - * utreexo - - * [ ] fetch utreexo from some kind of bridge node, tbd - * [ ] use utreexo to verify tx inputs - - * verify scripts - - * integration with Shinigami, tbd - - * block verification - - * [ ] verify coinbase tx - - * integration testing - - * [ ] test on individual historical blocks +* header verification + * [ ] block hash + * [ ] previous block hash + * [ ] proof-of-work + * [ ] median time + * [ ] difficulty adjustment +* transaction verification + * [ ] tx hash + * [ ] tx merkle root + * [ ] verify transaction fee +* utreexo + * [ ] fetch utreexo from some kind of bridge node, tbd + * [ ] use utreexo to verify tx inputs +* verify scripts + * integration with Shinigami, tbd +* block verification + * [ ] verify coinbase tx +* integration testing + * [ ] test on individual historical blocks ### Milestone 2 - Real Data - * [ ] feed it with real data - * [ ] test that you can produce and verify proofs of individual blocks +* [ ] feed it with real data +* [ ] test that you can produce and verify proofs of individual blocks ### Milestone 3 - Recursive Verification - * verify chain proofs with cairo verifier, tbd +* verify chain proofs with cairo verifier, tbd ## Name reference From 71fb420ed6faa12e1ab8752f2daf62e148c03f44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski?= Date: Wed, 7 Aug 2024 14:37:12 +0200 Subject: [PATCH 23/37] fix markdown 4 --- README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 005469b4..acbb1900 100644 --- a/README.md +++ b/README.md @@ -52,24 +52,24 @@ Although this is a highly experimental project without immediate plans for deplo ### Milestone 1 - Block Verification * header verification - * [ ] block hash - * [ ] previous block hash - * [ ] proof-of-work - * [ ] median time - * [ ] difficulty adjustment + * [ ] block hash + * [ ] previous block hash + * [ ] proof-of-work + * [ ] median time + * [ ] difficulty adjustment * transaction verification - * [ ] tx hash - * [ ] tx merkle root - * [ ] verify transaction fee + * [ ] tx hash + * [ ] tx merkle root + * [ ] verify transaction fee * utreexo - * [ ] fetch utreexo from some kind of bridge node, tbd - * [ ] use utreexo to verify tx inputs + * [ ] fetch utreexo from some kind of bridge node, tbd + * [ ] use utreexo to verify tx inputs * verify scripts - * integration with Shinigami, tbd + * integration with Shinigami, tbd * block verification - * [ ] verify coinbase tx + * [ ] verify coinbase tx * integration testing - * [ ] test on individual historical blocks + * [ ] test on individual historical blocks ### Milestone 2 - Real Data From 75b4a44961093d46af9303983c570756f5d564bd Mon Sep 17 00:00:00 2001 From: Xavek Date: Wed, 7 Aug 2024 19:03:39 +0545 Subject: [PATCH 24/37] address review comments --- src/validation.cairo | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/src/validation.cairo b/src/validation.cairo index 363d48aa..834ed93a 100644 --- a/src/validation.cairo +++ b/src/validation.cairo @@ -4,7 +4,7 @@ use super::state::{Block, ChainState}; impl BlockValidatorImpl of BlockValidator { fn validate_and_apply(self: ChainState, block: Block) -> Result { validate_prev_block_hash(@self, @block)?; - validate_proof_of_work(@self, @block)?; + validate_proof_of_work(@0_u256, @block)?; validate_target(@self, @block)?; validate_timestamp(@self, @block)?; @@ -29,9 +29,8 @@ fn validate_prev_block_hash(self: @ChainState, block: @Block) -> Result<(), Byte } } -fn validate_proof_of_work(self: @ChainState, block: @Block) -> Result<(), ByteArray> { - let target_u256: u256 = block.header.bits.clone().into(); - if block.header.prev_block_hash.clone() <= target_u256 { +fn validate_proof_of_work(target: @u256, block: @Block) -> Result<(), ByteArray> { + if block.header.prev_block_hash <= target { Result::Ok(()) } else { Result::Err( @@ -78,7 +77,7 @@ fn validate_merkle_root(self: @ChainState, block: @Block) -> Result<(), ByteArra #[cfg(test)] mod tests { - use super::{validate_target, validate_timestamp}; + use super::{validate_target, validate_timestamp, validate_proof_of_work}; use super::{Block, ChainState}; use super::super::state::{Header, Transaction, TxIn, TxOut}; @@ -144,4 +143,36 @@ mod tests { let result = validate_timestamp(@chain_state, @block); assert!(result.is_err(), "Median time is greater than block's timestamp"); } + + #[test] + fn test_validate_proof_of_work() { + let mut block = Block { + header: Header { + version: 1, prev_block_hash: 1, merkle_root_hash: 1, time: 12, bits: 1, nonce: 1, + }, + txs: ArrayTrait::new().span(), + }; + + // target is less than prev block hash + let result = validate_proof_of_work(@0_u256, @block); + assert!(result.is_err(), "Expect target less than prev block hash"); + + // target is greater than prev block hash + let result = validate_proof_of_work(@2_u256, @block); + assert!(result.is_ok(), "Expect target gt prev block hash"); + + // target is equal to prev block hash + let result = validate_proof_of_work(@1_u256, @block); + assert!(result.is_ok(), "Expect target equal to prev block hash"); + + // block prev block hash is greater than target + block.header.prev_block_hash = 2; + let result = validate_proof_of_work(@1_u256, @block); + assert!(result.is_err(), "Expect prev block hash gt target"); + + // block prev block hash is less than target + block.header.prev_block_hash = 9; + let result = validate_proof_of_work(@10_u256, @block); + assert!(result.is_ok(), "Expect prev block hash lt target"); + } } From 55cdd3bb900ba219d53e99ee9d38181937f48a63 Mon Sep 17 00:00:00 2001 From: Harsh Pratap Singh Date: Wed, 7 Aug 2024 18:51:59 +0530 Subject: [PATCH 25/37] fmt nit --- src/utils.cairo | 2 +- tests/tests.cairo | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils.cairo b/src/utils.cairo index e188b13f..51655339 100644 --- a/src/utils.cairo +++ b/src/utils.cairo @@ -32,4 +32,4 @@ pub fn fast_pow(base: u256, exp: u32) -> u256 { } base = base * base; } -} \ No newline at end of file +} diff --git a/tests/tests.cairo b/tests/tests.cairo index 2ee9eb93..76c15f51 100644 --- a/tests/tests.cairo +++ b/tests/tests.cairo @@ -1,7 +1,7 @@ use core::result::ResultTrait; use core::option::OptionTrait; use core::traits::Into; -use raito::engine::target_to_bits; +use raito::validation::target_to_bits; #[test] fn test_target_to_bits_large_target() { @@ -63,4 +63,4 @@ fn test_target_to_bits_overflow_target() { let target: u256 = 0x01000000000000000000000000000000000000000000000000000000000000000; let result = target_to_bits(target); assert!(result.is_err(), "Should error on overflow target"); -} \ No newline at end of file +} From 8eb8ccc972311dae49f6383802e7ff2c806a1b3f Mon Sep 17 00:00:00 2001 From: Harsh Pratap Singh Date: Wed, 7 Aug 2024 18:52:31 +0530 Subject: [PATCH 26/37] fmt nit --- src/utils.cairo | 2 +- tests/tests.cairo | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils.cairo b/src/utils.cairo index e188b13f..51655339 100644 --- a/src/utils.cairo +++ b/src/utils.cairo @@ -32,4 +32,4 @@ pub fn fast_pow(base: u256, exp: u32) -> u256 { } base = base * base; } -} \ No newline at end of file +} diff --git a/tests/tests.cairo b/tests/tests.cairo index 52ab226e..7d1b9bf2 100644 --- a/tests/tests.cairo +++ b/tests/tests.cairo @@ -1,4 +1,4 @@ -use raito::engine::bits_to_target; +use raito::validation::bits_to_target; #[test] fn test_bits_to_target_01003456() { @@ -73,4 +73,4 @@ fn test_bits_to_target_1707a429() { result.unwrap() == 0x00000000000000000007a4290000000000000000000000000000000000000000_u256, "Incorrect target for 0x1707a429" ); -} \ No newline at end of file +} From 045e3994b885ba811d445a433522232179c54bd8 Mon Sep 17 00:00:00 2001 From: Xavek Date: Wed, 7 Aug 2024 20:40:06 +0545 Subject: [PATCH 27/37] address review minor comment --- src/validation.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/validation.cairo b/src/validation.cairo index 834ed93a..c7605886 100644 --- a/src/validation.cairo +++ b/src/validation.cairo @@ -34,7 +34,7 @@ fn validate_proof_of_work(target: @u256, block: @Block) -> Result<(), ByteArray> Result::Ok(()) } else { Result::Err( - "Insufficient proof of work. Expected block hash {block.header.prev_block_hash} to be less than or equal to target {block.header.bits}." + "Insufficient proof of work. Expected block hash {block.header.prev_block_hash} to be less than or equal to {target}." ) } } From dc9dafba608f088e5e24a35154471d013198ca7e Mon Sep 17 00:00:00 2001 From: Harsh Pratap Singh Date: Wed, 7 Aug 2024 20:44:10 +0530 Subject: [PATCH 28/37] nits --- src/lib.cairo | 2 +- src/utils.cairo | 4 ++-- src/validation.cairo | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/lib.cairo b/src/lib.cairo index 6653860b..ce41db81 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -1,5 +1,5 @@ pub mod utils; +pub mod validation; mod state; -mod validation; mod main; diff --git a/src/utils.cairo b/src/utils.cairo index 51655339..fdf589fe 100644 --- a/src/utils.cairo +++ b/src/utils.cairo @@ -15,10 +15,10 @@ pub fn shr(value: u256, shift: u32) -> u256 { // Reference: https://github.com/keep-starknet-strange/alexandria/blob/bcdca70afdf59c9976148e95cebad5cf63d75a7f/packages/math/src/fast_power.cairo#L12 pub fn fast_pow(base: u256, exp: u32) -> u256 { if exp == 0 { - return 1.into(); + return 1_u256; } - let mut res: u256 = 1.into(); + let mut res: u256 = 1_u256; let mut base: u256 = base; let mut exp: u32 = exp; diff --git a/src/validation.cairo b/src/validation.cairo index 9d216292..312aba0b 100644 --- a/src/validation.cairo +++ b/src/validation.cairo @@ -2,6 +2,8 @@ use super::state::{Block, ChainState, UtreexoState}; use raito::utils::shl; use raito::utils::shr; +const MAX_TARGET: u256 = 0x00000000FFFF0000000000000000000000000000000000000000000000000000; + #[generate_trait] impl BlockValidatorImpl of BlockValidator { fn validate_and_apply(self: ChainState, block: Block) -> Result { From 26472d7642e3509094715da5a517951b5b4d29d5 Mon Sep 17 00:00:00 2001 From: Harsh Pratap Singh Date: Wed, 7 Aug 2024 20:45:31 +0530 Subject: [PATCH 29/37] nits --- src/lib.cairo | 2 +- src/utils.cairo | 4 ++-- src/validation.cairo | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/lib.cairo b/src/lib.cairo index 6653860b..ce41db81 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -1,5 +1,5 @@ pub mod utils; +pub mod validation; mod state; -mod validation; mod main; diff --git a/src/utils.cairo b/src/utils.cairo index 51655339..fdf589fe 100644 --- a/src/utils.cairo +++ b/src/utils.cairo @@ -15,10 +15,10 @@ pub fn shr(value: u256, shift: u32) -> u256 { // Reference: https://github.com/keep-starknet-strange/alexandria/blob/bcdca70afdf59c9976148e95cebad5cf63d75a7f/packages/math/src/fast_power.cairo#L12 pub fn fast_pow(base: u256, exp: u32) -> u256 { if exp == 0 { - return 1.into(); + return 1_u256; } - let mut res: u256 = 1.into(); + let mut res: u256 = 1_u256; let mut base: u256 = base; let mut exp: u32 = exp; diff --git a/src/validation.cairo b/src/validation.cairo index ccd56c82..37b26906 100644 --- a/src/validation.cairo +++ b/src/validation.cairo @@ -2,6 +2,8 @@ use super::state::{Block, ChainState, UtreexoState}; use raito::utils::shl; use raito::utils::shr; +const MAX_TARGET: u256 = 0x00000000FFFF0000000000000000000000000000000000000000000000000000; + #[generate_trait] impl BlockValidatorImpl of BlockValidator { fn validate_and_apply(self: ChainState, block: Block) -> Result { From 7981cd14e1c6c2cc8baa336fe5d0de9783fc4345 Mon Sep 17 00:00:00 2001 From: Harsh Pratap Singh Date: Wed, 7 Aug 2024 20:55:28 +0530 Subject: [PATCH 30/37] fmt nit --- src/utils.cairo | 3 ++- src/validation.cairo | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/utils.cairo b/src/utils.cairo index fdf589fe..0e542db3 100644 --- a/src/utils.cairo +++ b/src/utils.cairo @@ -12,7 +12,8 @@ pub fn shr(value: u256, shift: u32) -> u256 { } // Fast exponentiation using the square-and-multiply algorithm -// Reference: https://github.com/keep-starknet-strange/alexandria/blob/bcdca70afdf59c9976148e95cebad5cf63d75a7f/packages/math/src/fast_power.cairo#L12 +// Reference: +// https://github.com/keep-starknet-strange/alexandria/blob/bcdca70afdf59c9976148e95cebad5cf63d75a7f/packages/math/src/fast_power.cairo#L12 pub fn fast_pow(base: u256, exp: u32) -> u256 { if exp == 0 { return 1_u256; diff --git a/src/validation.cairo b/src/validation.cairo index 37b26906..02501b68 100644 --- a/src/validation.cairo +++ b/src/validation.cairo @@ -96,7 +96,7 @@ pub fn target_to_bits(target: u256) -> Result { // Extract mantissa (most significant 3 bytes) let mut mantissa: u32 = shr(compact, (size - 3) * 8).try_into().unwrap(); - // Normalize + // Normalize if mantissa > 0x7fffff { mantissa = (mantissa + 0x80) / 0x100; size += 1; @@ -113,7 +113,7 @@ pub fn target_to_bits(target: u256) -> Result { // Convert size to u256 let size_u256: u256 = size.into(); - // Combine size and mantissa + // Combine size and mantissa let result: u32 = (shl(size_u256, 24) + mantissa.into()).try_into().unwrap(); Result::Ok(result) From 6d00d1d0fc6c629bd910558f9ef2351ffee8ea3a Mon Sep 17 00:00:00 2001 From: Harsh Pratap Singh Date: Wed, 7 Aug 2024 20:55:49 +0530 Subject: [PATCH 31/37] fmt nit --- src/utils.cairo | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils.cairo b/src/utils.cairo index fdf589fe..0e542db3 100644 --- a/src/utils.cairo +++ b/src/utils.cairo @@ -12,7 +12,8 @@ pub fn shr(value: u256, shift: u32) -> u256 { } // Fast exponentiation using the square-and-multiply algorithm -// Reference: https://github.com/keep-starknet-strange/alexandria/blob/bcdca70afdf59c9976148e95cebad5cf63d75a7f/packages/math/src/fast_power.cairo#L12 +// Reference: +// https://github.com/keep-starknet-strange/alexandria/blob/bcdca70afdf59c9976148e95cebad5cf63d75a7f/packages/math/src/fast_power.cairo#L12 pub fn fast_pow(base: u256, exp: u32) -> u256 { if exp == 0 { return 1_u256; From 38ffcd1122e6fe223c9d70bccfd2c851586d5c25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski?= Date: Wed, 7 Aug 2024 16:23:27 +0200 Subject: [PATCH 32/37] add tg group --- README.md | 4 ++++ src/lib.cairo | 5 ++--- src/validation.cairo | 53 +++++++++++++++++++++++++++++++++++++++----- 3 files changed, 54 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index acbb1900..372b9f8f 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,10 @@ Raito is a reference to Light Yagami (夜神月, Yagami Raito) from the manga/an ![Raito and Raito](./docs/img/memes/raito_shinigami_fusion.jpg) +# Contact +* [Raito Telegram](https://t.me/RaitoStarknet) +* [Raito OnlyDust](https://app.onlydust.com/p/raito---bitcoin-zk-client) + ## Usage This will compile all the components: diff --git a/src/lib.cairo b/src/lib.cairo index ce41db81..49ebbf17 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -1,5 +1,4 @@ -pub mod utils; -pub mod validation; - +mod utils; +mod validation; mod state; mod main; diff --git a/src/validation.cairo b/src/validation.cairo index d88aa3ea..e49306c5 100644 --- a/src/validation.cairo +++ b/src/validation.cairo @@ -1,19 +1,20 @@ -use super::state::{Block, ChainState, UtreexoState}; -use raito::utils::shl; -use raito::utils::shr; +use super::utils::{shl, shr}; +use super::state::{Block, ChainState, Transaction, UtreexoState}; const MAX_TARGET: u256 = 0x00000000FFFF0000000000000000000000000000000000000000000000000000; + #[generate_trait] impl BlockValidatorImpl of BlockValidator { fn validate_and_apply(self: ChainState, block: Block) -> Result { + + validate_block_hash(@self, @block)?; validate_prev_block_hash(@self, @block)?; validate_proof_of_work(@0_u256, @block)?; validate_target(@self, @block)?; validate_timestamp(@self, @block)?; - validate_merkle_root(@self, @block)?; - // validate_and_apply_transactions + let (total_fee, merkle_root) = get_fee_and_merkle_root(@self, @block)?; let prev_timestamps = next_prev_timestamps(@self, @block); let total_work = compute_total_work(@self, @block); @@ -25,6 +26,23 @@ impl BlockValidatorImpl of BlockValidator { } } +#[generate_trait] +impl TransactionImplIml of TransactionImpl { + fn txid(self: @Transaction) -> u256 { + // TODO: implement + 0 + } + fn fee(self: @Transaction) -> u256 { + // TODO: implement + 0 + } +} + +fn validate_block_hash(self: @ChainState, block: @Block) -> Result<(), ByteArray> { + // TODO: implement + Result::Ok(()) +} + fn validate_prev_block_hash(self: @ChainState, block: @Block) -> Result<(), ByteArray> { if self.best_block_hash == block.header.prev_block_hash { Result::Ok(()) @@ -124,6 +142,31 @@ pub fn target_to_bits(target: u256) -> Result { Result::Ok(result) } +fn get_fee_and_merkle_root(self: @ChainState, block: @Block) -> Result<(u256, u256), ByteArray> { + + let mut txids = ArrayTrait::new(); + let mut total_fee = 0; + + for tx in *block.txs { + txids.append(tx.txid()); + total_fee += tx.fee(); + }; + + Result::Ok((total_fee, merkle_root(txids))) +} + +fn merkle_root(txids: Array) -> u256 { + // TODO: implement + 0 +} + +fn validate_transaction(tx: @Transaction) -> Result { + // TODO: implement + Result::Ok(0) +} + + + #[cfg(test)] mod tests { use super::{validate_target, validate_timestamp, validate_proof_of_work}; From 4d39b81f3f3020def404cbcc4bfe8b842fa2bd07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski?= Date: Wed, 7 Aug 2024 21:46:46 +0200 Subject: [PATCH 33/37] validate_coinbase draft --- src/state.cairo | 2 -- src/validation.cairo | 42 +++++++++++++++++++++++------------------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/state.cairo b/src/state.cairo index 2f5e3653..6fcaf700 100644 --- a/src/state.cairo +++ b/src/state.cairo @@ -75,8 +75,6 @@ pub struct Header { pub version: u32, /// The hash of the previous block in the blockchain. pub prev_block_hash: u256, - /// The Merkle root hash of the transactions in the block. - pub merkle_root_hash: u256, /// The timestamp of the block. pub time: u32, /// The difficulty target for mining the block. diff --git a/src/validation.cairo b/src/validation.cairo index e49306c5..262b9917 100644 --- a/src/validation.cairo +++ b/src/validation.cairo @@ -3,31 +3,40 @@ use super::state::{Block, ChainState, Transaction, UtreexoState}; const MAX_TARGET: u256 = 0x00000000FFFF0000000000000000000000000000000000000000000000000000; - #[generate_trait] impl BlockValidatorImpl of BlockValidator { fn validate_and_apply(self: ChainState, block: Block) -> Result { - - validate_block_hash(@self, @block)?; validate_prev_block_hash(@self, @block)?; validate_proof_of_work(@0_u256, @block)?; validate_target(@self, @block)?; validate_timestamp(@self, @block)?; - let (total_fee, merkle_root) = get_fee_and_merkle_root(@self, @block)?; + let (total_fees, merkle_root) = fee_and_merkle_root(@self, @block)?; + + validate_coinbase(@block, total_fees)?; + let best_block_hash = block_hash(@block, merkle_root)?; let prev_timestamps = next_prev_timestamps(@self, @block); let total_work = compute_total_work(@self, @block); let (current_target, epoch_start_time) = adjust_difficulty(@self, @block); + let block_height = self.block_height + 1; Result::Ok( - ChainState { total_work, current_target, epoch_start_time, prev_timestamps, ..self, } + ChainState { + block_height, + total_work, + best_block_hash, + current_target, + epoch_start_time, + prev_timestamps, + ..self, + } ) } } #[generate_trait] -impl TransactionImplIml of TransactionImpl { +impl TransactionValidatorImpl of TransactionValidator { fn txid(self: @Transaction) -> u256 { // TODO: implement 0 @@ -38,9 +47,9 @@ impl TransactionImplIml of TransactionImpl { } } -fn validate_block_hash(self: @ChainState, block: @Block) -> Result<(), ByteArray> { +fn block_hash(block: @Block, merkle_root: u256) -> Result { // TODO: implement - Result::Ok(()) + Result::Ok(0) } fn validate_prev_block_hash(self: @ChainState, block: @Block) -> Result<(), ByteArray> { @@ -144,6 +153,7 @@ pub fn target_to_bits(target: u256) -> Result { fn get_fee_and_merkle_root(self: @ChainState, block: @Block) -> Result<(u256, u256), ByteArray> { +fn fee_and_merkle_root(self: @ChainState, block: @Block) -> Result<(u256, u256), ByteArray> { let mut txids = ArrayTrait::new(); let mut total_fee = 0; @@ -160,13 +170,11 @@ fn merkle_root(txids: Array) -> u256 { 0 } -fn validate_transaction(tx: @Transaction) -> Result { - // TODO: implement - Result::Ok(0) +fn validate_coinbase(block: @Block, total_fees: u256) -> Result<(), ByteArray> { + //TODO implement + Result::Ok(()) } - - #[cfg(test)] mod tests { use super::{validate_target, validate_timestamp, validate_proof_of_work}; @@ -185,9 +193,7 @@ mod tests { utreexo_state: UtreexoState { roots: array![].span() }, }; let mut block = Block { - header: Header { - version: 1, prev_block_hash: 1, merkle_root_hash: 1, time: 1, bits: 1, nonce: 1, - }, + header: Header { version: 1, prev_block_hash: 1, time: 1, bits: 1, nonce: 1, }, txs: ArrayTrait::new().span(), }; @@ -217,9 +223,7 @@ mod tests { utreexo_state: UtreexoState { roots: array![].span() }, }; let mut block = Block { - header: Header { - version: 1, prev_block_hash: 1, merkle_root_hash: 1, time: 12, bits: 1, nonce: 1, - }, + header: Header { version: 1, prev_block_hash: 1, time: 12, bits: 1, nonce: 1, }, txs: ArrayTrait::new().span(), }; From 0cdc8b3672a6bf93a441190571d905e5a420234e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski?= Date: Wed, 7 Aug 2024 21:58:51 +0200 Subject: [PATCH 34/37] fixes --- src/lib.cairo | 2 +- src/validation.cairo | 6 +----- tests/tests.cairo | 3 --- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/lib.cairo b/src/lib.cairo index 49ebbf17..7778f44f 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -1,4 +1,4 @@ mod utils; -mod validation; +pub mod validation; mod state; mod main; diff --git a/src/validation.cairo b/src/validation.cairo index 262b9917..ce17c749 100644 --- a/src/validation.cairo +++ b/src/validation.cairo @@ -151,8 +151,6 @@ pub fn target_to_bits(target: u256) -> Result { Result::Ok(result) } -fn get_fee_and_merkle_root(self: @ChainState, block: @Block) -> Result<(u256, u256), ByteArray> { - fn fee_and_merkle_root(self: @ChainState, block: @Block) -> Result<(u256, u256), ByteArray> { let mut txids = ArrayTrait::new(); let mut total_fee = 0; @@ -245,9 +243,7 @@ mod tests { #[test] fn test_validate_proof_of_work() { let mut block = Block { - header: Header { - version: 1, prev_block_hash: 1, merkle_root_hash: 1, time: 12, bits: 1, nonce: 1, - }, + header: Header { version: 1, prev_block_hash: 1, time: 12, bits: 1, nonce: 1, }, txs: ArrayTrait::new().span(), }; diff --git a/tests/tests.cairo b/tests/tests.cairo index 76c15f51..0646d0a5 100644 --- a/tests/tests.cairo +++ b/tests/tests.cairo @@ -1,6 +1,3 @@ -use core::result::ResultTrait; -use core::option::OptionTrait; -use core::traits::Into; use raito::validation::target_to_bits; #[test] From e60c611d372f2ffaa5b9073a497345e0d08b3542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski?= Date: Wed, 7 Aug 2024 22:04:18 +0200 Subject: [PATCH 35/37] fix md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 372b9f8f..ed92fc57 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ Raito is a reference to Light Yagami (夜神月, Yagami Raito) from the manga/an ![Raito and Raito](./docs/img/memes/raito_shinigami_fusion.jpg) # Contact + * [Raito Telegram](https://t.me/RaitoStarknet) * [Raito OnlyDust](https://app.onlydust.com/p/raito---bitcoin-zk-client) From f5ca18ec0bc6fcbc0bea62c32267f2b79cbdeb00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski?= Date: Wed, 7 Aug 2024 22:47:06 +0200 Subject: [PATCH 36/37] :busts_in_silhouette: Add @harsh-ps-2003 as a contributor --- .all-contributorsrc | 9 +++++++++ README.md | 3 +++ 2 files changed, 12 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 89d255a6..2540cf08 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -72,6 +72,15 @@ "contributions": [ "code" ] + }, + { + "login": "harsh-ps-2003", + "name": "Harsh Pratap Singh", + "avatar_url": "https://avatars.githubusercontent.com/u/119954739?v=4", + "profile": "https://github.com/harsh-ps-2003", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index ed92fc57..52e3de2b 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d lomasson
lomasson

💻 Michael Zaikin
Michael Zaikin

💻 + + Harsh Pratap Singh
Harsh Pratap Singh

💻 + From 15f6e89cbbcded11d033bafebfc8fef16bfa9a8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski?= Date: Wed, 7 Aug 2024 22:47:38 +0200 Subject: [PATCH 37/37] :busts_in_silhouette: Add @Xavek as a contributor --- .all-contributorsrc | 9 +++++++++ README.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 2540cf08..b873cde0 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -81,6 +81,15 @@ "contributions": [ "code" ] + }, + { + "login": "Xavek", + "name": "Xavek", + "avatar_url": "https://avatars.githubusercontent.com/u/61218841?v=4", + "profile": "https://github.com/Xavek", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index 52e3de2b..5c3c8408 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Harsh Pratap Singh
Harsh Pratap Singh

💻 + Xavek
Xavek

💻