def check_block(block_height_new, miner_address, nonce, db_block_hash, diff0, received_timestamp, q_received_timestamp, q_db_timestamp_last, peer_ip='N/A', app_log=None): """ Checks that the given block matches the mining algo. :param block_height_new: :param miner_address: :param nonce: :param db_block_hash: :param diff0: :param received_timestamp: :param q_received_timestamp: :param q_db_timestamp_last: :param peer_ip: :param app_log: :return: """ mining_hash = bin_convert( hashlib.sha224((miner_address + nonce + db_block_hash).encode("utf-8")).hexdigest()) diff_drop_time = Decimal(180) mining_condition = bin_convert(db_block_hash)[0:int(diff0)] # simplified comparison, no backwards mining if mining_condition in mining_hash: if app_log: app_log.info( "Difficulty requirement satisfied for block {} from {}".format( block_height_new, peer_ip)) diff_save = diff0 elif Decimal(received_timestamp ) > q_db_timestamp_last + Decimal(diff_drop_time): # uses block timestamp, don't merge with diff() for security reasons time_difference = q_received_timestamp - q_db_timestamp_last diff_dropped = quantize_ten(diff0) - quantize_ten( time_difference / diff_drop_time) if diff_dropped < 50: diff_dropped = 50 mining_condition = bin_convert(db_block_hash)[0:int(diff_dropped)] if mining_condition in mining_hash: # simplified comparison, no backwards mining if app_log: app_log.info( "Readjusted difficulty requirement satisfied for block {} from {}" .format(block_height_new, peer_ip)) diff_save = diff0 # lie about what diff was matched not to mess up the diff algo else: raise ValueError( "Readjusted difficulty too low for block {} from {}, should be at least {}" .format(block_height_new, peer_ip, diff_dropped)) else: raise ValueError( "Difficulty too low for block {} from {}, should be at least {}". format(block_height_new, peer_ip, diff0)) return diff_save
def difficulty(node, db_handler): try: fork = Fork() db_handler.execute(db_handler.c, "SELECT * FROM transactions WHERE reward != 0 ORDER BY block_height DESC LIMIT 2") result = db_handler.c.fetchone() timestamp_last = Decimal(result[1]) block_height = int(result[0]) node.last_block_timestamp = timestamp_last #node.last_block = block_height do not fetch this here, could interfere with block saving previous = db_handler.c.fetchone() node.last_block_ago = int(time.time() - int(timestamp_last)) # Failsafe for regtest starting at block 1} timestamp_before_last = timestamp_last if previous is None else Decimal(previous[1]) db_handler.execute_param(db_handler.c, ( "SELECT timestamp FROM transactions WHERE block_height > ? AND reward != 0 ORDER BY block_height ASC LIMIT 2"), (block_height - 1441,)) timestamp_1441 = Decimal(db_handler.c.fetchone()[0]) block_time_prev = (timestamp_before_last - timestamp_1441) / 1440 temp = db_handler.c.fetchone() timestamp_1440 = timestamp_1441 if temp is None else Decimal(temp[0]) block_time = Decimal(timestamp_last - timestamp_1440) / 1440 db_handler.execute(db_handler.c, "SELECT difficulty FROM misc ORDER BY block_height DESC LIMIT 1") diff_block_previous = Decimal(db_handler.c.fetchone()[0]) time_to_generate = timestamp_last - timestamp_before_last if node.is_regnet: return (float('%.10f' % regnet.REGNET_DIFF), float('%.10f' % (regnet.REGNET_DIFF - 8)), float(time_to_generate), float(regnet.REGNET_DIFF), float(block_time), float(0), float(0), block_height) hashrate = pow(2, diff_block_previous / Decimal(2.0)) / ( block_time * math.ceil(28 - diff_block_previous / Decimal(16.0))) # Calculate new difficulty for desired blocktime of 60 seconds target = Decimal(60.00) ##D0 = diff_block_previous difficulty_new = Decimal( (2 / math.log(2)) * math.log(hashrate * target * math.ceil(28 - diff_block_previous / Decimal(16.0)))) # Feedback controller Kd = 10 difficulty_new = difficulty_new - Kd * (block_time - block_time_prev) diff_adjustment = (difficulty_new - diff_block_previous) / 720 # reduce by factor of 720 if diff_adjustment > Decimal(1.0): diff_adjustment = Decimal(1.0) difficulty_new_adjusted = quantize_ten(diff_block_previous + diff_adjustment) difficulty = difficulty_new_adjusted #fork handling if node.is_mainnet: if block_height == fork.POW_FORK - fork.FORK_AHEAD: fork.limit_version(node) #fork handling diff_drop_time = Decimal(180) if Decimal(time.time()) > Decimal(timestamp_last) + Decimal(2 * diff_drop_time): # Emergency diff drop time_difference = quantize_two(time.time()) - quantize_two(timestamp_last) diff_dropped = quantize_ten(difficulty) - quantize_ten(1) \ - quantize_ten(10 * (time_difference - 2 * diff_drop_time) / diff_drop_time) elif Decimal(time.time()) > Decimal(timestamp_last) + Decimal(diff_drop_time): time_difference = quantize_two(time.time()) - quantize_two(timestamp_last) diff_dropped = quantize_ten(difficulty) + quantize_ten(1) - quantize_ten(time_difference / diff_drop_time) else: diff_dropped = difficulty if difficulty < 50: difficulty = 50 if diff_dropped < 50: diff_dropped = 50 return ( float('%.10f' % difficulty), float('%.10f' % diff_dropped), float(time_to_generate), float(diff_block_previous), float(block_time), float(hashrate), float(diff_adjustment), block_height) # need to keep float here for database inserts support except: #new chain or regnet difficulty = [24,24,0,0,0,0,0,0] return difficulty
def check_block(block_height_new, miner_address, nonce, db_block_hash, diff0, received_timestamp, q_received_timestamp, q_db_timestamp_last, peer_ip='N/A', app_log=None): """ Checks that the given block matches the mining algo. :param block_height_new: :param miner_address: :param nonce: :param db_block_hash: :param diff0: :param received_timestamp: :param q_received_timestamp: :param q_db_timestamp_last: :param peer_ip: :param app_log: :return: """ if is_regnet: diff0 = regnet.REGNET_DIFF - 8 real_diff = diffme_heavy3(miner_address, nonce, db_block_hash) diff_drop_time = Decimal(180) mining_condition = bin_convert(db_block_hash)[0:int(diff0)] # simplified comparison, no backwards mining if real_diff >= int(diff0): if app_log: app_log.info( "Difficulty requirement satisfied for block {} from {}. {} >= {}" .format(block_height_new, peer_ip, real_diff, int(diff0))) diff_save = diff0 elif Decimal(received_timestamp ) > q_db_timestamp_last + Decimal(diff_drop_time): # uses block timestamp, don't merge with diff() for security reasons factor = 1 time_difference = q_received_timestamp - q_db_timestamp_last diff_dropped = quantize_ten(diff0) + quantize_ten(1) - quantize_ten( time_difference / diff_drop_time) # Emergency diff drop if Decimal(received_timestamp) > q_db_timestamp_last + Decimal( 2 * diff_drop_time): factor = 10 diff_dropped = quantize_ten(diff0) - quantize_ten( 1) - quantize_ten( factor * (time_difference - 2 * diff_drop_time) / diff_drop_time) if diff_dropped < 50: diff_dropped = 50 if real_diff >= int(diff_dropped): if app_log: app_log.info( "Readjusted difficulty requirement satisfied for block {} from {}, {} >= {} (factor {})" .format(block_height_new, peer_ip, real_diff, int(diff_dropped), factor)) diff_save = diff0 # lie about what diff was matched not to mess up the diff algo else: raise ValueError( "Readjusted difficulty too low for block {} from {}, {} should be at least {}" .format(block_height_new, peer_ip, real_diff, diff_dropped)) else: raise ValueError( "Difficulty {} too low for block {} from {}, should be at least {}" .format(real_diff, block_height_new, peer_ip, diff0)) return diff_save