Example #1
0
    def calculate_hash_difficulty(self):
        block = self.get_latest_block()
        current_difficulty = difficulty.decompress(block.difficulty)
        if block.index > 0 and block.index % config.DIFFICULTY_ADJUSTMENT_SPAN == 0:
            block_delta = self.get_block(block.index -
                                         config.DIFFICULTY_ADJUSTMENT_SPAN)
            timestamp_delta = (block.timestamp - block_delta.timestamp
                               ) // config.DIFFICULTY_ADJUSTMENT_SPAN
            numerator, denominator = (timestamp_delta,
                                      config.TARGET_TIME_PER_BLOCK)
            if denominator > config.DIFFICULTY_CHANGE_RATIO_LIMIT * numerator:
                numerator, denominator = (1,
                                          config.DIFFICULTY_CHANGE_RATIO_LIMIT)
            try:
                new_difficulty = difficulty.normalize(
                    difficulty.multiply(current_difficulty, numerator,
                                        denominator))
                if difficulty.less_or_equal(config.MINIMUM_HASH_DIFFICULTY,
                                            new_difficulty):
                    new_difficulty = config.MINIMUM_HASH_DIFFICULTY
            except OverflowError:
                new_difficulty = config.MINIMUM_HASH_DIFFICULTY

            return new_difficulty
        else:
            return current_difficulty
Example #2
0
 async def mine_next_block(self):
     if self.miner is not None and not self.miner.closed:
         block = self.get_next_block()
         await self.miner.send_json({
             'id': block.index,
             'data': block.serialize(header_only = True).hex(),
             'nonceOffset': 76,
             'nonceSize': 4,
             'timestampOffset': 72,
             'timestampSize': 4,
             'target': difficulty.decompress(block.difficulty).hex()
             })
Example #3
0
    def is_valid_block(self, block):
        # Check block size
        if len(block.serialize()) > config.MAX_BLOCK_SIZE:
            raise BlockTooLarge()

        # Check block validity.
        if not block.valid():
            raise InvalidBlock()

        # Check if it isn't an old block
        if block.index < self.get_height():
            raise BlockOld()

        # Check if minimum PoW has been done on it
        block_hash = block.calculate_hash()
        claimed_difficulty = difficulty.decompress(block.difficulty)

        if not difficulty.less_or_equal(block_hash, claimed_difficulty) or \
            not difficulty.less_or_equal(claimed_difficulty, config.MINIMUM_HASH_DIFFICULTY):
            raise InvalidDifficulty()

        return True
Example #4
0
    def is_next_block(self, block):
        # Check genesis block
        if self.get_height() == 0 and block == genesis.genesis_block():
            return

        # Check if it is a valid block
        self.is_valid_block(block)

        # Check if it is the next block
        if block.index != self.get_height():
            raise InvalidIndex()

        # Check if it points to the previous block
        if block.previous_hash != self.get_latest_block().calculate_hash():
            raise InvalidPreviousHash()

        # Check if timestamp is logical
        if block.index >= config.BLOCKS_CLOCK_CHECK:
            previous_blocks = self.get_block_range(
                block.index - config.BLOCKS_CLOCK_CHECK, block.index)
            timestamps = [b.timestamp for b in previous_blocks]
            med = misc.median(timestamps)
            if block.timestamp <= med:
                raise InvalidTimestamp()

        # Check if work has been done on the block
        claimed_difficulty = difficulty.decompress(block.difficulty)
        if claimed_difficulty != self.calculate_hash_difficulty():
            raise InvalidDifficulty()

        # Check if all transactions are valid
        payers = dict()
        hashes = set()
        fees = 0
        for transaction in block.transactions[:-2]:

            # Check if the transaction has minimum validity in this blockchain.
            self.is_valid_transaction(transaction)

            # Check if transaction is targeting this block
            if transaction.target != block.index:
                raise InvalidTransactionTarget()

            # Check if it is not a duplicate transaction
            transaction_hash = transaction.calculate_hash()
            if transaction_hash not in hashes:
                hashes.add(transaction_hash)
            else:
                raise DuplicatedTransactionsFound()

            source = self.resolve(transaction.source)
            destination = self.resolve(transaction.destination)
            if source not in payers:
                payers[source] = 0
            if destination not in payers:
                payers[destination] = 0
            payers[source] += transaction.amount + transaction.fee
            payers[destination] -= transaction.amount

            fees += transaction.fee

        # Check if payers have enough balance
        for payer in payers:
            balance = self.get_balance(payer)
            if payers[payer] > balance:
                raise BalanceNotEnough()

        # Check fee transaction
        fee_transaction = block.transactions[-2]
        if not fee_transaction.valid(
        ) or fee_transaction.source != config.NOWHERE_NAME or fee_transaction.amount != fees or self.resolve(
                fee_transaction.destination) is None:
            raise InvalidFeeTransaction()

        # Check reward transaction
        reward_transaction = block.transactions[-1]
        if not reward_transaction.valid(
        ) or reward_transaction.source != config.SUPPLY_NAME or reward_transaction.amount != self.calculate_reward(
        ) or self.resolve(reward_transaction.destination) is None:
            raise InvalidRewardTransaction()
Example #5
0
 def mine_block(block):
     diff = difficulty.decompress(block.difficulty)
     block.nonce = 0
     while not difficulty.less_or_equal(block.calculate_hash(), diff):
         block.nonce += 1
Example #6
0
 def test_compress_decompress(self):
     for i in range(32):
         diff = b'\0' * i + b'\x2e' + b'\0' * (31 - i)
         self.assertEquals(diff,
                           difficulty.decompress(difficulty.compress(diff)))