Ejemplo n.º 1
0
    def mine(cls,
             block: Block,
             mine_interrupt: threading.Event = None) -> Union[Block, None]:
        start = time.time()
        nonce = 0
        target = (1 << (256 - block.bits))
        mine_interrupt.clear()

        logger.info(f'[consensus] mining after block {block.prev_block_hash}')
        while int(Utils.sha256d(block.header(nonce)), 16) >= target:
            nonce += 1

            if mine_interrupt.is_set():
                logger.info(f'[consensus] mining interrupted +++ {nonce}')
                mine_interrupt.clear()
                return None

        block = block._replace(nonce=nonce)
        duration = max(time.time() - start, 0.0001)
        khs = (block.nonce // duration) // 1000
        logger.info(
            f'[consensus] mining block found at nonce={nonce} using {round(duration, 4)} s at rate {khs} KH/s: {block.id}'
        )

        return block
Ejemplo n.º 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
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
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
Ejemplo n.º 5
0
def mine(block: Block) -> Block:
    """
    A minimal function for calculating genisis_block nonce.
    """

    start = time.time()
    nonce = 0
    target = 1 << (256 - block.bits)

    while int(Utils.sha256d(block.header(nonce)), 16) >= target:
        nonce += 1

    block = block._replace(nonce=nonce)
    duration = max(time.time() - start, 0.0001)
    khs = (block.nonce // duration) // 1_000
    print(
        f"genesis_block found at nonce={nonce} using {round(duration, 4)}s at rate {khs}KH/s"
    )
    print(f"blockid={block.id}")
    return block
Ejemplo n.º 6
0
    def handleBlockSyncReq(self, blockid: str, peer: Peer):

        logger.info(f"[p2p] receive BlockSyncReq from peer {peer}")

        #with self.chain_lock:
        height = Block.locate_block(blockid, self.active_chain)[1]
        if height is None:
            logger.info(
                f'[p2p] cannot find blockid {blockid}, and do nothing for this BlockSyncReq from peer {peer}'
            )
            with self.chain_lock:
                block = copy.deepcopy(self.active_chain.chain[-1])

            message = Message(Actions.BlockRev, block, Params.PORT_CURRENT)
            self.request.sendall(Utils.encode_socket_data(message))

            return
        else:
            logger.info(
                f"[p2p] receive BlockSyncReq at height {height} from peer {peer}"
            )

        with self.chain_lock:
            blocks = copy.deepcopy(
                self.active_chain.chain[height:(height + Params.CHUNK_SIZE)])

        logger.info(f"[p2p] sending {len(blocks)} blocks to {peer}")

        message = Message(Actions.BlocksSyncGet, blocks, Params.PORT_CURRENT)
        self.request.sendall(Utils.encode_socket_data(message))

        if (peer not in self.peerManager.getAllPeers()) and not (peer == Peer('127.0.0.1', Params.PORT_CURRENT) or \
                peer == Peer('localhost', Params.PORT_CURRENT) or \
                    peer.ip == '0.0.0.0' or \
                    peer == Peer(Params.PUBLIC_IP, Params.PORT_CURRENT)):

            if Utils.is_peer_valid(peer):
                with self.peers_lock:
                    self.peerManager.add(peer)
                self.sendPeerExtend()
            else:
                self.peerManager.block(peer)
Ejemplo n.º 7
0
    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
Ejemplo n.º 8
0
    def __init__(self):

        # active_chain is initialized with a chain index and a list with genesis block in it
        self.active_chain: BlockChain = BlockChain(
            idx=Params.ACTIVE_CHAIN_IDX, chain=[Block.genesis_block()])
        self.side_branches: Iterable[BlockChain] = []
        self.orphan_blocks: Iterable[Block] = []
        self.utxo_set: UTXO_Set = UTXO_Set()
        self.mempool: MemPool = MemPool()
        self.wallet: Wallet = Wallet.init_wallet(Params.WALLET_FILE)

        # PeerManager use Peer.init_peer() to read peer from PEERS_FILE or peer list in Params.py
        self.peerManager: PeerManager = PeerManager(
            Peer.init_peers(Params.PEERS_FILE))

        self.mine_interrupt: threading.Event = threading.Event()
        self.ibd_done: threading.Event = threading.Event()
        self.chain_lock: threading.RLock = threading.RLock()
        self.peers_lock: threading.RLock = threading.RLock()

        self.gs = dict()
        (
            self.gs["Block"],
            self.gs["Transaction"],
            self.gs["UnspentTxOut"],
            self.gs["Message"],
            self.gs["TxIn"],
            self.gs["TxOut"],
            self.gs["Peer"],
            self.gs["OutPoint"],
        ) = (
            globals()["Block"],
            globals()["Transaction"],
            globals()["UnspentTxOut"],
            globals()["Message"],
            globals()["TxIn"],
            globals()["TxOut"],
            globals()["Peer"],
            globals()["OutPoint"],
        )
Ejemplo n.º 9
0
    def __init__(self):

        self.active_chain: BlockChain = BlockChain(
            idx=Params.ACTIVE_CHAIN_IDX, chain=[Block.genesis_block()])
        self.side_branches: Iterable[BlockChain] = []
        self.orphan_blocks: Iterable[Block] = []
        self.utxo_set: UTXO_Set = UTXO_Set()
        self.mempool: MemPool = MemPool()
        self.wallet: Wallet = Wallet.init_wallet(Params.WALLET_FILE)

        #self.peers: Iterable[Peer] = Peer.init_peers(Params.PEERS_FILE)
        self.peerManager: PeerManager = PeerManager(
            Peer.init_peers(Params.PEERS_FILE))

        self.mine_interrupt: threading.Event = threading.Event()
        self.ibd_done: threading.Event = threading.Event()
        self.chain_lock: _thread.RLock = threading.RLock()
        self.peers_lock: _thread.RLock = threading.RLock()

        self.gs = dict()
        self.gs['Block'], self.gs['Transaction'], self.gs['UnspentTxOut'], self.gs['Message'], self.gs['TxIn'], self.gs['TxOut'], self.gs['Peer'], self.gs['OutPoint']= \
                    globals()['Block'], globals()['Transaction'], globals()['UnspentTxOut'], globals()['Message'], \
                    globals()['TxIn'], globals()['TxOut'], globals()['Peer'], globals()['OutPoint']
Ejemplo n.º 10
0
        def _reorg_and_succeed(active_chain: BaseBlockChain, side_branches: Iterable[BaseBlockChain], \
                                mempool: MemPool, utxo_set:UTXO_Set, \
                                mine_interrupt: threading.Event) -> bool:


            def _do_reorg(branch_idx: int, side_branches: Iterable[BaseBlockChain], active_chain: BaseBlockChain, \
                           fork_height: int, mempool: MemPool, utxo_set:UTXO_Set, \
                           mine_interrupt: threading.Event) -> bool:

                branch_chain = side_branches[branch_idx - 1]

                fork_block = active_chain.chain[fork_height - 1]

                def disconnect_to_fork(active_chain: BaseBlockChain = active_chain, fork_block: Block = fork_block):
                    while active_chain.chain[-1].id != fork_block.id:
                        yield active_chain.disconnect_block(mempool, utxo_set)

                old_active = list(disconnect_to_fork(active_chain, fork_block))[::-1]

                assert branch_chain.chain[0].prev_block_hash == active_chain.chain[-1].id

                def rollback_reorg():

                    list(disconnect_to_fork(active_chain, fork_block))

                    for block in old_active:
                        assert active_chain.connect_block(block, active_chain, side_branches, mempool, utxo_set, \
                                                          mine_interrupt, \
                                                          doing_reorg=True) == True

                for block in branch_chain.chain:
                    if not active_chain.connect_block(block, active_chain, side_branches, mempool, utxo_set, \
                                                      mine_interrupt, doing_reorg=True):

                        logger.info(f'[ds] reorg of branch {branch_idx} to active_chain failed, decide to rollback')
                        rollback_reorg()
                        return False

                branch_chain.chain = list(old_active)

                logger.info(f'[ds] chain reorg successful with new active_chain height {active_chain.height} and top block id {active_chain.chain[-1].id}')

                return True


            reorged = False
            frozen_side_branches = list(side_branches)

            for _, branch_chain in enumerate(frozen_side_branches):
                branch_idx = branch_chain.idx
                fork_block, fork_height, _ = Block.locate_block(branch_chain.chain[0].prev_block_hash, active_chain)
                active_height = active_chain.height
                branch_height_real = branch_chain.height + fork_height

                if branch_height_real > active_height:
                    logger.info(f'[ds] decide to reorg branch {branch_idx} with height {branch_height_real} to active_chain with real height {active_height}')
                    reorged |= _do_reorg(branch_idx, side_branches, active_chain, fork_height, mempool, \
                                         utxo_set, mine_interrupt)
                    if reorged is True:
                        return reorged

            return reorged
Ejemplo n.º 11
0
from ds.Block import Block
from consensus.Consensus import PoW
import threading
import time

time_start = time.time()

genesis_block = Block.genesis_block()
genesis_block = genesis_block._replace(bits=24)
genesis_block = genesis_block._replace(timestamp=1554460209)
genesis_block = PoW.mine(genesis_block, threading.Event())
print(genesis_block.bits, genesis_block.nonce, genesis_block.id)
Ejemplo n.º 12
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
Ejemplo n.º 13
0
    def handleBlockRev(self, block: Block, peer: Peer):
        if not isinstance(block, Block):
            logger.info(f'[p2p] {block} is not a Block')
            return
        else:
            if peer != Peer('127.0.0.1', Params.PORT_CURRENT):
                logger.info(
                    f"[p2p] received block {block.id} from peer {peer}")
            with self.chain_lock:

                chain_idx  = TCPHandler.check_block_place(block, self.active_chain, self.utxo_set, self.mempool, \
                                                          self.side_branches)
                ret_outside_lock = False
                if chain_idx is not None and chain_idx >= 0:
                    ret_outside_lock = TCPHandler.do_connect_block_and_after(block, chain_idx, self.active_chain, self.side_branches, \
                                                       self.mempool, self.utxo_set, self.mine_interrupt)
                    if not ret_outside_lock:
                        #logger.info(f'####### out of chain_lock: {chain_use_id} of handleBlockRev')
                        return
                    if not Block.locate_block(block.id, self.active_chain,
                                              self.side_branches)[0]:
                        return

                #logger.info(f'####### out of chain_lock: {chain_use_id} of handleBlockRev')

            if ret_outside_lock is True:
                if len(self.active_chain.chain
                       ) % Params.SAVE_PER_SIZE == 0 or len(
                           self.active_chain.chain) <= 5:
                    Persistence.save_to_disk(self.active_chain)

            if chain_idx is not None and chain_idx >= 0:
                peers = self.peerManager.getPeers()
                if len(peers) > 0:
                    for _peer in random.sample(peers, min(len(peers), 5)):
                        if _peer != peer:
                            ret = Utils.send_to_peer(
                                Message(Actions.BlockRev, block,
                                        Params.PORT_CURRENT), _peer)
                            if ret == 1:
                                if _peer in peers:
                                    try:
                                        with self.peers_lock:
                                            self.peerManager.block(_peer)
                                    except:
                                        pass
                            elif ret != 0:
                                with self.peers_lock:
                                    self.peerManager.addLog(_peer, 1)
                            else:
                                with self.peers_lock:
                                    self.peerManager.addLog(_peer, 0)

                self.sendPeerExtend()

            elif chain_idx is None:
                logger.info(
                    f'[p2p] already seen block {block.id}, and do nothing')
            elif chain_idx == -1:
                # case of orphan block
                message = Message(Actions.TopBlocksSyncReq, 50,
                                  Params.PORT_CURRENT)
                if peer == Peer('127.0.0.1', Params.PORT_CURRENT):
                    getpeers = self.peerManager.getPeers(2)
                    if len(getpeers) > 0:
                        peer = random.sample(getpeers, 1)[0]
                    else:
                        return

                try:
                    with socket.socket(
                            socket.AF_INET, socket.SOCK_STREAM
                    ) as s:  #socket.create_connection(peer(), timeout=25) as s:
                        s.connect(peer())
                        s.sendall(Utils.encode_socket_data(message))
                        logger.info(
                            f'[p2p] succeed to send TopBlocksSyncReq to {peer}'
                        )
                        msg_len = int(binascii.hexlify(s.recv(4) or b'\x00'),
                                      16)
                        data = b''
                        while msg_len > 0:
                            tdat = s.recv(1024)
                            data += tdat
                            msg_len -= len(tdat)
                    s.close()
                except ConnectionRefusedError:
                    self.peerManager.block(peer)
                except:
                    self.peerManager.addLog(peer, 1)
                else:
                    self.peerManager.addLog(peer, 0)

                    message = Utils.deserialize(data.decode(),
                                                self.gs) if data else None
                    if message:
                        blocks = message.data
                        if blocks[0].prev_block_hash:
                            if not Block.locate_block(
                                    blocks[0].prev_block_hash,
                                    self.active_chain, self.side_branches)[0]:
                                logger.info(
                                    f"received sync blocks for the orphan block in handleBlockRev, but the first blocks's pre_block_hash cannot be seen on the chains"
                                )
                                self.peerManager.block(peer)
                                return
                        else:
                            blocks.pop(0)
                            if not Block.locate_block(
                                    blocks[0].prev_block_hash,
                                    self.active_chain, self.side_branches)[0]:
                                logger.info(
                                    f"received sync blocks for the orphan block in handleBlockRev, but the first blocks's pre_block_hash cannot be seen on the chains"
                                )
                                self.peerManager.block(peer)
                                return

                        message = Message(message.action, message.data,
                                          Params.PORT_CURRENT, peer)
                        ret = Utils.send_to_peer(message,
                                                 Peer('127.0.0.1',
                                                      Params.PORT_CURRENT),
                                                 itself=True)

                        if ret != 0:
                            logger.info(
                                f'[p2p] cannot send data to itself, and its current port is {Params.PORT_CURRENT}'
                            )
                        else:
                            #logger.info(f'[p2p] send BlocksSyncGet to itself')
                            pass
                    else:
                        logger.info(f'[p2p] recv nothing from peer {peer}')
Ejemplo n.º 14
0
    def handleBlockSyncGet(self, blocks: Iterable[Block], peer: Peer):
        if peer != Peer('127.0.0.1', Params.PORT_CURRENT):
            logger.info(
                f"[p2p] receive {len(blocks)} blocks for BlockSyncGet from {peer}"
            )
        new_blocks = [
            block for block in blocks if not Block.locate_block(
                block.id, self.active_chain, self.side_branches)[0]
        ]
        logger.info(
            f'[p2p] {len(new_blocks)} of {len(blocks)} blocks from {peer} is new'
        )

        #if not new_blocks:
        #    logger.info('[p2p] initial block download complete')
        #    self.ibd_done.set()
        #    return
        #else:
        #    self.ibd_done.clear()

        if not TCPHandler.check_blocks_headers(new_blocks):
            return

        with self.chain_lock:

            for block in new_blocks:
                if Block.locate_block(block.id, self.active_chain,
                                      self.side_branches)[0]:
                    new_blocks.pop(0)
                else:
                    break
            if not new_blocks:
                return

            chain_idx  = TCPHandler.check_block_place(new_blocks[0], self.active_chain, self.utxo_set, \
                                                          self.mempool, self.side_branches)
            if chain_idx is None:
                logger.info(
                    f'received blocks have been seen in BlockSyncGet, do nothing and return'
                )
                return
            if chain_idx <= -1:
                logger.info(f'[p2p] orphan or wrong blocks')
                if peer != Peer('127.0.0.1', Params.PORT_CURRENT):
                    with self.peers_lock:
                        self.peerManager.block(peer)
                return

            if chain_idx >= 1:
                # if is side branches, append the blocks (one block left) to the side branches directly
                logger.info(
                    f'[p2p] just append {len(new_blocks)-1} blocks to side branch {chain_idx}, leaving one block to '
                    f'be coped with method do_connect_block_and_after')
                while len(new_blocks) >= 2:
                    self.side_branches[chain_idx - 1].chain.append(
                        new_blocks.pop(0))

            for block in new_blocks:
                if not TCPHandler.do_connect_block_and_after(block, chain_idx, self.active_chain, self.side_branches, \
                                                self.mempool, self.utxo_set, self.mine_interrupt):
                    return

        if chain_idx == Params.ACTIVE_CHAIN_IDX:
            if len(self.active_chain.chain) % Params.SAVE_PER_SIZE == 0 or len(
                    self.active_chain.chain) <= 5:
                Persistence.save_to_disk(self.active_chain)

            logger.info(
                f'[p2p] current chain height {self.active_chain.height}, and continue initial block download ... '
            )

        if peer not in self.peerManager.getAllPeers():
            if peer== Peer('127.0.0.1', Params.PORT_CURRENT) or \
                            peer == Peer('localhost', Params.PORT_CURRENT) or \
                                peer.ip == '0.0.0.0' or \
                                peer == Peer(Params.PUBLIC_IP, Params.PORT_CURRENT):
                return
            if Utils.is_peer_valid(peer):
                with self.peers_lock:
                    self.peerManager.add(peer)  #self.peers.append(peer)
                self.sendPeerExtend()
            else:
                self.peerManager.block(peer)

        if peer == Peer('127.0.0.1', Params.PORT_CURRENT):
            logger.info(f'peer in handleBlockSyncGet cannot be itself')
            return

        top_id_chain_idx = new_blocks[-1].id
        message = Message(Actions.BlocksSyncReq, top_id_chain_idx,
                          Params.PORT_CURRENT)
        try:
            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
                s.connect(peer())
                s.sendall(Utils.encode_socket_data(message))
                logger.info(f'[p2p] succeed to send BlocksSyncReq to {peer}')
                msg_len = int(binascii.hexlify(s.recv(4) or b'\x00'), 16)
                data = b''
                while msg_len > 0:
                    tdat = s.recv(1024)
                    data += tdat
                    msg_len -= len(tdat)
            s.close()
        except ConnectionRefusedError:
            self.peerManager.block(peer)
        except:
            self.peerManager.addLog(peer, 1)
        else:
            self.peerManager.addLog(peer, 0)

            message = Utils.deserialize(data.decode(),
                                        self.gs) if data else None
            if message:
                logger.info(
                    f'[p2p] received blocks for sync blocks from peer {peer}')
                message = Message(message.action, message.data,
                                  Params.PORT_CURRENT, peer)
                ret = Utils.send_to_peer(message,
                                         Peer('127.0.0.1',
                                              Params.PORT_CURRENT),
                                         itself=True)
                if ret != 0:
                    logger.info(
                        f'[p2p] cannot send data to itself, and its current port is {Params.PORT_CURRENT}'
                    )

            else:
                logger.info(f'[p2p] recv nothing from peer {peer}')
Ejemplo n.º 15
0
        serviceId=None,
        postId=None,
        actionId=None,
        data=None,
        locktime=None,
    )
]
merkle_hash = MerkleNode.get_merkle_root_of_txns(txns)
print(f"merkle_hash={merkle_hash.val}")

genesis_block = Block(
    version="5465616d3a20456467656e63650a4c65616465723a20776f6c6662726f746865720a4d656d626572733a2063626f7a69"
    "2c204c6561684c69752c207069616f6c69616e676b622c2053616c7661746f7265303632362c2053696c7669614c69313"
    "232352c204a69617169204c69752c2078696179756e696c0a",
    prev_block_hash=None,
    merkle_hash=merkle_hash.val,
    timestamp=1554460209,
    bits=Params.INITIAL_DIFFICULTY_BITS,
    nonce=None,
    txns=txns,
)


def mine(block: Block) -> Block:
    """
    A minimal function for calculating genisis_block nonce.
    """

    start = time.time()
    nonce = 0
    target = 1 << (256 - block.bits)