Exemple #1
0
    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()
Exemple #4
0
    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()
Exemple #6
0
    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)
Exemple #7
0
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()
Exemple #8
0
    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)
Exemple #9
0
   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)
Exemple #10
0
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()