Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

start compute block reward impl #37

Merged
53 changes: 52 additions & 1 deletion src/validation.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ 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
pub const POW_SATS_AMOUNT: u256 = 8; // Pow to convert in SATS

#[generate_trait]
impl BlockValidatorImpl of BlockValidator {
Expand Down Expand Up @@ -206,9 +208,22 @@ fn validate_coinbase(block: @Block, total_fees: u256) -> Result<(), ByteArray> {
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<u64, ByteArray> {
MSghais marked this conversation as resolved.
Show resolved Hide resolved
let number_halvings = block_height / 210_000;
match number_halvings {
MSghais marked this conversation as resolved.
Show resolved Hide resolved
0 => { return Result::Ok(REWARD_INITIAL.try_into().unwrap()); }, // return REWARD_INITAL
_ => {}
}
let current_reward = shr(REWARD_INITIAL, number_halvings);
MSghais marked this conversation as resolved.
Show resolved Hide resolved
Result::Ok((current_reward).try_into().unwrap())
}
#[cfg(test)]
mod tests {
use super::{validate_target, validate_timestamp, validate_proof_of_work};
use super::{
validate_target, validate_timestamp, validate_proof_of_work, compute_block_reward, shr,
REWARD_INITIAL, POW_SATS_AMOUNT
};
use super::{Block, ChainState, UtreexoState};
use super::super::state::{Header, Transaction, TxIn, TxOut};

Expand Down Expand Up @@ -302,4 +317,40 @@ mod tests {
let result = validate_proof_of_work(@10_u256, @block);
assert!(result.is_ok(), "Expect prev block hash lt target");
}


// Ref implementation here: https://github.com/bitcoin/bitcoin/blob/0f68a05c084bef3e53e3f549c403bc90b1db319c/src/test/validation_tests.cpp#L24
#[test]
fn test_compute_block_reward() {
let max_halvings: u32 = 64;
MSghais marked this conversation as resolved.
Show resolved Hide resolved
let reward_initial: u32 = REWARD_INITIAL.try_into().unwrap();
let halving_block_range = 210_000; // every 210 000 blocks
let mut nprevious_subsidy = REWARD_INITIAL * 2;
let mut loop_index: u32 = 0;
assert_eq!(nprevious_subsidy.try_into().unwrap(), reward_initial*2);

// Testing all halvings rewards possible
loop {
MSghais marked this conversation as resolved.
Show resolved Hide resolved
if loop_index == max_halvings {
break;
}
let block_height: u32 = loop_index * halving_block_range;
// Compute reward
let reward = compute_block_reward(block_height);
// Check if reward is decrease when another halving is in process.
if let Result::Ok(r) = reward {
let cast_reward_initial: u64 = reward_initial.try_into().unwrap();
assert!(r <= cast_reward_initial);
let cast_reward_previous: u64 = nprevious_subsidy.try_into().unwrap();
assert_eq!(r, cast_reward_previous/2);
nprevious_subsidy = r.try_into().unwrap();
}
loop_index = loop_index + 1;
};
// Last halving with 0 block reward
let last_reward = compute_block_reward(max_halvings*halving_block_range);
if let Result::Ok(r) = last_reward {
assert_eq!(r, 0);
};
}
}