예제 #1
0
 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
예제 #2
0
    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
예제 #3
0
    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
            }
예제 #4
0
    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