Example #1
0
    def assemble_and_solve_block(self, txns=None) -> Block:
        """
        Construct a Block by pulling transactions from the mempool, then mine it.
        """
        with self.chain_lock:
            #chain_use_id = [str(number).split('.')[0] + '.' + str(number).split('.')[1][:5] for number in [random.random()]][0]
            #logger.info(f'####### into chain_lock: {chain_use_id} of assemble_and_solve_block')

            prev_block_hash = self.active_chain.chain[
                -1].id if self.active_chain.chain else None

            block = Block(
                version=0,
                prev_block_hash=prev_block_hash,
                merkle_hash='',
                timestamp=int(time.time()),
                bits=Block.get_next_work_required(prev_block_hash,
                                                  self.active_chain,
                                                  self.side_branches),
                nonce=0,
                txns=[None, *txns] if txns else [None],
            )

            if block.bits is None:
                #logger.info(f'####### out of chain_lock: {chain_use_id} of assemble_and_solve_block')
                return None

            if not block.txns[1:]:
                block = self.mempool.select_from_mempool(block, self.utxo_set)
                # print("EdgenceChain 113: build block with txn:", end="")
                # print(block)
                if len(block.txns[1:]) > 0:
                    logger.info(
                        f'{len(block.txns[1:])} transactions selected from mempool to construct this block'
                    )
                    # print("EdgenceChain 117: build txn:")
                    # print(block)

            fees = block.calculate_fees(self.utxo_set)
            # print("fee is: ", end="")
            # print(fees)
            my_address = self.wallet()[2]
            coinbase_txn = Transaction.create_coinbase(
                my_address,
                Block.get_block_subsidy(self.active_chain) + fees,
                self.active_chain.height)
            #logger.info(f'####### out of chain_lock: {chain_use_id} of assemble_and_solve_block')

        block.txns[0] = coinbase_txn
        block = block._replace(
            merkle_hash=MerkleNode.get_merkle_root_of_txns(block.txns).val)

        if len(Utils.serialize(block)) > Params.MAX_BLOCK_SERIALIZED_SIZE:
            raise ValueError('txns specified create a block too large')

        block = PoW.mine(block, self.mine_interrupt)
        # print("EdgenceChain 138: after mine: ")
        # print(block)
        return block
Example #2
0
    def do_connect_block_and_after(cls, block: Block, chain_idx, active_chain: BlockChain, side_branches: Iterable[BlockChain], \
                                mempool: BaseMemPool, utxo_set: BaseUTXO_Set, mine_interrupt: threading.Event) -> bool:
        if int(chain_idx) == int(Params.ACTIVE_CHAIN_IDX):
            if block.block_subsidy_fees != Block.get_block_subsidy(
                    active_chain) + block.calculate_fees(utxo_set):
                #logger.info(f'{block.block_subsidy_fees} != {Block.get_block_subsidy(active_chain)} + {block.calculate_fees(utxo_set)}')
                logger.info(
                    f'[p2p] subsidy and fees of this block are not right, so discard this block and return.'
                )
                #logger.info(f'after check subsid_fees, and give out a logger.exception')
                return False
            else:
                #logger.info(f'[p2p] subsidy and fees of this block are right.')
                pass
            connect_block_success = active_chain.connect_block(block, active_chain, \
                                                    side_branches, \
                                    mempool, utxo_set, mine_interrupt)
        else:
            connect_block_success = side_branches[chain_idx-1].connect_block(block, \
                                             active_chain, side_branches, \
                                    mempool, utxo_set, mine_interrupt)

        if connect_block_success is not False:

            if connect_block_success is not True:  # -1, success and reorg
                #logger.info(f'[p2p] a successful reorg is found, begin to deal with {len(side_branches)} side branches')

                for branch_chain in side_branches:
                    #logger.info(f'[p2p] number of blocks before slim side branch: {len(branch_chain.chain)}')

                    #TCPHandler.printBlockchainIDs(branch_chain, '[p2p] side branch removed from active chain ')

                    fork_height_from_end = 0
                    for block in branch_chain.chain[::-1]:
                        if not Block.locate_block(block.id, active_chain)[0]:
                            if not Block.locate_block(block.prev_block_hash,
                                                      active_chain)[0]:
                                fork_height_from_end += 1
                            else:
                                break
                        else:
                            branch_chain.chain = []
                            logger.info(
                                f'[p2p] the whole body of this branch chain is in active chain'
                            )
                            break
                    if fork_height_from_end >= branch_chain.height and branch_chain.height != 0:
                        branch_chain.chain = []
                        logger.info(
                            f'[p2p] all blocks are orphans to the current active chain'
                        )

                    else:
                        for num_to_pop in range(
                                1, branch_chain.height - fork_height_from_end):
                            branch_chain.chain.pop(0)
                    #logger.info(f'[p2p] number of blocks after slim side branch: {len(branch_chain.chain)}')

            side_branches_to_discard = []
            for branch_chain in side_branches:
                if branch_chain.chain == []:
                    side_branches_to_discard.append(branch_chain)
                    continue
                fork_block, fork_height, _ = Block.locate_block(
                    branch_chain.chain[0].prev_block_hash, active_chain)
                if fork_block is None:
                    side_branches_to_discard.append(branch_chain)

                branch_height_real = branch_chain.height + fork_height
                if active_chain.height - branch_height_real > Params.MAXIMUM_ALLOWABLE_HEIGHT_DIFF:
                    side_branches_to_discard.append(branch_chain)
            if len(side_branches_to_discard) > 0:
                logger.info(
                    f'[p2p] ## delete {len(side_branches_to_discard)} side branches beyond MAXIMUM_ALLOWABLE_HEIGHT_DIFF'
                )
                for branch_chain in side_branches_to_discard:
                    side_branches.remove(branch_chain)
            for index, branch_chain in enumerate(side_branches, 1):
                branch_chain.index = index
        else:
            logger.exception(f'[p2p] connect_block returned a False value')
        return True