예제 #1
0
    async def integrate_block_with_existing_chain(self,
                                                  block: Block,
                                                  extra_blocks=None):
        """Even in case of retrace, this is the only place where we insert a new block into the block collection and update BU"""
        try:
            # TODO: reorg the checks, to have the faster ones first.
            # Like, here we begin with checking every tx one by one, when <e did not even check index and provided hash matched previous one.
            try:
                block.verify()
            except Exception as e:
                print("Integrate block error 1", e)
                return False

            for transaction in block.transactions:
                try:
                    if extra_blocks:
                        transaction.extra_blocks = extra_blocks
                    transaction.verify()
                except InvalidTransactionException as e:
                    print(e)
                    return False
                except InvalidTransactionSignatureException as e:
                    print(e)
                    return False
                except MissingInputTransactionException as e:
                    print(e)
                    return False
                except NotEnoughMoneyException as e:
                    print(e)
                    return False
                except Exception as e:
                    print(e)
                    return False
            if block.index == 0:
                return True
            height = block.index
            last_block = self.existing_blockchain.blocks[block.index - 1]
            if last_block.index != (block.index -
                                    1) or last_block.hash != block.prev_hash:
                print("Integrate block error 2")
                raise ForkException()
            if not last_block:
                print("Integrate block error 3")
                raise ForkException()

            target = BlockFactory.get_target(height, last_block, block,
                                             self.existing_blockchain)
            delta_t = int(time()) - int(last_block.time)
            special_target = CHAIN.special_target(block.index, block.target,
                                                  delta_t,
                                                  get_config().network)
            target_block_time = CHAIN.target_block_time(self.config.network)

            if block.index >= 35200 and delta_t < 600 and block.special_min:
                raise Exception('Special min block too soon')

            # TODO: use a CHAIN constant for pow blocks limits
            if ((int(block.hash, 16) < target) or
                (block.special_min and int(block.hash, 16) < special_target)
                    or (block.special_min and block.index < 35200) or
                (block.index >= 35200 and block.index < 38600
                 and block.special_min and
                 (int(block.time) - int(last_block.time)) > target_block_time)
                ):

                if last_block.index == (
                        block.index -
                        1) and last_block.hash == block.prev_hash:
                    # self.mongo.db.blocks.update({'index': block.index}, block.to_dict(), upsert=True)
                    # self.mongo.db.blocks.remove({'index': {"$gt": block.index}}, multi=True)
                    # todo: is this useful? can we have more blocks above? No because if we had, we would have raised just above
                    await self.mongo.async_db.block.delete_many(
                        {'index': {
                            "$gte": block.index
                        }})
                    await self.mongo.async_db.blocks.replace_one(
                        {'index': block.index}, block.to_dict(), upsert=True)
                    # TODO: why do we need to keep that one in memory?
                    try:
                        self.existing_blockchain.blocks[block.index] = block
                        del self.existing_blockchain.blocks[block.index + 1:]
                    except:
                        self.existing_blockchain.blocks.append(block)
                    if self.debug:
                        self.app_log.info(
                            "New block inserted for height: {}".format(
                                block.index))
                    await self.config.on_new_block(
                        block)  # This will propagate to BU
                    return True
                else:
                    print("Integrate block error 4")
                    raise ForkException()
            else:
                print("Integrate block error 5")
                raise AboveTargetException()
            return False  # unreachable code
        except Exception as e:
            exc_type, exc_obj, exc_tb = exc_info()
            fname = path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            self.app_log.warning(
                "integrate_block_with_existing_chain {} {} {}".format(
                    exc_type, fname, exc_tb.tb_lineno))
            raise
예제 #2
0
파일: block.py 프로젝트: EggPool/yadacoin
    def get_target(cls, height, last_block, block, blockchain) -> int:
        try:
            # change target
            max_target = CHAIN.MAX_TARGET
            if get_config().network in ['regnet', 'testnet']:
                return int(max_target)
            max_block_time = CHAIN.target_block_time(get_config().network)
            retarget_period = CHAIN.RETARGET_PERIOD  # blocks
            max_seconds = CHAIN.TWO_WEEKS  # seconds
            min_seconds = CHAIN.HALF_WEEK  # seconds
            if height >= CHAIN.POW_FORK_V3:
                retarget_period = CHAIN.RETARGET_PERIOD_V3
                max_seconds = CHAIN.MAX_SECONDS_V3  # seconds
                min_seconds = CHAIN.MIN_SECONDS_V3  # seconds
            elif height >= CHAIN.POW_FORK_V2:
                retarget_period = CHAIN.RETARGET_PERIOD_V2
                max_seconds = CHAIN.MAX_SECONDS_V2  # seconds
                min_seconds = CHAIN.MIN_SECONDS_V2  # seconds
            if height > 0 and height % retarget_period == 0:
                get_config().debug_log(
                    "RETARGET get_target height {} - last_block {} - block {}/time {}"
                    .format(height, last_block.index, block.index, block.time))
                block_from_2016_ago = Block.from_dict(
                    get_config().BU.get_block_by_index(height -
                                                       retarget_period))
                get_config().debug_log(
                    "Block_from_2016_ago - block {}/time {}".format(
                        block_from_2016_ago.index, block_from_2016_ago.time))
                two_weeks_ago_time = block_from_2016_ago.time
                elapsed_time_from_2016_ago = int(
                    last_block.time) - int(two_weeks_ago_time)
                get_config().debug_log(
                    "elapsed_time_from_2016_ago {} s {} days".format(
                        int(elapsed_time_from_2016_ago),
                        elapsed_time_from_2016_ago / (60 * 60 * 24)))
                # greater than two weeks?
                if elapsed_time_from_2016_ago > max_seconds:
                    time_for_target = max_seconds
                    get_config().debug_log("gt max")
                elif elapsed_time_from_2016_ago < min_seconds:
                    time_for_target = min_seconds
                    get_config().debug_log("lt min")
                else:
                    time_for_target = int(elapsed_time_from_2016_ago)

                block_to_check = last_block

                if blockchain.partial:
                    start_index = len(blockchain.blocks) - 1
                else:
                    start_index = last_block.index
                get_config().debug_log("start_index {}".format(start_index))
                while 1:
                    if block_to_check.special_min or block_to_check.target == max_target or not block_to_check.target:
                        block_to_check = blockchain.blocks[start_index]
                        start_index -= 1
                    else:
                        target = block_to_check.target
                        break
                get_config().debug_log("start_index2 {}, target {}".format(
                    block_to_check.index,
                    hex(int(target))[2:].rjust(64, '0')))

                new_target = int((time_for_target * target) / max_seconds)
                get_config().debug_log("new_target {}".format(
                    hex(int(new_target))[2:].rjust(64, '0')))

                if new_target > max_target:
                    target = max_target
                else:
                    target = new_target

            elif height == 0:
                target = max_target
            else:
                block_to_check = block
                delta_t = int(block.time) - int(last_block.time)
                if block.index >= 38600 and delta_t > max_block_time and block.special_min:
                    special_target = CHAIN.special_target(
                        block.index, block.target, delta_t,
                        get_config().network)
                    return special_target

                block_to_check = last_block  # this would be accurate. right now, it checks if the current block is under its own target, not the previous block's target

                if blockchain.partial:
                    start_index = len(blockchain.blocks) - 1
                else:
                    start_index = last_block.index
                while 1:
                    if start_index == 0:
                        return block_to_check.target
                    if block_to_check.special_min or block_to_check.target == max_target or not block_to_check.target:
                        block_to_check = blockchain.blocks[start_index]
                        start_index -= 1
                    else:
                        target = block_to_check.target
                        break
            return int(target)
        except Exception as e:
            import sys, os
            print("Exception {} get_target".format(e))
            exc_type, exc_obj, exc_tb = sys.exc_info()
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            print(exc_type, fname, exc_tb.tb_lineno)
            raise