class TabRewards(): def __init__(self, caller): self.caller = caller self.apiClient = ApiClient() ##--- Initialize Selection self.rewards = None self.selectedRewards = None self.rawtransactions = {} ##--- Initialize GUI self.ui = TabRewards_gui() self.caller.tabRewards = self.ui self.ui.feeLine.setValue(MINIMUM_FEE) # Connect GUI buttons self.ui.addySelect.currentIndexChanged.connect(lambda: self.onChangeSelected()) self.ui.rewardsList.box.itemClicked.connect(lambda: self.updateSelection()) self.ui.btn_reload.clicked.connect(lambda: self.loadSelection()) self.ui.btn_selectAllRewards.clicked.connect(lambda: self.onSelectAllRewards()) self.ui.btn_deselectAllRewards.clicked.connect(lambda: self.onDeselectAllRewards()) self.ui.btn_sendRewards.clicked.connect(lambda: self.onSendRewards()) self.ui.btn_Cancel.clicked.connect(lambda: self.onCancel()) def display_utxos(self): try: if self.rewards is not None: def item(value): item = QTableWidgetItem(value) item.setTextAlignment(Qt.AlignCenter) item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) return item self.ui.rewardsList.box.setRowCount(len(self.rewards)) for row, utxo in enumerate(self.rewards): txId = utxo.get('tx_hash', None) pivxAmount = round(int(utxo.get('value', 0))/1e8, 8) self.ui.rewardsList.box.setItem(row, 0, item(str(pivxAmount))) self.ui.rewardsList.box.setItem(row, 1, item(str(utxo.get('confirmations', None)))) self.ui.rewardsList.box.setItem(row, 2, item(txId)) self.ui.rewardsList.box.setItem(row, 3, item(str(utxo.get('tx_ouput_n', None)))) self.ui.rewardsList.box.showRow(row) if len(self.rewards) > 0: self.ui.rewardsList.box.resizeColumnsToContents() self.ui.rewardsList.statusLabel.setVisible(False) self.ui.rewardsList.box.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch) else: if not self.caller.rpcConnected: self.ui.rewardsList.statusLabel.setText('<b style="color:purple">PIVX wallet not connected</b>') else: if self.apiConnected: self.ui.rewardsList.statusLabel.setText('<b style="color:red">Found no UTXOs for %s</b>' % self.curr_addr) else: self.ui.rewardsList.statusLabel.setText('<b style="color:purple">Unable to connect to API provider</b>') self.ui.rewardsList.statusLabel.setVisible(True) except Exception as e: print(e) def getSelection(self): try: returnData = [] items = self.ui.rewardsList.box.selectedItems() # Save row indexes to a set to avoid repetition rows = set() for i in range(0, len(items)): row = items[i].row() rows.add(row) rowList = list(rows) return [self.rewards[row] for row in rowList] return returnData except Exception as e: print(e) @pyqtSlot() def loadSelection(self): # Check dongle printDbg("Checking HW device") if self.caller.hwStatus != 2: self.caller.myPopUp2(QMessageBox.Critical, 'PET4L - hw device check', "Connect to HW device first") printDbg("Unable to connect - hw status: %d" % self.caller.hwStatus) return None self.ui.addySelect.clear() ThreadFuns.runInThread(self.loadSelection_thread, ()) def loadSelection_thread(self, ctrl): hwAcc = self.ui.edt_hwAccount.value() spathFrom = self.ui.edt_spathFrom.value() spathTo = self.ui.edt_spathTo.value() intExt = self.ui.edt_internalExternal.value() for i in range(spathFrom, spathTo+1): path = "44'/77'/%d'/%d/%d" % (hwAcc, intExt, i) address = self.caller.hwdevice.scanForAddress(path) try: balance = self.apiClient.getBalance(address) except Exception as e: print(e) balance = 0 itemLine = "%s -- %s" % (path, address) if(balance): itemLine += " [%s PIV]" % str(balance) self.ui.addySelect.addItem(itemLine, [path, address, balance]) def load_utxos_thread(self, ctrl): self.apiConnected = False try: if not self.caller.rpcConnected: self.rewards = [] printDbg('PIVX daemon not connected') else: try: if self.apiClient.getStatus() != 200: return self.apiConnected = True self.blockCount = self.caller.rpcClient.getBlockCount() self.rewards = self.apiClient.getAddressUtxos(self.curr_addr)['unspent_outputs'] for utxo in self.rewards: self.rawtransactions[utxo['tx_hash']] = self.caller.rpcClient.getRawTransaction(utxo['tx_hash']) except Exception as e: self.errorMsg = 'Error occurred while calling getaddressutxos method: ' + str(e) printDbg(self.errorMsg) except Exception as e: print(e) pass @pyqtSlot() def onCancel(self): self.ui.selectedRewardsLine.setText("0.0") self.ui.addySelect.setCurrentIndex(0) self.ui.destinationLine.setText('') self.ui.feeLine.setValue(MINIMUM_FEE) self.onChangeSelected() @pyqtSlot() def onChangeSelected(self): if self.ui.addySelect.currentIndex() >= 0: self.curr_path = self.ui.addySelect.itemData(self.ui.addySelect.currentIndex())[0] self.curr_addr = self.ui.addySelect.itemData(self.ui.addySelect.currentIndex())[1] self.curr_balance = self.ui.addySelect.itemData(self.ui.addySelect.currentIndex())[2] if self.curr_balance is not None: self.runInThread = ThreadFuns.runInThread(self.load_utxos_thread, (), self.display_utxos) @pyqtSlot() def onSelectAllRewards(self): self.ui.rewardsList.box.selectAll() self.updateSelection() @pyqtSlot() def onDeselectAllRewards(self): self.ui.rewardsList.box.clearSelection() self.updateSelection() @pyqtSlot() def onSendRewards(self): self.dest_addr = self.ui.destinationLine.text().strip() # Check dongle printDbg("Checking HW device") if self.caller.hwStatus != 2: self.caller.myPopUp2(QMessageBox.Critical, 'PET4L - hw device check', "Connect to HW device first") printDbg("Unable to connect - hw status: %d" % self.caller.hwStatus) return None # Check destination Address if not checkPivxAddr(self.dest_addr): self.caller.myPopUp2(QMessageBox.Critical, 'PET4L - PIVX address check', "Invalid Destination Address") return None # LET'S GO printDbg("Sending from PIVX address %s to PIVX address %s " % (self.curr_addr, self.dest_addr)) if self.selectedRewards: self.currFee = self.ui.feeLine.value() * 1e8 # connect signal self.caller.hwdevice.sigTxdone.connect(self.FinishSend) try: self.txFinished = False self.caller.hwdevice.prepare_transfer_tx(self.caller, self.curr_path, self.selectedRewards, self.dest_addr, self.currFee, self.rawtransactions) except Exception as e: err_msg = "Error while preparing transaction" printException(getCallerName(), getFunctionName(), err_msg, e.args) else: self.caller.myPopUp2(QMessageBox.Information, 'transaction NOT Sent', "No UTXO to send") # Activated by signal sigTxdone from hwdevice @pyqtSlot(bytearray, str) def FinishSend(self, serialized_tx, amount_to_send): if not self.txFinished: try: self.txFinished = True tx_hex = serialized_tx.hex() printDbg("Raw signed transaction: " + tx_hex) printDbg("Amount to send :" + amount_to_send) if len(tx_hex) > 90000: mess = "Transaction's length exceeds 90000 bytes. Select less UTXOs and try again." self.caller.myPopUp2(QMessageBox.Warning, 'transaction Warning', mess) else: message = 'Broadcast signed transaction?<br><br>Destination address:<br><b>%s</b><br><br>' % (self.dest_addr) message += 'Amount to send: <b>%s PIV</b><br>' % amount_to_send message += 'Fee: <b>%s PIV</b><br>Size: <b>%d bytes</b>' % (str(round(self.currFee / 1e8, 8) ), len(tx_hex)/2) reply = self.caller.myPopUp(QMessageBox.Information, 'Send transaction', message) if reply == QMessageBox.Yes: txid = self.caller.rpcClient.sendRawTransaction(tx_hex) mess = QMessageBox(QMessageBox.Information, 'transaction Sent', 'transaction Sent') mess.setDetailedText(txid) mess.exec_() else: self.caller.myPopUp2(QMessageBox.Information, 'transaction NOT Sent', "transaction NOT sent") self.onCancel() except Exception as e: err_msg = "Exception in sendRewards" printException(getCallerName(), getFunctionName(), err_msg, e.args) def updateSelection(self, clicked_item=None): total = 0 self.selectedRewards = self.getSelection() numOfInputs = len(self.selectedRewards) if numOfInputs: for i in range(0, numOfInputs): total += int(self.selectedRewards[i].get('value')) # update suggested fee and selected rewards estimatedTxSize = (44+numOfInputs*148)*1.0 / 1000 # kB feePerKb = self.caller.rpcClient.getFeePerKb() suggestedFee = round(feePerKb * estimatedTxSize, 8) printDbg("estimatedTxSize is %s kB" % str(estimatedTxSize)) printDbg("suggested fee is %s PIV (%s PIV/kB)" % (str(suggestedFee), str(feePerKb))) self.ui.selectedRewardsLine.setText(str(round(total/1e8, 8))) self.ui.feeLine.setValue(suggestedFee) else: self.ui.selectedRewardsLine.setText("") self.ui.feeLine.setValue(MINIMUM_FEE)
class TabMain(): def __init__(self, caller): self.caller = caller self.apiClient = ApiClient() self.runInThread = ThreadFuns.runInThread self.curr_masternode_alias = None self.curr_masternode_address = None self.curr_statusData = None self.mnToStartList = [] self.ui = TabMain_gui(caller) self.caller.tabMain = self.ui # Connect GUI buttons self.ui.button_addMasternode.clicked.connect( lambda: self.onNewMasternode()) self.ui.button_startAll.clicked.connect(lambda: self.onStartAllMN()) self.ui.button_getAllStatus.clicked.connect( lambda: self.onCheckAllMN()) for masternode in self.caller.masternode_list: name = masternode['name'] self.ui.btn_remove[name].clicked.connect(lambda: self.onRemoveMN()) self.ui.btn_edit[name].clicked.connect(lambda: self.onEditMN()) self.ui.btn_start[name].clicked.connect(lambda: self.onStartMN()) self.ui.btn_rewards[name].clicked.connect( lambda: self.onRewardsMN()) self.ui.btn_status[name].clicked.connect(lambda: self.onCheckMN()) def checkMN(self, ctrl): address = self.curr_masternode_address # Check rpc connection if not self.caller.rpcConnected: self.caller.myPopUp2(QMessageBox.Critical, 'SPMT - hw device check', "Connect to RPC server first") printDbg("Unable to connect: %s" % self.caller.rpcStatusMess) return None self.curr_statusData = self.caller.rpcClient.getMNStatus(address) try: if self.curr_statusData is not None: balance = self.apiClient.getBalance(address) self.curr_statusData['balance'] = balance except Exception as e: err_msg = "exception in checkMN" printException(getCallerName(), getFunctionName(), err_msg, e) def displayMNStatus(self): statusData = self.curr_statusData masternode_alias = self.curr_masternode_alias self.ui.btn_details[masternode_alias].disconnect() self.ui.btn_details[masternode_alias].clicked.connect( lambda: self.onDisplayStatusDetails(masternode_alias, statusData)) self.ui.btn_details[masternode_alias].show() if statusData is None: self.ui.mnLed[masternode_alias].setPixmap( self.caller.ledGrayV_icon) msg = "<b>ERROR! Masternode not found</b>" self.ui.mnStatusLabel[masternode_alias].setText(msg) self.ui.mnStatusLabel[masternode_alias].show() self.ui.btn_details[masternode_alias].setEnabled(False) else: printDbg( "Got status %s for %s (%s)" % (statusData['status'], masternode_alias, statusData['addr'])) if statusData['status'] == 'ENABLED': self.ui.mnLed[masternode_alias].setPixmap( self.caller.ledGreenV_icon) display_text = '<b>Status: </b><span style="color:green">%s</span>' % statusData[ 'status'] else: self.ui.mnLed[masternode_alias].setPixmap( self.caller.ledRedV_icon) display_text = '<b>Status: </b><span style="color:red">%s</span>' % statusData[ 'status'] if statusData['balance'] is not None: display_text += ' <b>Balance: </b><span style="color:purple">%s PIV</span>' % str( statusData['balance']) self.ui.mnStatusLabel[masternode_alias].setText(display_text) self.ui.mnStatusLabel[masternode_alias].show() self.ui.btn_details[masternode_alias].setEnabled(True) @pyqtSlot() def onCheckAllMN(self): try: printOK("Check-All pressed") for masternode in self.caller.masternode_list: self.curr_masternode_address = masternode['collateral'].get( 'address') self.curr_masternode_alias = masternode['name'] printOK( "Checking %s (%s)..." % (self.curr_masternode_alias, self.curr_masternode_address)) self.checkMN(None) self.displayMNStatus() QApplication.processEvents() except Exception as e: err_msg = "error in checkAllMN" printException(getCallerName(), getFunctionName(), err_msg, e) @pyqtSlot() def onCheckMN(self, data=None): if not data: try: target = self.ui.sender() masternode_alias = target.alias for mn_conf in self.caller.masternode_list: if mn_conf['name'] == masternode_alias: masternodeAddr = mn_conf['collateral'].get('address') self.curr_masternode_alias = masternode_alias self.curr_masternode_address = masternodeAddr self.runInThread(self.checkMN, (), self.displayMNStatus) break except Exception as e: err_msg = "error in onCheckMN" printException(getCallerName(), getFunctionName(), err_msg, e) @pyqtSlot() def onDisplayStatusDetails(self, masternode_alias, statusData): try: ui = MnStatus_dlg(self.ui, masternode_alias, statusData) ui.exec_() except Exception as e: err_msg = "error in displayStatusDetails" printException(getCallerName(), getFunctionName(), err_msg, e.args) @pyqtSlot() def onEditMN(self, data=None): if not data: target = self.ui.sender() masternode_alias = target.alias try: self.caller.tabs.insertTab(1, self.caller.tabMNConf, "Configuration") self.caller.tabs.setCurrentIndex(1) for masternode in self.caller.masternode_list: if masternode['name'] == masternode_alias: self.caller.mnode_to_change = masternode self.caller.tabMNConf.fillConfigForm(masternode) break except Exception as e: print(e) @pyqtSlot() def onNewMasternode(self): self.caller.tabs.insertTab(1, self.caller.tabMNConf, "Configuration") self.caller.tabMNConf.clearConfigForm() self.caller.tabs.setCurrentIndex(1) @pyqtSlot() def onRemoveMN(self, data=None): if not data: target = self.ui.sender() masternode_alias = target.alias reply = self.caller.myPopUp( QMessageBox.Warning, 'Confirm REMOVE', "Are you sure you want to remove\nmasternoode:'%s'" % masternode_alias, QMessageBox.No) if reply == QMessageBox.No: return for masternode in self.caller.masternode_list: if masternode['name'] == masternode_alias: self.caller.masternode_list.remove(masternode) break try: writeMNfile(self.caller.masternode_list) self.ui.myList.takeItem( self.ui.myList.row(self.ui.current_mn[masternode_alias])) except Exception as e: err_msg = "Error writing masternode file" printException(getCallerName(), getFunctionName(), err_msg, e) @pyqtSlot() def onRewardsMN(self, data=None): if not data: target = self.ui.sender() masternode_alias = target.alias tab_index = self.caller.tabs.indexOf(self.caller.tabRewards) self.caller.tabs.setCurrentIndex(tab_index) self.caller.tabRewards.mnSelect.setCurrentText(masternode_alias) @pyqtSlot() def onStartAllMN(self): printOK("Start-All pressed") # Check RPC & dongle if not self.caller.rpcConnected or self.caller.hwStatus != 2: self.caller.myPopUp2(QMessageBox.Critical, 'SPMT - hw/rpc device check', "Connect to RPC server and HW device first") printDbg("Hardware device or RPC server not connected") return None try: reply = self.caller.myPopUp( QMessageBox.Question, 'Confirm START', "Are you sure you want to start ALL masternodes?", QMessageBox.Yes) if reply == QMessageBox.Yes: for mn_conf in self.caller.masternode_list: self.masternodeToStart = Masternode( self, mn_conf['name'], mn_conf['ip'], mn_conf['port'], mn_conf['mnPrivKey'], mn_conf['hwAcc'], mn_conf['collateral']) # connect signal self.masternodeToStart.sigdone.connect(self.sendBroadcast) self.mnToStartList.append(self.masternodeToStart) self.startMN() except Exception as e: err_msg = "error before starting node" printException(getCallerName(), getFunctionName(), err_msg, e) @pyqtSlot() def onStartMN(self, data=None): # Check RPC & dongle if not self.caller.rpcConnected or self.caller.hwStatus != 2: self.caller.myPopUp2(QMessageBox.Critical, 'SPMT - hw/rpc device check', "Connect to RPC server and HW device first") printDbg("Hardware device or RPC server not connected") return None try: if not data: target = self.ui.sender() masternode_alias = target.alias printOK("Start-masternode %s pressed" % masternode_alias) for mn_conf in self.caller.masternode_list: if mn_conf['name'] == masternode_alias: reply = self.caller.myPopUp( QMessageBox.Question, 'Confirm START', "Are you sure you want to start masternoode:\n'%s'?" % mn_conf['name'], QMessageBox.Yes) if reply == QMessageBox.Yes: self.masternodeToStart = Masternode( self, mn_conf['name'], mn_conf['ip'], mn_conf['port'], mn_conf['mnPrivKey'], mn_conf['hwAcc'], mn_conf['collateral']) # connect signal self.masternodeToStart.sigdone.connect( self.sendBroadcast) self.mnToStartList.append(self.masternodeToStart) self.startMN() break except Exception as e: err_msg = "error before starting node" printException(getCallerName(), getFunctionName(), err_msg, e) # Activated by signal 'sigdone' from masternode def sendBroadcast(self, text): if text == "None": self.sendBroadcastCheck() return printOK("Start Message: %s" % text) ret = self.caller.rpcClient.decodemasternodebroadcast(text) if ret is None: self.caller.myPopUp2(QMessageBox.Critical, 'message decoding failed', 'message decoding failed') self.sendBroadcastCheck() return msg = "Broadcast START message?\n" + json.dumps( ret, indent=4, sort_keys=True) reply = self.caller.myPopUp(QMessageBox.Question, 'message decoded', msg, QMessageBox.Yes) if reply == QMessageBox.No: self.sendBroadcastCheck() return ret2 = self.caller.rpcClient.relaymasternodebroadcast(text) if json.dumps(ret2)[1:26] == "Masternode broadcast sent": message = "Start-message was successfully sent to the network.<br>" message += "If your remote server is correctly configured and connected to the network, " message += "the output of the <b>./pivx-cli masternode status</b> command on the VPS should show:<br>" message += "<br><em>\"message\": \"Masternode successfully started\"</em>" self.caller.myPopUp2(QMessageBox.Information, 'message relayed', message, QMessageBox.Ok) else: print(json.dumps(ret2)[1:26]) print("\n") self.sendBroadcastCheck() def sendBroadcastCheck(self): # If list is not empty, start other masternodes if self.mnToStartList: self.startMN() def startMN(self): if self.caller.hwStatus != 2: self.caller.myPopUp2(QMessageBox.Question, 'SPMT - hw device check', self.caller.hwStatusMess, QMessageBox.Ok) elif not self.caller.rpcConnected: self.caller.myPopUp2(QMessageBox.Question, 'SPMT - rpc device check', self.caller.rpcStatusMess, QMessageBox.Ok) else: try: self.masternodeToStart = self.mnToStartList.pop() printDbg("Starting...%s" % self.masternodeToStart.name) self.masternodeToStart.startMessage(self.caller.hwdevice, self.caller.rpcClient) # wait for signal when masternode.work is ready then ---> sendBroadcast except Exception as e: err_msg = "error in startMN" printException(getCallerName(), getFunctionName(), err_msg, e)
class TabRewards(): def __init__(self, caller): self.caller = caller self.apiClient = ApiClient() ##--- Initialize Selection self.rewards = None self.selectedRewards = None self.rawtransactions = {} ##--- Initialize GUI self.ui = TabRewards_gui() self.caller.tabRewards = self.ui self.ui.feeLine.setValue(MINIMUM_FEE) # Connect GUI buttons self.ui.mnSelect.currentIndexChanged.connect( lambda: self.onChangeSelectedMN()) self.ui.btn_toggleCollateral.clicked.connect( lambda: self.onToggleCollateral()) self.ui.rewardsList.box.itemClicked.connect( lambda: self.updateSelection()) self.ui.btn_selectAllRewards.clicked.connect( lambda: self.onSelectAllRewards()) self.ui.btn_deselectAllRewards.clicked.connect( lambda: self.onDeselectAllRewards()) self.ui.btn_sendRewards.clicked.connect(lambda: self.onSendRewards()) self.ui.btn_Cancel.clicked.connect(lambda: self.onCancel()) # Init first selection self.loadMnSelect() def display_utxos(self): if self.rewards is not None: def item(value): item = QTableWidgetItem(value) item.setTextAlignment(Qt.AlignCenter) item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) return item self.ui.rewardsList.box.setRowCount(len(self.rewards)) for row, utxo in enumerate(self.rewards): txId = utxo.get('tx_hash', None) pivxAmount = round(int(utxo.get('value', 0)) / 1e8, 8) self.ui.rewardsList.box.setItem(row, 0, item(str(pivxAmount))) self.ui.rewardsList.box.setItem( row, 1, item(str(utxo.get('confirmations', None)))) self.ui.rewardsList.box.setItem(row, 2, item(txId)) self.ui.rewardsList.box.setItem( row, 3, item(str(utxo.get('tx_ouput_n', None)))) self.ui.rewardsList.box.showRow(row) # MARK COLLATERAL UTXO if txId == self.curr_txid: for i in range(0, 4): self.ui.rewardsList.box.item(row, i).setFont( QFont("Arial", 9, QFont.Bold)) self.ui.rewardsList.box.collateralRow = row if self.ui.rewardsList.box.collateralRow is not None: self.ui.rewardsList.box.hideRow( self.ui.rewardsList.box.collateralRow) if len(self.rewards) > 0: self.ui.rewardsList.box.resizeColumnsToContents() self.ui.rewardsList.statusLabel.setVisible(False) self.ui.rewardsList.box.horizontalHeader( ).setSectionResizeMode(2, QHeaderView.Stretch) else: if not self.caller.rpcConnected: self.ui.rewardsList.statusLabel.setText( '<b style="color:purple">PIVX wallet not connected</b>' ) else: if self.apiConnected: self.ui.rewardsList.statusLabel.setText( '<b style="color:red">Found no Rewards for %s</b>' % self.curr_addr) else: self.ui.rewardsList.statusLabel.setText( '<b style="color:purple">Unable to connect to API provider</b>' ) self.ui.rewardsList.statusLabel.setVisible(True) def getSelection(self): try: returnData = [] items = self.ui.rewardsList.box.selectedItems() # Save row indexes to a set to avoid repetition rows = set() for i in range(0, len(items)): row = items[i].row() rows.add(row) rowList = list(rows) return [self.rewards[row] for row in rowList] return returnData except Exception as e: print(e) def loadMnSelect(self): try: self.ui.mnSelect.clear() for x in self.caller.masternode_list: name = x['name'] address = x['collateral'].get('address') txid = x['collateral'].get('txid') hwAcc = x['hwAcc'] spath = x['collateral'].get('spath') path = MPATH + "%d'/0/%d" % (hwAcc, spath) self.ui.mnSelect.addItem(name, [address, txid, path]) except Exception as e: print(e) def load_utxos_thread(self, ctrl): self.apiConnected = False try: if not self.caller.rpcConnected: self.rewards = [] printDbg('PIVX daemon not connected') else: try: if self.apiClient.getStatus() != 200: return self.apiConnected = True self.blockCount = self.caller.rpcClient.getBlockCount() self.rewards = self.apiClient.getAddressUtxos( self.curr_addr)['unspent_outputs'] for utxo in self.rewards: self.rawtransactions[utxo[ 'tx_hash']] = self.caller.rpcClient.getRawTransaction( utxo['tx_hash']) except Exception as e: self.errorMsg = 'Error occurred while calling getaddressutxos method: ' + str( e) printDbg(self.errorMsg) except Exception as e: print(e) pass @pyqtSlot() def onCancel(self): self.ui.selectedRewardsLine.setText("0.0") self.ui.mnSelect.setCurrentIndex(0) self.ui.destinationLine.setText('') self.ui.feeLine.setValue(MINIMUM_FEE) self.ui.btn_toggleCollateral.setText("Show Collateral") self.ui.collateralHidden = True self.onChangeSelectedMN() @pyqtSlot() def onChangeSelectedMN(self): if self.ui.mnSelect.currentIndex() >= 0: self.curr_addr = self.ui.mnSelect.itemData( self.ui.mnSelect.currentIndex())[0] self.curr_txid = self.ui.mnSelect.itemData( self.ui.mnSelect.currentIndex())[1] self.curr_path = self.ui.mnSelect.itemData( self.ui.mnSelect.currentIndex())[2] if self.curr_addr is not None: result = self.apiClient.getBalance(self.curr_addr) self.ui.addrAvailLine.setText("<i>%s PIVs</i>" % result) self.ui.selectedRewardsLine.setText("0.0") self.ui.rewardsList.box.clearSelection() self.ui.rewardsList.box.collateralRow = None self.ui.collateralHidden = True self.ui.btn_toggleCollateral.setText("Show Collateral") if result is not None: self.runInThread = ThreadFuns.runInThread( self.load_utxos_thread, (), self.display_utxos) @pyqtSlot() def onSelectAllRewards(self): self.ui.rewardsList.box.selectAll() self.updateSelection() @pyqtSlot() def onDeselectAllRewards(self): self.ui.rewardsList.box.clearSelection() self.updateSelection() @pyqtSlot() def onSendRewards(self): self.dest_addr = self.ui.destinationLine.text().strip() # Check dongle printDbg("Checking HW device") if self.caller.hwStatus != 2: self.caller.myPopUp2(QMessageBox.Critical, 'SPMT - hw device check', "Connect to HW device first") printDbg("Unable to connect - hw status: %d" % self.caller.hwStatus) return None # Check destination Address if not checkPivxAddr(self.dest_addr): self.caller.myPopUp2(QMessageBox.Critical, 'SPMT - PIVX address check', "Invalid Destination Address") return None # Check spending collateral if (not self.ui.collateralHidden and self.ui.rewardsList.box.collateralRow is not None and self.ui.rewardsList.box.item( self.ui.rewardsList.box.collateralRow, 0).isSelected()): warning1 = "Are you sure you want to transfer the collateral?" warning2 = "Really?" warning3 = "Take a deep breath. Do you REALLY want to transfer your collateral?" ans = self.caller.myPopUp(QMessageBox.Warning, 'SPMT - warning', warning1) if ans == QMessageBox.No: return None else: ans2 = self.caller.myPopUp(QMessageBox.Warning, 'SPMT - warning', warning2) if ans2 == QMessageBox.No: return None else: ans3 = self.caller.myPopUp(QMessageBox.Critical, 'SPMT - warning', warning3) if ans3 == QMessageBox.No: return None # LET'S GO if self.selectedRewards: printDbg("Sending from PIVX address %s to PIVX address %s " % (self.curr_addr, self.dest_addr)) printDbg("Preparing transaction. Please wait...") self.currFee = self.ui.feeLine.value() * 1e8 # connect signal self.caller.hwdevice.sigTxdone.connect(self.FinishSend) try: self.txFinished = False self.caller.hwdevice.prepare_transfer_tx( self.caller, self.curr_path, self.selectedRewards, self.dest_addr, self.currFee, self.rawtransactions) except Exception as e: err_msg = "Error while preparing transaction. <br>" err_msg += "Probably Blockchain wasn't synced when trying to fetch raw TXs.<br>" err_msg += "<b>Wait for full synchronization</b> then hit 'Clear/Reload'" printException(getCallerName(), getFunctionName(), err_msg, e.args) else: self.caller.myPopUp2(QMessageBox.Information, 'transaction NOT Sent', "No UTXO to send") @pyqtSlot() def onToggleCollateral(self): if (self.rewards is not None): if len(self.rewards ) and self.ui.rewardsList.box.collateralRow is not None: if not self.ui.collateralHidden: try: if self.ui.rewardsList.box.item( self.ui.rewardsList.box.collateralRow, 0).isSelected(): self.ui.rewardsList.box.selectRow( self.ui.rewardsList.box.collateralRow) except Exception as e: err_msg = "Error while preparing transaction" printException(getCallerName(), getFunctionName(), err_msg, e.args) self.ui.rewardsList.box.hideRow( self.ui.rewardsList.box.collateralRow) self.ui.btn_toggleCollateral.setText("Show Collateral") self.ui.collateralHidden = True self.updateSelection() else: self.ui.rewardsList.box.showRow( self.ui.rewardsList.box.collateralRow) self.ui.btn_toggleCollateral.setText("Hide Collateral") self.ui.collateralHidden = False self.updateSelection() self.ui.rewardsList.box.resizeColumnsToContents() self.ui.rewardsList.box.horizontalHeader( ).setSectionResizeMode(2, QHeaderView.Stretch) else: self.caller.myPopUp2(QMessageBox.Information, 'No Collateral', "No collateral selected") # Activated by signal sigTxdone from hwdevice #@pyqtSlot(bytearray, str) def FinishSend(self, serialized_tx, amount_to_send): if not self.txFinished: try: self.txFinished = True tx_hex = serialized_tx.hex() printDbg("Raw signed transaction: " + tx_hex) printDbg("Amount to send :" + amount_to_send) if len(tx_hex) > 90000: mess = "Transaction's length exceeds 90000 bytes. Select less UTXOs and try again." self.caller.myPopUp2(QMessageBox.Warning, 'transaction Warning', mess) else: decodedTx = self.caller.rpcClient.decodeRawTransaction( tx_hex) destination = decodedTx.get("vout")[0].get( "scriptPubKey").get("addresses")[0] amount = decodedTx.get("vout")[0].get("value") message = 'Broadcast signed transaction?<br><br>Destination address:<br><b>%s</b><br><br>' % destination message += 'Amount to send: <b>%s PIV</b><br>' % str( amount) message += 'Fee: <b>%s PIV</b><br>Size: <b>%d bytes</b>' % ( str(round(self.currFee / 1e8, 8)), len(tx_hex) / 2) mess1 = QMessageBox(QMessageBox.Information, 'Send transaction', message) mess1.setDetailedText( json.dumps(decodedTx, indent=4, sort_keys=False)) mess1.setStandardButtons(QMessageBox.Yes | QMessageBox.No) reply = mess1.exec_() if reply == QMessageBox.Yes: txid = self.caller.rpcClient.sendRawTransaction(tx_hex) mess2_text = "Transaction sent.<br><b>NOTE:</b> selected UTXOs will not disappear from the list until TX is confirmed" mess2 = QMessageBox(QMessageBox.Information, 'transaction Sent', mess2_text) mess2.setDetailedText(txid) mess2.exec_() self.onCancel() else: self.caller.myPopUp2(QMessageBox.Information, 'transaction NOT Sent', "transaction NOT sent") self.onCancel() except Exception as e: err_msg = "Exception in sendRewards" printException(getCallerName(), getFunctionName(), err_msg, e.args) def updateSelection(self, clicked_item=None): total = 0 self.selectedRewards = self.getSelection() numOfInputs = len(self.selectedRewards) if numOfInputs: for i in range(0, numOfInputs): total += int(self.selectedRewards[i].get('value')) # update suggested fee and selected rewards estimatedTxSize = (44 + numOfInputs * 148) * 1.0 / 1000 # kB feePerKb = self.caller.rpcClient.getFeePerKb() suggestedFee = round(feePerKb * estimatedTxSize, 8) printDbg("estimatedTxSize is %s kB" % str(estimatedTxSize)) printDbg("suggested fee is %s PIV (%s PIV/kB)" % (str(suggestedFee), str(feePerKb))) self.ui.selectedRewardsLine.setText(str(round(total / 1e8, 8))) self.ui.feeLine.setValue(suggestedFee) else: self.ui.selectedRewardsLine.setText("") self.ui.feeLine.setValue(MINIMUM_FEE)