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

Impl adjust difficulty #100

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/state.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ impl ChainStateDefault of Default<ChainState> {
total_work: 0,
best_block_hash: 0_u256.into(),
current_target: 26959535291011309493156476344723991336010898738574164086137773096960,
epoch_start_time: 0,
epoch_start_time: 1231006505,
prev_timestamps: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
].span(), utreexo_state: Default::default(),
Expand Down
6 changes: 5 additions & 1 deletion src/validation.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ pub impl BlockValidatorImpl of BlockValidator {
validate_coinbase(block.txs[0], total_fees, block_height, wtxid_root)?;

let (current_target, epoch_start_time) = adjust_difficulty(
self.current_target, self.epoch_start_time, block_height, block.header.time
self.current_target,
self.epoch_start_time,
self.block_height.unwrap_or(0),
*self.prev_timestamps[self.prev_timestamps.len() - 1],
block.header.time
);
let total_work = compute_total_work(self.total_work, current_target);
let best_block_hash = block.header.hash(self.best_block_hash, txid_root);
Expand Down
130 changes: 126 additions & 4 deletions src/validation/difficulty.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ use raito::utils::{hash::Hash, bit_shifts::{shl, shr}};

/// Maximum difficulty target allowed
const MAX_TARGET: u256 = 0x00000000FFFF0000000000000000000000000000000000000000000000000000;
/// Number of blocks per epoch
const BLOCKS_PER_EPOCH: u32 = 2016;
Jeanmichel7 marked this conversation as resolved.
Show resolved Hide resolved
/// Duration in seconds of an expected epoch of 2 weeks
const EXPECTED_EPOCH_TIMESPAN: u32 = 60 * 60 * 24 * 14;

/// Check if the given bits match the target difficulty.
pub fn validate_bits(target: u256, bits: u32) -> Result<(), ByteArray> {
Expand All @@ -19,12 +23,42 @@ pub fn validate_bits(target: u256, bits: u32) -> Result<(), ByteArray> {
}

/// Adjusts difficulty target given the block height and timestamp.
/// Previous block time is needed to calculate the time span.
/// Actual block time is needed to calculate the new epoch start time.
/// Returns new difficulty target and new epoch start time.
m-kus marked this conversation as resolved.
Show resolved Hide resolved
pub fn adjust_difficulty(
current_target: u256, epoch_start_time: u32, block_height: u32, block_time: u32
/// TODO: Split this function into smaller functions
current_target: u256,
epoch_start_time: u32,
block_height: u32,
prev_block_time: u32,
block_time: u32
) -> (u256, u32) {
// TODO: implement
(current_target, epoch_start_time)
if block_height % BLOCKS_PER_EPOCH == BLOCKS_PER_EPOCH - 1 {
let mut time_span = prev_block_time - epoch_start_time;

// Limit adjustment step
if (time_span < EXPECTED_EPOCH_TIMESPAN / 4) {
time_span = EXPECTED_EPOCH_TIMESPAN / 4;
}
if (time_span > EXPECTED_EPOCH_TIMESPAN * 4) {
time_span = EXPECTED_EPOCH_TIMESPAN * 4;
}

// Retarget calculation
let mut bn_new: u256 = current_target;
bn_new *= time_span.into();
bn_new /= EXPECTED_EPOCH_TIMESPAN.into();

if bn_new < MAX_TARGET {
// bits_to_target(target_to_bits(x)) to reduce difficulty precision
return (bits_to_target(target_to_bits(bn_new).unwrap()).unwrap(), block_time);
} else {
return (MAX_TARGET, block_time);
}
} else { // No adjustment needed, return current target and epoch start time
(current_target, epoch_start_time)
}
}

/// Convert target value to the compact form (bits)
Expand Down Expand Up @@ -108,7 +142,95 @@ fn bits_to_target(bits: u32) -> Result<u256, ByteArray> {

#[cfg(test)]
mod tests {
use super::{bits_to_target, target_to_bits};
use super::{bits_to_target, target_to_bits, adjust_difficulty};

#[test]
fn test_adjust_difficulty_block_2016_no_retargeting() {
// chainstate before block 2016
let current_target: u256 =
0x00000000ffff0000000000000000000000000000000000000000000000000000_u256;
let epoch_start_time: u32 = 1231006505;
let block_height: u32 = 2015;
let prev_block_time: u32 = 1233061996;

// block 2016
let block_time: u32 = 1233063531;

let (new_target, new_epoch_start_time) = adjust_difficulty(
current_target, epoch_start_time, block_height, prev_block_time, block_time
);

assert_eq!(
new_target, 0x00000000ffff0000000000000000000000000000000000000000000000000000_u256
);
assert_eq!(new_epoch_start_time, 1233063531);
}

#[test]
fn test_adjust_difficulty_block_2017_no_retargeting_no_new_epoch() {
// chainstate before block 2017
let current_target: u256 =
0x00000000ffff0000000000000000000000000000000000000000000000000000_u256;
let epoch_start_time: u32 = 1233063531;
let block_height: u32 = 2016;
let prev_block_time: u32 = 1233063531;

// block 2017
let block_time: u32 = 1233064909;

let (new_target, new_epoch_start_time) = adjust_difficulty(
current_target, epoch_start_time, block_height, prev_block_time, block_time
);

assert_eq!(
new_target, 0x00000000ffff0000000000000000000000000000000000000000000000000000_u256
);
assert_eq!(new_epoch_start_time, 1233063531);
}

#[test]
fn test_adjust_difficulty_block_32256_decrease() {
// chainstate before block 32256
let current_target: u256 =
0x00000000ffff0000000000000000000000000000000000000000000000000000_u256;
let epoch_start_time: u32 = 1261130161;
let block_height: u32 = 32255;
let prev_block_time: u32 = 1262152739;

// block 32256
let block_time: u32 = 1262153464;

let (new_target, new_epoch_start_time) = adjust_difficulty(
current_target, epoch_start_time, block_height, prev_block_time, block_time
);

assert_eq!(
new_target, 0x00000000d86a0000000000000000000000000000000000000000000000000000_u256
);
assert_eq!(new_epoch_start_time, 1262153464);
}

#[test]
fn test_adjust_difficulty_block_56448_increase() {
// chainstate before block 56448
let current_target: u256 =
0x0000000013ec5300000000000000000000000000000000000000000000000000_u256;
let epoch_start_time: u32 = 1272966376;
let block_height: u32 = 56447;
let prev_block_time: u32 = 1274278387;

// block 56448
let block_time: u32 = 1274278435;

let (new_target, new_epoch_start_time) = adjust_difficulty(
current_target, epoch_start_time, block_height, prev_block_time, block_time
);

assert_eq!(
new_target, 0x00000000159c2400000000000000000000000000000000000000000000000000_u256
);
assert_eq!(new_epoch_start_time, 1274278435);
}

#[test]
fn test_bits_to_target_01003456() {
Expand Down
17 changes: 11 additions & 6 deletions tests/tests.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@ fn test_block0() {
assert_eq!(result.block_height.unwrap(), 0);
assert_eq!(result.total_work, 4295032833);
assert_eq!(result.prev_timestamps, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1231006505].span());
assert_eq!(
result.current_target, 0x00000000ffff0000000000000000000000000000000000000000000000000000
);
println!("result.epoch_start_time: {:?}", result.epoch_start_time);
assert_eq!(result.epoch_start_time, 1231006505);
//to impl
// assert_eq!(result.best_block_hash, 0_u256.into());
// assert_eq!(result.current_target, 0_u256);
// assert_eq!(result.epoch_start_time, 0);
// assert_eq!(result.utreexo_state.roots, [...]);

}
Expand All @@ -32,7 +35,7 @@ fn test_block170() {
total_work: 0,
best_block_hash: 0_u256.into(),
current_target: 26959535291011309493156476344723991336010898738574164086137773096960,
epoch_start_time: 0,
epoch_start_time: 1231006505,
prev_timestamps: [
1231702618,
1231703466,
Expand Down Expand Up @@ -73,10 +76,12 @@ fn test_block170() {
1231731025
].span()
);
// //to impl
assert_eq!(
result.current_target, 0x00000000ffff0000000000000000000000000000000000000000000000000000
);
assert_eq!(result.epoch_start_time, 1231006505);
//to impl
// assert_eq!(result.best_block_hash, 0_u256.into());
// assert_eq!(result.current_target, 0_u256);
// assert_eq!(result.epoch_start_time, 0);
// assert_eq!(result.utreexo_state.roots, [...]);
}

Expand Down