diff options
Diffstat (limited to 'src/qt')
117 files changed, 735 insertions, 211 deletions
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index bfb5bf3fec..162ecdba4e 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -114,7 +114,7 @@ public: case CT_NEW: if(inModel) { - qWarning() << "AddressTablePriv::updateEntry : Warning: Got CT_NEW, but entry is already in model"; + qWarning() << "AddressTablePriv::updateEntry: Warning: Got CT_NEW, but entry is already in model"; break; } parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex); @@ -124,7 +124,7 @@ public: case CT_UPDATED: if(!inModel) { - qWarning() << "AddressTablePriv::updateEntry : Warning: Got CT_UPDATED, but entry is not in model"; + qWarning() << "AddressTablePriv::updateEntry: Warning: Got CT_UPDATED, but entry is not in model"; break; } lower->type = newEntryType; @@ -134,7 +134,7 @@ public: case CT_DELETED: if(!inModel) { - qWarning() << "AddressTablePriv::updateEntry : Warning: Got CT_DELETED, but entry is not in model"; + qWarning() << "AddressTablePriv::updateEntry: Warning: Got CT_DELETED, but entry is not in model"; break; } parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1); diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 1adf4e00cb..73c684e489 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -89,10 +89,24 @@ static std::string Translate(const char* psz) return QCoreApplication::translate("bitcoin-core", psz).toStdString(); } +static QString GetLangTerritory() +{ + QSettings settings; + // Get desired locale (e.g. "de_DE") + // 1) System default language + QString lang_territory = QLocale::system().name(); + // 2) Language from QSettings + QString lang_territory_qsettings = settings.value("language", "").toString(); + if(!lang_territory_qsettings.isEmpty()) + lang_territory = lang_territory_qsettings; + // 3) -lang command line argument + lang_territory = QString::fromStdString(GetArg("-lang", lang_territory.toStdString())); + return lang_territory; +} + /** Set up translations */ static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTranslator, QTranslator &translatorBase, QTranslator &translator) { - QSettings settings; // Remove old translators QApplication::removeTranslator(&qtTranslatorBase); @@ -102,13 +116,7 @@ static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTrans // Get desired locale (e.g. "de_DE") // 1) System default language - QString lang_territory = QLocale::system().name(); - // 2) Language from QSettings - QString lang_territory_qsettings = settings.value("language", "").toString(); - if(!lang_territory_qsettings.isEmpty()) - lang_territory = lang_territory_qsettings; - // 3) -lang command line argument - lang_territory = QString::fromStdString(GetArg("-lang", lang_territory.toStdString())); + QString lang_territory = GetLangTerritory(); // Convert to "de" only by truncating "_DE" QString lang = lang_territory; @@ -498,8 +506,6 @@ int main(int argc, char *argv[]) Q_INIT_RESOURCE(bitcoin); Q_INIT_RESOURCE(bitcoin_locale); - GUIUtil::SubstituteFonts(); - BitcoinApplication app(argc, argv); #if QT_VERSION > 0x050100 // Generate high-dpi pixmaps @@ -521,6 +527,7 @@ int main(int argc, char *argv[]) QApplication::setOrganizationName(QAPP_ORG_NAME); QApplication::setOrganizationDomain(QAPP_ORG_DOMAIN); QApplication::setApplicationName(QAPP_APP_NAME_DEFAULT); + GUIUtil::SubstituteFonts(GetLangTerritory()); /// 4. Initialization of translations, so that intro dialog is in user's language // Now that QSettings are accessible, initialize translations diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc index b54f2e2ed6..63af146fd0 100644 --- a/src/qt/bitcoin.qrc +++ b/src/qt/bitcoin.qrc @@ -35,9 +35,6 @@ <file alias="tx_input">res/icons/tx_input.png</file> <file alias="tx_output">res/icons/tx_output.png</file> <file alias="tx_inout">res/icons/tx_inout.png</file> - <file alias="unit_btc">res/icons/unit_btc.png</file> - <file alias="unit_mbtc">res/icons/unit_mbtc.png</file> - <file alias="unit_ubtc">res/icons/unit_ubtc.png</file> <file alias="lock_closed">res/icons/lock_closed.png</file> <file alias="lock_open">res/icons/lock_open.png</file> <file alias="key">res/icons/key.png</file> @@ -49,9 +46,6 @@ <file alias="about_qt">res/icons/about_qt.png</file> <file alias="verify">res/icons/verify.png</file> </qresource> - <qresource prefix="/images"> - <file alias="about">res/images/about.png</file> - </qresource> <qresource prefix="/movies"> <file alias="spinner-000">res/movies/spinner-000.png</file> <file alias="spinner-001">res/movies/spinner-001.png</file> diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index fdb9bcd6d6..d31a1e018b 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -20,6 +20,7 @@ class AmountSpinBox: public QAbstractSpinBox { Q_OBJECT + public: explicit AmountSpinBox(QWidget *parent): QAbstractSpinBox(parent), @@ -72,23 +73,6 @@ public: setValue(val); } - StepEnabled stepEnabled() const - { - StepEnabled rv = 0; - if(text().isEmpty()) // Allow step-up with empty field - return StepUpEnabled; - bool valid = false; - CAmount val = value(&valid); - if(valid) - { - if(val > 0) - rv |= StepDownEnabled; - if(val < BitcoinUnits::maxMoney()) - rv |= StepUpEnabled; - } - return rv; - } - void setDisplayUnit(int unit) { bool valid = false; @@ -139,6 +123,7 @@ public: } return cachedMinimumSizeHint; } + private: int currentUnit; CAmount singleStep; @@ -179,6 +164,26 @@ protected: return QAbstractSpinBox::event(event); } + StepEnabled stepEnabled() const + { + if (isReadOnly()) // Disable steps when AmountSpinBox is read-only + return StepNone; + if (text().isEmpty()) // Allow step-up with empty field + return StepUpEnabled; + + StepEnabled rv = 0; + bool valid = false; + CAmount val = value(&valid); + if(valid) + { + if(val > 0) + rv |= StepDownEnabled; + if(val < BitcoinUnits::maxMoney()) + rv |= StepUpEnabled; + } + return rv; + } + signals: void valueChanged(); }; @@ -273,7 +278,6 @@ void BitcoinAmountField::setValue(const CAmount& value) void BitcoinAmountField::setReadOnly(bool fReadOnly) { amount->setReadOnly(fReadOnly); - unit->setEnabled(!fReadOnly); } void BitcoinAmountField::unitChanged(int idx) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 3b8fd985a0..09f784387e 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -76,12 +76,14 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) : historyAction(0), quitAction(0), sendCoinsAction(0), + sendCoinsMenuAction(0), usedSendingAddressesAction(0), usedReceivingAddressesAction(0), signMessageAction(0), verifyMessageAction(0), aboutAction(0), receiveCoinsAction(0), + receiveCoinsMenuAction(0), optionsAction(0), toggleHideAction(0), encryptWalletAction(0), @@ -162,6 +164,9 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) : // Create status bar statusBar(); + + // Disable size grip because it looks ugly and nobody needs it + statusBar()->setSizeGripEnabled(false); // Status bar notification icons QFrame *frameBlocks = new QFrame(); @@ -256,6 +261,10 @@ void BitcoinGUI::createActions(const NetworkStyle *networkStyle) sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2)); tabGroup->addAction(sendCoinsAction); + sendCoinsMenuAction = new QAction(TextColorIcon(":/icons/send"), sendCoinsAction->text(), this); + sendCoinsMenuAction->setStatusTip(sendCoinsAction->statusTip()); + sendCoinsMenuAction->setToolTip(sendCoinsMenuAction->statusTip()); + receiveCoinsAction = new QAction(SingleColorIcon(":/icons/receiving_addresses"), tr("&Receive"), this); receiveCoinsAction->setStatusTip(tr("Request payments (generates QR codes and bitcoin: URIs)")); receiveCoinsAction->setToolTip(receiveCoinsAction->statusTip()); @@ -263,6 +272,10 @@ void BitcoinGUI::createActions(const NetworkStyle *networkStyle) receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3)); tabGroup->addAction(receiveCoinsAction); + receiveCoinsMenuAction = new QAction(TextColorIcon(":/icons/receiving_addresses"), receiveCoinsAction->text(), this); + receiveCoinsMenuAction->setStatusTip(receiveCoinsAction->statusTip()); + receiveCoinsMenuAction->setToolTip(receiveCoinsMenuAction->statusTip()); + historyAction = new QAction(SingleColorIcon(":/icons/history"), tr("&Transactions"), this); historyAction->setStatusTip(tr("Browse transaction history")); historyAction->setToolTip(historyAction->statusTip()); @@ -277,8 +290,12 @@ void BitcoinGUI::createActions(const NetworkStyle *networkStyle) connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewPage())); connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage())); + connect(sendCoinsMenuAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); + connect(sendCoinsMenuAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage())); connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage())); + connect(receiveCoinsMenuAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); + connect(receiveCoinsMenuAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage())); connect(historyAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage())); #endif // ENABLE_WALLET @@ -475,7 +492,9 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled) { overviewAction->setEnabled(enabled); sendCoinsAction->setEnabled(enabled); + sendCoinsMenuAction->setEnabled(enabled); receiveCoinsAction->setEnabled(enabled); + receiveCoinsMenuAction->setEnabled(enabled); historyAction->setEnabled(enabled); encryptWalletAction->setEnabled(enabled); backupWalletAction->setEnabled(enabled); @@ -522,8 +541,8 @@ void BitcoinGUI::createTrayIconMenu() // Configuration of the tray icon (or dock icon) icon menu trayIconMenu->addAction(toggleHideAction); trayIconMenu->addSeparator(); - trayIconMenu->addAction(sendCoinsAction); - trayIconMenu->addAction(receiveCoinsAction); + trayIconMenu->addAction(sendCoinsMenuAction); + trayIconMenu->addAction(receiveCoinsMenuAction); trayIconMenu->addSeparator(); trayIconMenu->addAction(signMessageAction); trayIconMenu->addAction(verifyMessageAction); @@ -1027,6 +1046,16 @@ UnitDisplayStatusBarControl::UnitDisplayStatusBarControl() : { createContextMenu(); setToolTip(tr("Unit to show amounts in. Click to select another unit.")); + QList<BitcoinUnits::Unit> units = BitcoinUnits::availableUnits(); + int max_width = 0; + const QFontMetrics fm(font()); + foreach (const BitcoinUnits::Unit unit, units) + { + max_width = qMax(max_width, fm.width(BitcoinUnits::name(unit))); + } + setMinimumSize(max_width, 0); + setAlignment(Qt::AlignRight | Qt::AlignVCenter); + setStyleSheet(QString("QLabel { color : %1 }").arg(SingleColor().name())); } /** So that it responds to button clicks */ @@ -1066,7 +1095,7 @@ void UnitDisplayStatusBarControl::setOptionsModel(OptionsModel *optionsModel) /** When Display Units are changed on OptionsModel it will refresh the display text of the control on the status bar */ void UnitDisplayStatusBarControl::updateDisplayUnit(int newUnits) { - setPixmap(SingleColorIcon(":/icons/unit_" + BitcoinUnits::id(newUnits)).pixmap(31,STATUSBAR_ICONSIZE)); + setText(BitcoinUnits::name(newUnits)); } /** Shows context menu with Display Unit options by the mouse coordinates */ diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 7509a00734..3216a7398e 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -90,12 +90,14 @@ private: QAction *historyAction; QAction *quitAction; QAction *sendCoinsAction; + QAction *sendCoinsMenuAction; QAction *usedSendingAddressesAction; QAction *usedReceivingAddressesAction; QAction *signMessageAction; QAction *verifyMessageAction; QAction *aboutAction; QAction *receiveCoinsAction; + QAction *receiveCoinsMenuAction; QAction *optionsAction; QAction *toggleHideAction; QAction *encryptWalletAction; diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp index 758fba7058..425b45d918 100644 --- a/src/qt/bitcoinunits.cpp +++ b/src/qt/bitcoinunits.cpp @@ -36,17 +36,6 @@ bool BitcoinUnits::valid(int unit) } } -QString BitcoinUnits::id(int unit) -{ - switch(unit) - { - case BTC: return QString("btc"); - case mBTC: return QString("mbtc"); - case uBTC: return QString("ubtc"); - default: return QString("???"); - } -} - QString BitcoinUnits::name(int unit) { switch(unit) diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h index a01fcc8cf9..1871c33a78 100644 --- a/src/qt/bitcoinunits.h +++ b/src/qt/bitcoinunits.h @@ -76,8 +76,6 @@ public: static QList<Unit> availableUnits(); //! Is unit ID valid? static bool valid(int unit); - //! Identifier, e.g. for image names - static QString id(int unit); //! Short name static QString name(int unit); //! Longer description diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 493cdd6dd2..03d94f2e13 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -212,14 +212,14 @@ static void ShowProgress(ClientModel *clientmodel, const std::string &title, int static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConnections) { - // Too noisy: qDebug() << "NotifyNumConnectionsChanged : " + QString::number(newNumConnections); + // Too noisy: qDebug() << "NotifyNumConnectionsChanged: " + QString::number(newNumConnections); QMetaObject::invokeMethod(clientmodel, "updateNumConnections", Qt::QueuedConnection, Q_ARG(int, newNumConnections)); } static void NotifyAlertChanged(ClientModel *clientmodel, const uint256 &hash, ChangeType status) { - qDebug() << "NotifyAlertChanged : " + QString::fromStdString(hash.GetHex()) + " status=" + QString::number(status); + qDebug() << "NotifyAlertChanged: " + QString::fromStdString(hash.GetHex()) + " status=" + QString::number(status); QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection, Q_ARG(QString, QString::fromStdString(hash.GetHex())), Q_ARG(int, status)); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 60e7d62a7a..3f4f082b8c 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -117,6 +117,10 @@ CoinControlDialog::CoinControlDialog(QWidget *parent) : // (un)select all connect(ui->pushButtonSelectAll, SIGNAL(clicked()), this, SLOT(buttonSelectAllClicked())); + // change coin control first column label due Qt4 bug. + // see https://github.com/bitcoin/bitcoin/issues/5716 + ui->treeWidget->headerItem()->setText(COLUMN_CHECKBOX, QString()); + ui->treeWidget->setColumnWidth(COLUMN_CHECKBOX, 84); ui->treeWidget->setColumnWidth(COLUMN_AMOUNT, 100); ui->treeWidget->setColumnWidth(COLUMN_LABEL, 170); @@ -213,7 +217,7 @@ void CoinControlDialog::showMenu(const QPoint &point) if (item->text(COLUMN_TXHASH).length() == 64) // transaction hash is 64 characters (this means its a child node, so its not a parent node in tree mode) { copyTransactionHashAction->setEnabled(true); - if (model->isLockedCoin(uint256(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt())) + if (model->isLockedCoin(uint256S(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt())) { lockAction->setEnabled(false); unlockAction->setEnabled(true); @@ -272,7 +276,7 @@ void CoinControlDialog::lockCoin() if (contextMenuItem->checkState(COLUMN_CHECKBOX) == Qt::Checked) contextMenuItem->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); - COutPoint outpt(uint256(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt()); + COutPoint outpt(uint256S(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt()); model->lockCoin(outpt); contextMenuItem->setDisabled(true); contextMenuItem->setIcon(COLUMN_CHECKBOX, SingleColorIcon(":/icons/lock_closed")); @@ -282,7 +286,7 @@ void CoinControlDialog::lockCoin() // context menu action: unlock coin void CoinControlDialog::unlockCoin() { - COutPoint outpt(uint256(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt()); + COutPoint outpt(uint256S(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt()); model->unlockCoin(outpt); contextMenuItem->setDisabled(false); contextMenuItem->setIcon(COLUMN_CHECKBOX, QIcon()); @@ -304,19 +308,19 @@ void CoinControlDialog::clipboardAmount() // copy label "Fee" to clipboard void CoinControlDialog::clipboardFee() { - GUIUtil::setClipboard(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" ")).replace("~", "")); + GUIUtil::setClipboard(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" ")).replace(ASYMP_UTF8, "")); } // copy label "After fee" to clipboard void CoinControlDialog::clipboardAfterFee() { - GUIUtil::setClipboard(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" ")).replace("~", "")); + GUIUtil::setClipboard(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" ")).replace(ASYMP_UTF8, "")); } // copy label "Bytes" to clipboard void CoinControlDialog::clipboardBytes() { - GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace("~", "")); + GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace(ASYMP_UTF8, "")); } // copy label "Priority" to clipboard @@ -334,7 +338,7 @@ void CoinControlDialog::clipboardLowOutput() // copy label "Change" to clipboard void CoinControlDialog::clipboardChange() { - GUIUtil::setClipboard(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" ")).replace("~", "")); + GUIUtil::setClipboard(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" ")).replace(ASYMP_UTF8, "")); } // treeview: sort @@ -388,7 +392,7 @@ void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column) { if (column == COLUMN_CHECKBOX && item->text(COLUMN_TXHASH).length() == 64) // transaction hash is 64 characters (this means its a child node, so its not a parent node in tree mode) { - COutPoint outpt(uint256(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt()); + COutPoint outpt(uint256S(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt()); if (item->checkState(COLUMN_CHECKBOX) == Qt::Unchecked) coinControl->UnSelect(outpt); @@ -600,16 +604,16 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) l2->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAmount)); // Amount l3->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nPayFee)); // Fee l4->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAfterFee)); // After Fee - l5->setText(((nBytes > 0) ? "~" : "") + QString::number(nBytes)); // Bytes + l5->setText(((nBytes > 0) ? ASYMP_UTF8 : "") + QString::number(nBytes)); // Bytes l6->setText(sPriorityLabel); // Priority l7->setText(fDust ? tr("yes") : tr("no")); // Dust l8->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nChange)); // Change if (nPayFee > 0 && !(payTxFee.GetFeePerK() > 0 && fPayAtLeastCustomFee && nBytes < 1000)) { - l3->setText("~" + l3->text()); - l4->setText("~" + l4->text()); + l3->setText(ASYMP_UTF8 + l3->text()); + l4->setText(ASYMP_UTF8 + l4->text()); if (nChange > 0) - l8->setText("~" + l8->text()); + l8->setText(ASYMP_UTF8 + l8->text()); } // turn labels "red" diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index 0974443066..5a91876f1f 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -25,6 +25,8 @@ namespace Ui { class CoinControlDialog; } +#define ASYMP_UTF8 "\xE2\x89\x88" + class CoinControlDialog : public QDialog { Q_OBJECT diff --git a/src/qt/coincontroltreewidget.cpp b/src/qt/coincontroltreewidget.cpp index 6cbcf7128d..5dcbf0c3f1 100644 --- a/src/qt/coincontroltreewidget.cpp +++ b/src/qt/coincontroltreewidget.cpp @@ -17,7 +17,8 @@ void CoinControlTreeWidget::keyPressEvent(QKeyEvent *event) { event->ignore(); int COLUMN_CHECKBOX = 0; - this->currentItem()->setCheckState(COLUMN_CHECKBOX, ((this->currentItem()->checkState(COLUMN_CHECKBOX) == Qt::Checked) ? Qt::Unchecked : Qt::Checked)); + if(this->currentItem()) + this->currentItem()->setCheckState(COLUMN_CHECKBOX, ((this->currentItem()->checkState(COLUMN_CHECKBOX) == Qt::Checked) ? Qt::Unchecked : Qt::Checked)); } else if (event->key() == Qt::Key_Escape) // press esc -> close dialog { @@ -29,4 +30,4 @@ void CoinControlTreeWidget::keyPressEvent(QKeyEvent *event) { this->QTreeWidget::keyPressEvent(event); } -}
\ No newline at end of file +} diff --git a/src/qt/forms/addressbookpage.ui b/src/qt/forms/addressbookpage.ui index 52fdc6ef06..264edeb720 100644 --- a/src/qt/forms/addressbookpage.ui +++ b/src/qt/forms/addressbookpage.ui @@ -27,7 +27,7 @@ <enum>Qt::CustomContextMenu</enum> </property> <property name="toolTip"> - <string>Double-click to edit address or label</string> + <string>Right-click to edit address or label</string> </property> <property name="tabKeyNavigation"> <bool>false</bool> diff --git a/src/qt/forms/helpmessagedialog.ui b/src/qt/forms/helpmessagedialog.ui index 81dbd90b12..dc7df9d6c8 100644 --- a/src/qt/forms/helpmessagedialog.ui +++ b/src/qt/forms/helpmessagedialog.ui @@ -6,36 +6,91 @@ <rect> <x>0</x> <y>0</y> - <width>800</width> + <width>780</width> <height>400</height> </rect> </property> - <property name="font"> - <font> - <pointsize>10</pointsize> - </font> - </property> <property name="windowTitle"> <string notr="true">Bitcoin Core - Command-line options</string> </property> <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>12</number> + </property> + <property name="topMargin"> + <number>12</number> + </property> + <property name="rightMargin"> + <number>12</number> + </property> + <property name="bottomMargin"> + <number>12</number> + </property> <item> - <widget class="QLabel" name="graphic"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Ignored"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> + <layout class="QVBoxLayout" name="verticalLayoutLogo" stretch="0,0"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>4</number> </property> - <property name="pixmap"> - <pixmap resource="../bitcoin.qrc">:/images/about</pixmap> + <property name="rightMargin"> + <number>0</number> </property> - </widget> + <item> + <widget class="QLabel" name="aboutLogo"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Ignored"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>100</width> + <height>100</height> + </size> + </property> + <property name="pixmap"> + <pixmap resource="../bitcoin.qrc">:/icons/bitcoin</pixmap> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + </widget> + </item> + <item> + <widget class="QFrame" name="frame"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + </widget> + </item> + </layout> </item> <item> <layout class="QVBoxLayout" name="verticalLayout"> <item> + <widget class="QTextEdit" name="helpMessage"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item> <widget class="QScrollArea" name="scrollArea"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> <property name="verticalScrollBarPolicy"> <enum>Qt::ScrollBarAlwaysOn</enum> </property> @@ -43,23 +98,18 @@ <bool>true</bool> </property> <widget class="QWidget" name="scrollAreaWidgetContents"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>659</width> - <height>348</height> - </rect> - </property> <layout class="QVBoxLayout" name="verticalLayout_2"> <item> - <widget class="QLabel" name="helpMessageLabel"> + <widget class="QLabel" name="aboutMessage"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> </property> <property name="textFormat"> <enum>Qt::PlainText</enum> </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> <property name="openExternalLinks"> <bool>true</bool> </property> @@ -73,6 +123,22 @@ </widget> </item> <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>4</width> + <height>4</height> + </size> + </property> + </spacer> + </item> + <item> <widget class="QDialogButtonBox" name="okButton"> <property name="orientation"> <enum>Qt::Horizontal</enum> diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui index 19421dc813..55c4f5ac58 100644 --- a/src/qt/forms/optionsdialog.ui +++ b/src/qt/forms/optionsdialog.ui @@ -330,7 +330,7 @@ <item> <widget class="QCheckBox" name="minimizeOnClose"> <property name="toolTip"> - <string>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu.</string> + <string>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</string> </property> <property name="text"> <string>M&inimize on close</string> diff --git a/src/qt/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui index eb7c92cfec..c1eb185501 100644 --- a/src/qt/forms/rpcconsole.ui +++ b/src/qt/forms/rpcconsole.ui @@ -1043,7 +1043,30 @@ </property> </widget> </item> - <item row="14" column="1"> + <item row="14" column="0"> + <widget class="QLabel" name="label_timeoffset"> + <property name="text"> + <string>Time Offset</string> + </property> + </widget> + </item> + <item row="14" column="2"> + <widget class="QLabel" name="timeoffset"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="15" column="1"> <spacer name="verticalSpacer_3"> <property name="orientation"> <enum>Qt::Vertical</enum> diff --git a/src/qt/forms/signverifymessagedialog.ui b/src/qt/forms/signverifymessagedialog.ui index 40b2da3228..92f6430c51 100644 --- a/src/qt/forms/signverifymessagedialog.ui +++ b/src/qt/forms/signverifymessagedialog.ui @@ -30,7 +30,7 @@ <item> <widget class="QLabel" name="infoLabel_SM"> <property name="text"> - <string>You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</string> + <string>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</string> </property> <property name="textFormat"> <enum>Qt::PlainText</enum> @@ -237,7 +237,7 @@ <item> <widget class="QLabel" name="infoLabel_VM"> <property name="text"> - <string>Enter the signing address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack.</string> + <string>Enter the receiver's address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction!</string> </property> <property name="textFormat"> <enum>Qt::PlainText</enum> diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index a3ede9fd62..2a13f43ea4 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -67,6 +67,9 @@ static boost::filesystem::detail::utf8_codecvt_facet utf8; #if defined(Q_OS_MAC) extern double NSAppKitVersionNumber; +#if !defined(NSAppKitVersionNumber10_8) +#define NSAppKitVersionNumber10_8 1187 +#endif #if !defined(NSAppKitVersionNumber10_9) #define NSAppKitVersionNumber10_9 1265 #endif @@ -383,7 +386,7 @@ void openDebugLogfile() QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathDebug))); } -void SubstituteFonts() +void SubstituteFonts(const QString& language) { #if defined(Q_OS_MAC) // Background: @@ -393,12 +396,28 @@ void SubstituteFonts() // If this fallback is not properly loaded, some characters may fail to // render correctly. // +// The same thing happened with 10.10. .Helvetica Neue DeskInterface is now default. +// // Solution: If building with the 10.7 SDK or lower and the user's platform // is 10.9 or higher at runtime, substitute the correct font. This needs to // happen before the QApplication is created. #if defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8 - if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_9) - QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande"); + if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_8) + { + if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_9) + /* On a 10.9 - 10.9.x system */ + QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande"); + else + { + /* 10.10 or later system */ + if (language == "zh_CN" || language == "zh_TW" || language == "zh_HK") // traditional or simplified Chinese + QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Heiti SC"); + else if (language == "ja") // Japanesee + QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Songti SC"); + else + QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Lucida Grande"); + } + } #endif #endif } @@ -696,7 +715,18 @@ LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(listSnapshot, i); UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes; CFURLRef currentItemURL = NULL; - LSSharedFileListItemResolve(item, resolutionFlags, ¤tItemURL, NULL); + +#if defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED >= 10100 + if(&LSSharedFileListItemCopyResolvedURL) + currentItemURL = LSSharedFileListItemCopyResolvedURL(item, resolutionFlags, NULL); +#if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && MAC_OS_X_VERSION_MIN_REQUIRED < 10100 + else + LSSharedFileListItemResolve(item, resolutionFlags, ¤tItemURL, NULL); +#endif +#else + LSSharedFileListItemResolve(item, resolutionFlags, ¤tItemURL, NULL); +#endif + if(currentItemURL && CFEqual(currentItemURL, findUrl)) { // found CFRelease(currentItemURL); @@ -843,4 +873,9 @@ QString formatPingTime(double dPingTime) return dPingTime == 0 ? QObject::tr("N/A") : QString(QObject::tr("%1 ms")).arg(QString::number((int)(dPingTime * 1000), 10)); } +QString formatTimeOffset(int64_t nTimeOffset) +{ + return QString(QObject::tr("%1 s")).arg(QString::number((int)nTimeOffset, 10)); +} + } // namespace GUIUtil diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 4f8c683147..bcbb540c37 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -107,7 +107,7 @@ namespace GUIUtil void openDebugLogfile(); // Replace invalid default fonts with known good ones - void SubstituteFonts(); + void SubstituteFonts(const QString& language); /** Qt event filter that intercepts ToolTipChange events, and replaces the tooltip with a rich text representation if needed. This assures that Qt can word-wrap long tooltip messages. @@ -188,7 +188,10 @@ namespace GUIUtil /* Format a CNodeCombinedStats.dPingTime into a user-readable string or display N/A, if 0*/ QString formatPingTime(double dPingTime); - + + /* Format a CNodeCombinedStats.nTimeOffset into a user-readable string. */ + QString formatTimeOffset(int64_t nTimeOffset); + #if defined(Q_OS_MAC) && QT_VERSION >= 0x050000 // workaround for Qt OSX Bug: // https://bugreports.qt-project.org/browse/QTBUG-15631 diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp index 35846bc153..4c1e898020 100644 --- a/src/qt/paymentrequestplus.cpp +++ b/src/qt/paymentrequestplus.cpp @@ -9,6 +9,8 @@ #include "paymentrequestplus.h" +#include "util.h" + #include <stdexcept> #include <openssl/x509.h> @@ -30,18 +32,18 @@ bool PaymentRequestPlus::parse(const QByteArray& data) { bool parseOK = paymentRequest.ParseFromArray(data.data(), data.size()); if (!parseOK) { - qWarning() << "PaymentRequestPlus::parse : Error parsing payment request"; + qWarning() << "PaymentRequestPlus::parse: Error parsing payment request"; return false; } if (paymentRequest.payment_details_version() > 1) { - qWarning() << "PaymentRequestPlus::parse : Received up-version payment details, version=" << paymentRequest.payment_details_version(); + qWarning() << "PaymentRequestPlus::parse: Received up-version payment details, version=" << paymentRequest.payment_details_version(); return false; } parseOK = details.ParseFromString(paymentRequest.serialized_payment_details()); if (!parseOK) { - qWarning() << "PaymentRequestPlus::parse : Error parsing payment details"; + qWarning() << "PaymentRequestPlus::parse: Error parsing payment details"; paymentRequest.Clear(); return false; } @@ -81,17 +83,17 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c digestAlgorithm = EVP_sha1(); } else if (paymentRequest.pki_type() == "none") { - qWarning() << "PaymentRequestPlus::getMerchant : Payment request: pki_type == none"; + qWarning() << "PaymentRequestPlus::getMerchant: Payment request: pki_type == none"; return false; } else { - qWarning() << "PaymentRequestPlus::getMerchant : Payment request: unknown pki_type " << QString::fromStdString(paymentRequest.pki_type()); + qWarning() << "PaymentRequestPlus::getMerchant: Payment request: unknown pki_type " << QString::fromStdString(paymentRequest.pki_type()); return false; } payments::X509Certificates certChain; if (!certChain.ParseFromString(paymentRequest.pki_data())) { - qWarning() << "PaymentRequestPlus::getMerchant : Payment request: error parsing pki_data"; + qWarning() << "PaymentRequestPlus::getMerchant: Payment request: error parsing pki_data"; return false; } @@ -101,12 +103,12 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c QByteArray certData(certChain.certificate(i).data(), certChain.certificate(i).size()); QSslCertificate qCert(certData, QSsl::Der); if (currentTime < qCert.effectiveDate() || currentTime > qCert.expiryDate()) { - qWarning() << "PaymentRequestPlus::getMerchant : Payment request: certificate expired or not yet active: " << qCert; + qWarning() << "PaymentRequestPlus::getMerchant: Payment request: certificate expired or not yet active: " << qCert; return false; } #if QT_VERSION >= 0x050000 if (qCert.isBlacklisted()) { - qWarning() << "PaymentRequestPlus::getMerchant : Payment request: certificate blacklisted: " << qCert; + qWarning() << "PaymentRequestPlus::getMerchant: Payment request: certificate blacklisted: " << qCert; return false; } #endif @@ -116,7 +118,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c certs.push_back(cert); } if (certs.empty()) { - qWarning() << "PaymentRequestPlus::getMerchant : Payment request: empty certificate chain"; + qWarning() << "PaymentRequestPlus::getMerchant: Payment request: empty certificate chain"; return false; } @@ -132,7 +134,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c // load the signing cert into it and verify. X509_STORE_CTX *store_ctx = X509_STORE_CTX_new(); if (!store_ctx) { - qWarning() << "PaymentRequestPlus::getMerchant : Payment request: error creating X509_STORE_CTX"; + qWarning() << "PaymentRequestPlus::getMerchant: Payment request: error creating X509_STORE_CTX"; return false; } @@ -150,7 +152,13 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c int result = X509_verify_cert(store_ctx); if (result != 1) { int error = X509_STORE_CTX_get_error(store_ctx); - throw SSLVerifyError(X509_verify_cert_error_string(error)); + // For testing payment requests, we allow self signed root certs! + // This option is just shown in the UI options, if -help-debug is enabled. + if (!(error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && GetBoolArg("-allowselfsignedrootcertificates", false))) { + throw SSLVerifyError(X509_verify_cert_error_string(error)); + } else { + qDebug() << "PaymentRequestPlus::getMerchant: Allowing self signed root certificate, because -allowselfsignedrootcertificates is true."; + } } X509_NAME *certname = X509_get_subject_name(signing_cert); @@ -183,7 +191,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c } catch (const SSLVerifyError& err) { fResult = false; - qWarning() << "PaymentRequestPlus::getMerchant : SSL error: " << err.what(); + qWarning() << "PaymentRequestPlus::getMerchant: SSL error: " << err.what(); } if (website) diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 3f8e89535e..9aab944f6b 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -46,7 +46,6 @@ #include <QUrlQuery> #endif -using namespace boost; using namespace std; const int BITCOIN_IPC_CONNECT_TIMEOUT = 1000; // milliseconds @@ -98,7 +97,7 @@ static QList<QString> savedPaymentRequests; static void ReportInvalidCertificate(const QSslCertificate& cert) { - qDebug() << "ReportInvalidCertificate : Payment server found an invalid certificate: " << cert.subjectInfo(QSslCertificate::CommonName); + qDebug() << "ReportInvalidCertificate: Payment server found an invalid certificate: " << cert.subjectInfo(QSslCertificate::CommonName); } // @@ -125,19 +124,22 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store) // and get 'I don't like X.509 certificates, don't trust anybody' behavior: QString certFile = QString::fromStdString(GetArg("-rootcertificates", "-system-")); - if (certFile.isEmpty()) - return; // Empty store + // Empty store + if (certFile.isEmpty()) { + qDebug() << QString("PaymentServer::%1: Payment request authentication via X.509 certificates disabled.").arg(__func__); + return; + } QList<QSslCertificate> certList; - if (certFile != "-system-") - { + if (certFile != "-system-") { + qDebug() << QString("PaymentServer::%1: Using \"%2\" as trusted root certificate.").arg(__func__).arg(certFile); + certList = QSslCertificate::fromPath(certFile); // Use those certificates when fetching payment requests, too: QSslSocket::setDefaultCaCertificates(certList); - } - else - certList = QSslSocket::systemCaCertificates (); + } else + certList = QSslSocket::systemCaCertificates(); int nRootCerts = 0; const QDateTime currentTime = QDateTime::currentDateTime(); @@ -169,7 +171,7 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store) continue; } } - qWarning() << "PaymentServer::LoadRootCAs : Loaded " << nRootCerts << " root certificates"; + qWarning() << "PaymentServer::LoadRootCAs: Loaded " << nRootCerts << " root certificates"; // Project for another day: // Fetch certificate revocation lists, and add them to certStore. @@ -242,7 +244,7 @@ void PaymentServer::ipcParseCommandLine(int argc, char* argv[]) { // Printing to debug.log is about the best we can do here, the // GUI hasn't started yet so we can't pop up a message box. - qWarning() << "PaymentServer::ipcSendCommandLine : Payment request file does not exist: " << arg; + qWarning() << "PaymentServer::ipcSendCommandLine: Payment request file does not exist: " << arg; } } } @@ -366,10 +368,10 @@ void PaymentServer::initNetManager() if (optionsModel->getProxySettings(proxy)) { netManager->setProxy(proxy); - qDebug() << "PaymentServer::initNetManager : Using SOCKS5 proxy" << proxy.hostName() << ":" << proxy.port(); + qDebug() << "PaymentServer::initNetManager: Using SOCKS5 proxy" << proxy.hostName() << ":" << proxy.port(); } else - qDebug() << "PaymentServer::initNetManager : No active proxy server found."; + qDebug() << "PaymentServer::initNetManager: No active proxy server found."; connect(netManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(netRequestFinished(QNetworkReply*))); @@ -413,12 +415,12 @@ void PaymentServer::handleURIOrFile(const QString& s) if (fetchUrl.isValid()) { - qDebug() << "PaymentServer::handleURIOrFile : fetchRequest(" << fetchUrl << ")"; + qDebug() << "PaymentServer::handleURIOrFile: fetchRequest(" << fetchUrl << ")"; fetchRequest(fetchUrl); } else { - qWarning() << "PaymentServer::handleURIOrFile : Invalid URL: " << fetchUrl; + qWarning() << "PaymentServer::handleURIOrFile: Invalid URL: " << fetchUrl; emit message(tr("URI handling"), tr("Payment request fetch URL is invalid: %1").arg(fetchUrl.toString()), CClientUIInterface::ICON_WARNING); @@ -519,27 +521,23 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins return false; if (request.IsInitialized()) { - const payments::PaymentDetails& details = request.getDetails(); - // Payment request network matches client network? - if (details.network() != Params().NetworkIDString()) - { + if (!verifyNetwork(request.getDetails())) { emit message(tr("Payment request rejected"), tr("Payment request network doesn't match client network."), CClientUIInterface::MSG_ERROR); return false; } - // Expired payment request? - if (details.has_expires() && (int64_t)details.expires() < GetTime()) - { - emit message(tr("Payment request rejected"), tr("Payment request has expired."), + // Make sure any payment requests involved are still valid. + // This is re-checked just before sending coins in WalletModel::sendCoins(). + if (verifyExpired(request.getDetails())) { + emit message(tr("Payment request rejected"), tr("Payment request expired."), CClientUIInterface::MSG_ERROR); return false; } - } - else { + } else { emit message(tr("Payment request error"), tr("Payment request is not initialized."), CClientUIInterface::MSG_ERROR); @@ -571,6 +569,14 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins return false; } + // Bitcoin amounts are stored as (optional) uint64 in the protobuf messages (see paymentrequest.proto), + // but CAmount is defined as int64_t. Because of that we need to verify that amounts are in a valid range + // and no overflow has happened. + if (!verifyAmount(sendingTo.second)) { + emit message(tr("Payment request rejected"), tr("Invalid payment request."), CClientUIInterface::MSG_ERROR); + return false; + } + // Extract and check amounts CTxOut txOut(sendingTo.second, sendingTo.first); if (txOut.IsDust(::minRelayTxFee)) { @@ -582,15 +588,20 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins } recipient.amount += sendingTo.second; + // Also verify that the final amount is still in a valid range after adding additional amounts. + if (!verifyAmount(recipient.amount)) { + emit message(tr("Payment request rejected"), tr("Invalid payment request."), CClientUIInterface::MSG_ERROR); + return false; + } } // Store addresses and format them to fit nicely into the GUI recipient.address = addresses.join("<br />"); if (!recipient.authenticatedMerchant.isEmpty()) { - qDebug() << "PaymentServer::processPaymentRequest : Secure payment request from " << recipient.authenticatedMerchant; + qDebug() << "PaymentServer::processPaymentRequest: Secure payment request from " << recipient.authenticatedMerchant; } else { - qDebug() << "PaymentServer::processPaymentRequest : Insecure payment request to " << addresses.join(", "); + qDebug() << "PaymentServer::processPaymentRequest: Insecure payment request to " << addresses.join(", "); } return true; @@ -645,7 +656,7 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipien else { // This should never happen, because sending coins should have // just unlocked the wallet and refilled the keypool. - qWarning() << "PaymentServer::fetchPaymentACK : Error getting refund key, refund_to not set"; + qWarning() << "PaymentServer::fetchPaymentACK: Error getting refund key, refund_to not set"; } } @@ -657,7 +668,7 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipien } else { // This should never happen, either. - qWarning() << "PaymentServer::fetchPaymentACK : Error serializing payment message"; + qWarning() << "PaymentServer::fetchPaymentACK: Error serializing payment message"; } } @@ -667,8 +678,7 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply) // BIP70 DoS protection if (reply->size() > BIP70_MAX_PAYMENTREQUEST_SIZE) { - QString msg = tr("Payment request %2 is too large (%3 bytes, allowed %4 bytes).") - .arg(__func__) + QString msg = tr("Payment request %1 is too large (%2 bytes, allowed %3 bytes).") .arg(reply->request().url().toString()) .arg(reply->size()) .arg(BIP70_MAX_PAYMENTREQUEST_SIZE); @@ -697,7 +707,7 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply) SendCoinsRecipient recipient; if (!request.parse(data)) { - qWarning() << "PaymentServer::netRequestFinished : Error parsing payment request"; + qWarning() << "PaymentServer::netRequestFinished: Error parsing payment request"; emit message(tr("Payment request error"), tr("Payment request cannot be parsed!"), CClientUIInterface::MSG_ERROR); @@ -715,7 +725,7 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply) QString msg = tr("Bad response from server %1") .arg(reply->request().url().toString()); - qWarning() << "PaymentServer::netRequestFinished : " << msg; + qWarning() << "PaymentServer::netRequestFinished: " << msg; emit message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR); } else @@ -731,7 +741,7 @@ void PaymentServer::reportSslErrors(QNetworkReply* reply, const QList<QSslError> QString errString; foreach (const QSslError& err, errs) { - qWarning() << "PaymentServer::reportSslErrors : " << err; + qWarning() << "PaymentServer::reportSslErrors: " << err; errString += err.errorString() + "\n"; } emit message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR); @@ -747,3 +757,39 @@ void PaymentServer::handlePaymentACK(const QString& paymentACKMsg) // currently we don't futher process or store the paymentACK message emit message(tr("Payment acknowledged"), paymentACKMsg, CClientUIInterface::ICON_INFORMATION | CClientUIInterface::MODAL); } + +bool PaymentServer::verifyNetwork(const payments::PaymentDetails& requestDetails) +{ + bool fVerified = requestDetails.network() == Params().NetworkIDString(); + if (!fVerified) { + qWarning() << QString("PaymentServer::%1: Payment request network \"%2\" doesn't match client network \"%3\".") + .arg(__func__) + .arg(QString::fromStdString(requestDetails.network())) + .arg(QString::fromStdString(Params().NetworkIDString())); + } + return fVerified; +} + +bool PaymentServer::verifyExpired(const payments::PaymentDetails& requestDetails) +{ + bool fVerified = (requestDetails.has_expires() && (int64_t)requestDetails.expires() < GetTime()); + if (fVerified) { + const QString requestExpires = QString::fromStdString(DateTimeStrFormat("%Y-%m-%d %H:%M:%S", (int64_t)requestDetails.expires())); + qWarning() << QString("PaymentServer::%1: Payment request expired \"%2\".") + .arg(__func__) + .arg(requestExpires); + } + return fVerified; +} + +bool PaymentServer::verifyAmount(const CAmount& requestAmount) +{ + bool fVerified = MoneyRange(requestAmount); + if (!fVerified) { + qWarning() << QString("PaymentServer::%1: Payment request amount out of allowed range (%2, allowed 0 - %3).") + .arg(__func__) + .arg(requestAmount) + .arg(MAX_MONEY); + } + return fVerified; +} diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h index 2fc24395f6..6bf5ac2eea 100644 --- a/src/qt/paymentserver.h +++ b/src/qt/paymentserver.h @@ -91,6 +91,13 @@ public: // This is now public, because we use it in paymentservertests.cpp static bool readPaymentRequestFromFile(const QString& filename, PaymentRequestPlus& request); + // Verify that the payment request network matches the client network + static bool verifyNetwork(const payments::PaymentDetails& requestDetails); + // Verify if the payment request is expired + static bool verifyExpired(const payments::PaymentDetails& requestDetails); + // Verify the payment request amount is valid + static bool verifyAmount(const CAmount& requestAmount); + signals: // Fired when a valid payment request is received void receivedPaymentRequest(SendCoinsRecipient); diff --git a/src/qt/res/icons/about.png b/src/qt/res/icons/about.png Binary files differindex eeef943355..83eb3c07ee 100644 --- a/src/qt/res/icons/about.png +++ b/src/qt/res/icons/about.png diff --git a/src/qt/res/icons/about_qt.png b/src/qt/res/icons/about_qt.png Binary files differindex d3665e9892..dd27a99d0a 100644 --- a/src/qt/res/icons/about_qt.png +++ b/src/qt/res/icons/about_qt.png diff --git a/src/qt/res/icons/add.png b/src/qt/res/icons/add.png Binary files differindex ef995cc0b5..1442b4e85e 100644 --- a/src/qt/res/icons/add.png +++ b/src/qt/res/icons/add.png diff --git a/src/qt/res/icons/address-book.png b/src/qt/res/icons/address-book.png Binary files differindex 0c9238c18e..b11c7d5356 100644 --- a/src/qt/res/icons/address-book.png +++ b/src/qt/res/icons/address-book.png diff --git a/src/qt/res/icons/bitcoin.png b/src/qt/res/icons/bitcoin.png Binary files differindex 705a20260a..435621af23 100644 --- a/src/qt/res/icons/bitcoin.png +++ b/src/qt/res/icons/bitcoin.png diff --git a/src/qt/res/icons/clock1.png b/src/qt/res/icons/clock1.png Binary files differindex 65adba5e21..ceae5ed0d9 100644 --- a/src/qt/res/icons/clock1.png +++ b/src/qt/res/icons/clock1.png diff --git a/src/qt/res/icons/clock2.png b/src/qt/res/icons/clock2.png Binary files differindex 196a79ce4a..159f69a8fc 100644 --- a/src/qt/res/icons/clock2.png +++ b/src/qt/res/icons/clock2.png diff --git a/src/qt/res/icons/clock3.png b/src/qt/res/icons/clock3.png Binary files differindex 3d04655ed9..d668e35ffc 100644 --- a/src/qt/res/icons/clock3.png +++ b/src/qt/res/icons/clock3.png diff --git a/src/qt/res/icons/clock4.png b/src/qt/res/icons/clock4.png Binary files differindex c3210c5af1..5ebf8ed7ac 100644 --- a/src/qt/res/icons/clock4.png +++ b/src/qt/res/icons/clock4.png diff --git a/src/qt/res/icons/clock5.png b/src/qt/res/icons/clock5.png Binary files differindex 84a9fa2842..96f15ef7d9 100644 --- a/src/qt/res/icons/clock5.png +++ b/src/qt/res/icons/clock5.png diff --git a/src/qt/res/icons/configure.png b/src/qt/res/icons/configure.png Binary files differindex fe9c6ec5ec..5333c83d5e 100644 --- a/src/qt/res/icons/configure.png +++ b/src/qt/res/icons/configure.png diff --git a/src/qt/res/icons/connect0.png b/src/qt/res/icons/connect0.png Binary files differindex 99bb2575d6..58e2c3e965 100644 --- a/src/qt/res/icons/connect0.png +++ b/src/qt/res/icons/connect0.png diff --git a/src/qt/res/icons/connect1.png b/src/qt/res/icons/connect1.png Binary files differindex dffc692c76..949e7a922d 100644 --- a/src/qt/res/icons/connect1.png +++ b/src/qt/res/icons/connect1.png diff --git a/src/qt/res/icons/connect2.png b/src/qt/res/icons/connect2.png Binary files differindex 3594fb117c..143b2054fb 100644 --- a/src/qt/res/icons/connect2.png +++ b/src/qt/res/icons/connect2.png diff --git a/src/qt/res/icons/connect3.png b/src/qt/res/icons/connect3.png Binary files differindex 3594fb117c..143b2054fb 100644 --- a/src/qt/res/icons/connect3.png +++ b/src/qt/res/icons/connect3.png diff --git a/src/qt/res/icons/connect4.png b/src/qt/res/icons/connect4.png Binary files differindex 0c667c7e06..f96e3455ce 100644 --- a/src/qt/res/icons/connect4.png +++ b/src/qt/res/icons/connect4.png diff --git a/src/qt/res/icons/debugwindow.png b/src/qt/res/icons/debugwindow.png Binary files differindex 576e57ab03..290fe60864 100644 --- a/src/qt/res/icons/debugwindow.png +++ b/src/qt/res/icons/debugwindow.png diff --git a/src/qt/res/icons/edit.png b/src/qt/res/icons/edit.png Binary files differindex 4df2229e98..46582716ef 100644 --- a/src/qt/res/icons/edit.png +++ b/src/qt/res/icons/edit.png diff --git a/src/qt/res/icons/editcopy.png b/src/qt/res/icons/editcopy.png Binary files differindex db0c51772c..74ac8b2774 100644 --- a/src/qt/res/icons/editcopy.png +++ b/src/qt/res/icons/editcopy.png diff --git a/src/qt/res/icons/editpaste.png b/src/qt/res/icons/editpaste.png Binary files differindex be8634674d..7b47f4d52b 100644 --- a/src/qt/res/icons/editpaste.png +++ b/src/qt/res/icons/editpaste.png diff --git a/src/qt/res/icons/export.png b/src/qt/res/icons/export.png Binary files differindex 18d0596194..ac76cc1eff 100644 --- a/src/qt/res/icons/export.png +++ b/src/qt/res/icons/export.png diff --git a/src/qt/res/icons/eye.png b/src/qt/res/icons/eye.png Binary files differindex 7036708de5..f2f139dbb2 100644 --- a/src/qt/res/icons/eye.png +++ b/src/qt/res/icons/eye.png diff --git a/src/qt/res/icons/eye_minus.png b/src/qt/res/icons/eye_minus.png Binary files differindex bdbe073627..795bf6436a 100644 --- a/src/qt/res/icons/eye_minus.png +++ b/src/qt/res/icons/eye_minus.png diff --git a/src/qt/res/icons/eye_plus.png b/src/qt/res/icons/eye_plus.png Binary files differindex 2ba5e68c76..eaab69297a 100644 --- a/src/qt/res/icons/eye_plus.png +++ b/src/qt/res/icons/eye_plus.png diff --git a/src/qt/res/icons/filesave.png b/src/qt/res/icons/filesave.png Binary files differindex a53390f594..779cca1d52 100644 --- a/src/qt/res/icons/filesave.png +++ b/src/qt/res/icons/filesave.png diff --git a/src/qt/res/icons/history.png b/src/qt/res/icons/history.png Binary files differindex cb723abc5f..68d841fa85 100644 --- a/src/qt/res/icons/history.png +++ b/src/qt/res/icons/history.png diff --git a/src/qt/res/icons/info.png b/src/qt/res/icons/info.png Binary files differindex 085fa8ea73..692b50c2a9 100644 --- a/src/qt/res/icons/info.png +++ b/src/qt/res/icons/info.png diff --git a/src/qt/res/icons/key.png b/src/qt/res/icons/key.png Binary files differindex d21f81364d..f301c4f38c 100644 --- a/src/qt/res/icons/key.png +++ b/src/qt/res/icons/key.png diff --git a/src/qt/res/icons/lock_closed.png b/src/qt/res/icons/lock_closed.png Binary files differindex 77914ab2ce..1bd98b21a6 100644 --- a/src/qt/res/icons/lock_closed.png +++ b/src/qt/res/icons/lock_closed.png diff --git a/src/qt/res/icons/lock_open.png b/src/qt/res/icons/lock_open.png Binary files differindex 50615b7336..a7045133b1 100644 --- a/src/qt/res/icons/lock_open.png +++ b/src/qt/res/icons/lock_open.png diff --git a/src/qt/res/icons/open.png b/src/qt/res/icons/open.png Binary files differindex 390d3dab64..4d958f0e18 100644 --- a/src/qt/res/icons/open.png +++ b/src/qt/res/icons/open.png diff --git a/src/qt/res/icons/overview.png b/src/qt/res/icons/overview.png Binary files differindex 36e1003c3c..411595413d 100644 --- a/src/qt/res/icons/overview.png +++ b/src/qt/res/icons/overview.png diff --git a/src/qt/res/icons/quit.png b/src/qt/res/icons/quit.png Binary files differindex 6e44a2d329..55e34de4b8 100644 --- a/src/qt/res/icons/quit.png +++ b/src/qt/res/icons/quit.png diff --git a/src/qt/res/icons/receive.png b/src/qt/res/icons/receive.png Binary files differindex a53390f594..f4e6f58d05 100644 --- a/src/qt/res/icons/receive.png +++ b/src/qt/res/icons/receive.png diff --git a/src/qt/res/icons/remove.png b/src/qt/res/icons/remove.png Binary files differindex 3849cdd6d8..8e738d6301 100644 --- a/src/qt/res/icons/remove.png +++ b/src/qt/res/icons/remove.png diff --git a/src/qt/res/icons/send.png b/src/qt/res/icons/send.png Binary files differindex 18d0596194..ac76cc1eff 100644 --- a/src/qt/res/icons/send.png +++ b/src/qt/res/icons/send.png diff --git a/src/qt/res/icons/synced.png b/src/qt/res/icons/synced.png Binary files differindex d33914f0b4..5ac28d36a3 100644 --- a/src/qt/res/icons/synced.png +++ b/src/qt/res/icons/synced.png diff --git a/src/qt/res/icons/transaction0.png b/src/qt/res/icons/transaction0.png Binary files differindex fd41da0680..1091b86e68 100644 --- a/src/qt/res/icons/transaction0.png +++ b/src/qt/res/icons/transaction0.png diff --git a/src/qt/res/icons/transaction2.png b/src/qt/res/icons/transaction2.png Binary files differindex d33914f0b4..5ac28d36a3 100644 --- a/src/qt/res/icons/transaction2.png +++ b/src/qt/res/icons/transaction2.png diff --git a/src/qt/res/icons/transaction_conflicted.png b/src/qt/res/icons/transaction_conflicted.png Binary files differindex 6e44a2d329..55e34de4b8 100644 --- a/src/qt/res/icons/transaction_conflicted.png +++ b/src/qt/res/icons/transaction_conflicted.png diff --git a/src/qt/res/icons/tx_inout.png b/src/qt/res/icons/tx_inout.png Binary files differindex cecd332ad1..0a6e72a898 100644 --- a/src/qt/res/icons/tx_inout.png +++ b/src/qt/res/icons/tx_inout.png diff --git a/src/qt/res/icons/tx_input.png b/src/qt/res/icons/tx_input.png Binary files differindex 1b4cfd967c..9e9ee92932 100644 --- a/src/qt/res/icons/tx_input.png +++ b/src/qt/res/icons/tx_input.png diff --git a/src/qt/res/icons/tx_mined.png b/src/qt/res/icons/tx_mined.png Binary files differindex 421a9cf639..5a6ef521c0 100644 --- a/src/qt/res/icons/tx_mined.png +++ b/src/qt/res/icons/tx_mined.png diff --git a/src/qt/res/icons/tx_output.png b/src/qt/res/icons/tx_output.png Binary files differindex 06d9d0adf2..6f66ab6547 100644 --- a/src/qt/res/icons/tx_output.png +++ b/src/qt/res/icons/tx_output.png diff --git a/src/qt/res/icons/unit_btc.png b/src/qt/res/icons/unit_btc.png Binary files differdeleted file mode 100644 index f3246fa999..0000000000 --- a/src/qt/res/icons/unit_btc.png +++ /dev/null diff --git a/src/qt/res/icons/unit_mbtc.png b/src/qt/res/icons/unit_mbtc.png Binary files differdeleted file mode 100644 index 4e82b65274..0000000000 --- a/src/qt/res/icons/unit_mbtc.png +++ /dev/null diff --git a/src/qt/res/icons/unit_ubtc.png b/src/qt/res/icons/unit_ubtc.png Binary files differdeleted file mode 100644 index 96b254770d..0000000000 --- a/src/qt/res/icons/unit_ubtc.png +++ /dev/null diff --git a/src/qt/res/icons/verify.png b/src/qt/res/icons/verify.png Binary files differindex 9ff35c2793..8e2cb2cc14 100644 --- a/src/qt/res/icons/verify.png +++ b/src/qt/res/icons/verify.png diff --git a/src/qt/res/images/about.png b/src/qt/res/images/about.png Binary files differdeleted file mode 100644 index fdede66172..0000000000 --- a/src/qt/res/images/about.png +++ /dev/null diff --git a/src/qt/res/movies/spinner-000.png b/src/qt/res/movies/spinner-000.png Binary files differindex b296a58481..1e92d859da 100644 --- a/src/qt/res/movies/spinner-000.png +++ b/src/qt/res/movies/spinner-000.png diff --git a/src/qt/res/movies/spinner-001.png b/src/qt/res/movies/spinner-001.png Binary files differindex 4f6f9a487b..d167f20541 100644 --- a/src/qt/res/movies/spinner-001.png +++ b/src/qt/res/movies/spinner-001.png diff --git a/src/qt/res/movies/spinner-002.png b/src/qt/res/movies/spinner-002.png Binary files differindex 4f14e3ca93..4a1f1f8e56 100644 --- a/src/qt/res/movies/spinner-002.png +++ b/src/qt/res/movies/spinner-002.png diff --git a/src/qt/res/movies/spinner-003.png b/src/qt/res/movies/spinner-003.png Binary files differindex d7756e73bf..fb1c2cd4ad 100644 --- a/src/qt/res/movies/spinner-003.png +++ b/src/qt/res/movies/spinner-003.png diff --git a/src/qt/res/movies/spinner-004.png b/src/qt/res/movies/spinner-004.png Binary files differindex 4b381b81b2..4df2132344 100644 --- a/src/qt/res/movies/spinner-004.png +++ b/src/qt/res/movies/spinner-004.png diff --git a/src/qt/res/movies/spinner-005.png b/src/qt/res/movies/spinner-005.png Binary files differindex cbdb5b5797..5d6f41e0dc 100644 --- a/src/qt/res/movies/spinner-005.png +++ b/src/qt/res/movies/spinner-005.png diff --git a/src/qt/res/movies/spinner-006.png b/src/qt/res/movies/spinner-006.png Binary files differindex 55d4540c92..c1f7d18899 100644 --- a/src/qt/res/movies/spinner-006.png +++ b/src/qt/res/movies/spinner-006.png diff --git a/src/qt/res/movies/spinner-007.png b/src/qt/res/movies/spinner-007.png Binary files differindex b25f59a445..1e794b2626 100644 --- a/src/qt/res/movies/spinner-007.png +++ b/src/qt/res/movies/spinner-007.png diff --git a/src/qt/res/movies/spinner-008.png b/src/qt/res/movies/spinner-008.png Binary files differindex 6493184a7a..df12ea8719 100644 --- a/src/qt/res/movies/spinner-008.png +++ b/src/qt/res/movies/spinner-008.png diff --git a/src/qt/res/movies/spinner-009.png b/src/qt/res/movies/spinner-009.png Binary files differindex 938c49f9d3..18fc3a7d16 100644 --- a/src/qt/res/movies/spinner-009.png +++ b/src/qt/res/movies/spinner-009.png diff --git a/src/qt/res/movies/spinner-010.png b/src/qt/res/movies/spinner-010.png Binary files differindex 7eb645eda5..a79c845fe8 100644 --- a/src/qt/res/movies/spinner-010.png +++ b/src/qt/res/movies/spinner-010.png diff --git a/src/qt/res/movies/spinner-011.png b/src/qt/res/movies/spinner-011.png Binary files differindex fd4b63ca5a..57baf66895 100644 --- a/src/qt/res/movies/spinner-011.png +++ b/src/qt/res/movies/spinner-011.png diff --git a/src/qt/res/movies/spinner-012.png b/src/qt/res/movies/spinner-012.png Binary files differindex 10d26a3a53..9deae7853a 100644 --- a/src/qt/res/movies/spinner-012.png +++ b/src/qt/res/movies/spinner-012.png diff --git a/src/qt/res/movies/spinner-013.png b/src/qt/res/movies/spinner-013.png Binary files differindex 863a9d2908..0659d48dec 100644 --- a/src/qt/res/movies/spinner-013.png +++ b/src/qt/res/movies/spinner-013.png diff --git a/src/qt/res/movies/spinner-014.png b/src/qt/res/movies/spinner-014.png Binary files differindex d01086cb98..bc1ef51bde 100644 --- a/src/qt/res/movies/spinner-014.png +++ b/src/qt/res/movies/spinner-014.png diff --git a/src/qt/res/movies/spinner-015.png b/src/qt/res/movies/spinner-015.png Binary files differindex 402dbea693..24b57b62c2 100644 --- a/src/qt/res/movies/spinner-015.png +++ b/src/qt/res/movies/spinner-015.png diff --git a/src/qt/res/movies/spinner-016.png b/src/qt/res/movies/spinner-016.png Binary files differindex 1db20e6078..d622872651 100644 --- a/src/qt/res/movies/spinner-016.png +++ b/src/qt/res/movies/spinner-016.png diff --git a/src/qt/res/movies/spinner-017.png b/src/qt/res/movies/spinner-017.png Binary files differindex e2c2e2ef78..f48f688db2 100644 --- a/src/qt/res/movies/spinner-017.png +++ b/src/qt/res/movies/spinner-017.png diff --git a/src/qt/res/movies/spinner-018.png b/src/qt/res/movies/spinner-018.png Binary files differindex 6f1fe73756..a2c8f38b1d 100644 --- a/src/qt/res/movies/spinner-018.png +++ b/src/qt/res/movies/spinner-018.png diff --git a/src/qt/res/movies/spinner-019.png b/src/qt/res/movies/spinner-019.png Binary files differindex 5f18f65608..9d7cc35d82 100644 --- a/src/qt/res/movies/spinner-019.png +++ b/src/qt/res/movies/spinner-019.png diff --git a/src/qt/res/movies/spinner-020.png b/src/qt/res/movies/spinner-020.png Binary files differindex c12ae20016..1a07acc454 100644 --- a/src/qt/res/movies/spinner-020.png +++ b/src/qt/res/movies/spinner-020.png diff --git a/src/qt/res/movies/spinner-021.png b/src/qt/res/movies/spinner-021.png Binary files differindex d81ceade23..9cea8f2543 100644 --- a/src/qt/res/movies/spinner-021.png +++ b/src/qt/res/movies/spinner-021.png diff --git a/src/qt/res/movies/spinner-022.png b/src/qt/res/movies/spinner-022.png Binary files differindex 69c6657942..60250f6dea 100644 --- a/src/qt/res/movies/spinner-022.png +++ b/src/qt/res/movies/spinner-022.png diff --git a/src/qt/res/movies/spinner-023.png b/src/qt/res/movies/spinner-023.png Binary files differindex 7bed5bae85..fc290a0cf2 100644 --- a/src/qt/res/movies/spinner-023.png +++ b/src/qt/res/movies/spinner-023.png diff --git a/src/qt/res/movies/spinner-024.png b/src/qt/res/movies/spinner-024.png Binary files differindex b3be8d3e8e..c5dcf1eae9 100644 --- a/src/qt/res/movies/spinner-024.png +++ b/src/qt/res/movies/spinner-024.png diff --git a/src/qt/res/movies/spinner-025.png b/src/qt/res/movies/spinner-025.png Binary files differindex 3a7fa9ab0d..7f3577a4de 100644 --- a/src/qt/res/movies/spinner-025.png +++ b/src/qt/res/movies/spinner-025.png diff --git a/src/qt/res/movies/spinner-026.png b/src/qt/res/movies/spinner-026.png Binary files differindex dd92fc4fc1..1663ddf44c 100644 --- a/src/qt/res/movies/spinner-026.png +++ b/src/qt/res/movies/spinner-026.png diff --git a/src/qt/res/movies/spinner-027.png b/src/qt/res/movies/spinner-027.png Binary files differindex 9adefee268..d0e6da4503 100644 --- a/src/qt/res/movies/spinner-027.png +++ b/src/qt/res/movies/spinner-027.png diff --git a/src/qt/res/movies/spinner-028.png b/src/qt/res/movies/spinner-028.png Binary files differindex 83e7cdd583..2a7aba50e2 100644 --- a/src/qt/res/movies/spinner-028.png +++ b/src/qt/res/movies/spinner-028.png diff --git a/src/qt/res/movies/spinner-029.png b/src/qt/res/movies/spinner-029.png Binary files differindex 6cbdbb0fe1..c8ca15c1e1 100644 --- a/src/qt/res/movies/spinner-029.png +++ b/src/qt/res/movies/spinner-029.png diff --git a/src/qt/res/movies/spinner-030.png b/src/qt/res/movies/spinner-030.png Binary files differindex e4a09a44bc..c847c99a93 100644 --- a/src/qt/res/movies/spinner-030.png +++ b/src/qt/res/movies/spinner-030.png diff --git a/src/qt/res/movies/spinner-031.png b/src/qt/res/movies/spinner-031.png Binary files differindex 3c3d505741..403443144e 100644 --- a/src/qt/res/movies/spinner-031.png +++ b/src/qt/res/movies/spinner-031.png diff --git a/src/qt/res/movies/spinner-032.png b/src/qt/res/movies/spinner-032.png Binary files differindex 7460f80da3..f9db080567 100644 --- a/src/qt/res/movies/spinner-032.png +++ b/src/qt/res/movies/spinner-032.png diff --git a/src/qt/res/movies/spinner-033.png b/src/qt/res/movies/spinner-033.png Binary files differindex d327e8fb08..43f57719e7 100644 --- a/src/qt/res/movies/spinner-033.png +++ b/src/qt/res/movies/spinner-033.png diff --git a/src/qt/res/movies/spinner-034.png b/src/qt/res/movies/spinner-034.png Binary files differindex d8432751da..c26656ff17 100644 --- a/src/qt/res/movies/spinner-034.png +++ b/src/qt/res/movies/spinner-034.png diff --git a/src/qt/res/movies/spinner-035.png b/src/qt/res/movies/spinner-035.png Binary files differindex c89c959c94..e471f950a3 100644 --- a/src/qt/res/movies/spinner-035.png +++ b/src/qt/res/movies/spinner-035.png diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index a5e3ae2b35..9f3991c4c5 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -610,6 +610,7 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats) ui->peerBytesRecv->setText(FormatBytes(stats->nodeStats.nRecvBytes)); ui->peerConnTime->setText(GUIUtil::formatDurationStr(GetTime() - stats->nodeStats.nTimeConnected)); ui->peerPingTime->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingTime)); + ui->timeoffset->setText(GUIUtil::formatTimeOffset(stats->nodeStats.nTimeOffset)); ui->peerVersion->setText(QString("%1").arg(stats->nodeStats.nVersion)); ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer)); ui->peerDirection->setText(stats->nodeStats.fInbound ? tr("Inbound") : tr("Outbound")); diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index ffee56131d..5aef2d7539 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -526,8 +526,12 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn msgParams.first = tr("The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."); msgParams.second = CClientUIInterface::MSG_ERROR; break; - case WalletModel::InsaneFee: - msgParams.first = tr("A fee higher than %1 is considered an insanely high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), 10000000)); + case WalletModel::AbsurdFee: + msgParams.first = tr("A fee higher than %1 is considered an absurdly high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), 10000000)); + break; + case WalletModel::PaymentRequestExpired: + msgParams.first = tr("Payment request expired!"); + msgParams.second = CClientUIInterface::MSG_ERROR; break; // included to prevent a compiler warning. case WalletModel::OK: @@ -657,19 +661,19 @@ void SendCoinsDialog::coinControlClipboardAmount() // Coin Control: copy label "Fee" to clipboard void SendCoinsDialog::coinControlClipboardFee() { - GUIUtil::setClipboard(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" ")).replace("~", "")); + GUIUtil::setClipboard(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" ")).replace(ASYMP_UTF8, "")); } // Coin Control: copy label "After fee" to clipboard void SendCoinsDialog::coinControlClipboardAfterFee() { - GUIUtil::setClipboard(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" ")).replace("~", "")); + GUIUtil::setClipboard(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" ")).replace(ASYMP_UTF8, "")); } // Coin Control: copy label "Bytes" to clipboard void SendCoinsDialog::coinControlClipboardBytes() { - GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace("~", "")); + GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace(ASYMP_UTF8, "")); } // Coin Control: copy label "Priority" to clipboard @@ -687,7 +691,7 @@ void SendCoinsDialog::coinControlClipboardLowOutput() // Coin Control: copy label "Change" to clipboard void SendCoinsDialog::coinControlClipboardChange() { - GUIUtil::setClipboard(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" ")).replace("~", "")); + GUIUtil::setClipboard(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" ")).replace(ASYMP_UTF8, "")); } // Coin Control: settings menu - coin control enabled/disabled by user diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 366ed3df3d..e6a7fcaec5 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -42,7 +42,7 @@ SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle) QString copyrightText = QChar(0xA9)+QString(" 2009-%1 ").arg(COPYRIGHT_YEAR) + QString(tr("The Bitcoin Core developers")); QString titleAddText = networkStyle->getTitleAddText(); - QString font = "Arial"; + QString font = QApplication::font().toString(); // create a bitmap according to device pixelratio QSize splashSize(480*devicePixelRatio,320*devicePixelRatio); diff --git a/src/qt/test/paymentrequestdata.h b/src/qt/test/paymentrequestdata.h index 37544cdebb..c548ffe429 100644 --- a/src/qt/test/paymentrequestdata.h +++ b/src/qt/test/paymentrequestdata.h @@ -6,16 +6,16 @@ // Data for paymentservertests.cpp // -// Base64/DER-encoded fake certificate authority certificate. +// Base64/DER-encoded fake certificate authority certificates. // Convert pem to base64/der with: -// cat file.pem | openssl x509 -inform PEM -outform DER | openssl enc -base64 -// +// openssl x509 -in cert.pem -inform PEM -outform DER | openssl enc -base64 + // Serial Number: 10302349811211485352 (0x8ef94c91b112c0a8) // Issuer: CN=PaymentRequest Test CA // Subject: CN=PaymentRequest Test CA // Not Valid After : Dec 8 16:37:24 2022 GMT // -const char* caCert_BASE64 = +const char* caCert1_BASE64 = "\ MIIB0DCCATmgAwIBAgIJAI75TJGxEsCoMA0GCSqGSIb3DQEBCwUAMCExHzAdBgNV\ BAMTFlBheW1lbnRSZXF1ZXN0IFRlc3QgQ0EwHhcNMTIxMjEwMTYzNzI0WhcNMjIx\ @@ -29,11 +29,36 @@ RtQcf0AJ9olzUMY4syehxbzUJP6aeXhZEYiMvdvcv9D55clq6+WLLlNT3jBgAaVn\ p3waRjPD4bUX3nv+ojz5s4puw7Qq5QUZlhGsMzPvwDGCmZkL\ "; +// Serial Number: f0:da:97:e4:38:d7:64:16 +// Issuer: CN=PaymentRequest Test CA +// Subject: CN=PaymentRequest Test CA +// Not Valid After : Jan 8 18:21:06 2025 GMT +// +const char* caCert2_BASE64 = +"\ +MIIC1TCCAb2gAwIBAgIJAPDal+Q412QWMA0GCSqGSIb3DQEBCwUAMCExHzAdBgNV\ +BAMMFlBheW1lbnRSZXF1ZXN0IFRlc3QgQ0EwHhcNMTUwMTExMTgyMTA2WhcNMjUw\ +MTA4MTgyMTA2WjAhMR8wHQYDVQQDDBZQYXltZW50UmVxdWVzdCBUZXN0IENBMIIB\ +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1S9wVLfTplJuT/1OaaBgl/Mb\ +I392v8S9kHbzYz7B4OTMslaO7piz0v3SO3TKMh0dswjiRdHrIgpO7XdIUQiU/ugg\ +xDw0kuNehfz1ycaGedlFFtFHTNXqLyIUF3dlwHhQwaomM6RXoJmxLny5BhYHEcmk\ +yWwr3Cdjd9gAZpblugVJB9C1e40uyL8ao4PHdLzOqO27iSe6riP8SwwisJZEbMaz\ +AZpgNEEMbIXPJEFvm5HTRXSMtQCOTSZYMFF0M2yrtmlECnz7hWP19b9bcoDzZQB4\ +ylIsFG/7q2jV7MC/e2STZv+niJiHL08RUdoFpAgzaxMgqj63C7B55HgNDNHJYQID\ +AQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBGejPxLxj9\ ++crv6gUeEBMZPiUx7pUgcI22Wm5yymP96B4fwI3Y0DBehq20d76vbWGPN17Z6pH3\ +ge7PVY1SYqXtS6hXTo4olCm/BZADli+2Bs2xCiaa+Ltve4ufVej+bKJXN/YnrhvO\ +Kq+klQkuuHywU+GJV/NQeBqToIrSOBgi477NgLFCCCmmx2QWsxHoCFGfuRCBVseT\ +z2k/tMuALCDXGeZBRPTsGHu1y4cj84swAeoDK5QSQcI+Ub7GKc+zkoj02sdDLiMo\ +3wokYPcIy47oclhmb4xubHc+y7nF610yZBoC/zgbhbawnZ65hDDWkdQ/SVAnWZD7\ +9PFfmNnYPTQH\ +"; + // // This payment request validates directly against the -// above certificate authority. +// caCert1 certificate authority. // -const char* paymentrequest1_BASE64 = +const char* paymentrequest1_cert1_BASE64 = "\ Egt4NTA5K3NoYTI1NhrxAwruAzCCAeowggFToAMCAQICAQEwDQYJKoZIhvcNAQEL\ BQAwITEfMB0GA1UEAxMWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xMjEyMTAx\ @@ -55,7 +80,7 @@ SiWVbw0tX/68iSQEGGfh9n6ee/8Myb3ICdw=\ // // Signed, but expired, merchant cert in the request // -const char* paymentrequest2_BASE64 = +const char* paymentrequest2_cert1_BASE64 = "\ Egt4NTA5K3NoYTI1NhrsAwrpAzCCAeUwggFOoAMCAQICAQMwDQYJKoZIhvcNAQEL\ BQAwITEfMB0GA1UEAxMWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xMzAyMjMy\ @@ -75,9 +100,9 @@ tejrSPOBNSJ3Mi/q5u2Yl4gJZY2b\ "; // -// 10-long chain, all intermediates valid +// 10-long certificate chain, all intermediates valid // -const char* paymentrequest3_BASE64 = +const char* paymentrequest3_cert1_BASE64 = "\ Egt4NTA5K3NoYTI1Nhq8JAr/AzCCAfswggFkoAMCAQICAQEwDQYJKoZIhvcNAQEL\ BQAwPzEUMBIGA1UEAwwLdGVzdGNhOC5vcmcxJzAlBgNVBAoMHlBheW1lbnQgUmVx\ @@ -184,9 +209,9 @@ chhR/aHOuEMTxmc12K4rNlgYtHCsxLP9zd+6u0cva3TucZ6EzS8PKEib/+r12/52\ "; // -// Long chain, with an invalid (expired) cert in the middle +// Long certificate chain, with an expired certificate in the middle // -const char* paymentrequest4_BASE64 = +const char* paymentrequest4_cert1_BASE64 = "\ Egt4NTA5K3NoYTI1NhqeJAr/AzCCAfswggFkoAMCAQICAQEwDQYJKoZIhvcNAQEL\ BQAwPzEUMBIGA1UEAwwLdGVzdGNhOC5vcmcxJzAlBgNVBAoMHlBheW1lbnQgUmVx\ @@ -291,7 +316,10 @@ HXQjsfdR58qZQS9CS5DAtRUf0R8+43/wijO/hb49VNaNXmY+/cPHMkahP2aV3tZi\ FAyZblLik9A7ZvF+UsjeFQiHB5wzWQvbqk5wQ4yabHIXoYv/E0q+eQ==\ "; -const char* paymentrequest5_BASE64 = +// +// Validly signed, but by a CA not in our root CA list +// +const char* paymentrequest5_cert1_BASE64 = "\ Egt4NTA5K3NoYTI1NhrxAwruAzCCAeowggFToAMCAQICAQEwDQYJKoZIhvcNAQEL\ BQAwITEfMB0GA1UEAxMWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xMzA0MTkx\ @@ -309,3 +337,124 @@ ssymvca1S/1KeM3n8Ydi2fi1JUzAAr59xPvNJRUeqCLP9upHn5z7br3P12Oz9A20\ 5/4wL4ClPRPVnOHgij0bEg+y0tGESqmF1rfOfXDszlo2U92wCxS07kq79YAZJ1Zo\ XYh860/Q4wvc7lfiTe+dXBzPKAKhMy91yETY\ "; + +// +// Contains a testnet paytoaddress, so payment request network doesn't match client network +// +const char* paymentrequest1_cert2_BASE64 = +"\ +Egt4NTA5K3NoYTI1NhrQBArNBDCCAkkwggExoAMCAQICAQEwDQYJKoZIhvcNAQEL\ +BQAwITEfMB0GA1UEAwwWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xNTAxMTEx\ +ODIxMDhaFw0yNTAxMDgxODIxMDhaMCExHzAdBgNVBAMMFlBheW1lbnRSZXF1ZXN0\ +IFRlc3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMsZqzkzeBGo+i2N\ +mUak3Ciodr1V7S062VOy7N0OQYNDQHYkgDFAUET7cEb5VJaHPv5m3ppTBpU9xBcf\ +wbHHUt4VjA+mhRmYrl1khjvZM+X8kEqvWn20BtcM9R6r0yIYec8UERDDHBleL/P8\ +RkxEnVLjYTV9zigCXfMsgYb3EQShAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJ\ +KoZIhvcNAQELBQADggEBABUJpl3QCqsoDSxAsQdV6zKT4VGV76AzoGj7etQsQY+r\ ++S26VfWh/fMobEzuxFChr0USgLJ6FoK78hAtoZvt1lrye9yqFv/ig3WLWsJKWHHb\ +3RT6oR03CIwZXFSUasi08QDVLxafwsU5OMcPLucF3a1lRL1ccYrNgVCCx1+X7Bos\ +tIgDGRQQ4AyoHTcfVd2hEGeUv7k14mOxFsAp6851yosHq9Q2kwmdH+rHEJbjof87\ +yyKLagc4owyXBZYkQmkeHWCNqnuRmO5vUsfVb0UUrkD64o7Th/NjwooA7SCiUXl6\ +dfygT1b7ggpx7GC+sP2DsIM47IAZ55drjqX5u2f+Ba0iPQoEdGVzdBIhCIDWwowE\ +Ehl2qRQErGqUUwSsaMpDvWIaGnJGNQqi8oisGNeMy6UFKgxKdXN0IFRlc3Rpbmcq\ +gAFwThsozZxkZxzCn4R8WxNiLFV6m0ye9fEtSbolfaW+EjBMpO03lr/dwNnrclhg\ +ew+A05xfZztrAt16XKEY7qKJ/eY2nLd0fVAIu/nIt+7/VYVXT83zLrWc150aRS7W\ +AdJbL3JOJLs6Eyp5zrPbfI8faRttFAdONKDrJgIpuW1E3g==\ +"; + +// +// Expired payment request (expires is set to 1 = 1970-01-01 00:00:01) +// +const char* paymentrequest2_cert2_BASE64 = +"\ +Egt4NTA5K3NoYTI1NhrQBArNBDCCAkkwggExoAMCAQICAQEwDQYJKoZIhvcNAQEL\ +BQAwITEfMB0GA1UEAwwWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xNTAxMTEx\ +ODIxMDhaFw0yNTAxMDgxODIxMDhaMCExHzAdBgNVBAMMFlBheW1lbnRSZXF1ZXN0\ +IFRlc3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMsZqzkzeBGo+i2N\ +mUak3Ciodr1V7S062VOy7N0OQYNDQHYkgDFAUET7cEb5VJaHPv5m3ppTBpU9xBcf\ +wbHHUt4VjA+mhRmYrl1khjvZM+X8kEqvWn20BtcM9R6r0yIYec8UERDDHBleL/P8\ +RkxEnVLjYTV9zigCXfMsgYb3EQShAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJ\ +KoZIhvcNAQELBQADggEBABUJpl3QCqsoDSxAsQdV6zKT4VGV76AzoGj7etQsQY+r\ ++S26VfWh/fMobEzuxFChr0USgLJ6FoK78hAtoZvt1lrye9yqFv/ig3WLWsJKWHHb\ +3RT6oR03CIwZXFSUasi08QDVLxafwsU5OMcPLucF3a1lRL1ccYrNgVCCx1+X7Bos\ +tIgDGRQQ4AyoHTcfVd2hEGeUv7k14mOxFsAp6851yosHq9Q2kwmdH+rHEJbjof87\ +yyKLagc4owyXBZYkQmkeHWCNqnuRmO5vUsfVb0UUrkD64o7Th/NjwooA7SCiUXl6\ +dfygT1b7ggpx7GC+sP2DsIM47IAZ55drjqX5u2f+Ba0iQgoEdGVzdBIgCICt4gQS\ +GXapFASsapRTBKxoykO9YhoackY1CqLyiKwYiNLUpQUgASoQVGVzdGluZyB0ZXN0\ +bmV0ISqAATXq9A5nmJgtmee/bQTeHeif4w1YYFPBlKghwx6qbVgXTWnwBJtOQhhV\ +sZdzbTl95ENR7/Y7VJupW9kDWobCK7zUUhLAzUlwmLlcx6itHw8LTUF5HK+AwsZm\ +Zs85lISGvOS0NZW/ENa6l+oQRnL87oqVZr/EDGiuqjz6T0ThQi0l\ +"; + +// +// Unexpired payment request (expires is set to 0x7FFFFFFFFFFFFFFF = max. int64_t) +// +const char* paymentrequest3_cert2_BASE64 = +"\ +Egt4NTA5K3NoYTI1NhrQBArNBDCCAkkwggExoAMCAQICAQEwDQYJKoZIhvcNAQEL\ +BQAwITEfMB0GA1UEAwwWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xNTAxMTEx\ +ODIxMDhaFw0yNTAxMDgxODIxMDhaMCExHzAdBgNVBAMMFlBheW1lbnRSZXF1ZXN0\ +IFRlc3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMsZqzkzeBGo+i2N\ +mUak3Ciodr1V7S062VOy7N0OQYNDQHYkgDFAUET7cEb5VJaHPv5m3ppTBpU9xBcf\ +wbHHUt4VjA+mhRmYrl1khjvZM+X8kEqvWn20BtcM9R6r0yIYec8UERDDHBleL/P8\ +RkxEnVLjYTV9zigCXfMsgYb3EQShAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJ\ +KoZIhvcNAQELBQADggEBABUJpl3QCqsoDSxAsQdV6zKT4VGV76AzoGj7etQsQY+r\ ++S26VfWh/fMobEzuxFChr0USgLJ6FoK78hAtoZvt1lrye9yqFv/ig3WLWsJKWHHb\ +3RT6oR03CIwZXFSUasi08QDVLxafwsU5OMcPLucF3a1lRL1ccYrNgVCCx1+X7Bos\ +tIgDGRQQ4AyoHTcfVd2hEGeUv7k14mOxFsAp6851yosHq9Q2kwmdH+rHEJbjof87\ +yyKLagc4owyXBZYkQmkeHWCNqnuRmO5vUsfVb0UUrkD64o7Th/NjwooA7SCiUXl6\ +dfygT1b7ggpx7GC+sP2DsIM47IAZ55drjqX5u2f+Ba0iSgoEdGVzdBIgCICt4gQS\ +GXapFASsapRTBKxoykO9YhoackY1CqLyiKwYyNfZpQUg//////////9/KhBUZXN0\ +aW5nIHRlc3RuZXQhKoABNwi8WnMW4aMvbmvorTiiWJLFhofLFnsoWCJnj3rWLnLh\ +n3w6q/fZ26p50ERL/noxdTUfeFsKnlECkUu/fOcOrqyYDiwvxI0SZ034DleVyFU1\ +Z3T+X0zcL8oe7bX01Yf+s2V+5JXQXarKnKBrZCGgv2ARjFNSZe7E7vGg5K4Q6Q8=\ +"; + +// +// Unexpired payment request (expires is set to 0x8000000000000000 > max. int64_t, allowed uint64) +// +const char* paymentrequest4_cert2_BASE64 = +"\ +Egt4NTA5K3NoYTI1NhrQBArNBDCCAkkwggExoAMCAQICAQEwDQYJKoZIhvcNAQEL\ +BQAwITEfMB0GA1UEAwwWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xNTAxMTEx\ +ODIxMDhaFw0yNTAxMDgxODIxMDhaMCExHzAdBgNVBAMMFlBheW1lbnRSZXF1ZXN0\ +IFRlc3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMsZqzkzeBGo+i2N\ +mUak3Ciodr1V7S062VOy7N0OQYNDQHYkgDFAUET7cEb5VJaHPv5m3ppTBpU9xBcf\ +wbHHUt4VjA+mhRmYrl1khjvZM+X8kEqvWn20BtcM9R6r0yIYec8UERDDHBleL/P8\ +RkxEnVLjYTV9zigCXfMsgYb3EQShAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJ\ +KoZIhvcNAQELBQADggEBABUJpl3QCqsoDSxAsQdV6zKT4VGV76AzoGj7etQsQY+r\ ++S26VfWh/fMobEzuxFChr0USgLJ6FoK78hAtoZvt1lrye9yqFv/ig3WLWsJKWHHb\ +3RT6oR03CIwZXFSUasi08QDVLxafwsU5OMcPLucF3a1lRL1ccYrNgVCCx1+X7Bos\ +tIgDGRQQ4AyoHTcfVd2hEGeUv7k14mOxFsAp6851yosHq9Q2kwmdH+rHEJbjof87\ +yyKLagc4owyXBZYkQmkeHWCNqnuRmO5vUsfVb0UUrkD64o7Th/NjwooA7SCiUXl6\ +dfygT1b7ggpx7GC+sP2DsIM47IAZ55drjqX5u2f+Ba0iSwoEdGVzdBIgCICt4gQS\ +GXapFASsapRTBKxoykO9YhoackY1CqLyiKwYt+HZpQUggICAgICAgICAASoQVGVz\ +dGluZyB0ZXN0bmV0ISqAAXSQG8+GFA18VaKarlYrOz293rNMIub0swKGcQm8jAGX\ +HSLaRgHfUDeEPr4hydy4dtfu59KNwe2xsHOHu/SpO4L8SrA4Dm9A7SlNBVWdcLbw\ +d2hj739GDLz0b5KuJ2SG6VknMRQM976w/m2qlq0ccVGaaZ2zMIGfpzL3p6adwx/5\ +"; + +// +// Payment request with amount overflow (amount is set to 21000001 BTC) +// +const char* paymentrequest5_cert2_BASE64 = +"\ +Egt4NTA5K3NoYTI1NhrQBArNBDCCAkkwggExoAMCAQICAQEwDQYJKoZIhvcNAQEL\ +BQAwITEfMB0GA1UEAwwWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xNTAxMTEx\ +ODIxMDhaFw0yNTAxMDgxODIxMDhaMCExHzAdBgNVBAMMFlBheW1lbnRSZXF1ZXN0\ +IFRlc3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMsZqzkzeBGo+i2N\ +mUak3Ciodr1V7S062VOy7N0OQYNDQHYkgDFAUET7cEb5VJaHPv5m3ppTBpU9xBcf\ +wbHHUt4VjA+mhRmYrl1khjvZM+X8kEqvWn20BtcM9R6r0yIYec8UERDDHBleL/P8\ +RkxEnVLjYTV9zigCXfMsgYb3EQShAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJ\ +KoZIhvcNAQELBQADggEBABUJpl3QCqsoDSxAsQdV6zKT4VGV76AzoGj7etQsQY+r\ ++S26VfWh/fMobEzuxFChr0USgLJ6FoK78hAtoZvt1lrye9yqFv/ig3WLWsJKWHHb\ +3RT6oR03CIwZXFSUasi08QDVLxafwsU5OMcPLucF3a1lRL1ccYrNgVCCx1+X7Bos\ +tIgDGRQQ4AyoHTcfVd2hEGeUv7k14mOxFsAp6851yosHq9Q2kwmdH+rHEJbjof87\ +yyKLagc4owyXBZYkQmkeHWCNqnuRmO5vUsfVb0UUrkD64o7Th/NjwooA7SCiUXl6\ +dfygT1b7ggpx7GC+sP2DsIM47IAZ55drjqX5u2f+Ba0iTAoEdGVzdBIkCIDC9P+F\ +vt0DEhl2qRQErGqUUwSsaMpDvWIaGnJGNQqi8oisGLzcrKYFKhhUZXN0aW5nIGFt\ +b3VudCBvdmVyZmxvdyEqgAG8S7WEDUC6tCL6q2CTBjop/AitgEy31RL9IqYruytR\ +iEBFUrBDJZU+UEezGwr7/zoECjo5ZY3PmtZcM2sILNjyweJF6XVzGqTxUw6pN6sW\ +XR2T3Gy2LzRvhVA25QgGqpz0/juS2BtmNbsZPkN9gMMwKimgzc+PuCzmEKwPK9cQ\ +YQ==\ +"; diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp index 70254cd75d..e2ec439b2e 100644 --- a/src/qt/test/paymentservertests.cpp +++ b/src/qt/test/paymentservertests.cpp @@ -7,7 +7,10 @@ #include "optionsmodel.h" #include "paymentrequestdata.h" +#include "amount.h" #include "random.h" +#include "script/script.h" +#include "script/standard.h" #include "util.h" #include "utilstrencodings.h" @@ -65,38 +68,44 @@ void PaymentServerTests::paymentServerTests() OptionsModel optionsModel; PaymentServer* server = new PaymentServer(NULL, false); X509_STORE* caStore = X509_STORE_new(); - X509_STORE_add_cert(caStore, parse_b64der_cert(caCert_BASE64)); + X509_STORE_add_cert(caStore, parse_b64der_cert(caCert1_BASE64)); PaymentServer::LoadRootCAs(caStore); server->setOptionsModel(&optionsModel); server->uiReady(); - // Now feed PaymentRequests to server, and observe signals it produces: - std::vector<unsigned char> data = DecodeBase64(paymentrequest1_BASE64); - SendCoinsRecipient r = handleRequest(server, data); + std::vector<unsigned char> data; + SendCoinsRecipient r; QString merchant; + + // Now feed PaymentRequests to server, and observe signals it produces + + // This payment request validates directly against the + // caCert1 certificate authority: + data = DecodeBase64(paymentrequest1_cert1_BASE64); + r = handleRequest(server, data); r.paymentRequest.getMerchant(caStore, merchant); QCOMPARE(merchant, QString("testmerchant.org")); - // Version of the above, with an expired certificate: - data = DecodeBase64(paymentrequest2_BASE64); + // Signed, but expired, merchant cert in the request: + data = DecodeBase64(paymentrequest2_cert1_BASE64); r = handleRequest(server, data); r.paymentRequest.getMerchant(caStore, merchant); QCOMPARE(merchant, QString("")); - // Long certificate chain: - data = DecodeBase64(paymentrequest3_BASE64); + // 10-long certificate chain, all intermediates valid: + data = DecodeBase64(paymentrequest3_cert1_BASE64); r = handleRequest(server, data); r.paymentRequest.getMerchant(caStore, merchant); QCOMPARE(merchant, QString("testmerchant8.org")); // Long certificate chain, with an expired certificate in the middle: - data = DecodeBase64(paymentrequest4_BASE64); + data = DecodeBase64(paymentrequest4_cert1_BASE64); r = handleRequest(server, data); r.paymentRequest.getMerchant(caStore, merchant); QCOMPARE(merchant, QString("")); // Validly signed, but by a CA not in our root CA list: - data = DecodeBase64(paymentrequest5_BASE64); + data = DecodeBase64(paymentrequest5_cert1_BASE64); r = handleRequest(server, data); r.paymentRequest.getMerchant(caStore, merchant); QCOMPARE(merchant, QString("")); @@ -104,12 +113,71 @@ void PaymentServerTests::paymentServerTests() // Try again with no root CA's, verifiedMerchant should be empty: caStore = X509_STORE_new(); PaymentServer::LoadRootCAs(caStore); - data = DecodeBase64(paymentrequest1_BASE64); + data = DecodeBase64(paymentrequest1_cert1_BASE64); r = handleRequest(server, data); r.paymentRequest.getMerchant(caStore, merchant); QCOMPARE(merchant, QString("")); - // Just get some random data big enough to trigger BIP70 DoS protection + // Load second root certificate + caStore = X509_STORE_new(); + X509_STORE_add_cert(caStore, parse_b64der_cert(caCert2_BASE64)); + PaymentServer::LoadRootCAs(caStore); + + QByteArray byteArray; + + // For the tests below we just need the payment request data from + // paymentrequestdata.h parsed + stored in r.paymentRequest. + // + // These tests require us to bypass the following normal client execution flow + // shown below to be able to explicitly just trigger a certain condition! + // + // handleRequest() + // -> PaymentServer::eventFilter() + // -> PaymentServer::handleURIOrFile() + // -> PaymentServer::readPaymentRequestFromFile() + // -> PaymentServer::processPaymentRequest() + + // Contains a testnet paytoaddress, so payment request network doesn't match client network: + data = DecodeBase64(paymentrequest1_cert2_BASE64); + byteArray = QByteArray((const char*)&data[0], data.size()); + r.paymentRequest.parse(byteArray); + // Ensure the request is initialized, because network "main" is default, even for + // uninizialized payment requests and that will fail our test here. + QVERIFY(r.paymentRequest.IsInitialized()); + QCOMPARE(PaymentServer::verifyNetwork(r.paymentRequest.getDetails()), false); + + // Expired payment request (expires is set to 1 = 1970-01-01 00:00:01): + data = DecodeBase64(paymentrequest2_cert2_BASE64); + byteArray = QByteArray((const char*)&data[0], data.size()); + r.paymentRequest.parse(byteArray); + // Ensure the request is initialized + QVERIFY(r.paymentRequest.IsInitialized()); + // compares 1 < GetTime() == false (treated as expired payment request) + QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), true); + + // Unexpired payment request (expires is set to 0x7FFFFFFFFFFFFFFF = max. int64_t): + // 9223372036854775807 (uint64), 9223372036854775807 (int64_t) and -1 (int32_t) + // -1 is 1969-12-31 23:59:59 (for a 32 bit time values) + data = DecodeBase64(paymentrequest3_cert2_BASE64); + byteArray = QByteArray((const char*)&data[0], data.size()); + r.paymentRequest.parse(byteArray); + // Ensure the request is initialized + QVERIFY(r.paymentRequest.IsInitialized()); + // compares 9223372036854775807 < GetTime() == false (treated as unexpired payment request) + QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), false); + + // Unexpired payment request (expires is set to 0x8000000000000000 > max. int64_t, allowed uint64): + // 9223372036854775808 (uint64), -9223372036854775808 (int64_t) and 0 (int32_t) + // 0 is 1970-01-01 00:00:00 (for a 32 bit time values) + data = DecodeBase64(paymentrequest4_cert2_BASE64); + byteArray = QByteArray((const char*)&data[0], data.size()); + r.paymentRequest.parse(byteArray); + // Ensure the request is initialized + QVERIFY(r.paymentRequest.IsInitialized()); + // compares -9223372036854775808 < GetTime() == true (treated as expired payment request) + QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), true); + + // Test BIP70 DoS protection: unsigned char randData[BIP70_MAX_PAYMENTREQUEST_SIZE + 1]; GetRandBytes(randData, sizeof(randData)); // Write data to a temp file: @@ -117,9 +185,22 @@ void PaymentServerTests::paymentServerTests() tempFile.open(); tempFile.write((const char*)randData, sizeof(randData)); tempFile.close(); - // Trigger BIP70 DoS protection QCOMPARE(PaymentServer::readPaymentRequestFromFile(tempFile.fileName(), r.paymentRequest), false); + // Payment request with amount overflow (amount is set to 21000001 BTC): + data = DecodeBase64(paymentrequest5_cert2_BASE64); + byteArray = QByteArray((const char*)&data[0], data.size()); + r.paymentRequest.parse(byteArray); + // Ensure the request is initialized + QVERIFY(r.paymentRequest.IsInitialized()); + // Extract address and amount from the request + QList<std::pair<CScript, CAmount> > sendingTos = r.paymentRequest.getPayTo(); + foreach (const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) { + CTxDestination dest; + if (ExtractDestination(sendingTo.first, dest)) + QCOMPARE(PaymentServer::verifyAmount(sendingTo.second), false); + } + delete server; } diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 6771e77180..df1afbfaaa 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -94,7 +94,7 @@ public: */ void updateWallet(const uint256 &hash, int status, bool showTransaction) { - qDebug() << "TransactionTablePriv::updateWallet : " + QString::fromStdString(hash.ToString()) + " " + QString::number(status); + qDebug() << "TransactionTablePriv::updateWallet: " + QString::fromStdString(hash.ToString()) + " " + QString::number(status); // Find bounds of this transaction in model QList<TransactionRecord>::iterator lower = qLowerBound( @@ -122,7 +122,7 @@ public: case CT_NEW: if(inModel) { - qWarning() << "TransactionTablePriv::updateWallet : Warning: Got CT_NEW, but transaction is already in model"; + qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_NEW, but transaction is already in model"; break; } if(showTransaction) @@ -132,7 +132,7 @@ public: std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(hash); if(mi == wallet->mapWallet.end()) { - qWarning() << "TransactionTablePriv::updateWallet : Warning: Got CT_NEW, but transaction is not in wallet"; + qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_NEW, but transaction is not in wallet"; break; } // Added -- insert at the right position @@ -154,7 +154,7 @@ public: case CT_DELETED: if(!inModel) { - qWarning() << "TransactionTablePriv::updateWallet : Warning: Got CT_DELETED, but transaction is not in model"; + qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_DELETED, but transaction is not in model"; break; } // Removed -- remove entire transaction from table @@ -664,7 +664,7 @@ public: void invoke(QObject *ttm) { QString strHash = QString::fromStdString(hash.GetHex()); - qDebug() << "NotifyTransactionChanged : " + strHash + " status= " + QString::number(status); + qDebug() << "NotifyTransactionChanged: " + strHash + " status= " + QString::number(status); QMetaObject::invokeMethod(ttm, "updateTransaction", Qt::QueuedConnection, Q_ARG(QString, strHash), Q_ARG(int, status), diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index 2858982f09..092d919042 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -49,10 +49,10 @@ public: }; enum ColumnWidths { - STATUS_COLUMN_WIDTH = 23, + STATUS_COLUMN_WIDTH = 30, WATCHONLY_COLUMN_WIDTH = 23, DATE_COLUMN_WIDTH = 120, - TYPE_COLUMN_WIDTH = 120, + TYPE_COLUMN_WIDTH = 113, AMOUNT_MINIMUM_COLUMN_WIDTH = 120, MINIMUM_COLUMN_WIDTH = 23 }; diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index e6cec8173e..63dd6efb52 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -12,12 +12,15 @@ #include "clientversion.h" #include "init.h" +#include "util.h" #include <stdio.h> #include <QCloseEvent> #include <QLabel> #include <QRegExp> +#include <QTextTable> +#include <QTextCursor> #include <QVBoxLayout> /** "Help message" or "About" dialog box */ @@ -52,28 +55,89 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) : // Replace newlines with HTML breaks licenseInfoHTML.replace("\n\n", "<br><br>"); - ui->helpMessageLabel->setTextFormat(Qt::RichText); + ui->aboutMessage->setTextFormat(Qt::RichText); ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); text = version + "\n" + licenseInfo; - ui->helpMessageLabel->setText(version + "<br><br>" + licenseInfoHTML); - ui->helpMessageLabel->setWordWrap(true); + ui->aboutMessage->setText(version + "<br><br>" + licenseInfoHTML); + ui->aboutMessage->setWordWrap(true); + ui->helpMessage->setVisible(false); } else { setWindowTitle(tr("Command-line options")); - QString header = tr("Usage:") + "\n" + - " bitcoin-qt [" + tr("command-line options") + "] " + "\n"; + QTextCursor cursor(ui->helpMessage->document()); + cursor.insertText(version); + cursor.insertBlock(); + cursor.insertText(tr("Usage:") + '\n' + + " bitcoin-qt [" + tr("command-line options") + "]\n"); + + cursor.insertBlock(); + QTextTableFormat tf; + tf.setBorderStyle(QTextFrameFormat::BorderStyle_None); + tf.setCellPadding(2); + QVector<QTextLength> widths; + widths << QTextLength(QTextLength::PercentageLength, 35); + widths << QTextLength(QTextLength::PercentageLength, 65); + tf.setColumnWidthConstraints(widths); + QTextTable *table = cursor.insertTable(2, 2, tf); QString coreOptions = QString::fromStdString(HelpMessage(HMM_BITCOIN_QT)); - - QString uiOptions = tr("UI options") + ":\n" + - " -choosedatadir " + tr("Choose data directory on startup (default: 0)") + "\n" + - " -lang=<lang> " + tr("Set language, for example \"de_DE\" (default: system locale)") + "\n" + - " -min " + tr("Start minimized") + "\n" + - " -rootcertificates=<file> " + tr("Set SSL root certificates for payment request (default: -system-)") + "\n" + - " -splash " + tr("Show splash screen on startup (default: 1)"); - - ui->helpMessageLabel->setFont(GUIUtil::bitcoinAddressFont()); - text = version + "\n" + header + "\n" + coreOptions + "\n" + uiOptions; - ui->helpMessageLabel->setText(text); + bool first = true; + QTextCharFormat bold; + bold.setFontWeight(QFont::Bold); + // note that coreOptions is not translated. + foreach (const QString &line, coreOptions.split('\n')) { + if (!first) { + table->appendRows(1); + cursor.movePosition(QTextCursor::NextRow); + } + first = false; + + if (line.startsWith(" ")) { + int index = line.indexOf(' ', 3); + if (index > 0) { + cursor.insertText(line.left(index).trimmed()); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText(line.mid(index).trimmed()); + continue; + } + } + cursor.movePosition(QTextCursor::NextCell, QTextCursor::KeepAnchor); + table->mergeCells(cursor); + cursor.insertText(line.trimmed(), bold); + } + + table->appendRows(6); + cursor.movePosition(QTextCursor::NextRow); + cursor.insertText(tr("UI options") + ":", bold); + cursor.movePosition(QTextCursor::NextRow); + if (GetBoolArg("-help-debug", false)) { + cursor.insertText("-allowselfsignedrootcertificates"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText(tr("Allow self signed root certificates (default: 0)")); + cursor.movePosition(QTextCursor::NextCell); + } + cursor.insertText("-choosedatadir"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText(tr("Choose data directory on startup (default: 0)")); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("-lang=<lang>"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText(tr("Set language, for example \"de_DE\" (default: system locale)")); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("-min"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText(tr("Start minimized")); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("-rootcertificates=<file>"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText(tr("Set SSL root certificates for payment request (default: -system-)")); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("-splash"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText(tr("Show splash screen on startup (default: 1)")); + + ui->helpMessage->moveCursor(QTextCursor::Start); + ui->scrollArea->setVisible(false); + ui->aboutLogo->setVisible(false); } } diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 6006a7bd7b..79f5191fc0 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -6,6 +6,7 @@ #include "addresstablemodel.h" #include "guiconstants.h" +#include "paymentserver.h" #include "recentrequeststablemodel.h" #include "transactiontablemodel.h" @@ -278,9 +279,9 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact return TransactionCreationFailed; } - // reject insane fee > 0.1 bitcoin + // reject absurdly high fee > 0.1 bitcoin if (nFeeRequired > 10000000) - return InsaneFee; + return AbsurdFee; } return SendCoinsReturn(OK); @@ -294,11 +295,16 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran LOCK2(cs_main, wallet->cs_wallet); CWalletTx *newTx = transaction.getTransaction(); - // Store PaymentRequests in wtx.vOrderForm in wallet. foreach(const SendCoinsRecipient &rcp, transaction.getRecipients()) { if (rcp.paymentRequest.IsInitialized()) { + // Make sure any payment requests involved are still valid. + if (PaymentServer::verifyExpired(rcp.paymentRequest.getDetails())) { + return PaymentRequestExpired; + } + + // Store PaymentRequests in wtx.vOrderForm in wallet. std::string key("PaymentRequest"); std::string value; rcp.paymentRequest.SerializeToString(&value); @@ -446,7 +452,7 @@ static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet, QString strLabel = QString::fromStdString(label); QString strPurpose = QString::fromStdString(purpose); - qDebug() << "NotifyAddressBookChanged : " + strAddress + " " + strLabel + " isMine=" + QString::number(isMine) + " purpose=" + strPurpose + " status=" + QString::number(status); + qDebug() << "NotifyAddressBookChanged: " + strAddress + " " + strLabel + " isMine=" + QString::number(isMine) + " purpose=" + strPurpose + " status=" + QString::number(status); QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection, Q_ARG(QString, strAddress), Q_ARG(QString, strLabel), diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index d8df25f660..4a9a12beaa 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -40,7 +40,7 @@ public: explicit SendCoinsRecipient(const QString &addr, const QString &label, const CAmount& amount, const QString &message): address(addr), label(label), amount(amount), message(message), nVersion(SendCoinsRecipient::CURRENT_VERSION) {} - // If from an insecure payment request, this is used for storing + // If from an unauthenticated payment request, this is used for storing // the addresses, e.g. address-A<br />address-B<br />address-C. // Info: As we don't need to process addresses in here when using // payment requests, we can abuse it for displaying an address list. @@ -111,7 +111,8 @@ public: DuplicateAddress, TransactionCreationFailed, // Error returned when wallet is still locked TransactionCommitFailed, - InsaneFee + AbsurdFee, + PaymentRequestExpired }; enum EncryptionStatus |