class EmulatorModeServer(QtNetwork.QLocalServer): signal_data_received = QtCore.pyqtSignal(object) _SOCKET_TIMEOUT = 2000 def __init__(self): super().__init__() self.setSocketOptions(QtNetwork.QLocalServer.WorldAccessOption) self.newConnection.connect(self._handleConnection) def listen(self): if not super().listen(Emulator.GUI_PLUGIN_SERVER_NAME): raise RuntimeError( f'Could not start server: {Emulator.GUI_PLUGIN_SERVER_NAME}') def close(self): super().close() self.removeServer(self.fullServerName()) def _handleConnection(self): socket = self.nextPendingConnection() if socket is not None: data = None if socket.waitForReadyRead(self._SOCKET_TIMEOUT): data = socket.readAll().data().decode('utf-8') logger.debug(f'Read data from emulator: {data}') socket.disconnectFromServer() socket.deleteLater() if data is not None: self.signal_data_received.emit(data) logger.debug('Data emitted.')
class GraphView(QGraphicsView): positionsChanged = QtCore.pyqtSignal(np.ndarray) # Emitted when nodes' selected or highlighted state changes selectionChanged = QtCore.pyqtSignal() # Emitted when the relayout() animation finishes animationFinished = QtCore.pyqtSignal() def __init__(self, parent=None): super().__init__(parent) self.nodes = [] self.edges = [] self._selection = [] self._clicked_node = None self.is_animating = False scene = QGraphicsScene(self) scene.setItemIndexMethod(scene.BspTreeIndex) scene.setBspTreeDepth(2) self.setScene(scene) self.setText('') self.setCacheMode(self.CacheBackground) self.setViewportUpdateMode( self.FullViewportUpdate ) # BoundingRectViewportUpdate doesn't work on Mac self.setTransformationAnchor(self.AnchorUnderMouse) self.setResizeAnchor(self.AnchorViewCenter) self.setDragMode(self.RubberBandDrag) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.positionsChanged.connect(self._update_positions, type=Qt.BlockingQueuedConnection) self.animationFinished.connect( lambda: setattr(self, 'is_animating', False)) def mousePressEvent(self, event): self._selection = [] if event.button() == Qt.LeftButton: if self.is_animating: self.is_animating = False return # Save the current selection and restore it on mouse{Move,Release} self._clicked_node = self.itemAt(event.pos()) if event.modifiers() & Qt.ShiftModifier: self._selection = self.scene().selectedItems() # On right mouse button, switch to pan mode elif event.button() == Qt.RightButton: self.setDragMode(self.ScrollHandDrag) # Forge left mouse button event event = QtGui.QMouseEvent(event.type(), event.pos(), event.globalPos(), Qt.LeftButton, event.buttons(), event.modifiers()) super().mousePressEvent(event) # Reselect the selection that had just been discarded for node in self._selection: node.setSelected(True) def mouseMoveEvent(self, event): super().mouseMoveEvent(event) if not self._clicked_node: for node in self._selection: node.setSelected(True) def mouseReleaseEvent(self, event): super().mouseReleaseEvent(event) if self.dragMode() == self.RubberBandDrag: for node in self._selection: node.setSelected(True) self.selectionChanged.emit() if self._clicked_node: self.selectionChanged.emit() # The following line is required (QTBUG-48443) self.setDragMode(self.NoDrag) # Restore default drag mode self.setDragMode(self.RubberBandDrag) def setText(self, text): text = self._text = QtGui.QStaticText(text or '') text.setPerformanceHint(text.AggressiveCaching) option = QtGui.QTextOption() option.setWrapMode(QtGui.QTextOption.NoWrap) text.setTextOption(option) scene = self.scene() scene.invalidate(layers=scene.BackgroundLayer) def drawForeground(self, painter, rect): painter.resetTransform() painter.drawStaticText(10, 10, self._text) super().drawForeground(painter, rect) def scrollContentsBy(self, dx, dy): scene = self.scene() scene.invalidate(layers=scene.BackgroundLayer) super().scrollContentsBy(dx, dy) def _setState(self, nodes, extend, state_setter): nodes = set(nodes) if extend: for node in self.nodes: if node.id in nodes: getattr(node, state_setter)(True) else: for node in self.nodes: getattr(node, state_setter)(node.id in nodes) self.selectionChanged.emit() def getSelected(self): return [node.id for node in self.scene().selectedItems()] def getUnselected(self): return [ node.id for node in (set(self.scene().items()) - set(self.scene().selectedItems())) if isinstance(node, Node) ] def setSelected(self, nodes, extend=False): self._setState(nodes, extend, 'setSelected') def getHighlighted(self): return [ node.id for node in self.nodes if node.isHighlighted() and not node.isSelected() ] def setHighlighted(self, nodes): self._setState(nodes, False, 'setHighlighted') def clear(self): self.scene().clear() self.scene().setSceneRect(QRectF()) self.nodes.clear() self.edges.clear() def set_graph(self, graph, relayout=True): assert not graph or isinstance(graph, nx.Graph) self.graph = graph if not graph: self.clear() return large_graph = IS_LARGE_GRAPH(graph) very_large_graph = IS_VERY_LARGE_GRAPH(graph) self.setViewport( QtOpenGL.QGLWidget() # FIXME: Try reenable the following test after Qt5 port if large_graph and HAVE_OPENGL else QWidget()) self.setRenderHints(QtGui.QPainter.RenderHint( ) if very_large_graph else (QtGui.QPainter.Antialiasing | QtGui.QPainter.TextAntialiasing)) self.clear() nodes = {} for v in sorted(graph.nodes()): node = Node(v, view=self) self.addNode(node) nodes[v] = node for u, v in graph.edges(): self.addEdge(Edge(nodes[u], nodes[v], view=self)) self.selectionChanged.emit() if relayout: self.relayout() def addNode(self, node): assert isinstance(node, Node) self.nodes.append(node) self.scene().addItem(node) def addEdge(self, edge): assert isinstance(edge, Edge) self.edges.append(edge) self.scene().addItem(edge) def wheelEvent(self, event): if event.angleDelta().x() != 0: return self.scaleView(2**(event.angleDelta().y() / 240)) def scaleView(self, factor): magnitude = self.transform().scale(factor, factor).mapRect(QRectF(0, 0, 1, 1)).width() if 0.2 < magnitude < 30: self.scale(factor, factor) # Reposition nodes' labela and edges, both of which are node-dependend # (and nodes just "moved") for node in self.nodes: node.adjust() for edge in self.edges: edge.adjust() @property def is_animating(self): return self._is_animating @is_animating.setter def is_animating(self, value): self.setCursor(Qt.ForbiddenCursor if value else Qt.ArrowCursor) self._is_animating = value def relayout(self, randomize=True, weight=None): if self.is_animating: return self.is_animating = True if weight is None: weight = 'weight' pos, graphview = None, self if not randomize: pos = [[pos.x(), pos.y()] for pos in (node.pos() for node in self.nodes)] class AnimationThread(Thread): def __init__(self, iterations, callback): super().__init__() self.iterations = iterations self.callback = callback def run(self): newpos = fruchterman_reingold_layout( graphview.graph, pos=pos, weight=weight, iterations=self.iterations, callback=self.callback) if not self.callback: # update once at the end graphview.update_positions(newpos) graphview.animationFinished.emit() iterations, callback = FR_ITERATIONS, self.update_positions if IS_VERY_LARGE_GRAPH(self.graph): # Don't animate very large graphs iterations, callback = 5, None AnimationThread(iterations, callback).start() def update_positions(self, positions): self.positionsChanged.emit(positions) return self._is_animating def _update_positions(self, positions): for node, pos in zip(self.nodes, positions * 300): node.setPos(*pos) qApp.processEvents()
class wallet_functions(QtCore.QThread): data_output = QtCore.pyqtSignal(object) def __init__(self, coin_list): QtCore.QThread.__init__(self) self.coin_list = coin_list def run(self): LOG_PATH = 'RPC.log' logging.basicConfig(filename=LOG_PATH, level=logging.INFO) log = logging.getLogger(__name__) output = self.check_for_stake(self.coin_list, log) self.data_output.emit('{0}: {1}'.format(self.coin_list['coin_name'], output)) def check_for_stake(self, RPC, log): try: rpc_connection = AuthServiceProxy("http://%s:%[email protected]:%s"%(RPC['user'], RPC['pw'], RPC['port'])) # Check integrity of wallet before getting wallet info check_wallet = rpc_connection.checkwallet() except: return "Unable to connect to wallet. Verify that it's running and your RPC settings are correct" if 'wallet check passed' not in check_wallet: log.info(check_wallet) rpc_connection.repairwallet() log.info("**Wallet was repaired**") try: txs = rpc_connection.listunspent(int(RPC['min_conf']), int(RPC['max_conf'])) # Only work with inputs that aren't mature except: return "Unable to run 'listunspent' over RPC, check that the wallet is still running" input_sum = 0 utxo_size = Decimal(RPC['UTXO_size']) input_tx = [] addresses_to_reuse = [] for each_tx in txs: # Check out each existing transaction for desired size, sum up inputs that aren't if each_tx['amount'] != utxo_size: input_sum += each_tx['amount'] input_tx.append({"txid":each_tx['txid'],"vout":each_tx['vout']}) if 'account' in each_tx and each_tx['account'] == 'stake_script' and each_tx['address'] not in addresses_to_reuse: # reuse input addresses for a new output if they have the label 'stake_script' addresses_to_reuse.append(each_tx['address']) if input_sum < utxo_size: log.debug("DEBUG: Total coins: {0} is not enough to make a new packet of {1}".format(input_sum, utxo_size)) return "Total coins: {0} is not enough to make a new packet of {1} :DEBUG".format(input_sum, utxo_size) # Reuse or make a new change and stake addresses change_address = rpc_connection.getaddressesbyaccount("change") if len(change_address) == 0: change_address = [rpc_connection.getnewaddress("change")] stake_addresses = rpc_connection.getaddressesbyaccount("stake_script") for addr in stake_addresses: amount = rpc_connection.getreceivedbyaddress(addr) if amount == 0 and addr not in addresses_to_reuse: # Only reuse addresses with the label stake_script and zero balance for safety addresses_to_reuse.append(addr) output_addresses = {} number_of_splits = int(input_sum / utxo_size) if len(addresses_to_reuse) < number_of_splits: # Make as many new addresses as needed to split inputs into 'size' outputs num_to_make = number_of_splits - len(addresses_to_reuse) #if not arg.noconfirm: # TODO implement # print("About to make {0} new stake address(es), confirm".format(num_to_make)) # get_permission() for _ in range(num_to_make): addresses_to_reuse.append(rpc_connection.getnewaddress('stake_script')) for _ in range(number_of_splits): output_addresses[addresses_to_reuse.pop()] = utxo_size #print(output_addresses) assert(int(input_sum / utxo_size) == len(output_addresses)), "Not enough output addresses for number of UTXO splits!" number_of_splits = len(output_addresses) numbytes = 181 * len(input_tx) + 34* (number_of_splits+1) + 10 numKB = math.ceil(numbytes / 1000) TX_FEE = Decimal(RPC['transaction_fee']) * numKB log.debug("transaction fee is %d : %d bytes, fee multiple is %d"%(TX_FEE, numbytes,numKB)) change_amount = input_sum - (utxo_size * number_of_splits) - TX_FEE output_addresses[change_address[0]] = change_amount assert (change_amount > 0), "Change amount cannot be less than zero" assert(change_amount + TX_FEE + (utxo_size*number_of_splits) == input_sum), "Coins will be lost if the total output != input" log.debug("{0} Inputs {1}".format(len(input_tx),input_tx)) log.debug("{0} Outputs {1}".format(len(output_addresses), output_addresses)) log.info("{0} (Input total) = {2} ({1}_UTXO packets) + {3} (change) + {4} (fee)".format(input_sum,number_of_splits,utxo_size*number_of_splits,change_amount, TX_FEE)) # Generate, sign, and send the raw transaction raw_tx = rpc_connection.createrawtransaction(input_tx, output_addresses) signed_tx = rpc_connection.signrawtransaction(raw_tx) if not signed_tx['complete']: log.error("Signing failed of raw tranaction: {0}\nInputs: {1}\nOutputs: {2}".format(raw_tx, input_tx, output_addresses)) return "Signing of raw transaction did not complete successfully, make sure wallet is functioning properly" #if not arg.noconfirm: # print("About to send transaction, confirm") # get_permission() log.info("Attempting to send: {0} (Total inputs) = {2} ({1} new UTXO) + {3} (change) + {4} (fee)".format(input_sum,number_of_splits,utxo_size*number_of_splits,change_amount, TX_FEE)) try: sent = rpc_connection.sendrawtransaction(signed_tx['hex']) except Exception as e: return "Sending transaction failed (Your wallet might need more time to update): {0}".format(str(e)) log.info("TX successful: transaction ID: {0}".format(sent)) now = datetime.datetime.now().strftime("%m-%d %H:%M") return "{6} TX {5} successful: {0} (Total inputs) = {2} ({1} new UTXO) + {3} (change) + {4} (fee)".format(input_sum,number_of_splits,utxo_size*number_of_splits,change_amount, TX_FEE, sent, now)