def __init__(self, parent, main): super(VerifyOfflinePackageDialog, self).__init__(parent, main) self.main = main layout = QVBoxLayout(self) load = QGroupBox(tr("Load Signed Package"), self) layout.addWidget(load) layoutload = QVBoxLayout() load.setLayout(layoutload) self.loadFileButton = QPushButton(tr("Select file to verify..."), load) layoutload.addWidget(self.loadFileButton) self.connect(self.loadFileButton, SIGNAL('clicked()'), self.load) self.lblVerified = QRichLabel('', hAlign=Qt.AlignHCenter, doWrap=False) layout.addWidget(self.lblVerified) save = QGroupBox(tr("Save Verified Package"), self) layout.addItem(QSpacerItem(10, 10)) layout.addWidget(save) layoutsave = QVBoxLayout() save.setLayout(layoutsave) self.saveFileButton = QPushButton(tr("Select file to save to..."), load) self.saveFileButton.setEnabled(False) layoutsave.addWidget(self.saveFileButton) self.connect(self.saveFileButton, SIGNAL('clicked()'), self.save) self.setWindowTitle('Verify Signed Package')
def __init__(self, parent, main): super(VerifyOfflinePackageDialog, self).__init__(parent) self.main = main layout = QVBoxLayout(self) load = QGroupBox(tr("Load Signed Package"), self) layout.addWidget(load) layoutload = QVBoxLayout() load.setLayout(layoutload) self.loadFileButton = QPushButton(tr("Select file to verify..."), load); layoutload.addWidget(self.loadFileButton) self.connect(self.loadFileButton, SIGNAL('clicked()'), self.load) self.lblVerified = QRichLabel('', hAlign=Qt.AlignHCenter, doWrap=False) layout.addWidget(self.lblVerified) save = QGroupBox(tr("Save Verified Package"), self) layout.addItem(QSpacerItem(10,10)) layout.addWidget(save) layoutsave = QVBoxLayout() save.setLayout(layoutsave) self.saveFileButton = QPushButton(tr("Select file to save to..."), load); self.saveFileButton.setEnabled(False) layoutsave.addWidget(self.saveFileButton) self.connect(self.saveFileButton, SIGNAL('clicked()'), self.save)
def __init__(self, main): self.main = main def updateLogDisplay(): self.pyLogTextDisplay.setText(getLastBytesOfFile(ARMORY_LOG_FILE)) self.pyLogTextDisplay.moveCursor(QtGui.QTextCursor.End) self.cppLogTextDisplay.setText(getLastBytesOfFile(ARMCPP_LOG_FILE)) self.cppLogTextDisplay.moveCursor(QtGui.QTextCursor.End) lblHeader = QRichLabel(tr("""<b>Log File Display</b>"""), doWrap=False) self.updateButton = QPushButton("Update") self.main.connect(self.updateButton, SIGNAL('clicked()'), updateLogDisplay) topRow = makeHorizFrame([lblHeader, self.updateButton, 'stretch']) self.pyLogTextDisplay = self.createLogDisplay() self.cppLogTextDisplay = self.createLogDisplay() logTabPanel = QTabWidget() logTabPanel.addTab(self.pyLogTextDisplay, "Python Log") logTabPanel.addTab(self.cppLogTextDisplay, "C++ Log") self.logFrame = makeVertFrame([topRow, logTabPanel]) # Now set the scrollarea widget to the layout self.tabToDisplay = QScrollArea() self.tabToDisplay.setWidgetResizable(True) self.tabToDisplay.setWidget(self.logFrame) updateLogDisplay()
def __init__(self, parent, main, wlt): super(CoinControlDlg, self).__init__(parent, main) self.wlt = wlt lblDescr = QRichLabel( self. tr('By default, transactions are created using any available coins from ' 'all addresses in this wallet. You can control the source addresses ' 'used for this transaction by selecting them below, and unchecking ' 'all other addresses.')) self.useAllCheckBox = QCheckBox(self.tr("Use all selected UTXOs")) useAllToolTip = self.main.createToolTipWidget( self. tr('By default, Armory will pick a subset of the UTXOs you chose ' 'explicitly through the coin control feature to best suit the ' 'total spend value of the transaction you are constructing. ' '<br><br>' 'Checking \'Use all selected UTXOs\' forces the construction of a ' 'transaction that will redeem the exact list of UTXOs you picked ' 'instead.')) frmCheckAll = makeHorizFrame( [self.useAllCheckBox, useAllToolTip, 'Stretch']) self.ccTreeModel = CoinControlTreeModel(self, wlt) self.ccView = QTreeView() self.ccView.setModel(self.ccTreeModel) self.setMinimumWidth(400) self.setMinimumHeight(300) self.btnAccept = QPushButton(self.tr("Accept")) self.btnCancel = QPushButton(self.tr("Cancel")) self.connect(self.btnAccept, SIGNAL('clicked()'), self.accept) self.connect(self.btnCancel, SIGNAL('clicked()'), self.reject) buttonBox = QDialogButtonBox() buttonBox.addButton(self.btnAccept, QDialogButtonBox.AcceptRole) buttonBox.addButton(self.btnCancel, QDialogButtonBox.RejectRole) hexgeom = self.main.settings.get('ccDlgGeometry') tblgeom = self.main.settings.get('ccDlgAddrCols') if len(hexgeom) > 0: geom = QByteArray.fromHex(hexgeom) self.restoreGeometry(geom) if len(tblgeom) > 0: restoreTableView(self.ccView, tblgeom) layout = QGridLayout() layout.addWidget(lblDescr, 0, 0) layout.addWidget(frmCheckAll, 1, 0) layout.addWidget(self.ccView, 2, 0) layout.addWidget(buttonBox, 5, 0) self.setLayout(layout) self.setWindowTitle(self.tr('Coin Control (Expert)'))
def __init__(self, parent, main): super(MirrorWalletsDialog, self).__init__(parent, main) self.progressText = "" self.counter = 1 self.progress = False self.progressThr = None self.setWindowFlags(Qt.Dialog) infoLabel = QRichLabel( self. tr('Starting v0.96, Armory needs to mirror Python ' 'wallets into C++ wallets in order to operate. Mirrored C++ wallets ' 'are watching only (they do not hold any private keys).<br><br> ' 'Mirrored wallets are used to interface with the database and perform ' 'operations that aren\'t available to the legacy Python wallets, such ' 'support for compressed public keys and Segregated Witness transactions. ' '<br><br>' 'Mirroring only needs to happen once per wallet. Synchronization ' 'will happen every time the Python wallet address chain is ahead of the ' 'mirrored Cpp wallet address chain (this typically rarely happens).' '<br><br>' 'This process can take up to a few minutes per wallet.<br><br>' )) self.statusLabel = QLabel('...') self.statusLabel.setAlignment(Qt.AlignCenter | Qt.AlignVCenter) frmProgress = QFrame() frmProgress.setFrameStyle(STYLE_RAISED) progressLayout = QGridLayout() progressLayout.addWidget(self.statusLabel, 0, 0, 1, 1) frmProgress.setLayout(progressLayout) self.connect(self, SIGNAL('UpdateTextStatus'), self.updateTextStatus) self.connect(self, SIGNAL('TerminateDlg'), self.shutdown) layout = QGridLayout() layout.addWidget(infoLabel, 0, 0, 3, 1) layout.addWidget(frmProgress, 3, 0, 1, 1) self.setWindowTitle(self.tr('Mirroring Wallets')) self.setLayout(layout) self.setMinimumWidth(500) self.setFocus()
def __init__(self, main): def searchItem(): searchString = str(self.searchEntry.text()) if len(searchString) > 0: likelyDataType = isLikelyDataType(searchString) for wltID, wlt in self.main.walletMap.iteritems(): if wlt.hasAddr(searchString): searchHash = searchString if likelyDataType == DATATYPE.Hex \ else addrStr_to_hash160(searchString)[1] dialog = DlgAddressInfo(wlt, searchHash, main=self.main) dialog.exec_() break if likelyDataType == DATATYPE.Hex: walletLedger = wlt.cppWallet.getTxLedger() txHashToFind = hex_to_binary(searchString, endOut=BIGENDIAN) txFound = False for entry in walletLedger: if entry.getTxHash() == txHashToFind: cppTx = TheBDM.getTxByHash(txHashToFind) serializedCppTx = cppTx.serialize() pytx = PyTx().unserialize(serializedCppTx) DlgDispTxInfo(pytx, wlt, self.main, self.main).exec_() txFound = True break if txFound: break self.main = main lblHeader = QRichLabel(tr("""<b>Search Armory: </b>"""), doWrap=False) self.searchButton = QPushButton("Search") self.searchEntry = QLineEdit() self.main.connect(self.searchButton, SIGNAL('clicked()'), searchItem) topRow = makeHorizFrame( [lblHeader, self.searchEntry, self.searchButton, 'stretch']) self.searchPanel = makeVertFrame([topRow, 'stretch']) # Now set the scrollarea widget to the layout self.tabToDisplay = QScrollArea() self.tabToDisplay.setWidgetResizable(True) self.tabToDisplay.setWidget(self.searchPanel)
class VerifyOfflinePackageDialog(ArmoryDialog): def __init__(self, parent, main): super(VerifyOfflinePackageDialog, self).__init__(parent, main) self.main = main layout = QVBoxLayout(self) load = QGroupBox(tr("Load Signed Package"), self) layout.addWidget(load) layoutload = QVBoxLayout() load.setLayout(layoutload) self.loadFileButton = QPushButton(tr("Select file to verify..."), load) layoutload.addWidget(self.loadFileButton) self.connect(self.loadFileButton, SIGNAL('clicked()'), self.load) self.lblVerified = QRichLabel('', hAlign=Qt.AlignHCenter, doWrap=False) layout.addWidget(self.lblVerified) save = QGroupBox(tr("Save Verified Package"), self) layout.addItem(QSpacerItem(10, 10)) layout.addWidget(save) layoutsave = QVBoxLayout() save.setLayout(layoutsave) self.saveFileButton = QPushButton(tr("Select file to save to..."), load) self.saveFileButton.setEnabled(False) layoutsave.addWidget(self.saveFileButton) self.connect(self.saveFileButton, SIGNAL('clicked()'), self.save) self.setWindowTitle('Verify Signed Package') def load(self): self.fileData = None #self.fromfile = QFileDialog.getOpenFileName(self, tr("Load file to verify"), "", tr("Armory Signed Packages (*.signed)")) self.fromfile = self.main.getFileLoad(tr('Load file to Verify'),\ ['Armory Signed Packages (*.signed)']) if len(self.fromfile) == 0: return df = open(self.fromfile, "rb") allfile = df.read() df.close() magicstart = "START_OF_SIGNATURE_SECTION" magicend = "END_OF_SIGNATURE_SECTION" if 0 != allfile.find(magicstart, 0, 1024 * 1024 * 4): # don't search past 4MiB QMessageBox.warning(self, tr("Invalid File"), tr("This file is not a signed package")) return end = allfile.find(magicend, 0, 1024 * 1024 * 4) # don't search past 4MiB if -1 == end: # don't search past 4MiB QMessageBox.warning( self, tr("Invalid File"), tr("The end of the signature in the file could not be found")) signatureData = allfile[len(magicstart):end] fileData = allfile[end + len(magicend):] print "All:", end, end + len(magicend), len(fileData), len(allfile) allsigs = downloadLinkParser(filetext=signatureData).downloadMap res = binary_to_hex(sha256(fileData)) good = False url = None print "Hash of package file: ", res # simply check if any of the hashes match for pack in allsigs.itervalues(): for packver in pack.itervalues(): for packos in packver.itervalues(): for packosver in packos.itervalues(): for packosarch in packosver.itervalues(): okhash = packosarch[1] if okhash == res: url = packosarch[0] good = True if good: self.saveFileButton.setEnabled(True) self.fileData = fileData self.fileName = os.path.basename(url) self.lblVerified.setText( tr("""<font color="%s"><b>Signature is Valid!</b></font>""") % htmlColor('TextGreen')) reply = QMessageBox.warning(self, tr("Signature Valid"), tr(""" The downloaded file has a <b>valid</b> signature from <font color="%s"><b>Armory Technologies, Inc.</b></font>, and is safe to install. <br><br> Would you like to overwrite the original file with the extracted installer? If you would like to save it to a new location, click "No" and then use the "Save Verified Package" button to select a new save location.""") % htmlColor('TextGreen'), \ QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.Yes: newFile = self.fromfile if newFile.endswith('.signed'): newFile = self.fromfile[:-7] LOGINFO('Saving installer to: ' + newFile) with open(newFile, 'wb') as df: df.write(self.fileData) if os.path.exists(newFile): LOGINFO('Removing original file: ' + self.fromfile) os.remove(self.fromfile) QMessageBox.warning( self, tr('Saved!'), tr(""" The installer was successfully extracted and saved to the following location: <br><br> %s""") % newFile, QMessageBox.Ok) else: self.saveFileButton.setEnabled(False) self.lblVerified.setText( tr("""<font color="%s">Invalid signature on loaded file!</font>""") % htmlColor('TextRed')) QMessageBox.warning(self, tr("Signature failure"), \ tr("This file has an invalid signature")) def save(self): tofile = QFileDialog.getSaveFileName(self, tr("Save confirmed package"), \ QDir.homePath() + "/" + self.fileName) if len(tofile) == 0: return df = open(tofile, "wb") df.write(self.fileData) df.close()
def __init__(self, main): def updateDustLimit(): try: self.dustTableModel.updateDustList( self.getSelectedWlt(), str2coin(self.dustLimitText.text())) self.beGoneDustButton.setEnabled( len(self.dustTableModel.dustTxOutlist) > 0) if self.dustTableModel.wlt: self.lblHeader.setText( tr("""<b>Dust Outputs for Wallet: %s</b>""" % self.dustTableModel.wlt.labelName)) except NegativeValueError: pass except TooMuchPrecisionError: pass except: LOGEXCEPT("Unexpected exception") pass def sendDust(): try: utxiList = [] for utxo in self.dustTableModel.dustTxOutlist: # The PyCreateAndSignTx method require PyTx and PyBtcAddress objects rawTx = TheBDM.getTxByHash(utxo.getTxHash()).serialize() a160 = CheckHash160(utxo.getRecipientScrAddr()) for pyAddr in self.dustTableModel.wlt.addrMap.values(): if a160 == pyAddr.getAddr160(): pubKey = pyAddr.binPublicKey65.toBinStr() txoIdx = utxo.getTxOutIndex() utxiList.append( UnsignedTxInput(rawTx, txoIdx, None, pubKey)) break # Make copies, destroy them in the finally clause privKeyMap = {} for addrObj in self.dustTableModel.wlt.addrMap.values(): scrAddr = SCRADDR_P2PKH_BYTE + addrObj.getAddr160() if self.dustTableModel.wlt.useEncryption and self.dustTableModel.wlt.isLocked: # Target wallet is encrypted... unlockdlg = DlgUnlockWallet(self.dustTableModel.wlt, self.main, self.main, 'Unlock Wallet to Import') if not unlockdlg.exec_(): QMessageBox.critical(self, 'Wallet is Locked', \ 'Cannot send dust without unlocking the wallet!', \ QMessageBox.Ok) return privKeyMap[scrAddr] = addrObj.binPrivKey32_Plain.copy() signedTx = PyCreateAndSignTx( utxiList, [], privKeyMap, SIGHASH_NONE | SIGHASH_ANYONECANPAY) print "-------------" print binary_to_hex(signedTx.serialize()) # sock = socket.create_connection(('dust-b-gone.bitcoin.petertodd.org',80)) # sock.send(signedTx.serialize()) # sock.send(b'\n') # sock.close() except socket.error as err: QMessageBox.critical( self.main, tr('Negative Value'), tr(""" Failed to connect to dust-b-gone server: %s""" % err.strerror), QMessageBox.Ok) except NegativeValueError: QMessageBox.critical( self.main, tr('Negative Value'), tr(""" You must enter a positive value of at least 0.0000 0001 and less than %s for the dust limit.""" % MAX_DUST_LIMIT_STR), QMessageBox.Ok) except TooMuchPrecisionError: QMessageBox.critical( self.main.main, tr('Too much precision'), tr(""" Bitcoins can only be specified down to 8 decimal places. The smallest unit of a Bitcoin is 0.0000 0001 BTC. Please enter a dust limit of at least 0.0000 0001 and less than %s.""" % MAX_DUST_LIMIT_STR), QMessageBox.Ok) finally: for scraddr in privKeyMap: privKeyMap[scraddr].destroy() self.main = main self.lblHeader = QRichLabel( tr("""<b>Dust Outputs for Wallet: None Selected</b>"""), doWrap=False) self.beGoneDustButton = QPushButton("Remove Dust") self.beGoneDustButton.setEnabled(False) self.main.connect(self.beGoneDustButton, SIGNAL('clicked()'), sendDust) topRow = makeHorizFrame([self.lblHeader, 'stretch']) secondRow = makeHorizFrame([self.beGoneDustButton, 'stretch']) self.dustLimitLabel = QLabel("Max Dust Value (BTC): ") self.dustLimitText = QLineEdit() self.dustLimitText.setFont(GETFONT('Fixed')) self.dustLimitText.setMinimumWidth( tightSizeNChar(self.dustLimitText, 6)[0]) self.dustLimitText.setMaximumWidth( tightSizeNChar(self.dustLimitText, 12)[0]) self.dustLimitText.setAlignment(Qt.AlignRight) self.dustLimitText.setText(coin2str(DEFAULT_DUST_LIMIT)) self.main.connect(self.dustLimitText, SIGNAL('textChanged(QString)'), updateDustLimit) limitPanel = makeHorizFrame( [self.dustLimitLabel, self.dustLimitText, 'stretch']) self.dustTableModel = DustDisplayModel() self.dustTableView = QTableView() self.dustTableView.setModel(self.dustTableModel) self.dustTableView.setSelectionMode(QTableView.NoSelection) self.dustTableView.verticalHeader().setDefaultSectionSize(20) self.dustTableView.verticalHeader().hide() h = tightSizeNChar(self.dustTableView, 1)[1] self.dustTableView.setMinimumHeight(2 * (1.3 * h)) self.dustTableView.setMaximumHeight(10 * (1.3 * h)) initialColResize(self.dustTableView, [100, .7, .3]) self.dustTableView.setContextMenuPolicy(Qt.CustomContextMenu) self.lblTxioInfo = QRichLabel('') self.lblTxioInfo.setMinimumWidth( tightSizeNChar(self.lblTxioInfo, 30)[0]) self.main.connect(self.main.walletsView, SIGNAL('clicked(QModelIndex)'), updateDustLimit) self.dustBGoneFrame = makeVertFrame( [topRow, secondRow, limitPanel, self.dustTableView, 'stretch']) # Now set the scrollarea widget to the layout self.tabToDisplay = QScrollArea() self.tabToDisplay.setWidgetResizable(True) self.tabToDisplay.setWidget(self.dustBGoneFrame)
def __init__(self, main): self.main = main ########################################################################## ##### Display the conversion values based on the Coinbase API self.lastPriceFetch = 0 self.lblHeader = QRichLabel(tr("""<b>Tracking buy and sell prices on Coinbase every 60 seconds</b>"""), doWrap=False) self.lblLastTime = QRichLabel('', doWrap=False) self.lblSellLabel = QRichLabel(tr('Coinbase <b>Sell</b> Price (USD):'), doWrap=False) self.lblBuyLabel = QRichLabel(tr('Coinbase <b>Buy</b> Price (USD):'), doWrap=False) self.lblSellPrice = QRichLabel('<Not Available>') self.lblBuyPrice = QRichLabel('<Not Available>') self.lastSellStr = '' self.lastBuyStr = '' self.btnUpdate = QPushButton(tr('Check Now')) self.main.connect(self.btnUpdate, SIGNAL('clicked()'), self.checkUpdatePrice) ########################################################################## ##### A calculator for converting prices between USD and BTC lblCalcTitle = QRichLabel(tr("""Convert between USD and BTC using Coinbase sell price"""), hAlign=Qt.AlignHCenter, doWrap=False) self.edtEnterUSD = QLineEdit() self.edtEnterBTC = QLineEdit() self.lblEnterUSD1 = QRichLabel('$') self.lblEnterUSD2 = QRichLabel('USD') self.lblEnterBTC = QRichLabel('BTC') btnClear = QPushButton('Clear') self.main.connect(self.edtEnterUSD, SIGNAL('textEdited(QString)'), self.updateCalcBTC) self.main.connect(self.edtEnterBTC, SIGNAL('textEdited(QString)'), self.updateCalcUSD) def clearCalc(): self.edtEnterUSD.setText('') self.edtEnterBTC.setText('') self.main.connect(btnClear, SIGNAL('clicked()'), clearCalc) frmCalcMid = makeHorizFrame( [self.lblEnterUSD1, self.edtEnterUSD, self.lblEnterUSD2, 'Stretch', self.edtEnterBTC, self.lblEnterBTC]) frmCalcClear = makeHorizFrame(['Stretch', btnClear, 'Stretch']) frmCalc = makeVertFrame([lblCalcTitle, frmCalcMid, frmCalcClear], STYLE_PLAIN) ########################################################################## ##### A table showing you the total balance of each wallet in USD and BTC lblWltTableTitle = QRichLabel(tr("Wallet balances converted to USD"), doWrap=False, hAlign=Qt.AlignHCenter) numWallets = len(self.main.walletMap) self.wltTable = QTableWidget(self.main) self.wltTable.setRowCount(numWallets) self.wltTable.setColumnCount(4) self.wltTable.horizontalHeader().setStretchLastSection(True) self.wltTable.setMinimumWidth(600) ########################################################################## ##### Setup the main layout for the tab mainLayout = QGridLayout() i=0 mainLayout.addWidget(self.lblHeader, i,0, 1,3) i+=1 mainLayout.addItem(QSpacerItem(15,15), i,0) mainLayout.addWidget(self.lblSellLabel, i,1) mainLayout.addWidget(self.lblSellPrice, i,2) i+=1 mainLayout.addItem(QSpacerItem(15,15), i,0) mainLayout.addWidget(self.lblBuyLabel, i,1) mainLayout.addWidget(self.lblBuyPrice, i,2) i+=1 mainLayout.addWidget(self.lblLastTime, i,0, 1,2) mainLayout.addWidget(self.btnUpdate, i,2) i+=1 mainLayout.addItem(QSpacerItem(20,20), i,0) i+=1 mainLayout.addWidget(frmCalc, i,0, 1,3) i+=1 mainLayout.addItem(QSpacerItem(30,30), i,0) i+=1 mainLayout.addWidget(lblWltTableTitle, i,0, 1,3) i+=1 mainLayout.addWidget(self.wltTable, i,0, 1,3) mainLayout.setColumnStretch(0,0) mainLayout.setColumnStretch(1,1) mainLayout.setColumnStretch(2,1) tabWidget = QWidget() tabWidget.setLayout(mainLayout) frmH = makeHorizFrame(['Stretch', tabWidget, 'Stretch']) frm = makeVertFrame(['Space(20)', frmH, 'Stretch']) # Now set the scrollarea widget to the layout self.tabToDisplay = QScrollArea() self.tabToDisplay.setWidgetResizable(True) self.tabToDisplay.setWidget(frm)
class PluginObject(object): tabName = 'Exchange Rates' maxVersion = '0.92' ############################################################################# def __init__(self, main): self.main = main ########################################################################## ##### Display the conversion values based on the Coinbase API self.lastPriceFetch = 0 self.lblHeader = QRichLabel(tr("""<b>Tracking buy and sell prices on Coinbase every 60 seconds</b>"""), doWrap=False) self.lblLastTime = QRichLabel('', doWrap=False) self.lblSellLabel = QRichLabel(tr('Coinbase <b>Sell</b> Price (USD):'), doWrap=False) self.lblBuyLabel = QRichLabel(tr('Coinbase <b>Buy</b> Price (USD):'), doWrap=False) self.lblSellPrice = QRichLabel('<Not Available>') self.lblBuyPrice = QRichLabel('<Not Available>') self.lastSellStr = '' self.lastBuyStr = '' self.btnUpdate = QPushButton(tr('Check Now')) self.main.connect(self.btnUpdate, SIGNAL('clicked()'), self.checkUpdatePrice) ########################################################################## ##### A calculator for converting prices between USD and BTC lblCalcTitle = QRichLabel(tr("""Convert between USD and BTC using Coinbase sell price"""), hAlign=Qt.AlignHCenter, doWrap=False) self.edtEnterUSD = QLineEdit() self.edtEnterBTC = QLineEdit() self.lblEnterUSD1 = QRichLabel('$') self.lblEnterUSD2 = QRichLabel('USD') self.lblEnterBTC = QRichLabel('BTC') btnClear = QPushButton('Clear') self.main.connect(self.edtEnterUSD, SIGNAL('textEdited(QString)'), self.updateCalcBTC) self.main.connect(self.edtEnterBTC, SIGNAL('textEdited(QString)'), self.updateCalcUSD) def clearCalc(): self.edtEnterUSD.setText('') self.edtEnterBTC.setText('') self.main.connect(btnClear, SIGNAL('clicked()'), clearCalc) frmCalcMid = makeHorizFrame( [self.lblEnterUSD1, self.edtEnterUSD, self.lblEnterUSD2, 'Stretch', self.edtEnterBTC, self.lblEnterBTC]) frmCalcClear = makeHorizFrame(['Stretch', btnClear, 'Stretch']) frmCalc = makeVertFrame([lblCalcTitle, frmCalcMid, frmCalcClear], STYLE_PLAIN) ########################################################################## ##### A table showing you the total balance of each wallet in USD and BTC lblWltTableTitle = QRichLabel(tr("Wallet balances converted to USD"), doWrap=False, hAlign=Qt.AlignHCenter) numWallets = len(self.main.walletMap) self.wltTable = QTableWidget(self.main) self.wltTable.setRowCount(numWallets) self.wltTable.setColumnCount(4) self.wltTable.horizontalHeader().setStretchLastSection(True) self.wltTable.setMinimumWidth(600) ########################################################################## ##### Setup the main layout for the tab mainLayout = QGridLayout() i=0 mainLayout.addWidget(self.lblHeader, i,0, 1,3) i+=1 mainLayout.addItem(QSpacerItem(15,15), i,0) mainLayout.addWidget(self.lblSellLabel, i,1) mainLayout.addWidget(self.lblSellPrice, i,2) i+=1 mainLayout.addItem(QSpacerItem(15,15), i,0) mainLayout.addWidget(self.lblBuyLabel, i,1) mainLayout.addWidget(self.lblBuyPrice, i,2) i+=1 mainLayout.addWidget(self.lblLastTime, i,0, 1,2) mainLayout.addWidget(self.btnUpdate, i,2) i+=1 mainLayout.addItem(QSpacerItem(20,20), i,0) i+=1 mainLayout.addWidget(frmCalc, i,0, 1,3) i+=1 mainLayout.addItem(QSpacerItem(30,30), i,0) i+=1 mainLayout.addWidget(lblWltTableTitle, i,0, 1,3) i+=1 mainLayout.addWidget(self.wltTable, i,0, 1,3) mainLayout.setColumnStretch(0,0) mainLayout.setColumnStretch(1,1) mainLayout.setColumnStretch(2,1) tabWidget = QWidget() tabWidget.setLayout(mainLayout) frmH = makeHorizFrame(['Stretch', tabWidget, 'Stretch']) frm = makeVertFrame(['Space(20)', frmH, 'Stretch']) # Now set the scrollarea widget to the layout self.tabToDisplay = QScrollArea() self.tabToDisplay.setWidgetResizable(True) self.tabToDisplay.setWidget(frm) ############################################################################# def getTabToDisplay(self): return self.tabToDisplay ############################################################################# def addCommasToPrice(self, pstr): dispStr = pstr.strip().split('.')[0] dispStr = ','.join([dispStr[::-1][3*i:3*(i+1)][::-1] \ for i in range((len(dispStr)-1)/3+1)][::-1]) if '.' in pstr: dispStr = dispStr + '.' + pstr.split('.')[1] return dispStr ############################################################################# def fetchFormattedPrice(self, url): sock = urllib2.urlopen(url) value = ast.literal_eval(sock.read())['subtotal']['amount'] return self.addCommasToPrice(value) ############################################################################# def checkUpdatePrice(self): urlBase = 'http://coinbase.com/api/v1/prices/' urlSell = urlBase + 'sell' urlBuy = urlBase + 'buy' try: self.lastSellStr = self.fetchFormattedPrice(urlSell) self.lastBuyStr = self.fetchFormattedPrice(urlBuy) self.lblSellPrice.setText('<b><font color="%s">$%s</font> / BTC</b>' % \ (htmlColor('TextBlue'), self.lastSellStr)) self.lblBuyPrice.setText( '<b><font color="%s">$%s</font> / BTC</b>' % \ (htmlColor('TextBlue'), self.lastBuyStr)) self.lastPriceFetch = RightNow() self.updateLastTimeStr() self.updateWalletTable() self.updateCalcUSD(self.edtEnterBTC.text()) except: #LOGEXCEPT('Failed to fetch price data from %s' % urlBase) pass ############################################################################# def updateLastTimeStr(self): secs = RightNow() - self.lastPriceFetch tstr = 'Less than 1 min' if secs > 60: tstr = secondsToHumanTime(secs) self.lblLastTime.setText(tr("""<font color="%s">Last updated: %s ago</font>""") % (htmlColor('DisableFG'), tstr)) ############################################################################# def injectGoOnlineFunc(self, topBlock): self.checkUpdatePrice() ############################################################################# def injectHeartbeatAlwaysFunc(self): # Check the price every 60 seconds, update widgets self.updateLastTimeStr() if RightNow() < self.lastPriceFetch+60: return self.lastPriceFetch = RightNow() self.checkUpdatePrice() ############################################################################# def updateCalcUSD(self, newBTCVal): try: convertVal = float(self.lastSellStr.replace(',','')) usdVal = convertVal * float(newBTCVal.replace(',','')) self.edtEnterUSD.setText(self.addCommasToPrice('%0.2f' % usdVal)) except: self.edtEnterUSD.setText('') ############################################################################# def updateCalcBTC(self, newUSDVal): try: convertVal = float(self.lastSellStr.replace(',','')) btcVal = float(newUSDVal.replace(',','')) / convertVal self.edtEnterBTC.setText(self.addCommasToPrice('%0.8f' % btcVal)) except: self.edtEnterBTC.setText('') ############################################################################# def updateWalletTable(self): numWallets = len(self.main.walletMap) self.wltTable.setRowCount(numWallets) self.wltTable.setColumnCount(4) row = 0 for wltID,wltObj in self.main.walletMap.iteritems(): wltValueBTC = '(...)' wltValueUSD = '(...)' if TheBDM.getBDMState()=='BlockchainReady': convertVal = float(self.lastSellStr.replace(',','')) wltBal = wltObj.getBalance('Total') wltValueBTC = coin2str(wltBal, maxZeros=2) wltValueUSD = '$' + self.addCommasToPrice('%0.2f' % (wltBal*convertVal/1e8)) rowItems = [] rowItems.append(QTableWidgetItem(wltID)) rowItems.append(QTableWidgetItem(wltObj.labelName)) rowItems.append(QTableWidgetItem(wltValueBTC)) rowItems.append(QTableWidgetItem(wltValueUSD)) rowItems[-2].setTextAlignment(Qt.AlignRight) rowItems[-1].setTextAlignment(Qt.AlignRight) rowItems[-2].setFont(GETFONT('Fixed', 10)) rowItems[-1].setFont(GETFONT('Fixed', 10)) for i,item in enumerate(rowItems): self.wltTable.setItem(row, i, item) item.setFlags(Qt.NoItemFlags) self.wltTable.setHorizontalHeaderItem(0, QTableWidgetItem(tr('Wallet ID'))) self.wltTable.setHorizontalHeaderItem(1, QTableWidgetItem(tr('Wallet Name'))) self.wltTable.setHorizontalHeaderItem(2, QTableWidgetItem(tr('BTC Balance'))) self.wltTable.setHorizontalHeaderItem(3, QTableWidgetItem(tr('USD ($) Value'))) self.wltTable.verticalHeader().hide() row += 1
def __init__(self, main): def updateDustLimit(): try: self.dustTableModel.updateDustList(self.getSelectedWlt(), str2coin(self.dustLimitText.text())) self.beGoneDustButton.setEnabled(len(self.dustTableModel.dustTxOutlist)>0) if self.dustTableModel.wlt: self.lblHeader.setText(tr("""<b>Dust Outputs for Wallet: %s</b>""" % self.dustTableModel.wlt.labelName)) except NegativeValueError: pass except TooMuchPrecisionError: pass except: LOGEXCEPT("Unexpected exception") pass def sendDust(): try: utxiList = [] for utxo in self.dustTableModel.dustTxOutlist: # The PyCreateAndSignTx method require PyTx and PyBtcAddress objects rawTx = TheBDM.getTxByHash(utxo.getTxHash()).serialize() a160 = CheckHash160(utxo.getRecipientScrAddr()) for pyAddr in self.dustTableModel.wlt.addrMap.values(): if a160 == pyAddr.getAddr160(): pubKey = pyAddr.binPublicKey65.toBinStr() txoIdx = utxo.getTxOutIndex() utxiList.append(UnsignedTxInput(rawTx, txoIdx, None, pubKey)) break # Make copies, destroy them in the finally clause privKeyMap = {} for addrObj in self.dustTableModel.wlt.addrMap.values(): scrAddr = SCRADDR_P2PKH_BYTE + addrObj.getAddr160() if self.dustTableModel.wlt.useEncryption and self.dustTableModel.wlt.isLocked: # Target wallet is encrypted... unlockdlg = DlgUnlockWallet(self.dustTableModel.wlt, self.main, self.main, 'Unlock Wallet to Import') if not unlockdlg.exec_(): QMessageBox.critical(self, 'Wallet is Locked', \ 'Cannot send dust without unlocking the wallet!', \ QMessageBox.Ok) return privKeyMap[scrAddr] = addrObj.binPrivKey32_Plain.copy() signedTx = PyCreateAndSignTx(utxiList, [], privKeyMap, SIGHASH_NONE|SIGHASH_ANYONECANPAY ) print "-------------" print binary_to_hex(signedTx.serialize()) # sock = socket.create_connection(('dust-b-gone.bitcoin.petertodd.org',80)) # sock.send(signedTx.serialize()) # sock.send(b'\n') # sock.close() except socket.error as err: QMessageBox.critical(self.main, tr('Negative Value'), tr(""" Failed to connect to dust-b-gone server: %s""" % err.strerror), QMessageBox.Ok) except NegativeValueError: QMessageBox.critical(self.main, tr('Negative Value'), tr(""" You must enter a positive value of at least 0.0000 0001 and less than %s for the dust limit.""" % MAX_DUST_LIMIT_STR), QMessageBox.Ok) except TooMuchPrecisionError: QMessageBox.critical(self.main.main, tr('Too much precision'), tr(""" Bitcoins can only be specified down to 8 decimal places. The smallest unit of a Groestlcoin is 0.0000 0001 GRS. Please enter a dust limit of at least 0.0000 0001 and less than %s.""" % MAX_DUST_LIMIT_STR), QMessageBox.Ok) finally: for scraddr in privKeyMap: privKeyMap[scraddr].destroy() self.main = main self.lblHeader = QRichLabel(tr("""<b>Dust Outputs for Wallet: None Selected</b>"""), doWrap=False) self.beGoneDustButton = QPushButton("Remove Dust") self.beGoneDustButton.setEnabled(False) self.main.connect(self.beGoneDustButton, SIGNAL('clicked()'), sendDust) topRow = makeHorizFrame([self.lblHeader,'stretch']) secondRow = makeHorizFrame([self.beGoneDustButton, 'stretch']) self.dustLimitLabel = QLabel("Max Dust Value (GRS): ") self.dustLimitText = QLineEdit() self.dustLimitText.setFont(GETFONT('Fixed')) self.dustLimitText.setMinimumWidth(tightSizeNChar(self.dustLimitText, 6)[0]) self.dustLimitText.setMaximumWidth(tightSizeNChar(self.dustLimitText, 12)[0]) self.dustLimitText.setAlignment(Qt.AlignRight) self.dustLimitText.setText(coin2str(DEFAULT_DUST_LIMIT)) self.main.connect(self.dustLimitText, SIGNAL('textChanged(QString)'), updateDustLimit) limitPanel = makeHorizFrame([self.dustLimitLabel, self.dustLimitText, 'stretch']) self.dustTableModel = DustDisplayModel() self.dustTableView = QTableView() self.dustTableView.setModel(self.dustTableModel) self.dustTableView.setSelectionMode(QTableView.NoSelection) self.dustTableView.verticalHeader().setDefaultSectionSize(20) self.dustTableView.verticalHeader().hide() h = tightSizeNChar(self.dustTableView, 1)[1] self.dustTableView.setMinimumHeight(2 * (1.3 * h)) self.dustTableView.setMaximumHeight(10 * (1.3 * h)) initialColResize(self.dustTableView, [100, .7, .3]) self.dustTableView.setContextMenuPolicy(Qt.CustomContextMenu) self.lblTxioInfo = QRichLabel('') self.lblTxioInfo.setMinimumWidth(tightSizeNChar(self.lblTxioInfo, 30)[0]) self.main.connect(self.main.walletsView, SIGNAL('clicked(QModelIndex)'), updateDustLimit) self.dustBGoneFrame = makeVertFrame([topRow, secondRow, limitPanel, self.dustTableView, 'stretch']) # Now set the scrollarea widget to the layout self.tabToDisplay = QScrollArea() self.tabToDisplay.setWidgetResizable(True) self.tabToDisplay.setWidget(self.dustBGoneFrame)
class VerifyOfflinePackageDialog(QDialog): def __init__(self, parent, main): super(VerifyOfflinePackageDialog, self).__init__(parent) self.main = main layout = QVBoxLayout(self) load = QGroupBox(tr("Load Signed Package"), self) layout.addWidget(load) layoutload = QVBoxLayout() load.setLayout(layoutload) self.loadFileButton = QPushButton(tr("Select file to verify..."), load); layoutload.addWidget(self.loadFileButton) self.connect(self.loadFileButton, SIGNAL('clicked()'), self.load) self.lblVerified = QRichLabel('', hAlign=Qt.AlignHCenter, doWrap=False) layout.addWidget(self.lblVerified) save = QGroupBox(tr("Save Verified Package"), self) layout.addItem(QSpacerItem(10,10)) layout.addWidget(save) layoutsave = QVBoxLayout() save.setLayout(layoutsave) self.saveFileButton = QPushButton(tr("Select file to save to..."), load); self.saveFileButton.setEnabled(False) layoutsave.addWidget(self.saveFileButton) self.connect(self.saveFileButton, SIGNAL('clicked()'), self.save) def load(self): self.fileData = None #self.fromfile = QFileDialog.getOpenFileName(self, tr("Load file to verify"), "", tr("Armory Signed Packages (*.signed)")) self.fromfile = self.main.getFileLoad(tr('Load file to Verify'),\ ['Armory Signed Packages (*.signed)']) if len(self.fromfile)==0: return df = open(self.fromfile, "rb") allfile = df.read() df.close() magicstart="START_OF_SIGNATURE_SECTION" magicend="END_OF_SIGNATURE_SECTION" if 0 != allfile.find(magicstart, 0, 1024*1024*4): # don't search past 4MiB QMessageBox.warning(self, tr("Invalid File"), tr("This file is not a signed package")) return end = allfile.find(magicend, 0, 1024*1024*4) # don't search past 4MiB if -1 == end: # don't search past 4MiB QMessageBox.warning(self, tr("Invalid File"), tr("The end of the signature in the file could not be found")) signatureData = allfile[len(magicstart):end] fileData = allfile[end+len(magicend):] print "All:",end, end+len(magicend), len(fileData), len(allfile) allsigs = downloadLinkParser(filetext=signatureData).downloadMap res = binary_to_hex(sha256(fileData)) good=False url=None print "Hash of package file: ", res # simply check if any of the hashes match for pack in allsigs.itervalues(): for packver in pack.itervalues(): for packos in packver.itervalues(): for packosver in packos.itervalues(): for packosarch in packosver.itervalues(): okhash = packosarch[1] if okhash == res: url = packosarch[0] good=True if good: self.saveFileButton.setEnabled(True) self.fileData = fileData self.fileName = os.path.basename(url) self.lblVerified.setText(tr("""<font color="%s"><b>Signature is Valid!</b></font>""") % htmlColor('TextGreen')) reply = QMessageBox.warning(self, tr("Signature Valid"), tr(""" The downloaded file has a <b>valid</b> signature from <font color="%s"><b>Armory Technologies, Inc.</b></font>, and is safe to install. <br><br> Would you like to overwrite the original file with the extracted installer? If you would like to save it to a new location, click "No" and then use the "Save Verified Package" button to select a new save location.""") % htmlColor('TextGreen'), \ QMessageBox.Yes | QMessageBox.No) if reply==QMessageBox.Yes: newFile = self.fromfile if newFile.endswith('.signed'): newFile = self.fromfile[:-7] LOGINFO('Saving installer to: ' + newFile) with open(newFile, 'wb') as df: df.write(self.fileData) if os.path.exists(newFile): LOGINFO('Removing original file: ' + self.fromfile) os.remove(self.fromfile) QMessageBox.warning(self, tr('Saved!'), tr(""" The installer was successfully extracted and saved to the following location: <br><br> %s""") % newFile, QMessageBox.Ok) else: self.saveFileButton.setEnabled(False) self.lblVerified.setText(tr("""<font color="%s">Invalid signature on loaded file!</font>""") % htmlColor('TextRed')) QMessageBox.warning(self, tr("Signature failure"), \ tr("This file has an invalid signature")) def save(self): tofile = QFileDialog.getSaveFileName(self, tr("Save confirmed package"), \ QDir.homePath() + "/" + self.fileName) if len(tofile)==0: return df = open(tofile, "wb") df.write(self.fileData) df.close()