Difficulty adjustment fix
This commit is contained in:
parent
88e49d6230
commit
e463782b6f
|
@ -340,17 +340,15 @@ async def validate_unfinished_header_block(
|
|||
)
|
||||
if expected_sub_epoch_summary.get_hash() != ses_hash:
|
||||
return None, Err.INVALID_SUB_EPOCH_SUMMARY
|
||||
print(f"Verified sub epoch: {expected_sub_epoch_summary}")
|
||||
else:
|
||||
# 3d. Check that we don't have to include a sub-epoch summary
|
||||
if new_sub_slot and not genesis_block:
|
||||
print("New sub slot")
|
||||
finishes = finishes_sub_epoch(
|
||||
constants, prev_sb.height, prev_sb.deficit, False, sub_blocks, prev_sb.prev_hash
|
||||
)
|
||||
if finishes:
|
||||
return None, Err.INVALID_SUB_EPOCH_SUMMARY
|
||||
else:
|
||||
print("Not new sub-slot")
|
||||
|
||||
# 4. Check proof of space
|
||||
if header_block.reward_chain_sub_block.challenge_chain_sp_vdf is None:
|
||||
|
@ -680,7 +678,7 @@ async def validate_unfinished_header_block(
|
|||
# For blocks 1 to 10, average timestamps of all previous blocks
|
||||
assert curr_sb.height == 0
|
||||
prev_time: uint64 = uint64(int(sum(last_timestamps) // len(last_timestamps)))
|
||||
if header_block.foliage_block.timestamp < prev_time:
|
||||
if header_block.foliage_block.timestamp <= prev_time:
|
||||
return None, Err.TIMESTAMP_TOO_FAR_IN_PAST
|
||||
if header_block.foliage_block.timestamp > int(time.time() + constants.MAX_FUTURE_TIME):
|
||||
return None, Err.TIMESTAMP_TOO_FAR_IN_FUTURE
|
||||
|
|
|
@ -49,8 +49,10 @@ def _get_last_block_in_previous_epoch(
|
|||
|
||||
# The sub-blocks selected for the timestamps are the last sub-block which is also a block, and which is infused
|
||||
# before the final sub-block in the epoch. Block at height 0 is an exception.
|
||||
height_epoch_surpass: uint32 = next_height % constants.EPOCH_SUB_BLOCKS
|
||||
if height_epoch_surpass > constants.MAX_SLOT_SUB_BLOCKS:
|
||||
# TODO: check edge cases here
|
||||
height_epoch_surpass: uint32 = next_height - (next_height % constants.EPOCH_SUB_BLOCKS)
|
||||
height_prev_epoch_surpass: uint32 = height_epoch_surpass - constants.EPOCH_SUB_BLOCKS
|
||||
if (next_height - height_epoch_surpass) > constants.MAX_SLOT_SUB_BLOCKS:
|
||||
raise ValueError(f"Height at {next_height} should not create a new slot, it is far past the epoch barrier")
|
||||
|
||||
# If the prev slot is the first slot, the iterations start at 0
|
||||
|
@ -59,24 +61,27 @@ def _get_last_block_in_previous_epoch(
|
|||
prev_slot_start_iters: uint128
|
||||
prev_slot_time_start: uint64
|
||||
|
||||
if height_epoch_surpass == 0:
|
||||
# The genesis block is an edge case, where we measure from the first block in epoch, as opposed to the last
|
||||
# block in the previous epoch
|
||||
return _get_blocks_at_height(height_to_hash, sub_blocks, prev_sb, uint32(0))[1]
|
||||
if height_prev_epoch_surpass == 0:
|
||||
# The genesis block is an edge case, where we measure from the first block in epoch (height 0), as opposed to
|
||||
# the last sub-block in the previous epoch, which would be height -1
|
||||
return _get_blocks_at_height(height_to_hash, sub_blocks, prev_sb, uint32(0))[0]
|
||||
else:
|
||||
fetched_blocks = _get_blocks_at_height(
|
||||
height_to_hash,
|
||||
sub_blocks,
|
||||
prev_sb,
|
||||
uint32(height_epoch_surpass - constants.EPOCH_SUB_BLOCKS - constants.MAX_SLOT_SUB_BLOCKS - 1),
|
||||
uint32(height_prev_epoch_surpass - constants.MAX_SLOT_SUB_BLOCKS - 1),
|
||||
uint32(2 * constants.MAX_SLOT_SUB_BLOCKS + 1),
|
||||
)
|
||||
# This is the last sb in the slot at which we surpass the height. The last block in epoch will be before this.
|
||||
last_sb_in_slot: SubBlockRecord = fetched_blocks[constants.MAX_SLOT_SUB_BLOCKS]
|
||||
fetched_index: int = constants.MAX_SLOT_SUB_BLOCKS + 1
|
||||
fetched_index: int = constants.MAX_SLOT_SUB_BLOCKS
|
||||
last_sb_in_slot: SubBlockRecord = fetched_blocks[fetched_index]
|
||||
fetched_index += 1
|
||||
assert last_sb_in_slot.height == height_prev_epoch_surpass - 1
|
||||
curr: SubBlockRecord = fetched_blocks[fetched_index]
|
||||
# Wait until the slot finishes with a challenge chain infusion at start of slot
|
||||
while not curr.deficit == constants.MIN_SUB_BLOCKS_PER_CHALLENGE_BLOCK - 1:
|
||||
# Note that there are no overflow blocks at the start of new epochs
|
||||
while not curr.is_challenge_sub_block(constants):
|
||||
last_sb_in_slot = curr
|
||||
curr = fetched_blocks[fetched_index]
|
||||
fetched_index += 1
|
||||
|
@ -130,7 +135,7 @@ def finishes_sub_epoch(
|
|||
|
||||
# For checking new epoch, make sure the epoch sub blocks are aligned
|
||||
if also_finishes_epoch:
|
||||
if height + 1 % constants.EPOCH_SUB_BLOCKS > constants.MAX_SLOT_SUB_BLOCKS:
|
||||
if (height + 1) % constants.EPOCH_SUB_BLOCKS > constants.MAX_SLOT_SUB_BLOCKS:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
@ -138,8 +143,8 @@ def finishes_sub_epoch(
|
|||
|
||||
def get_next_ips(
|
||||
constants: ConsensusConstants,
|
||||
height_to_hash: Dict[uint32, bytes32],
|
||||
sub_blocks: Dict[bytes32, SubBlockRecord],
|
||||
height_to_hash: Dict[uint32, bytes32],
|
||||
prev_header_hash: bytes32,
|
||||
height: uint32,
|
||||
deficit: uint8,
|
||||
|
@ -200,21 +205,6 @@ def get_next_ips(
|
|||
return max([uint64(1), new_ips, min_ips])
|
||||
|
||||
|
||||
def get_difficulty(
|
||||
constants: ConsensusConstants,
|
||||
sub_blocks: Dict[bytes32, SubBlockRecord],
|
||||
header_hash: bytes32,
|
||||
) -> uint64:
|
||||
"""
|
||||
Returns the difficulty of the sub-block referred to by header_hash
|
||||
"""
|
||||
sub_block = sub_blocks[header_hash]
|
||||
|
||||
if sub_block.height == 0:
|
||||
return uint64(constants.DIFFICULTY_STARTING)
|
||||
return uint64(sub_block.weight - sub_blocks[sub_block.prev_hash].weight)
|
||||
|
||||
|
||||
def get_next_difficulty(
|
||||
constants: ConsensusConstants,
|
||||
sub_blocks: Dict[bytes32, SubBlockRecord],
|
||||
|
@ -256,7 +246,7 @@ def get_next_difficulty(
|
|||
last_block_curr = sub_blocks[last_block_curr.prev_hash]
|
||||
|
||||
actual_epoch_time = last_block_curr.timestamp - last_block_prev.timestamp
|
||||
old_difficulty = get_difficulty(constants, sub_blocks, last_block_curr)
|
||||
old_difficulty = uint64(prev_sb.weight - sub_blocks[prev_sb.prev_hash].weight)
|
||||
|
||||
# Terms are rearranged so there is only one division.
|
||||
new_difficulty_precise = (
|
||||
|
|
|
@ -857,8 +857,8 @@ class FullNode:
|
|||
prev_sp_iters = calculate_sp_iters(self.constants, prev_sb.ips, prev_sb.required_iters)
|
||||
ips = get_next_ips(
|
||||
self.constants,
|
||||
self.blockchain.height_to_hash,
|
||||
self.blockchain.sub_blocks,
|
||||
self.blockchain.height_to_hash,
|
||||
block.prev_header_hash,
|
||||
prev_sb.height,
|
||||
prev_sb.deficit,
|
||||
|
|
|
@ -214,14 +214,14 @@ class BlockTools:
|
|||
fees: uint64 = uint64(0),
|
||||
transaction_data_at_height: Dict[int, Tuple[Program, G2Element]] = None,
|
||||
seed: bytes = b"",
|
||||
timestamp: Optional[uint64] = None,
|
||||
time_per_sub_block: Optional[float] = None,
|
||||
force_overflow: bool = False,
|
||||
force_empty_slots: uint32 = uint32(0), # Force at least this number of empty slots before the first SB
|
||||
) -> List[FullBlock]:
|
||||
if transaction_data_at_height is None:
|
||||
transaction_data_at_height = {}
|
||||
if timestamp is None:
|
||||
timestamp = time.time()
|
||||
if time_per_sub_block is None:
|
||||
time_per_sub_block = constants.SLOT_TIME_TARGET / constants.SLOT_SUB_BLOCKS_TARGET
|
||||
if block_list is None or len(block_list) == 0:
|
||||
genesis = self.create_genesis_block(
|
||||
constants,
|
||||
|
@ -229,6 +229,7 @@ class BlockTools:
|
|||
seed,
|
||||
force_overflow=force_overflow,
|
||||
force_empty_slots=force_empty_slots,
|
||||
timestamp=uint64(int(time.time())),
|
||||
)
|
||||
block_list = [genesis]
|
||||
num_blocks -= 1
|
||||
|
@ -239,6 +240,11 @@ class BlockTools:
|
|||
height_to_hash, difficulty, sub_blocks = load_block_list(block_list, constants)
|
||||
|
||||
latest_sub_block: SubBlockRecord = sub_blocks[block_list[-1].header_hash]
|
||||
curr = latest_sub_block
|
||||
while not curr.is_block:
|
||||
curr = sub_blocks[curr.prev_hash]
|
||||
start_timestamp = curr.timestamp
|
||||
start_height = curr.height
|
||||
|
||||
curr = latest_sub_block
|
||||
while not curr.first_in_sub_slot:
|
||||
|
@ -279,6 +285,7 @@ class BlockTools:
|
|||
if force_overflow and not is_overflow_block:
|
||||
continue
|
||||
|
||||
assert latest_sub_block.header_hash in sub_blocks
|
||||
unfinished_block = self.create_unfinished_block(
|
||||
constants,
|
||||
sub_slot_start_total_iters,
|
||||
|
@ -292,7 +299,9 @@ class BlockTools:
|
|||
farmer_reward_puzzle_hash,
|
||||
pool_reward_puzzle_hash,
|
||||
fees,
|
||||
timestamp,
|
||||
uint64(
|
||||
start_timestamp + int((latest_sub_block.height + 1 - start_height) * time_per_sub_block)
|
||||
),
|
||||
seed,
|
||||
transaction_data_at_height.get(latest_sub_block.height + 1, None),
|
||||
latest_sub_block,
|
||||
|
|
|
@ -92,12 +92,14 @@ class TestGenesisBlock:
|
|||
class TestAddingMoreBlocks:
|
||||
@pytest.mark.asyncio
|
||||
async def test_non_genesis(self, empty_blockchain):
|
||||
blocks = bt.get_consecutive_blocks(test_constants, 150, force_overflow=False, force_empty_slots=0)
|
||||
blocks = bt.get_consecutive_blocks(test_constants, 500, force_overflow=False, force_empty_slots=0)
|
||||
for block in blocks:
|
||||
result, err, _ = await empty_blockchain.receive_block(block)
|
||||
assert err is None
|
||||
assert result == ReceiveBlockResult.NEW_PEAK
|
||||
print(f"Added block {block.height}")
|
||||
print(
|
||||
f"Added block {block.height} total iters {block.total_iters} new slot? {len(block.finished_sub_slots)}"
|
||||
)
|
||||
assert empty_blockchain.get_peak().height == len(blocks) - 1
|
||||
|
||||
|
||||
|
|
|
@ -29,8 +29,8 @@ test_constants = constants.replace(
|
|||
**{
|
||||
"DIFFICULTY_STARTING": 1,
|
||||
"DISCRIMINANT_SIZE_BITS": 32,
|
||||
"SUB_EPOCH_SUB_BLOCKS": 128,
|
||||
"EPOCH_SUB_BLOCKS": 512,
|
||||
"SUB_EPOCH_SUB_BLOCKS": 70,
|
||||
"EPOCH_SUB_BLOCKS": 140,
|
||||
"IPS_STARTING": 10 * 1,
|
||||
"NUMBER_ZERO_BITS_PLOT_FILTER": 1, # H(plot signature of the challenge) must start with these many zeroes
|
||||
"NUMBER_ZERO_BITS_SP_FILTER": 1, # H(plot signature of the challenge) must start with these many zeroes
|
||||
|
|
Loading…
Reference in New Issue