def _connect_block(block: Block, active_chain: BlockChain, utxo_set: UTXO_Set) -> bool:
        """
        Add block after current chain. Return True if block added successfully, else False. 
        """

        if block.validate_block(active_chain, utxo_set) is None:
            return False

        logger.info(
            f"connecting the {len(active_chain.chain)+1}th block {block.id} to chain {active_chain.idx}"
        )
        active_chain.chain.append(block)

        # Minipulate transactions in this block.
        # Remove txin from utxo_set, add txout to utxo_set.
        for tx in block.txns:
            if not tx.is_coinbase:
                for txin in tx.txins:
                    utxo_set.rm_from_utxo(*txin.to_spend)
            for i, txout in enumerate(tx.txouts):
                utxo_set.add_to_utxo(
                    txout, tx, i, tx.is_coinbase, len(active_chain.chain)
                )

        return True
Exemple #2
0
    def check_block_place(
        cls,
        block: Block,
        active_chain: BlockChain,
        utxo_set: BaseUTXO_Set,
        mempool: BaseMemPool,
        side_branches: Iterable[BlockChain],
    ) -> int:
        if Block.locate_block(block.id, active_chain, side_branches)[0]:
            logger.debug(
                f"[p2p] ignore block that already be seen: {block.id}")
            return None  # already seen block

        try:
            chain_idx = block.validate_block(active_chain, utxo_set, mempool,
                                             side_branches)
        except BlockValidationError as e:
            if e.to_orphan:
                logger.info(
                    f"[p2p]  block {block.id} failed validation as an orphan block"
                )
                return -1  # orphan block
            else:
                logger.exception(
                    f"[p2p] block {block.id} failed validation due to internal error in this block"
                )
                return -2  # Internal error in this block

        if chain_idx != Params.ACTIVE_CHAIN_IDX and len(
                side_branches) < chain_idx:
            logger.info(
                f"[p2p] creating a new side branch (idx {chain_idx}) for block {block.id}"
            )
            side_branches.append(BlockChain(idx=chain_idx, chain=[]))

            prev_block, prev_block_height, prev_block_chain_idx = Block.locate_block(
                block.prev_block_hash, active_chain, side_branches)
            if prev_block_chain_idx != Params.ACTIVE_CHAIN_IDX:  # branch of a branch
                logger.info(
                    f"[p2p] branch (idx {chain_idx}) of an existing side branch (idx {prev_block_chain_idx}) for block {block.id}"
                )
                branch_fork_height = Block.locate_block(
                    block.prev_block_hash,
                    side_branches[prev_block_chain_idx - 1])[1]
                side_branches[chain_idx - 1].chain = list(
                    side_branches[prev_block_chain_idx -
                                  1].chain[:branch_fork_height])

        return chain_idx
    def _connect_block(block: Block, active_chain: BlockChain,
                       utxo_set: UTXO_Set) -> bool:

        if block.validate_block(active_chain, utxo_set) is None:
            return False

        logger.info(
            f'connecting the {len(active_chain.chain)+1}th block {block.id} to chain {active_chain.idx}'
        )
        active_chain.chain.append(block)

        for tx in block.txns:
            if not tx.is_coinbase:
                for txin in tx.txins:
                    utxo_set.rm_from_utxo(*txin.to_spend)
            for i, txout in enumerate(tx.txouts):
                utxo_set.add_to_utxo(txout, tx, i, tx.is_coinbase,
                                     len(active_chain.chain))

        return True