Skip to content

Commit

Permalink
Better UTXO fetching
Browse files Browse the repository at this point in the history
- add fetching-utxo percent signal
- reload UTXOs only on demand
- sweepAll dialog opens only if hw/rpc connected
- permit broadcast of undecoded TX
  • Loading branch information
random-zebra committed Dec 3, 2018
1 parent c6197f4 commit 45584ab
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 45 deletions.
3 changes: 3 additions & 0 deletions src/mainWindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ class MainWindow(QWidget):
# signal: RPC list has been reloaded (emitted by updateRPClist)
sig_RPClistReloaded = pyqtSignal()

# signal: UTXO list loading percent (emitted by load_utxos_thread in tabRewards)
sig_UTXOsLoading = pyqtSignal(int)

# signal: UTXO list has been reloaded (emitted by load_utxos_thread in tabRewards)
sig_UTXOsLoaded = pyqtSignal()

Expand Down
45 changes: 29 additions & 16 deletions src/qt/dlg_sweepAll.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,16 @@ def __init__(self, main_tab):
self.setupUI()
# Connect GUI buttons
self.connectButtons()
# Connect reloadUTXO signal
self.main_tab.caller.sig_UTXOsLoading.connect(self.update_loading_utxos)
# Connect reloadUTXO signal
self.main_tab.caller.sig_UTXOsLoaded.connect(self.display_utxos)


# Called each time before exec_ in showDialog
def load_data(self):
# clear table
self.ui.tableW.setRowCount(0)
# load last used destination from cache
self.ui.edt_destination.setText(self.main_tab.caller.parent.cache.get("lastAddress"))
# load useSwiftX check from cache
Expand Down Expand Up @@ -189,7 +193,7 @@ def onButtonSend(self):

except Exception as e:
err_msg = "Exception in onButtonSend"
printException(getCallerName(), getFunctionName(), err_msg, e.args)
printException(getCallerName(), getFunctionName(), err_msg, e)



Expand All @@ -204,32 +208,32 @@ def AbortSend(self):
# Activated by signal sigTxdone from hwdevice
def FinishSend(self, serialized_tx, amount_to_send):
self.AbortSend()
QApplication.processEvents()
if not self.txFinished:
try:
self.txFinished = True
self.close()
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."
myPopUp_sb(self.main_tab.caller, "warn", 'transaction Warning', mess)
myPopUp_sb(self.main_tab.caller, "crit", 'transaction Warning', mess)

else:
decodedTx = self.main_tab.caller.rpcClient.decodeRawTransaction(tx_hex)
if decodedTx is None:
raise Exception("Unable to decode TX - connection to RPC server lost.")
destination = decodedTx.get("vout")[0].get("scriptPubKey").get("addresses")[0]
amount = decodedTx.get("vout")[0].get("value")
message = '<p>Broadcast signed transaction?</p><p>Destination address:<br><b>%s</b></p>' % destination
message += '<p>Amount: <b>%s</b> PIV<br>' % str(amount)
message += 'Fees: <b>%s</b> PIV <br>Size: <b>%d</b> Bytes</p>' % (str(round(self.currFee / 1e8, 8) ), len(tx_hex)/2)

if decodedTx is not None:
destination = decodedTx.get("vout")[0].get("scriptPubKey").get("addresses")[0]
amount = decodedTx.get("vout")[0].get("value")
message = '<p>Broadcast signed transaction?</p><p>Destination address:<br><b>%s</b></p>' % destination
message += '<p>Amount: <b>%s</b> PIV<br>' % str(amount)
message += 'Fees: <b>%s</b> PIV <br>Size: <b>%d</b> Bytes</p>' % (str(round(self.currFee / 1e8, 8) ), len(tx_hex)/2)
else:
message = '<p>Unable to decode TX- Broadcast anyway?</p>'

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.main_tab.caller.rpcClient.sendRawTransaction(tx_hex, self.useSwiftX())
Expand All @@ -248,6 +252,9 @@ def FinishSend(self, serialized_tx, amount_to_send):
except Exception as e:
err_msg = "Exception in FinishSend"
printException(getCallerName(), getFunctionName(), err_msg, e)

finally:
self.accept()



Expand All @@ -265,7 +272,15 @@ def updateFee(self):
self.ui.feeLine.setEnabled(False)
else:
self.ui.feeLine.setValue(self.suggestedFee)
self.ui.feeLine.setEnabled(True)
self.ui.feeLine.setEnabled(True)



def update_loading_utxos(self, percent):
self.ui.lblMessage.setVisible(True)
self.ui.lblMessage.setText("Loading rewards...%d%%" % percent)





Expand Down Expand Up @@ -331,10 +346,8 @@ def setupUi(self, SweepAllDlg):
self.loadingLine.hide()
self.loadingLinePercent.hide()
myForm.addRow(QLabel("Total Rewards: "), hBox)
hBox = QHBoxLayout()
self.noOfUtxosLine = QLabel("<b>0</b>")
hBox.addWidget(self.noOfUtxosLine)
myForm.addRow(QLabel("Total number of UTXOs: "), hBox)
myForm.addRow(QLabel("Total number of UTXOs: "), self.noOfUtxosLine)
hBox = QHBoxLayout()
self.edt_destination = QLineEdit()
self.edt_destination.setToolTip("PIVX address to transfer rewards to")
Expand Down
3 changes: 3 additions & 0 deletions src/tabMain.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,9 @@ def onStartMN(self, data=None):


def onSweepAllRewards(self):
if not self.caller.rpcConnected or self.caller.hwStatus != 2:
myPopUp_sb(self.caller, "crit", 'SPMT - hw/rpc device check', "Connect to RPC server and HW device first")
return None
try:
self.sweepAllDlg.showDialog()

Expand Down
74 changes: 47 additions & 27 deletions src/tabRewards.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def __init__(self, caller):
self.caller.hwdevice.sigTxdone.connect(self.FinishSend)
self.caller.hwdevice.sigTxabort.connect(self.onCancel)
self.caller.hwdevice.tx_progress.connect(self.updateProgressPercent)
self.caller.sig_UTXOsLoading.connect(self.update_loading_utxos)
self.caller.sig_UTXOsLoaded.connect(self.display_mn_utxos)


Expand Down Expand Up @@ -210,6 +211,8 @@ def load_utxos_thread(self, ctrl):

self.apiConnected = True

total_num_of_utxos = 0
mn_rewards = {}
for mn in self.caller.masternode_list:
# Load UTXOs from API client
rewards = self.caller.apiClient.getAddressUtxos(
Expand All @@ -218,29 +221,42 @@ def load_utxos_thread(self, ctrl):
if rewards is None:
printError('API client not responding.')
return

# for each UTXO
for utxo in rewards:
# get raw TX from RPC client
rawtx = self.caller.rpcClient.getRawTransaction(utxo['tx_hash'])

# Don't save UTXO if raw TX is unavailable
if rawtx is None:
printError("Unable to get raw TX with hash=%s from RPC server" % utxo['tx_hash'])
continue

# Add mn_name and raw_tx to UTXO and save it to DB
else:
utxo['mn_name'] = mn['name']
utxo['raw_tx'] = rawtx
self.caller.parent.db.addReward(utxo)


mn_rewards[mn['name']] = rewards
total_num_of_utxos += len(rewards)

printDbg("Number of UTXOs to load: %d" % total_num_of_utxos)
curr_utxo = 0
percent = 0

for mn in mn_rewards:
# for each UTXO
for utxo in mn_rewards[mn]:
percent = int(100*curr_utxo / total_num_of_utxos)
# get raw TX from RPC client
rawtx = self.caller.rpcClient.getRawTransaction(utxo['tx_hash'])

# Don't save UTXO if raw TX is unavailable
if rawtx is None:
printError("Unable to get raw TX with hash=%s from RPC server" % utxo['tx_hash'])
continue

# Add mn_name and raw_tx to UTXO and save it to DB
else:
utxo['mn_name'] = mn
utxo['raw_tx'] = rawtx
self.caller.parent.db.addReward(utxo)

# emit percent
self.caller.sig_UTXOsLoading.emit(percent)
curr_utxo += 1

self.caller.sig_UTXOsLoading.emit(100)
printDbg("--# REWARDS table updated")
self.utxoLoaded = True
self.caller.sig_UTXOsLoaded.emit()




def onCancel(self):
self.ui.rewardsList.box.clearSelection()
Expand Down Expand Up @@ -422,23 +438,24 @@ def FinishSend(self, serialized_tx, amount_to_send):

else:
decodedTx = self.caller.rpcClient.decodeRawTransaction(tx_hex)
if decodedTx is None:
raise Exception("Unable to decode TX - connection to RPC server lost.")
destination = decodedTx.get("vout")[0].get("scriptPubKey").get("addresses")[0]
amount = decodedTx.get("vout")[0].get("value")
message = '<p>Broadcast signed transaction?</p><p>Destination address:<br><b>%s</b></p>' % destination
message += '<p>Amount: <b>%s</b> PIV<br>' % str(amount)
message += 'Fees: <b>%s</b> PIV <br>Size: <b>%d</b> Bytes</p>' % (str(round(self.currFee / 1e8, 8) ), len(tx_hex)/2)

if decodedTx is not None:
destination = decodedTx.get("vout")[0].get("scriptPubKey").get("addresses")[0]
amount = decodedTx.get("vout")[0].get("value")
message = '<p>Broadcast signed transaction?</p><p>Destination address:<br><b>%s</b></p>' % destination
message += '<p>Amount: <b>%s</b> PIV<br>' % str(amount)
message += 'Fees: <b>%s</b> PIV <br>Size: <b>%d</b> Bytes</p>' % (str(round(self.currFee / 1e8, 8) ), len(tx_hex)/2)
else:
message = '<p>Unable to decode TX- Broadcast anyway?</p>'

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, self.useSwiftX())
if txid is None:
raise Exception("Unable to send TX - connection to RPC server lost.")

mess2_text = "<p>Transaction successfully sent.</p>"
mess2 = QMessageBox(QMessageBox.Information, 'transaction Sent', mess2_text)
mess2.setDetailedText(txid)
Expand Down Expand Up @@ -508,6 +525,9 @@ def updateSelection(self, clicked_item=None):
self.updateFee()



def update_loading_utxos(self, percent):
self.ui.resetStatusLabel('<em><b style="color:purple">Checking explorer... %d%%</b></em>' % percent)



Expand Down
4 changes: 2 additions & 2 deletions src/version.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"number": "0.4.0",
"tag": "e",
"comments": ["bugfixes"]
"tag": "f",
"comments": ["better UTXO fetching"]
}

0 comments on commit 45584ab

Please sign in to comment.