Fix some serious timelord issues

This commit is contained in:
Mariano Sorgente 2020-12-05 20:07:49 +09:00 committed by Yostra
parent 5df0c275d4
commit 6d4e32d93c
4 changed files with 71 additions and 49 deletions

View File

@ -7,17 +7,17 @@ testnet_kwargs = {
"MIN_SUB_BLOCKS_PER_CHALLENGE_BLOCK": 16,
"MAX_SUB_SLOT_SUB_BLOCKS": 128,
"NUM_SPS_SUB_SLOT": 64,
"SUB_SLOT_ITERS_STARTING": 2 ** 27,
"SUB_SLOT_ITERS_STARTING": 2 ** 25,
# DIFFICULTY_STARTING is the starting difficulty for the first epoch, which is then further
# multiplied by another factor of 2^25, to be used in the VDF iter calculation formula.
"DIFFICULTY_STARTING": 2 ** 15,
"DIFFICULTY_STARTING": 2 ** 14,
"DIFFICULTY_FACTOR": 3, # The next difficulty is truncated to range [prev / FACTOR, prev * FACTOR]
# These 3 constants must be changed at the same time
"SUB_EPOCH_SUB_BLOCKS": 128, # The number of sub-blocks per sub-epoch, mainnet 284
"EPOCH_SUB_BLOCKS": 4096, # The number of sub-blocks per epoch, mainnet 32256
"SIGNIFICANT_BITS": 12, # The number of bits to look at in difficulty and min iters. The rest are zeroed
"DISCRIMINANT_SIZE_BITS": 1024, # Max is 1024 (based on ClassGroupElement int size)
"NUMBER_ZERO_BITS_PLOT_FILTER": 9, # H(plot signature of the challenge) must start with these many zeroes
"NUMBER_ZERO_BITS_PLOT_FILTER": 7, # H(plot signature of the challenge) must start with these many zeroes
"SUB_SLOT_TIME_TARGET": 600, # The target number of seconds per slot
"NUM_SP_INTERVALS_EXTRA": 3, # The number of sp intervals to add to the signage point
"MAX_FUTURE_TIME": 7200, # The next block can have a timestamp of at most these many seconds more

View File

@ -600,7 +600,7 @@ class FullNodeAPI:
prev_sb = self.full_node.blockchain.sub_blocks.get(prev_sb.prev_hash, None)
attempts += 1
if not found:
self.log.error("Did not find a previous block with the correct reward chain hash")
self.log.info("Did not find a previous block with the correct reward chain hash")
return
elif request.signage_point_index > 0:
assert finished_sub_slots[-1].reward_chain.get_hash() == sp_vdfs.rc_vdf.challenge
@ -716,18 +716,18 @@ class FullNodeAPI:
self.log.warning(f"Previous block is None, infusion point {request.reward_chain_ip_vdf.challenge}")
return
# We should also find the prev block from the signage point, in the path. If not found, that means
# it was based on a reorged block.
curr = prev_sb
attempts = 0
while curr is not None and curr.header_hash != unfinished_block.prev_header_hash and attempts < 10:
curr = self.full_node.blockchain.sub_blocks.get(curr.prev_hash, None)
attempts += 1
if attempts == 10 or (
curr is None and unfinished_block.prev_header_hash != self.full_node.constants.GENESIS_PREV_HASH
):
self.log.error("Have IP VDF that does not match SP VDF")
return
# # We should also find the prev block from the signage point, in the path. If not found, that means
# # it was based on a reorged block.
# curr = prev_sb
# attempts = 0
# while curr is not None and curr.header_hash != unfinished_block.prev_header_hash and attempts < 10:
# curr = self.full_node.blockchain.sub_blocks.get(curr.prev_hash, None)
# attempts += 1
# if attempts == 10 or (
# curr is None and unfinished_block.prev_header_hash != self.full_node.constants.GENESIS_PREV_HASH
# ):
# self.log.error("Have IP VDF that does not match SP VDF")
# return
sub_slot_iters, difficulty = get_sub_slot_iters_and_difficulty(
self.full_node.constants,
@ -785,7 +785,7 @@ class FullNodeAPI:
try:
await self.respond_sub_block(full_node_protocol.RespondSubBlock(block))
except ConsensusError as e:
self.log.warning("Consensus error validating sub-block: {e}")
self.log.warning(f"Consensus error validating sub-block: {e}")
@peer_required
@api_request

View File

@ -134,7 +134,7 @@ class LastState:
self.sub_slot_iters = state.challenge_chain.new_sub_slot_iters
self.reward_challenge_cache.append((self.get_challenge(Chain.REWARD_CHAIN), self.total_iters))
log.warning(f"Updated peak to {self.peak.reward_chain_sub_block.get_hash()}")
log.info(f"Updated timelord peak to {self.get_challenge(Chain.REWARD_CHAIN)}, total iters: {self.total_iters}")
while len(self.reward_challenge_cache) > 2 * self.constants.MAX_SUB_SLOT_SUB_BLOCKS:
self.reward_challenge_cache.pop(0)
@ -315,14 +315,53 @@ class Timelord:
self.allows_iters.remove(chain)
self.unspawned_chains.append(chain)
def _can_infuse_unfinished_block(self, block: timelord_protocol.NewUnfinishedSubBlock) -> Optional[uint64]:
sub_slot_iters = self.last_state.get_sub_slot_iters()
difficulty = self.last_state.get_difficulty()
ip_iters = self.last_state.get_last_ip()
rc_block = block.reward_chain_sub_block
block_sp_iters, block_ip_iters = iters_from_sub_block(
self.constants,
rc_block,
sub_slot_iters,
difficulty,
)
block_sp_total_iters = self.last_state.total_iters - ip_iters + block_sp_iters
found_index = -1
for index, (rc, total_iters) in enumerate(self.last_state.reward_challenge_cache):
if rc == block.rc_prev:
found_index = index
break
if found_index == -1:
log.warning(f"Will not infuse {block.rc_prev} because it's reward chain challenge is not in the chain")
return None
new_block_iters = block_ip_iters - ip_iters
if len(self.last_state.reward_challenge_cache) > found_index + 1:
if self.last_state.reward_challenge_cache[found_index + 1][1] < block_sp_total_iters:
log.warning(
f"Will not infuse unfinished block {block.rc_prev} total iters {block_sp_total_iters}, "
f"because there is another infusion before it's SP"
)
return None
if self.last_state.reward_challenge_cache[found_index][1] > block_sp_total_iters:
log.error(
f"Will not infuse unfinished block {block.rc_prev}, total iters: {block_sp_total_iters}, "
f"because it's iters are too low"
)
return None
if new_block_iters > 0:
return new_block_iters
async def _reset_chains(self):
# First, stop all chains.
ip_iters = self.last_state.get_last_ip()
sub_slot_iters = self.last_state.get_sub_slot_iters()
difficulty = self.last_state.get_difficulty()
# print(ip_iters, sub_slot_iters, difficulty)
for chain in self.chain_type_to_stream.keys():
await self._stop_chain(chain)
# Adjust all signage points iterations to the peak.
iters_per_signage = uint64(sub_slot_iters // self.constants.NUM_SPS_SUB_SLOT)
self.signage_point_iters = [
@ -341,30 +380,8 @@ class Timelord:
self.iters_submitted[chain] = []
self.iteration_to_proof_type = {}
for block in self.unfinished_blocks:
found_index = -1
for index, (rc, total_iters) in enumerate(self.last_state.reward_challenge_cache):
if rc == block.rc_prev:
found_index = index
break
if found_index == -1:
log.error(f"INVALID unfinished block will not infuse it {block.rc_prev}")
continue
rc_block = block.reward_chain_sub_block
block_sp_iters, block_ip_iters = iters_from_sub_block(
self.constants,
rc_block,
sub_slot_iters,
difficulty,
)
block_sp_total_iters = self.last_state.total_iters - ip_iters + block_sp_iters
if len(self.last_state.reward_challenge_cache) > found_index + 1:
if self.last_state.reward_challenge_cache[found_index + 1][1] < block_sp_total_iters:
log.error(f"INVALID2 unfinished block will not infuse it {block.rc_prev}")
continue
new_block_iters = block_ip_iters - ip_iters
if new_block_iters > 0:
new_block_iters: Optional[uint64] = self._can_infuse_unfinished_block(block)
if new_block_iters:
new_unfinished_blocks.append(block)
for chain in Chain:
self.iters_to_submit[chain].append(new_block_iters)
@ -514,6 +531,8 @@ class Timelord:
next_iters_count += 1
if next_iters_count == 3:
break
# Break so we alternate between checking SP and IP
break
for r in to_remove:
self.signage_point_iters.remove(r)
@ -646,6 +665,7 @@ class Timelord:
self.last_state.reward_challenge_cache,
)
await self._handle_new_peak()
# Break so we alternate between checking SP and IP
break
async def _check_for_end_of_subslot(self):

View File

@ -1,4 +1,4 @@
from typing import Callable
from typing import Callable, Optional
import logging
from src.protocols import timelord_protocol
from src.timelord import Timelord, iters_from_sub_block, Chain, IterationType
@ -44,7 +44,9 @@ class TimelordAPI:
if sp_iters > ip_iters:
self.timelord.overflow_blocks.append(new_unfinished_subblock)
elif ip_iters > last_ip_iters:
self.timelord.unfinished_blocks.append(new_unfinished_subblock)
for chain in Chain:
self.timelord.iters_to_submit[chain].append(uint64(ip_iters - last_ip_iters))
self.timelord.iteration_to_proof_type[ip_iters - last_ip_iters] = IterationType.INFUSION_POINT
new_block_iters: Optional[uint64] = self.timelord._can_infuse_unfinished_block(new_unfinished_subblock)
if new_block_iters:
self.timelord.unfinished_blocks.append(new_unfinished_subblock)
for chain in Chain:
self.timelord.iters_to_submit[chain].append(new_block_iters)
self.timelord.iteration_to_proof_type[new_block_iters] = IterationType.INFUSION_POINT