From 87fea26a8d4b76937cf00997c0e95365e6abfa6c Mon Sep 17 00:00:00 2001 From: JoeGruffins <34998433+JoeGruffins@users.noreply.github.com> Date: Wed, 22 Apr 2020 22:23:34 +0900 Subject: [PATCH] app: Add relay fee setting (#152) * app: Add relay fee setting Add a relay fee to settings and allow changing. The fee is not yet used. Save the relay fee with the account. Allow changing of the relay fee in Account settings as apposed to App settings. Change relay fee input field to radio buttons with labels low, default, and high. Set appropriate values for low (4000) and high (114000). * Add AccoutManager method setRelayFee. --- decred/decred/dcr/account.py | 6 +- decred/decred/wallet/accounts.py | 12 ++++ tinywallet/tinywallet/screens.py | 95 +++++++++++++++++++++++++++++++- 3 files changed, 110 insertions(+), 3 deletions(-) diff --git a/decred/decred/dcr/account.py b/decred/decred/dcr/account.py index be4ba7ee..6af1fdfa 100644 --- a/decred/decred/dcr/account.py +++ b/decred/decred/dcr/account.py @@ -7,6 +7,7 @@ from decred import DecredError from decred.crypto import crypto, opcode from decred.dcr import addrlib +from decred.dcr.txscript import DefaultRelayFeePerKb from decred.util import encode, helpers from decred.util.encode import BuildyBytes, ByteArray, unblobCheck @@ -801,6 +802,7 @@ def __init__( self.coinID = BIPID self.netID = netID self.netParams = nets.parse(netID) + self.relayFee = int(DefaultRelayFeePerKb) # For external addresses, the cursor can sit on the last seen address, # so start the lastSeen at the 0th external address. This is necessary # because the currentAddress method grabs the address at the current @@ -856,6 +858,7 @@ def blob(acct): .addData(encode.intToBytes(acct.cursorExt, signed=True)) .addData(acct.cursorInt) .addData(acct.gapLimit) + .addData(acct.relayFee) .b ) @@ -863,7 +866,7 @@ def blob(acct): def unblob(b): """Satisfies the encode.Blobber API""" ver, d = encode.decodeBlob(b) - unblobCheck("Account", ver, len(d), {0: 8}) + unblobCheck("Account", ver, len(d), {0: 9}) iFunc = encode.intFromBytes @@ -876,6 +879,7 @@ def unblob(b): acct.cursorExt = iFunc(d[5], signed=True) acct.cursorInt = iFunc(d[6]) acct.gapLimit = iFunc(d[7]) + acct.relayFee = iFunc(d[8]) return acct @staticmethod diff --git a/decred/decred/wallet/accounts.py b/decred/decred/wallet/accounts.py index bb47ffa5..b5868ea8 100644 --- a/decred/decred/wallet/accounts.py +++ b/decred/decred/wallet/accounts.py @@ -145,6 +145,18 @@ def setNode(self, node): for acct in self.accounts.values(): acct.setNode(node) + def setRelayFee(self, idx, fee): + """ + Save the relay fee for account at index. + + Args: + idx (int): The account's index. + fee (int): The relay fee in smallest unit/kb. + """ + acct = self.accounts[idx] + acct.relayFee = fee + self.acctDB[idx] = acct + def coinKey(self, cryptoKey): """ Decrypt the coin-type extended key. diff --git a/tinywallet/tinywallet/screens.py b/tinywallet/tinywallet/screens.py index 341422a0..6112b213 100644 --- a/tinywallet/tinywallet/screens.py +++ b/tinywallet/tinywallet/screens.py @@ -18,6 +18,7 @@ from decred.crypto import crypto from decred.dcr import constants as DCR, nets from decred.dcr.blockchain import LocalNode +from decred.dcr.txscript import DefaultRelayFeePerKb from decred.dcr.vsp import VotingServiceProvider from decred.util import chains, database, helpers from decred.wallet.wallet import Wallet @@ -475,7 +476,9 @@ def __init__(self, acctMgr, acct, assetScreen): self.canGoHome = False self.ticketStats = None self.balance = None - self.settingsScreen = AccountSettingsScreen(self.saveName) + self.settingsScreen = AccountSettingsScreen( + self.account.relayFee, self.saveName, self.setRelayFee + ) self.stakeScreen = StakingScreen(acct) self.wgt.setFixedSize( TinyDialog.maxWidth * 0.9, @@ -716,6 +719,15 @@ def saveName(self, newName): self.assetScreen.doButtons() app.home() + def setRelayFee(self, relayFee): + """ + Changes and saves the relayFee of the account. + + Args: + int: The new relayFee. + """ + self.acctMgr.setRelayFee(self.account.idx, relayFee) + def stackAndSync(self): """ Start syncing the account. @@ -1832,7 +1844,7 @@ class AccountSettingsScreen(Screen): Account settings screen. """ - def __init__(self, saveName): + def __init__(self, relayFee, saveName, setRelayFee): """ Args: saveName (function): A callback function to be called after the user @@ -1846,6 +1858,7 @@ def __init__(self, saveName): TinyDialog.maxHeight * 0.9 - TinyDialog.topMenuHeight, ) self.saveName = saveName + self.setRelayFee = setRelayFee gear = SVGWidget("gear", h=20) lbl = Q.makeLabel("Account Settings", 22) @@ -1854,6 +1867,11 @@ def __init__(self, saveName): self.layout.addStretch(1) + def insertSpace(): + spacer = Q.makeLabel("", 5) + spacer.setContentsMargins(0, 5, 0, 0) + grid.addWidget(spacer, row, 0, 1, 4) + # ACCOUNT NAME wgt, grid = Q.makeWidget(QtWidgets.QWidget, Q.GRID) @@ -1869,8 +1887,67 @@ def __init__(self, saveName): bttn.clicked.connect(self.nameChangeClicked) grid.addWidget(bttn, row, 1) + # RELAY FEE + + # Set string constants. + self.lowStr = "low" + self.defaultStr = "default" + self.highStr = "high" + + # Set values that are considered low, default, and high. + self.feeRates = { + self.lowStr: 4000, + self.defaultStr: int(DefaultRelayFeePerKb), + self.highStr: 50000, + } + self.feeLvl = "" + + # Find the current level. Warn if the current level isn't one of the + # three. + for k, v in self.feeRates.items(): + if v == relayFee: + self.feeLvl = k + break + else: + log.warn(f"non standard relay fee set: {relayFee}") + + # Helper to check the current value. + def setChecked(btn): + if self.feeLvl == btn.text(): + btn.setChecked(True) + + row += 1 + insertSpace() + row += 1 + lbl = Q.makeLabel("Relay Fee", 14, Q.ALIGN_LEFT) + grid.addWidget(lbl, row, 0) + self.feeLbl = lbl = Q.makeLabel("", 14, Q.ALIGN_LEFT) + self.setFeeLbl(relayFee) + grid.addWidget(lbl, row, 1) + row += 1 + btn1 = QtWidgets.QRadioButton(self.lowStr) + Q.setProperties(btn1, fontFamily="Roboto", fontSize=14) + setChecked(btn1) + btn1.toggled.connect(lambda: self.relayFeeChangeClicked(self.lowStr)) + btn2 = QtWidgets.QRadioButton(self.defaultStr) + Q.setProperties(btn2, fontFamily="Roboto", fontSize=14) + setChecked(btn2) + btn2.toggled.connect(lambda: self.relayFeeChangeClicked(self.defaultStr)) + btn3 = QtWidgets.QRadioButton(self.highStr) + Q.setProperties(btn3, fontFamily="Roboto", fontSize=14) + setChecked(btn3) + btn3.toggled.connect(lambda: self.relayFeeChangeClicked(self.highStr)) + wgt, _ = Q.makeRow(btn1, btn2, btn3) + grid.addWidget(wgt, row, 0, 1, -1) + self.layout.addStretch(1) + def setFeeLbl(self, fee): + """ + Set the displayed fee as atoms/byte. + """ + self.feeLbl.setText(f"{fee//1000} atoms/byte") + def nameChangeClicked(self, e): """ Qt slot for nameField.clicked signal. @@ -1882,6 +1959,20 @@ def nameChangeClicked(self, e): self.nameField.setText("") self.saveName(newName) + def relayFeeChangeClicked(self, feeLvl): + """ + Qt slot connected to relay fee radio button clicked signal. Changes the + relay fee to feeLvl. + """ + if self.feeLvl == feeLvl: + return + self.feeLvl = feeLvl + fee = self.feeRates[feeLvl] + self.setRelayFee(fee) + self.setFeeLbl(fee) + log.info(f"relay fee changed to {fee} atoms/kb") + app.appWindow.showSuccess(f"using {feeLvl} fees") + class NewAccountScreen(Screen): """