示例#1
0
    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)
示例#2
0
    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)
示例#3
0
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
示例#4
0
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)
示例#5
0
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()
示例#6
0
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)
示例#7
0
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()