def updateRPCstatus(self, ctrl, fDebug=False): self.sig_clearRPCstatus.emit() self.rpcClient = None rpc_index, rpc_protocol, rpc_host, rpc_user, rpc_password = self.getRPCserver( ) if fDebug: printDbg("Trying to connect to RPC %s://%s..." % (rpc_protocol, rpc_host)) try: rpcClient = RpcClient(rpc_protocol, rpc_host, rpc_user, rpc_password) except Exception as e: printException(getCallerName(), getFunctionName(), "exception in updateRPCstatus", str(e)) return try: status, statusMess, lastBlock, r_time1, isTestnet = rpcClient.getStatus( ) isBlockchainSynced, r_time2 = rpcClient.isBlockchainSynced() except Exception as e: return rpcResponseTime = None if r_time1 is not None and r_time2 != 0: rpcResponseTime = round((r_time1 + r_time2) / 2, 3) # Update status and client only if selected server is not changed if rpc_index != self.header.rpcClientsBox.currentIndex(): return with self.lock: self.rpcClient = rpcClient self.rpcConnected = status self.rpcLastBlock = lastBlock self.rpcStatusMess = statusMess self.isBlockchainSynced = isBlockchainSynced self.rpcResponseTime = rpcResponseTime # if testnet flag is changed, update api client and persist setting if isTestnet != self.isTestnetRPC: self.isTestnetRPC = isTestnet self.parent.cache['isTestnetRPC'] = persistCacheSetting( 'isTestnetRPC', isTestnet) self.apiClient = ApiClient(isTestnet) self.sig_RPCstatusUpdated.emit(rpc_index, fDebug)
def updateRPCstatus(self, ctrl, fDebug=False): self.sig_clearRPCstatus.emit() self.rpcClient = None rpc_index, rpc_protocol, rpc_host, rpc_user, rpc_password = self.getRPCserver( ) rpc_url = "%s://%s:%s@%s" % (rpc_protocol, rpc_user, rpc_password, rpc_host) rpcClient = RpcClient(rpc_protocol, rpc_host, rpc_user, rpc_password) if fDebug: printDbg("Trying to connect to RPC %s://%s..." % (rpc_protocol, rpc_host)) status, statusMess, lastBlock, r_time1 = rpcClient.getStatus() isBlockchainSynced, r_time2 = rpcClient.isBlockchainSynced() rpcResponseTime = None if r_time1 is not None and r_time2 is not None: rpcResponseTime = round((r_time1 + r_time2) / 2, 3) # Update status and client only if selected server is not changed if rpc_index != self.header.rpcClientsBox.currentIndex(): return with self.lock: self.rpcClient = rpcClient self.rpcConnected = status self.rpcLastBlock = lastBlock self.rpcStatusMess = statusMess self.isBlockchainSynced = isBlockchainSynced self.rpcResponseTime = rpcResponseTime self.sig_RPCstatusUpdated.emit(rpc_index, fDebug)
class MainWindow(QWidget): def __init__(self, parent, imgDir): super(QWidget, self).__init__(parent) self.parent = parent self.imgDir = imgDir self.runInThread = ThreadFuns.runInThread ###-- Create clients and statuses self.hwdevice = None self.hwStatus = 0 self.hwStatusMess = "Not Connected" self.rpcClient = None self.rpcConnected = False self.rpcStatusMess = "Not Connected" ###-- Load icons & images self.loadIcons() ###-- Create main layout self.layout = QVBoxLayout() self.header = GuiHeader(self) self.initConsole() self.layout.addWidget(self.header) ###-- Create RPC Whatchdog self.rpc_watchdogThread = QThread() self.myRpcWd = RpcWatchdog(self) self.myRpcWd.moveToThread(self.rpc_watchdogThread) self.rpc_watchdogThread.started.connect(self.myRpcWd.run) self.rpc_watchdogThread.start() ###-- Create Queues and redirect stdout and stderr (eventually) self.queue = Queue() self.queue2 = Queue() sys.stdout = WriteStream(self.queue) sys.stderr = WriteStream(self.queue2) ###-- Init last logs logFile = open(log_File, 'w+') timestamp = strftime('%Y-%m-%d %H:%M:%S', gmtime(now())) log_line = '<b style="color: blue">{}</b><br>'.format( 'STARTING PET4L at ' + timestamp) logFile.write(log_line) logFile.close() ###-- Create the thread to update console log for stdout self.consoleLogThread = QThread() self.myWSReceiver = WriteStreamReceiver(self.queue) self.myWSReceiver.mysignal.connect(self.append_to_console) self.myWSReceiver.moveToThread(self.consoleLogThread) self.consoleLogThread.started.connect(self.myWSReceiver.run) self.consoleLogThread.start() printDbg("Console Log thread started") ###-- Create the thread to update console log for stderr self.consoleLogThread2 = QThread() self.myWSReceiver2 = WriteStreamReceiver(self.queue2) self.myWSReceiver2.mysignal.connect(self.append_to_console) self.myWSReceiver2.moveToThread(self.consoleLogThread2) self.consoleLogThread2.started.connect(self.myWSReceiver2.run) self.consoleLogThread2.start() printDbg("Console Log thread 2 started") ###-- Initialize tabs self.tabs = QTabWidget() self.t_rewards = TabRewards(self) ###-- Add tabs self.tabs.addTab(self.tabRewards, "Spend from Ledger") ###-- Draw Tabs self.splitter = QSplitter(Qt.Vertical) ###-- Add tabs and console to Layout self.splitter.addWidget(self.tabs) self.splitter.addWidget(self.console) self.splitter.setStretchFactor(0, 0) self.splitter.setStretchFactor(1, 1) self.splitter.setSizes([2, 1]) self.layout.addWidget(self.splitter) ###-- Set Layout self.setLayout(self.layout) ###-- Let's go self.mnode_to_change = None printOK("Hello! Welcome to " + parent.title) @pyqtSlot(str) def append_to_console(self, text): self.consoleArea.moveCursor(QTextCursor.End) self.consoleArea.insertHtml(text) # update last logs logFile = open(log_File, 'a+') logFile.write(text) logFile.close() def initConsole(self): self.console = QGroupBox() self.console.setTitle("Console Log") layout = QVBoxLayout() self.btn_consoleToggle = QPushButton('Hide') self.btn_consoleToggle.setToolTip('Show/Hide console') self.btn_consoleToggle.clicked.connect(lambda: self.onToggleConsole()) consoleHeader = QHBoxLayout() consoleHeader.addWidget(self.btn_consoleToggle) self.consoleSaveButton = QPushButton('Save') self.consoleSaveButton.clicked.connect(lambda: self.onSaveConsole()) consoleHeader.addWidget(self.consoleSaveButton) self.btn_consoleClean = QPushButton('Clean') self.btn_consoleClean.setToolTip('Clean console log area') self.btn_consoleClean.clicked.connect(lambda: self.onCleanConsole()) consoleHeader.addWidget(self.btn_consoleClean) consoleHeader.addStretch(1) layout.addLayout(consoleHeader) self.consoleArea = QTextEdit() almostBlack = QColor(40, 40, 40) palette = QPalette() palette.setColor(QPalette.Base, almostBlack) green = QColor(0, 255, 0) palette.setColor(QPalette.Text, green) self.consoleArea.setPalette(palette) layout.addWidget(self.consoleArea) self.console.setLayout(layout) def loadIcons(self): # Load Icons self.ledPurpleH_icon = QPixmap( os.path.join(self.imgDir, 'icon_purpleLedH.png')).scaledToHeight( 17, Qt.SmoothTransformation) self.ledGrayH_icon = QPixmap( os.path.join(self.imgDir, 'icon_grayLedH.png')).scaledToHeight( 17, Qt.SmoothTransformation) self.ledHalfPurpleH_icon = QPixmap( os.path.join(self.imgDir, 'icon_halfPurpleLedH.png')).scaledToHeight( 17, Qt.SmoothTransformation) self.ledRedV_icon = QPixmap( os.path.join(self.imgDir, 'icon_redLedV.png')).scaledToHeight( 17, Qt.SmoothTransformation) self.ledGrayV_icon = QPixmap( os.path.join(self.imgDir, 'icon_grayLedV.png')).scaledToHeight( 17, Qt.SmoothTransformation) self.ledGreenV_icon = QPixmap( os.path.join(self.imgDir, 'icon_greenLedV.png')).scaledToHeight( 17, Qt.SmoothTransformation) self.ledgerImg = QPixmap(os.path.join(self.imgDir, 'ledger.png')) def myPopUp(self, messType, messTitle, messText, defaultButton=QMessageBox.No): mess = QMessageBox(messType, messTitle, messText, defaultButton, parent=self) mess.setStandardButtons(QMessageBox.Yes | QMessageBox.No) mess.setDefaultButton(defaultButton) return mess.exec_() def myPopUp2(self, messType, messTitle, messText, singleButton=QMessageBox.Ok): mess = QMessageBox(messType, messTitle, messText, singleButton, parent=self) mess.setStandardButtons(singleButton | singleButton) return mess.exec_() @pyqtSlot() def onCheckHw(self): printDbg("Checking for HW device...") self.runInThread(self.updateHWstatus, (), self.showHWstatus) @pyqtSlot() def onCheckRpc(self): printDbg("Checking RPC server...") self.runInThread(self.updateRPCstatus, (), self.showRPCstatus) @pyqtSlot() def onCleanConsole(self): self.consoleArea.clear() @pyqtSlot() def onSaveConsole(self): timestamp = strftime('%Y-%m-%d_%H-%M-%S', gmtime(now())) options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog fileName, _ = QFileDialog.getSaveFileName( self, "Save Logs to file", "PET4L_Logs_%s.txt" % timestamp, "All Files (*);; Text Files (*.txt)", options=options) try: if fileName: printOK("Saving logs to %s" % fileName) log_file = open(fileName, 'w+') log_text = self.consoleArea.toPlainText() log_file.write(log_text) log_file.close() except Exception as e: err_msg = "error writing Log file" printException(getCallerName(), getFunctionName(), err_msg, e.args) @pyqtSlot() def onToggleConsole(self): if self.btn_consoleToggle.text() == 'Hide': self.btn_consoleToggle.setText('Show') self.consoleArea.hide() self.previousH = self.splitter.sizes()[1] self.console.setMaximumHeight(70) else: self.console.setMinimumHeight(self.previousH) self.console.setMaximumHeight(starting_height) self.btn_consoleToggle.setText('Hide') self.consoleArea.show() def showHWstatus(self): self.updateHWleds() self.myPopUp2(QMessageBox.Information, 'PET4L - hw check', "STATUS: %s" % self.hwStatusMess, QMessageBox.Ok) def showRPCstatus(self): self.updateRPCled() self.myPopUp2(QMessageBox.Information, 'PET4L - rpc check', "STATUS: %s" % self.rpcStatusMess, QMessageBox.Ok) def updateHWleds(self): if self.hwStatus == 1: self.header.hwLed.setPixmap(self.ledHalfPurpleH_icon) elif self.hwStatus == 2: self.header.hwLed.setPixmap(self.ledPurpleH_icon) else: self.header.hwLed.setPixmap(self.ledGrayH_icon) self.header.hwLed.setToolTip(self.hwStatusMess) def updateHWstatus(self, ctrl): if self.hwdevice is None: self.hwdevice = HWdevice() device = self.hwdevice statusCode = device.getStatusCode() statusMess = device.getStatusMess(statusCode) printDbg("code: %s - mess: %s" % (statusCode, statusMess)) if statusCode != 2: try: if getattr(self.hwdevice, 'dongle', None) is not None: self.hwdevice.dongle.close() self.hwdevice.initDevice() device = self.hwdevice statusCode = device.getStatusCode() statusMess = device.getStatusMess(statusCode) except Exception as e: err_msg = "error in checkHw" printException(getCallerName(), getFunctionName(), err_msg, e.args) self.hwStatus = statusCode self.hwStatusMess = statusMess def updateLastBlockLabel(self): text = '--' if self.rpcLastBlock == 1: text = "Loading block index..." elif self.rpcLastBlock > 0 and self.rpcConnected: text = str(self.rpcLastBlock) self.header.lastBlockLabel.setText(text) def updateRPCled(self): if self.rpcConnected: self.header.rpcLed.setPixmap(self.ledPurpleH_icon) else: if self.rpcLastBlock == 1: self.header.rpcLed.setPixmap(self.ledHalfPurpleH_icon) else: self.header.rpcLed.setPixmap(self.ledGrayH_icon) self.header.rpcLed.setToolTip(self.rpcStatusMess) self.updateLastBlockLabel() def updateRPCstatus(self, ctrl): if self.rpcClient is None: try: self.rpcClient = RpcClient() except Exception as e: print(e) status, lastBlock = self.rpcClient.getStatus() statusMess = self.rpcClient.getStatusMess(status) if not status and lastBlock == 0: try: self.rpcClient = RpcClient() status, lastBlock = self.rpcClient.getStatus() statusMess = self.rpcClient.getStatusMess(status) except Exception as e: err_msg = "error in checkRpc" printException(getCallerName(), getFunctionName(), err_msg, e) elif lastBlock == 1: statusMess = "PIVX wallet is connected but still synchronizing / verifying blocks" self.rpcConnected = status self.rpcLastBlock = lastBlock self.rpcStatusMess = statusMess
class TestMasternodeMethods(unittest.TestCase): def setUp(self): self.rpcClient = RpcClient() rpcStatus, _ = self.rpcClient.getStatus() if not rpcStatus: self.skipTest("RPC not connected") # read masternode data from file with open('test_masternode.data.json') as data_file: input_data_list = json.load(data_file) self.mnode_list = [] for input_data in input_data_list: # Rename input data name = input_data['name'] ip = input_data['ip'] port = input_data['port'] mnPrivKey = input_data['mnPrivKey'] hwAcc = input_data['hwAcc'] collateral = input_data['collateral'] # Create masternode object mnode = Masternode(self, name, ip, port, mnPrivKey, hwAcc, collateral) mnode.sig1 = input_data['sig1'] mnode.rpcClient = self.rpcClient mnode.sig_time = int(time.time()) mnode.protocol_version = self.rpcClient.getProtocolVersion() # Add it to list self.mnode_list.append(mnode) def tearDown(self): if hasattr(self.rpcClient, 'conn'): self.rpcClient.parent = None def test_finalizeStartMessage(self): for mnode in self.mnode_list: # Test message construction mnode.finalizeStartMessage(mnode.sig1) sleep(3) # Activated by signal from masternode @pyqtSlot(str) def finalizeStartMessage_end(self, text): # decode message ret = self.caller.rpcClient.decodemasternodebroadcast(text) # find masternode in list and check for mnode in self.mnode_list: ip_addr = mnode.ip + ":" + mnode.port if ret['addr'] == ip_addr: # check ping signature ping_sig = b64encode(text[638:768]) self.assertEqual(ret['lastPing'].get('vchSig'), ping_sig) # check nLastDsq self.assertEqual(ret['nLastDsq'], 0) # check protocol version pv = self.rpcClient.getProtocolVersion() self.assertEqual(ret['protocolVersion'], pv) # check masternode pubkey1 self.assertEqual(ret['pubkey'], mnode['collateral'].get('address')) # check masternode pubkey2 pk2 = pubkey_to_address(privkey_to_pubkey(mnode.mnPrivKey)) self.assertEqual(ret['pubkey2'], pk2) # check masternode signature node_sig = b64encode(text[320:450]) self.assertEqual(ret['vchSig'], node_sig) if __name__ == '__main__': unittest.main(verbosity=2)
class MainWindow(QWidget): def __init__(self, parent, masternode_list, imgDir): super(QWidget, self).__init__(parent) self.parent = parent self.imgDir = imgDir self.runInThread = ThreadFuns.runInThread ###-- Masternode list self.masternode_list = masternode_list ###-- Create clients and statuses self.hwdevice = None self.hwStatus = 0 self.hwStatusMess = "Not Connected" self.rpcClient = None self.rpcConnected = False self.rpcStatusMess = "Not Connected" self.isBlockchainSynced = False ###-- Load icons & images self.loadIcons() ###-- Create main layout self.layout = QVBoxLayout() self.header = GuiHeader(self) self.initConsole() self.layout.addWidget(self.header) ###-- Create RPC Whatchdog self.rpc_watchdogThread = QThread() self.myRpcWd = RpcWatchdog(self) self.myRpcWd.moveToThread(self.rpc_watchdogThread) self.rpc_watchdogThread.started.connect(self.myRpcWd.run) self.rpc_watchdogThread.start() ###-- Create Queues and redirect stdout and stderr (eventually) self.queue = Queue() self.queue2 = Queue() sys.stdout = WriteStream(self.queue) sys.stderr = WriteStream(self.queue2) ###-- Init last logs logFile = open(log_File, 'w+') timestamp = strftime('%Y-%m-%d %H:%M:%S', gmtime(now())) log_line = '<b style="color: blue">{}</b><br>'.format('STARTING SPMT at '+ timestamp) logFile.write(log_line) logFile.close() ###-- Create the thread to update console log for stdout self.consoleLogThread = QThread() self.myWSReceiver = WriteStreamReceiver(self.queue) self.myWSReceiver.mysignal.connect(self.append_to_console) self.myWSReceiver.moveToThread(self.consoleLogThread) self.consoleLogThread.started.connect(self.myWSReceiver.run) self.consoleLogThread.start() printDbg("Console Log thread started") ###-- Create the thread to update console log for stderr self.consoleLogThread2 = QThread() self.myWSReceiver2 = WriteStreamReceiver(self.queue2) self.myWSReceiver2.mysignal.connect(self.append_to_console) self.myWSReceiver2.moveToThread(self.consoleLogThread2) self.consoleLogThread2.started.connect(self.myWSReceiver2.run) self.consoleLogThread2.start() printDbg("Console Log thread 2 started") ###-- Initialize tabs self.tabs = QTabWidget() self.t_main = TabMain(self) self.t_mnconf = TabMNConf(self) self.t_rewards = TabRewards(self) ###-- Add tabs self.tabs.addTab(self.tabMain, "Masternode Control") #self.tabs.addTab(self.tabMNConf, "MN Configuration") self.tabs.addTab(self.tabRewards, "Transfer Rewards") ###-- Connect change action self.tabs.currentChanged.connect(lambda: self.onTabChange()) ###-- Draw Tabs self.splitter = QSplitter(Qt.Vertical) ###-- Add tabs and console to Layout self.splitter.addWidget(self.tabs) self.splitter.addWidget(self.console) self.splitter.setStretchFactor(0,0) self.splitter.setStretchFactor(1,1) self.splitter.setSizes(self.parent.cache.get("splitter_sizes")) self.layout.addWidget(self.splitter) ###-- Set Layout self.setLayout(self.layout) ###-- Let's go self.mnode_to_change = None printOK("Hello! Welcome to " + parent.title) ###-- Hide console if it was previously hidden if self.parent.cache.get("console_hidden"): self.onToggleConsole() ##-- Check version self.onCheckVersion() @pyqtSlot(str) def append_to_console(self, text): self.consoleArea.moveCursor(QTextCursor.End) self.consoleArea.insertHtml(text) # update last logs logFile = open(log_File, 'a+') logFile.write(text) logFile.close() def initConsole(self): self.console = QGroupBox() self.console.setTitle("Console Log") layout = QVBoxLayout() self.btn_consoleToggle = QPushButton('Hide') self.btn_consoleToggle.setToolTip('Show/Hide console') self.btn_consoleToggle.clicked.connect(lambda: self.onToggleConsole()) consoleHeader = QHBoxLayout() consoleHeader.addWidget(self.btn_consoleToggle) self.consoleSaveButton = QPushButton('Save') self.consoleSaveButton.clicked.connect(lambda: self.onSaveConsole()) consoleHeader.addWidget(self.consoleSaveButton) self.btn_consoleClean = QPushButton('Clean') self.btn_consoleClean.setToolTip('Clean console log area') self.btn_consoleClean.clicked.connect(lambda: self.onCleanConsole()) consoleHeader.addWidget(self.btn_consoleClean) consoleHeader.addStretch(1) self.versionLabel = QLabel("--") self.versionLabel.setOpenExternalLinks(True) consoleHeader.addWidget(self.versionLabel) self.btn_checkVersion = QPushButton("Check SPMT version") self.btn_checkVersion.setToolTip("Check latest stable release of SPMT") self.btn_checkVersion.clicked.connect(lambda: self.onCheckVersion()) consoleHeader.addWidget(self.btn_checkVersion) layout.addLayout(consoleHeader) self.consoleArea = QTextEdit() almostBlack = QColor(40, 40, 40) palette = QPalette() palette.setColor(QPalette.Base, almostBlack) green = QColor(0, 255, 0) palette.setColor(QPalette.Text, green) self.consoleArea.setPalette(palette) layout.addWidget(self.consoleArea) self.console.setLayout(layout) def loadIcons(self): # Load Icons self.ledPurpleH_icon = QPixmap(os.path.join(self.imgDir, 'icon_purpleLedH.png')).scaledToHeight(17, Qt.SmoothTransformation) self.ledGrayH_icon = QPixmap(os.path.join(self.imgDir, 'icon_grayLedH.png')).scaledToHeight(17, Qt.SmoothTransformation) self.ledHalfPurpleH_icon = QPixmap(os.path.join(self.imgDir, 'icon_halfPurpleLedH.png')).scaledToHeight(17, Qt.SmoothTransformation) self.ledRedV_icon = QPixmap(os.path.join(self.imgDir, 'icon_redLedV.png')).scaledToHeight(17, Qt.SmoothTransformation) self.ledGrayV_icon = QPixmap(os.path.join(self.imgDir, 'icon_grayLedV.png')).scaledToHeight(17, Qt.SmoothTransformation) self.ledGreenV_icon = QPixmap(os.path.join(self.imgDir, 'icon_greenLedV.png')).scaledToHeight(17, Qt.SmoothTransformation) def myPopUp(self, messType, messTitle, messText, defaultButton=QMessageBox.No): mess = QMessageBox(messType, messTitle, messText, defaultButton, parent=self) mess.setStandardButtons(QMessageBox.Yes | QMessageBox.No) mess.setDefaultButton(defaultButton) return mess.exec_() def myPopUp2(self, messType, messTitle, messText, singleButton=QMessageBox.Ok): mess = QMessageBox(messType, messTitle, messText, singleButton, parent=self) mess.setStandardButtons(singleButton | singleButton) return mess.exec_() @pyqtSlot() def onCheckHw(self): printDbg("Checking for HW device...") self.updateHWstatus(None) self.showHWstatus() @pyqtSlot() def onCheckRpc(self): printDbg("Checking RPC server...") self.runInThread(self.updateRPCstatus, (), self.showRPCstatus) @pyqtSlot() def onCheckVersion(self): printDbg("Checking SPMT version...") self.versionLabel.setText("--") self.runInThread(self.checkVersion, (), self.updateVersion) def checkVersion(self, ctrl): local_version = self.parent.version['number'].split('.') remote_version = getRemoteSPMTversion().split('.') if (remote_version[0] > local_version[0]) or \ (remote_version[0] == local_version[0] and remote_version[1] > local_version[1]) or \ (remote_version[0] == local_version[0] and remote_version[1] == local_version[1] and remote_version[2] > local_version[2]): self.versionMess = '<b style="color:red">New Version Available:</b> %s.%s.%s ' % (remote_version[0], remote_version[1], remote_version[2]) self.versionMess += '(<a href="https://github.com/PIVX-Project/PIVX-SPMT/releases/">download</a>)' else: self.versionMess = "You have the latest version of SPMT" def updateVersion(self): if self.versionMess is not None: self.versionLabel.setText(self.versionMess) @pyqtSlot() def onCleanConsole(self): self.consoleArea.clear() @pyqtSlot() def onSaveConsole(self): timestamp = strftime('%Y-%m-%d_%H-%M-%S', gmtime(now())) options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog fileName, _ = QFileDialog.getSaveFileName(self,"Save Logs to file","SPMT_Logs_%s.txt" % timestamp,"All Files (*);; Text Files (*.txt)", options=options) try: if fileName: printOK("Saving logs to %s" % fileName) log_file = open(fileName, 'w+') log_text = self.consoleArea.toPlainText() log_file.write(log_text) log_file.close() except Exception as e: err_msg = "error writing Log file" printException(getCallerName(), getFunctionName(), err_msg, e.args) @pyqtSlot() def onTabChange(self): # reload (and re-sort)masternode list in tabs if self.tabs.currentWidget() == self.tabRewards: # reload last used address self.tabRewards.destinationLine.setText(self.parent.cache.get("lastAddress")) # get new order mnOrder = {} mnList = self.tabMain.myList for i in range(mnList.count()): mnName = mnList.itemWidget(mnList.item(i)).alias mnOrder[mnName] = i self.parent.cache['mnList_order'] = mnOrder # Sort masternode list (by alias if no previous order set) if self.parent.cache.get('mnList_order') != {}: self.masternode_list.sort(key=self.parent.extract_order) self.t_rewards.loadMnSelect() self.t_rewards.selectedRewards = None @pyqtSlot() def onToggleConsole(self): if self.btn_consoleToggle.text() == 'Hide': self.btn_consoleToggle.setText('Show') self.consoleArea.hide() self.console.setMinimumHeight(70) self.console.setMaximumHeight(70) else: self.console.setMinimumHeight(70) self.console.setMaximumHeight(starting_height) self.btn_consoleToggle.setText('Hide') self.consoleArea.show() def showHWstatus(self): self.updateHWleds() self.myPopUp2(QMessageBox.Information, 'SPMT - hw check', "%s" % self.hwStatusMess, QMessageBox.Ok) def showRPCstatus(self): self.updateRPCled() self.myPopUp2(QMessageBox.Information, 'SPMT - rpc check', "%s" % self.rpcStatusMess, QMessageBox.Ok) def updateHWleds(self): if self.hwStatus == 1: self.header.hwLed.setPixmap(self.ledHalfPurpleH_icon) elif self.hwStatus == 2: self.header.hwLed.setPixmap(self.ledPurpleH_icon) else: self.header.hwLed.setPixmap(self.ledGrayH_icon) self.header.hwLed.setToolTip(self.hwStatusMess) def updateHWstatus(self, ctrl): if self.hwdevice is None: self.hwdevice = HWdevice() device = self.hwdevice statusCode = device.getStatusCode() statusMess = device.getStatusMess(statusCode) printDbg("code: %s - mess: %s" % (statusCode, statusMess)) if statusCode != 2: try: if getattr(self.hwdevice, 'dongle', None) is not None: self.hwdevice.dongle.close() self.hwdevice.initDevice() device = self.hwdevice statusCode = device.getStatusCode() statusMess = device.getStatusMess(statusCode) except Exception as e: err_msg = "error in checkHw" printException(getCallerName(), getFunctionName(), err_msg, e.args) self.hwStatus = statusCode self.hwStatusMess = statusMess def updateLastBlockLabel(self): text = '--' if self.rpcLastBlock == 1: text = "Loading block index..." elif self.rpcLastBlock > 0 and self.rpcConnected: text = str(self.rpcLastBlock) text += " (" if not self.isBlockchainSynced: text += "Synchronizing" else: text += "Synced" text += ")" self.header.lastBlockLabel.setText(text) def updateRPCled(self): if self.rpcConnected: self.header.rpcLed.setPixmap(self.ledPurpleH_icon) else: if self.rpcLastBlock == 1: self.header.rpcLed.setPixmap(self.ledHalfPurpleH_icon) else: self.header.rpcLed.setPixmap(self.ledGrayH_icon) self.header.rpcLed.setToolTip(self.rpcStatusMess) self.updateLastBlockLabel() def updateRPCstatus(self, ctrl): if self.rpcClient is None: try: self.rpcClient = RpcClient() except Exception as e: print(e) status, lastBlock = self.rpcClient.getStatus() statusMess = self.rpcClient.getStatusMess(status) if not status and lastBlock==0: try: self.rpcClient = RpcClient() status, lastBlock = self.rpcClient.getStatus() statusMess = self.rpcClient.getStatusMess(status) except Exception as e: err_msg = "error in checkRpc" printException(getCallerName(), getFunctionName(), err_msg, e) elif lastBlock == 1: statusMess = "PIVX wallet is connected but still synchronizing / verifying blocks" self.rpcConnected = status self.rpcLastBlock = lastBlock self.rpcStatusMess = statusMess self.isBlockchainSynced = self.rpcClient.isBlockchainSynced()
class TestHwDeviceMethods(unittest.TestCase): def setUp(self): self.device = HWdevice() self.rpcClient = RpcClient() hwStatus = self.device.getStatusCode() rpcStatus, _ = self.rpcClient.getStatus() if hwStatus != 2: self.skipTest("Ledger not connected or pivx app closed") if not rpcStatus: self.skipTest("RPC not connected") def tearDown(self): if hasattr(self.device, 'dongle'): self.device.dongle.close() self.device.parent = None print("Dongle Closed") if hasattr(self.rpcClient, 'conn'): self.rpcClient.parent = None def test_transaction(self): # Read input data from file import simplejson as json with open('test_transaction.data.json', encoding="utf-8") as data_file: input_data = json.load(data_file) data_file.close() # Rename input data path = input_data['path'] pivx_address_to = input_data['address_from'] fee = input_data['fee'] utxos = input_data['unspent_outputs'] rawtransactions = input_data['raw_transactions'] print("=================================") print(" Press 'OK' on Ledger device ") print("---------------------------------") txraw, amount = self.signTx(self.device, path, utxos, pivx_address_to, fee, rawtransactions) # Check total amount total = sum([int(utxo['value']) for utxo in utxos], 0) amount = round(float(amount) * 1e8) self.assertEqual(total - fee, amount) # Decode Raw Tx to inspect and check inputs inputs = [utxo["tx_hash"] for utxo in utxos] decodedTx = self.rpcClient.decodeRawTx(txraw.hex()) decoded_inputs = [ decoded_input["txid"] for decoded_input in decodedTx["vin"] ] while len(inputs) > 0: input_tx = inputs.pop() self.assertIn(input_tx, decoded_inputs) decoded_inputs.remove(input_tx) def test_scanForBip32(self): # Get accounts obtained from seed outside ledger # (5 accounts. 5 addresses per account) with open('accounts.data.txt', encoding="utf-8") as datafile: # datafile has 4 lines of header (lines_offset) for _ in range(4): datafile.readline() for account_n in range(5): for address_n in range(5): address = datafile.readline().split()[0] result, _ = self.device.scanForBip32( account_n, address, starting_spath=address_n, spath_count=1) # Address found in account_n with index. self.assertTrue(result) def test_scanForPubKey(self): # Get accounts obtained from seed outside ledger # (5 accounts. 5 addresses per account) with open('accounts.data.txt', encoding="utf-8") as datafile: # datafile has 4 lines of header (lines_offset) for _ in range(4): datafile.readline() for account_n in range(5): for address_n in range(5): pubkey = datafile.readline().split()[1] result = self.device.scanForPubKey(account_n, address_n) # Pubkey checks out self.assertEqual(result, pubkey) def test_signature(self): # Get message and path from datafile import simplejson as json with open('test_signature.data.json', encoding="utf-8") as data_file: input_data = json.load(data_file) # Rename input data message = input_data['message'] path = input_data['path'] pivx_address = self.device.chip.getWalletPublicKey(path).get( 'address')[12:-2] # sign message on ledger print("=================================") print(" Press 'OK' on Ledger device ") print("---------------------------------") signature = self.signMess(path, message) # verify with rpc client result = self.rpcClient.verifyMessage(pivx_address, signature, message) print("sig = %s\naddress=%s" % (signature, pivx_address)) self.assertTrue(result) # ----------------------------------------------------------------------------------- # from: # -- hwdevice.signMess # -- hwdevice.signMessSign # -- hwdevice.signMessFinish # without gui def signMess(self, path, message): from utils import b64encode # Ledger doesn't accept characters other that ascii printable: # https://ledgerhq.github.io/btchip-doc/bitcoin-technical.html#_sign_message message = message.encode('ascii', 'ignore') self.device.chip.signMessagePrepare(path, message) signature = self.device.chip.signMessageSign(None) if signature is not None: if len(signature) > 4: rLength = signature[3] r = signature[4:4 + rLength] if len(signature) > 4 + rLength + 1: sLength = signature[4 + rLength + 1] if len(signature) > 4 + rLength + 2: s = signature[4 + rLength + 2:] if rLength == 33: r = r[1:] if sLength == 33: s = s[1:] work = bytes(chr(27 + 4 + (signature[0] & 0x01)), "utf-8") + r + s print("Message signed") sig1 = work.hex() else: print( 'client.signMessageSign() returned invalid response (code 3): ' + signature.hex()) sig1 = "None" else: print( 'client.signMessageSign() returned invalid response (code 2): ' + signature.hex()) sig1 = "None" else: print( 'client.signMessageSign() returned invalid response (code 1): ' + signature.hex()) sig1 = "None" else: print("Signature refused by the user") sig1 = "None" return b64encode(sig1) # from: # -- hwdevice.prepare_transfer_tx # -- hwdevice.signTxSign # -- hwdevice.signTxFinish # without gui def signTx(self, device, bip32_path, utxos_to_spend, dest_address, tx_fee, rawtransactions): # For each UTXO create a Ledger 'trusted input' self.trusted_inputs = [] # https://klmoney.wordpress.com/bitcoin-dissecting-transactions-part-2-building-a-transaction-by-hand) self.arg_inputs = [] self.amount = 0 for idx, utxo in enumerate(utxos_to_spend): self.amount += int(utxo['value']) raw_tx = bytearray.fromhex(rawtransactions[utxo['tx_hash']]) if not raw_tx: raise Exception("Can't find raw transaction for txid: " + rawtransactions[utxo['tx_hash']]) # parse the raw transaction, so that we can extract the UTXO locking script we refer to prev_transaction = bitcoinTransaction(raw_tx) utxo_tx_index = utxo['tx_ouput_n'] if utxo_tx_index < 0 or utxo_tx_index > len( prev_transaction.outputs): raise Exception('Incorrect value of outputIndex for UTXO %s' % str(idx)) trusted_input = self.device.chip.getTrustedInput( prev_transaction, utxo_tx_index) self.trusted_inputs.append(trusted_input) # Hash check curr_pubkey = compress_public_key( device.chip.getWalletPublicKey(bip32_path)['publicKey']) pubkey_hash = bin_hash160(curr_pubkey) pubkey_hash_from_script = extract_pkh_from_locking_script( prev_transaction.outputs[utxo_tx_index].script) if pubkey_hash != pubkey_hash_from_script: text = "Error: different public key hashes for the BIP32 path and the UTXO" text += "locking script. Your signed transaction will not be validated by the network.\n" text += "pubkey_hash: %s\n" % str(pubkey_hash) text += "pubkey_hash_from_script: %s\n" % str( pubkey_hash_from_script) print(text) self.arg_inputs.append({ 'locking_script': prev_transaction.outputs[utxo['tx_ouput_n']].script, 'pubkey': curr_pubkey, 'bip32_path': bip32_path, 'outputIndex': utxo['tx_ouput_n'], 'txid': utxo['tx_hash'] }) self.amount -= int(tx_fee) self.amount = int(self.amount) arg_outputs = [{ 'address': dest_address, 'valueSat': self.amount }] # there will be multiple outputs soon self.new_transaction = bitcoinTransaction( ) # new transaction object to be used for serialization at the last stage self.new_transaction.version = bytearray([0x01, 0x00, 0x00, 0x00]) try: for o in arg_outputs: output = bitcoinOutput() output.script = compose_tx_locking_script(o['address']) output.amount = int.to_bytes(o['valueSat'], 8, byteorder='little') self.new_transaction.outputs.append(output) except Exception: raise # join all outputs - will be used by Ledger for signing transaction self.all_outputs_raw = self.new_transaction.serializeOutputs() starting = True # sign all inputs on Ledger and add inputs in the self.new_transaction object for serialization for idx, new_input in enumerate(self.arg_inputs): device.chip.startUntrustedTransaction(starting, idx, self.trusted_inputs, new_input['locking_script']) device.chip.finalizeInputFull(self.all_outputs_raw) sig = device.chip.untrustedHashSign(new_input['bip32_path'], lockTime=0) new_input['signature'] = sig inputTx = bitcoinInput() inputTx.prevOut = bytearray.fromhex( new_input['txid'])[::-1] + int.to_bytes( new_input['outputIndex'], 4, byteorder='little') inputTx.script = bytearray([len(sig)]) + sig + bytearray( [0x21]) + new_input['pubkey'] inputTx.sequence = bytearray([0xFF, 0xFF, 0xFF, 0xFF]) self.new_transaction.inputs.append(inputTx) starting = False self.new_transaction.lockTime = bytearray([0, 0, 0, 0]) self.tx_raw = bytearray(self.new_transaction.serialize()) if self.tx_raw is not None: return (self.tx_raw, str(round(self.amount / 1e8, 8))) else: # transaction refused by user return (None, "") if __name__ == '__main__': unittest.main(verbosity=2)
class MainWindow(QWidget): def __init__(self, parent, masternode_list, imgDir): super(QWidget, self).__init__(parent) self.parent = parent self.imgDir = imgDir self.runInThread = ThreadFuns.runInThread ###-- Masternode list self.masternode_list = masternode_list ###-- Create clients and statuses self.hwdevice = None self.hwStatus = 0 self.hwStatusMess = "Not Connected" self.rpcClient = None self.rpcConnected = False self.rpcStatusMess = "Not Connected" self.isBlockchainSynced = False ###-- Load icons & images self.loadIcons() ###-- Create main layout self.layout = QVBoxLayout() self.header = GuiHeader(self) self.initConsole() self.layout.addWidget(self.header) ###-- Create RPC Whatchdog self.rpc_watchdogThread = QThread() self.myRpcWd = RpcWatchdog(self) self.myRpcWd.moveToThread(self.rpc_watchdogThread) self.rpc_watchdogThread.started.connect(self.myRpcWd.run) ###-- Create Queues and redirect stdout and stderr self.queue = Queue() self.queue2 = Queue() sys.stdout = WriteStream(self.queue) sys.stderr = WriteStream(self.queue2) ###-- Init last logs logFile = open(log_File, 'w+') timestamp = strftime('%Y-%m-%d %H:%M:%S', gmtime(now())) log_line = '<b style="color: blue">{}</b><br>'.format('STARTING QMT at ' + timestamp) logFile.write(log_line) logFile.close() ###-- Create the thread to update console log for stdout self.consoleLogThread = QThread() self.myWSReceiver = WriteStreamReceiver(self.queue) self.myWSReceiver.mysignal.connect(self.append_to_console) self.myWSReceiver.moveToThread(self.consoleLogThread) self.consoleLogThread.started.connect(self.myWSReceiver.run) self.consoleLogThread.start() printDbg("Console Log thread started") ###-- Create the thread to update console log for stderr self.consoleLogThread2 = QThread() self.myWSReceiver2 = WriteStreamReceiver(self.queue2) self.myWSReceiver2.mysignal.connect(self.append_to_console) self.myWSReceiver2.moveToThread(self.consoleLogThread2) self.consoleLogThread2.started.connect(self.myWSReceiver2.run) self.consoleLogThread2.start() printDbg("Console Log thread 2 started") ###-- Initialize tabs self.tabs = QTabWidget() self.t_main = TabMain(self) self.t_mnconf = TabMNConf(self) self.t_rewards = TabRewards(self) self.t_governance = TabGovernance(self) self.t_add_torrent = TabAddTorrent(self) ###-- Add tabs self.tabs.addTab(self.tabGovernance, "Search Torrents") self.tabs.addTab(self.tabAddTorrent, "Add Torrents") # self.tabs.addTab(self.tabMain, "Masternode Control") # self.tabs.addTab(self.tabMNConf, "MN Configuration") # We will put these back later, just with RPC instead of messy key handling which we don't need or want anyway ! # self.tabs.addTab(self.tabRewards, "Transfer Rewards") ###-- Connect change action self.tabs.currentChanged.connect(lambda: self.onTabChange()) ###-- Draw Tabs self.splitter = QSplitter(Qt.Vertical) ###-- Add tabs and console to Layout self.splitter.addWidget(self.tabs) self.splitter.addWidget(self.console) self.splitter.setStretchFactor(0, 0) self.splitter.setStretchFactor(1, 1) self.splitter.setSizes(self.parent.cache.get("splitter_sizes")) self.layout.addWidget(self.splitter) ###-- Set Layout self.setLayout(self.layout) ###-- Let's go self.mnode_to_change = None printOK("Hello! Welcome to " + parent.title) ###-- Hide console if it was previously hidden if self.parent.cache.get("console_hidden"): self.onToggleConsole() ##-- Check version self.onCheckVersion() ##-- init Api Client self.apiClient = ApiClient() @pyqtSlot(str) def append_to_console(self, text): self.consoleArea.moveCursor(QTextCursor.End) self.consoleArea.insertHtml(text) def initConsole(self): self.console = QGroupBox() self.console.setTitle("Console Log") layout = QVBoxLayout() self.btn_consoleToggle = QPushButton('Hide') self.btn_consoleToggle.setToolTip('Show/Hide console') self.btn_consoleToggle.clicked.connect(lambda: self.onToggleConsole()) consoleHeader = QHBoxLayout() consoleHeader.addWidget(self.btn_consoleToggle) self.consoleSaveButton = QPushButton('Save') self.consoleSaveButton.clicked.connect(lambda: self.onSaveConsole()) consoleHeader.addWidget(self.consoleSaveButton) self.btn_consoleClean = QPushButton('Clean') self.btn_consoleClean.setToolTip('Clean console log area') self.btn_consoleClean.clicked.connect(lambda: self.onCleanConsole()) consoleHeader.addWidget(self.btn_consoleClean) consoleHeader.addStretch(1) self.versionLabel = QLabel("--") self.versionLabel.setOpenExternalLinks(True) consoleHeader.addWidget(self.versionLabel) self.btn_checkVersion = QPushButton("Check QMT version") self.btn_checkVersion.setToolTip("Check latest stable release of QMT") self.btn_checkVersion.clicked.connect(lambda: self.onCheckVersion()) consoleHeader.addWidget(self.btn_checkVersion) layout.addLayout(consoleHeader) self.consoleArea = QTextEdit() almostBlack = QColor(40, 40, 40) palette = QPalette() palette.setColor(QPalette.Base, almostBlack) green = QColor(0, 255, 0) palette.setColor(QPalette.Text, green) self.consoleArea.setPalette(palette) layout.addWidget(self.consoleArea) self.console.setLayout(layout) def isMasternodeInList(self, mn_alias): return (mn_alias in [x['name'] for x in self.masternode_list]) def loadIcons(self): # Load Icons self.ledPurpleH_icon = QPixmap(os.path.join(self.imgDir, 'icon_purpleLedH.png')).scaledToHeight(17, Qt.SmoothTransformation) self.ledGrayH_icon = QPixmap(os.path.join(self.imgDir, 'icon_grayLedH.png')).scaledToHeight(17, Qt.SmoothTransformation) self.ledHalfPurpleH_icon = QPixmap(os.path.join(self.imgDir, 'icon_halfPurpleLedH.png')).scaledToHeight(17, Qt.SmoothTransformation) self.ledRedV_icon = QPixmap(os.path.join(self.imgDir, 'icon_redLedV.png')).scaledToHeight(17, Qt.SmoothTransformation) self.ledGrayV_icon = QPixmap(os.path.join(self.imgDir, 'icon_grayLedV.png')).scaledToHeight(17, Qt.SmoothTransformation) self.ledGreenV_icon = QPixmap(os.path.join(self.imgDir, 'icon_greenLedV.png')).scaledToHeight(17, Qt.SmoothTransformation) def loadMNConf(self, fileName): hot_masternodes = loadMNConfFile(fileName) if hot_masternodes == None: messText = "Unable to load data from file '%s'" % fileName self.myPopUp2(QMessageBox.Warning, "QMT - warning", messText) else: # Append new masternodes to list new_masternodes = [] skip_masternodes = [] for x in hot_masternodes: if not self.isMasternodeInList(x['name']): self.masternode_list.append(x) new_masternodes.append(x) else: skip_masternodes.append(x) # Show new list for new_masternode in new_masternodes: name = new_masternode['name'] self.tabMain.insert_mn_list(name, new_masternode['ip'], new_masternode['port'], None, isHardware=False) self.tabMain.btn_remove[name].clicked.connect(lambda: self.t_main.onRemoveMN()) # print number of nodes added new_nodes = len(new_masternodes) final_message = "" if new_nodes == 0: final_message = "No External Masternode " elif new_nodes == 1: final_message = "1 External Masternode " else: final_message = "%d External Masternodes " % new_nodes final_message += "added to the list. " if new_nodes > 0: final_message += str([x['name'] for x in new_masternodes]) + ". " if len(skip_masternodes) > 0: final_message += "Following entries skipped due to duplicate names:" final_message += str([x['name'] for x in skip_masternodes]) + ". " printDbg(final_message) if new_nodes > 0: # update files printDbg("saving MN configuration file") writeToFile(self.masternode_list, masternodes_File) printDbg("saved") # Clear voting masternodes configuration and update cache self.t_governance.clear() def myPopUp(self, messType, messTitle, messText, defaultButton=QMessageBox.No): mess = QMessageBox(messType, messTitle, messText, defaultButton, parent=self) mess.setStandardButtons(QMessageBox.Yes | QMessageBox.No) mess.setDefaultButton(defaultButton) return mess.exec_() def myPopUp2(self, messType, messTitle, messText, singleButton=QMessageBox.Ok): mess = QMessageBox(messType, messTitle, messText, singleButton, parent=self) mess.setStandardButtons(singleButton | singleButton) return mess.exec_() @pyqtSlot() def onCheckHw(self): printDbg("Checking for HW device...") self.updateHWstatus(None) self.showHWstatus() @pyqtSlot() def onCheckRpc(self): printDbg("Checking RPC server...") self.runInThread(self.updateRPCstatus, (), self.showRPCstatus) @pyqtSlot() def onCheckVersion(self): printDbg("Checking QMT version...") self.versionLabel.setText("--") self.runInThread(self.checkVersion, (), self.updateVersion) def checkVersion(self, ctrl): local_version = self.parent.version['number'].split('.') remote_version = getRemoteQMTversion().split('.') if (remote_version[0] > local_version[0]) or \ (remote_version[0] == local_version[0] and remote_version[1] > local_version[1]) or \ (remote_version[0] == local_version[0] and remote_version[1] == local_version[1] and remote_version[2] > local_version[2]): self.versionMess = '<b style="color:red">New Version Available:</b> %s.%s.%s ' % ( remote_version[0], remote_version[1], remote_version[2]) self.versionMess += '(<a href="https://github.com/project-qmc/QMT/releases/">download</a>)' else: self.versionMess = "You have the latest version of QMT" def updateVersion(self): if self.versionMess is not None: self.versionLabel.setText(self.versionMess) @pyqtSlot() def onCleanConsole(self): self.consoleArea.clear() @pyqtSlot() def onSaveConsole(self): timestamp = strftime('%Y-%m-%d_%H-%M-%S', gmtime(now())) options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog fileName, _ = QFileDialog.getSaveFileName(self, "Save Logs to file", "QMT_Logs_%s.txt" % timestamp, "All Files (*);; Text Files (*.txt)", options=options) try: if fileName: printOK("Saving logs to %s" % fileName) log_file = open(fileName, 'w+') log_text = self.consoleArea.toPlainText() log_file.write(log_text) log_file.close() except Exception as e: err_msg = "error writing Log file" printException(getCallerName(), getFunctionName(), err_msg, e.args) @pyqtSlot() def onTabChange(self): # reload (and re-sort)masternode list in tabs if self.tabs.currentWidget() == self.tabRewards: # reload last used address self.tabRewards.destinationLine.setText(self.parent.cache.get("lastAddress")) # get new order mnOrder = {} mnList = self.tabMain.myList for i in range(mnList.count()): mnName = mnList.itemWidget(mnList.item(i)).alias mnOrder[mnName] = i self.parent.cache['mnList_order'] = mnOrder # Sort masternode list (by alias if no previous order set) if self.parent.cache.get('mnList_order') != {}: self.masternode_list.sort(key=self.parent.extract_order) self.t_rewards.loadMnSelect() self.t_rewards.selectedRewards = None # reload torrent and voting masternode list if self.tabs.currentWidget() == self.tabGovernance: self.t_governance.onRefreshTorrents() self.t_governance.updateSelectedMNlabel() @pyqtSlot() def onToggleConsole(self): if self.btn_consoleToggle.text() == 'Hide': self.btn_consoleToggle.setText('Show') self.consoleArea.hide() self.console.setMinimumHeight(70) self.console.setMaximumHeight(70) else: self.console.setMinimumHeight(70) self.console.setMaximumHeight(starting_height) self.btn_consoleToggle.setText('Hide') self.consoleArea.show() def showHWstatus(self): self.updateHWleds() self.myPopUp2(QMessageBox.Information, 'QMT - hw check', "%s" % self.hwStatusMess, QMessageBox.Ok) def showRPCstatus(self): self.updateRPCled() self.myPopUp2(QMessageBox.Information, 'QMT - rpc check', "%s" % self.rpcStatusMess, QMessageBox.Ok) def updateHWleds(self): if self.hwStatus == 1: self.header.hwLed.setPixmap(self.ledHalfPurpleH_icon) elif self.hwStatus == 2: self.header.hwLed.setPixmap(self.ledPurpleH_icon) else: self.header.hwLed.setPixmap(self.ledGrayH_icon) self.header.hwLed.setToolTip(self.hwStatusMess) def updateHWstatus(self, ctrl): if self.hwdevice is not None: if hasattr(self.hwdevice, 'dongle'): self.hwdevice.dongle.close() self.hwdevice = HWdevice() statusCode, statusMess = self.hwdevice.getStatus() printDbg("mess: %s" % statusMess) if statusCode != 2: # If is not connected try again try: if hasattr(self.hwdevice, 'dongle'): self.hwdevice.dongle.close() self.hwdevice = HWdevice() self.hwdevice.initDevice() statusCode, statusMess = self.hwdevice.getStatus() except Exception as e: err_msg = "error in checkHw" printException(getCallerName(), getFunctionName(), err_msg, e.args) self.hwStatus = statusCode self.hwStatusMess = statusMess # if all is good connect the signals if statusCode == 2: self.hwdevice.sigTxdone.connect(self.t_rewards.FinishSend) self.hwdevice.sigTxabort.connect(self.t_rewards.onCancel) self.hwdevice.tx_progress.connect(self.t_rewards.updateProgressPercent) def updateLastBlockLabel(self): text = '--' if self.rpcLastBlock == 1: text = "Loading block index..." elif self.rpcLastBlock > 0 and self.rpcConnected: text = str(self.rpcLastBlock) text += " (" if not self.isBlockchainSynced: text += "Synchronizing" else: text += "Synced" text += ")" self.header.lastBlockLabel.setText(text) def updateRPCled(self): if self.rpcConnected: self.header.rpcLed.setPixmap(self.ledPurpleH_icon) else: if self.rpcLastBlock == 1: self.header.rpcLed.setPixmap(self.ledHalfPurpleH_icon) else: self.header.rpcLed.setPixmap(self.ledGrayH_icon) self.header.rpcLed.setToolTip(self.rpcStatusMess) self.updateLastBlockLabel() def updateRPCstatus(self, ctrl): if self.rpcClient is None: self.rpcClient = RpcClient() status, statusMess, lastBlock = self.rpcClient.getStatus() self.rpcConnected = status self.rpcLastBlock = lastBlock self.rpcStatusMess = statusMess self.isBlockchainSynced = self.rpcClient.isBlockchainSynced() # If is not connected try again if not status: self.rpcClient = RpcClient()