Пример #1
0
class P2P_network:
    def __init__(self, _id=""):
        self.peerID = _getPeerID(_id)  # my peer ID
        self.clientSocket_pool = []
        self.serverSocket_pool = []  # available port to receive connection
        self.serverPort_pool = []
        self.thread_pool = []
        self.peer_ports = []
        self.conn_peerID_pair = {}  # existing socket-peerID pair
        self.unspent = []
        self.pendingTx = []
        self.blockchain = Blockchain(self.peerID, self.unspent, self.pendingTx)
        self.seq_peerID_pair = self.blockchain.seq_pair  # existing seq numbexr-peerID pair
        self._addServerSocket()
        self._addClientSocket()

        print(self.serverPort_pool)

    def _createServerSocket(self):
        while True:
            try:
                port = random.randint(10000, 50000)
                server_socket = socket.socket(socket.AF_INET,
                                              socket.SOCK_STREAM)
                server_socket.bind((host_name, port))
                server_socket.listen()
                t = ConnectionThread(server_socket, self.peer_ports,
                                     self.peerID, self.conn_peerID_pair,
                                     self.seq_peerID_pair, self.blockchain,
                                     self.serverPort_pool, port,
                                     self.pendingTx)
                t.setDaemon(True)
                t.start()
                return (server_socket, port, t)
            except Exception as e:
                logging.debug("OSError {} {}".format(e, self.port))

    def _addServerSocket(self):
        for _ in range(5):
            soc, port, t = self._createServerSocket()
            self.serverSocket_pool.append(soc)
            # self.serverPort_pool.append(port)
            self.thread_pool.append(t)

    def _addClientSocket(self):
        for _ in range(5):
            soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.clientSocket_pool.append(soc)

    def connects(self, port):
        if len(self.clientSocket_pool) == 0:
            for _ in range(5):
                self._addClientSocket()

        soc = self.clientSocket_pool.pop(0)
        try:
            soc.connect((localIP, int(port)))
            # self.peer_connectTo.append(port)
            # self.clientSocket_connecting.append(soc)
        except Exception as e:
            self.clientSocket_pool.append(soc)
            logging.debug("Cannot connect to port " + str(port) + ':' + str(e))
            return

        t = HandleMsgThread(soc, self.peerID, self.conn_peerID_pair,
                            self.seq_peerID_pair, self.blockchain,
                            self.pendingTx)
        t.setDaemon(True)
        t.start()

        msg = json.dumps({'type': 'REQUEST_PEERID', 'peerID': self.peerID})
        soc.sendall(bytes(msg, 'utf-8'))

    def updateSeqNum(self):
        self.seq_peerID_pair[self.peerID] += 1
        self.blockchain.updateSeq(self.seq_peerID_pair)

    def broadcast(self, txt):
        self.updateSeqNum()
        msg = json.dumps({
            'type': 'txt',
            'source': self.peerID,
            'data': str(txt),
            'seq_no': self.seq_peerID_pair[self.peerID]
        })
        for key, soc in self.conn_peerID_pair.items():
            soc.sendall(bytes(msg, 'utf-8'))

    # assume only owner of coin can be sender of transaction
    def broadcastTransaction(self, dest_addr, value):
        if self.blockchain.checkInOut(value, self.peerID, dest_addr, True):
            self.updateSeqNum()
            msg = json.dumps({
                'type': 'RECEIVE_TRANSACTION',
                'source': self.peerID,
                'value': int(value),
                'seq_no': self.seq_peerID_pair[self.peerID],
                'source_addr': self.peerID,
                'dest_addr': dest_addr,
                'timestamp': _getTime()
            })
            for key, soc in self.conn_peerID_pair.items():
                soc.sendall(bytes(msg, 'utf-8'))
        else:
            print('You do not have enough value to do transaction')

    def mine(self, transac=''):
        if transac:
            transac['source_addr'] = self.peerID
            transac['timestamp'] = _getTime()
            self.pendingTx.append(transac)
            # print('p2p[163]', transac)
        tx = self.blockchain.addPendingTransaction()
        # print('[164]', tx)
        if tx:
            self.blockchain.mine(tx)
        else:
            self.blockchain.mine()

        self.updateSeqNum()
        msg = JSONEncoder().encode({
            'type': 'RECEIVE_LATEST_BLOCK',
            'source': self.peerID,
            'block': self.blockchain.latest_block,
            'seq_no': self.seq_peerID_pair[self.peerID],
            'sender': self.peerID
        })
        for _id, soc in self.conn_peerID_pair.items():
            soc.send(bytes(msg, 'utf-8'))

    def getDataByHash(self, h):
        bc = self.blockchain.block_chain
        for i in bc:
            if i['current_hash'] == h:
                print('Block:')
                pprint(i)
                return
            for j in i['transaction']:
                if j['hash'] == h:
                    print('Transaction:')
                    pprint(j)
                    return
        print('No matching hash found')

    def info(self):
        pprint({
            'peerID':
            self.peerID,
            'server_port':
            self.serverPort_pool,
            'conn_peerID':
            self.conn_peerID_pair,
            'balance':
            sum([i[2] for i in self.unspent if i[0] == self.peerID])
        })

    def debug(self):
        pprint({
            'unspent': self.unspent,
            'pendingTx': self.pendingTx,
            'seq_pair': self.seq_peerID_pair
        })