async def set_target(self, to_time): if not self.block_factory.special_min: await self.set_target_from_last_non_special_min( self.config.LatestBlock.block) # todo: keep block target at normal target, for header and block info. # Only tweak target at validation time, and don't include special_min into header if self.block_factory.index >= CHAIN.SPECIAL_MIN_FORK: # TODO: use a CHAIN constant # print("test target", int(to_time), self.last_block_time) if self.block_factory.target == 0: # If the node is started when the current block is special_min, then we have a 0 target await self.set_target_as_previous_non_special_min() # print('target set to', self.block_factory.target) delta_t = int(to_time) - self.last_block_time if delta_t \ > CHAIN.special_min_trigger(self.config.network, self.block_factory.index): special_target = CHAIN.special_target( self.block_factory.index, self.block_factory.target, delta_t, self.config.network) self.block_factory.special_min = True self.block_factory.special_target = special_target self.block_factory.time = int(to_time) else: self.block_factory.special_min = False elif self.block_factory.index < CHAIN.SPECIAL_MIN_FORK: # TODO: use a CHAIN constant if (int(to_time) - self.last_block_time) > self.target_block_time: self.block_factory.target = self.max_target self.block_factory.special_min = True self.block_factory.time = int(to_time) else: self.block_factory.special_min = False
async def test_block(self, block, extra_blocks=[], simulate_last_block=None): try: block.verify() except Exception as e: self.config.app_log.warning( "Integrate block error 1: {}".format(e)) return False async def get_txns(txns): for x in txns: yield x async def get_inputs(inputs): for x in inputs: yield x if block.index == 0: return True if simulate_last_block: last_block = simulate_last_block else: last_block_data = await self.config.mongo.async_db.blocks.find_one( {'index': block.index - 1}) if last_block_data: last_block = await Block.from_dict(last_block_data) else: return False if block.index >= CHAIN.FORK_10_MIN_BLOCK: target = await CHAIN.get_target_10min(block.index, last_block, block, extra_blocks) else: target = await CHAIN.get_target(block.index, last_block, block, extra_blocks) delta_t = int(time()) - int(last_block.time) special_target = CHAIN.special_target(block.index, block.target, delta_t, get_config().network) if block.index >= 35200 and delta_t < 600 and block.special_min: return False used_inputs = {} i = 0 async for transaction in get_txns(block.transactions): if extra_blocks: transaction.extra_blocks = extra_blocks self.config.app_log.warning('verifying txn: {} block: {}'.format( i, block.index)) i += 1 try: await transaction.verify() except InvalidTransactionException as e: self.config.app_log.warning(e) return False except InvalidTransactionSignatureException as e: self.config.app_log.warning(e) return False except MissingInputTransactionException as e: self.config.app_log.warning(e) return False except NotEnoughMoneyException as e: self.config.app_log.warning(e) return False except Exception as e: self.config.app_log.warning(e) return False if transaction.inputs: failed = False used_ids_in_this_txn = [] async for x in get_inputs(transaction.inputs): txn = self.config.BU.get_transaction_by_id(x.id, instance=True) if not txn: txn = await transaction.find_in_extra_blocks(x) if not txn: failed = True if self.config.BU.is_input_spent(x.id, transaction.public_key, from_index=block.index): failed = True if x.id in used_ids_in_this_txn: failed = True if (x.id, transaction.public_key) in used_inputs: failed = True used_inputs[(x.id, transaction.public_key)] = transaction used_ids_in_this_txn.append(x.id) if failed and block.index >= CHAIN.CHECK_DOUBLE_SPEND_FROM: return False elif failed and block.index < CHAIN.CHECK_DOUBLE_SPEND_FROM: continue if block.index >= 35200 and delta_t < 600 and block.special_min: self.config.app_log.warning( f'Failed: {block.index} >= {35200} and {delta_t} < {600} and {block.special_min}' ) return False if int(block.index) > CHAIN.CHECK_TIME_FROM and int(block.time) < int( last_block.time): self.config.app_log.warning( f'Failed: {int(block.index)} > {CHAIN.CHECK_TIME_FROM} and {int(block.time)} < {int(last_block.time)}' ) return False if last_block.index != (block.index - 1) or last_block.hash != block.prev_hash: self.config.app_log.warning( f'Failed: {last_block.index} != {(block.index - 1)} or {last_block.hash} != {block.prev_hash}' ) return False if int(block.index) > CHAIN.CHECK_TIME_FROM and ( int(block.time) < (int(last_block.time) + 600)) and block.special_min: self.config.app_log.warning( f'Failed: {int(block.index)} > {CHAIN.CHECK_TIME_FROM} and ({int(block.time)} < ({int(last_block.time)} + {600})) and {block.special_min}' ) return False target_block_time = CHAIN.target_block_time(self.config.network) checks_passed = False if (block.index >= CHAIN.BLOCK_V5_FORK) and int( block.little_hash(), 16) < target: self.config.app_log.warning('5') checks_passed = True elif (int(block.hash, 16) < target): self.config.app_log.warning('6') checks_passed = True elif (block.special_min and int(block.hash, 16) < special_target): self.config.app_log.warning('7') checks_passed = True elif (block.special_min and block.index < 35200): self.config.app_log.warning('8') checks_passed = True elif (block.index >= 35200 and block.index < 38600 and block.special_min and (int(block.time) - int(last_block.time)) > target_block_time): self.config.app_log.warning('9') checks_passed = True else: self.config.app_log.warning( "Integrate block error - index and time error") if not checks_passed: return False return True
async def on_miner_nonce(self, nonce: str, job: Job, address: str = '') -> bool: nonce = nonce + job.extra_nonce.encode().hex() hash1 = self.block_factory.generate_hash_from_header( self.block_factory.index, self.block_factory.header, nonce) if self.block_factory.index >= CHAIN.BLOCK_V5_FORK: hash1_test = self.little_hash(hash1) else: hash1_test = hash1 if (int(hash1_test, 16) > self.block_factory.target and self.config.network != 'regnet' and (self.block_factory.special_min and int(hash1, 16) > self.block_factory.special_target)): return False block_candidate = await self.block_factory.copy() block_candidate.hash = hash1 block_candidate.nonce = nonce if block_candidate.special_min: delta_t = int(block_candidate.time) - int(self.last_block_time) special_target = CHAIN.special_target(block_candidate.index, block_candidate.target, delta_t, self.config.network) block_candidate.special_target = special_target if (block_candidate.index >= 35200 and (int(block_candidate.time) - int(self.last_block_time)) < 600 and block_candidate.special_min): self.app_log.warning( "Special min block too soon: hash {} header {} nonce {}". format(block_candidate.hash, block_candidate.header, block_candidate.nonce)) return False accepted = False if ((int(block_candidate.target) + 0x0000F00000000000000000000000000000000000000000000000000000000000 ) > int(hash1, 16) or (block_candidate.index >= CHAIN.BLOCK_V5_FORK and (int(block_candidate.target) + 0x0000F00000000000000000000000000000000000000000000000000000000000 ) > int(block_candidate.little_hash(), 16))): # submit share only now, not to slow down if we had a block await self.mongo.async_db.shares.update_one( {'hash': block_candidate.hash}, { '$set': { 'address': address, 'index': block_candidate.index, 'hash': block_candidate.hash, 'nonce': nonce, 'time': int(time()) } }, upsert=True) accepted = True if (int(block_candidate.target) > int(block_candidate.hash, 16) or (block_candidate.index >= CHAIN.BLOCK_V5_FORK and int(block_candidate.target) > int( block_candidate.little_hash(), 16))): block_candidate.signature = self.config.BU.generate_signature( block_candidate.hash, self.config.private_key) try: block_candidate.verify() except Exception as e: self.app_log.warning( "Verify error {} - hash {} header {} nonce {}".format( e, block_candidate.hash, block_candidate.header, block_candidate.nonce)) return False # accept winning block await self.accept_block(block_candidate) # Conversion to dict is important, or the object may change self.app_log.debug('block ok') return { 'hash': block_candidate.hash, 'nonce': nonce, 'height': block_candidate.index, 'id': block_candidate.signature } elif (block_candidate.special_min and (int(block_candidate.special_target) > int( block_candidate.hash, 16)) or (block_candidate.index >= CHAIN.BLOCK_V5_FORK and block_candidate.special_min and (int(block_candidate.special_target) > int( block_candidate.little_hash(), 16)))): block_candidate.signature = self.config.BU.generate_signature( block_candidate.hash, self.config.private_key) try: block_candidate.verify() except Exception as e: self.app_log.warning( "Verify error {} - hash {} header {} nonce {}".format( e, block_candidate.hash, block_candidate.header, block_candidate.nonce)) return False # accept winning block await self.accept_block(block_candidate) # Conversion to dict is important, or the object may change self.app_log.debug('block ok - special_min') return { 'hash': block_candidate.hash, 'nonce': nonce, 'height': block_candidate.index, 'id': block_candidate.signature } if accepted: return { 'hash': block_candidate.hash, 'nonce': nonce, 'height': block_candidate.index, 'id': block_candidate.signature }
async def test_block(self, block): try: block.verify() except Exception as e: self.config.app_log.warning("Integrate block error 1: {}".format(e)) return False async def get_txns(txns): for x in txns: yield x async def get_inputs(inputs): for x in inputs: yield x if block.index == 0: return True last_block = await Block.from_dict(await self.config.mongo.async_db.blocks.find_one({'index': block.index - 1})) if block.index >= CHAIN.FORK_10_MIN_BLOCK: target = await CHAIN.get_target_10min(block.index, last_block, block) else: target = await CHAIN.get_target(block.index, last_block, block) delta_t = int(time()) - int(last_block.time) special_target = CHAIN.special_target(block.index, block.target, delta_t, get_config().network) if block.index >= 35200 and delta_t < 600 and block.special_min: return False used_inputs = {} i = 0 async for transaction in get_txns(block.transactions): self.config.app_log.warning('verifying txn: {} block: {}'.format(i, block.index)) i += 1 try: await transaction.verify() except InvalidTransactionException as e: self.config.app_log.warning(e) return False except InvalidTransactionSignatureException as e: self.config.app_log.warning(e) return False except MissingInputTransactionException as e: self.config.app_log.warning(e) except NotEnoughMoneyException as e: self.config.app_log.warning(e) return False except Exception as e: self.config.app_log.warning(e) return False if transaction.inputs: failed = False used_ids_in_this_txn = [] async for x in get_inputs(transaction.inputs): if self.config.BU.is_input_spent(x.id, transaction.public_key, from_index=block.index): failed = True if x.id in used_ids_in_this_txn: failed = True if (x.id, transaction.public_key) in used_inputs: failed = True used_inputs[(x.id, transaction.public_key)] = transaction used_ids_in_this_txn.append(x.id) if failed and block.index >= CHAIN.CHECK_DOUBLE_SPEND_FROM: return False elif failed and block.index < CHAIN.CHECK_DOUBLE_SPEND_FROM: continue if block.index >= 35200 and delta_t < 600 and block.special_min: self.config.app_log.warning('1') return False if int(block.index) > CHAIN.CHECK_TIME_FROM and int(block.time) < int(last_block.time): self.config.app_log.warning('2') return False if last_block.index != (block.index - 1) or last_block.hash != block.prev_hash: self.config.app_log.warning('3') return False if int(block.index) > CHAIN.CHECK_TIME_FROM and (int(block.time) < (int(last_block.time) + 600)) and block.special_min: self.config.app_log.warning('4') return False if block.index >= 35200 and delta_t < 600 and block.special_min: self.config.app_log.warning('5') return False target_block_time = CHAIN.target_block_time(self.config.network) checks_passed = False if (int(block.hash, 16) < target): self.config.app_log.warning('6') checks_passed = True elif (block.special_min and int(block.hash, 16) < special_target): self.config.app_log.warning('7') checks_passed = True elif (block.special_min and block.index < 35200): self.config.app_log.warning('8') checks_passed = True elif (block.index >= 35200 and block.index < 38600 and block.special_min and (int(block.time) - int(last_block.time)) > target_block_time): self.config.app_log.warning('9') checks_passed = True else: self.config.app_log.warning("Integrate block error - index and time error") if not checks_passed: return False return True