diff options
-rw-r--r-- | src/bitcoinrpc.h | 3 | ||||
-rw-r--r-- | src/qt/bitcoin.cpp | 2 | ||||
-rw-r--r-- | src/qt/bitcoingui.cpp | 16 | ||||
-rw-r--r-- | src/qt/bitcoingui.h | 2 | ||||
-rw-r--r-- | src/qt/paymentserver.cpp | 36 | ||||
-rw-r--r-- | src/qt/paymentserver.h | 3 | ||||
-rw-r--r-- | src/qt/transactiondesc.cpp | 5 | ||||
-rw-r--r-- | src/rpcnet.cpp | 8 | ||||
-rw-r--r-- | src/rpcwallet.cpp | 4 | ||||
-rw-r--r-- | src/test/rpc_tests.cpp | 31 |
10 files changed, 80 insertions, 30 deletions
diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index 275369ddd2..0c1c722b50 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -49,10 +49,13 @@ enum RPCErrorCode RPC_INVALID_PARAMETER = -8, // Invalid, missing or duplicate parameter RPC_DATABASE_ERROR = -20, // Database error RPC_DESERIALIZATION_ERROR = -22, // Error parsing or validating structure in raw format + RPC_SERVER_NOT_STARTED = -18, // RPC server was not started (StartRPCThreads() not called) // P2P client errors RPC_CLIENT_NOT_CONNECTED = -9, // Bitcoin is not connected RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, // Still downloading initial blocks + RPC_CLIENT_NODE_ALREADY_ADDED = -23, // Node is already added + RPC_CLIENT_NODE_NOT_ADDED = -24, // Node has not been added before // Wallet errors RPC_WALLET_ERROR = -4, // Unspecified problem with wallet (key not found etc.) diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index e73a82978a..09f2a53680 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -331,8 +331,6 @@ int main(int argc, char *argv[]) &window, SLOT(handlePaymentRequest(SendCoinsRecipient))); QObject::connect(&walletModel, SIGNAL(coinsSent(CWallet*,SendCoinsRecipient,QByteArray)), paymentServer, SLOT(fetchPaymentACK(CWallet*,const SendCoinsRecipient&,QByteArray))); - QObject::connect(paymentServer, SIGNAL(receivedPaymentACK(QString)), - &window, SLOT(showPaymentACK(QString))); QObject::connect(paymentServer, SIGNAL(message(QString,QString,unsigned int)), guiref, SLOT(message(QString,QString,unsigned int))); QTimer::singleShot(100, paymentServer, SLOT(uiReady())); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 5bcbf3cfdf..b210e22b63 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -230,7 +230,7 @@ void BitcoinGUI::createActions(bool fIsTestnet) aboutQtAction = new QAction(QIcon(":/trolltech/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), this); #else aboutQtAction = new QAction(QIcon(":/qt-project.org/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), this); -#endif +#endif aboutQtAction->setStatusTip(tr("Show information about Qt")); aboutQtAction->setMenuRole(QAction::AboutQtRole); optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this); @@ -637,6 +637,8 @@ void BitcoinGUI::message(const QString &title, const QString &message, unsigned if (!(buttons = (QMessageBox::StandardButton)(style & CClientUIInterface::BTN_MASK))) buttons = QMessageBox::Ok; + // Ensure we get users attention + showNormalIfMinimized(); QMessageBox mBox((QMessageBox::Icon)nMBoxIcon, strTitle, message, buttons, this); int r = mBox.exec(); if (ret != NULL) @@ -688,9 +690,8 @@ void BitcoinGUI::askFee(qint64 nFeeRequired, bool *payFee) QString strMessage = tr("This transaction is over the size limit. You can still send it for a fee of %1, " "which goes to the nodes that process your transaction and helps to support the network. " "Do you want to pay the fee?").arg(BitcoinUnits::formatWithUnit(clientModel->getOptionsModel()->getDisplayUnit(), nFeeRequired)); - QMessageBox::StandardButton retval = QMessageBox::question( - this, tr("Confirm transaction fee"), strMessage, - QMessageBox::Yes|QMessageBox::Cancel, QMessageBox::Yes); + QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm transaction fee"), strMessage, + QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); *payFee = (retval == QMessageBox::Yes); } @@ -733,7 +734,7 @@ void BitcoinGUI::dropEvent(QDropEvent *event) walletFrame->gotoSendCoinsPage(); else message(tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters."), - CClientUIInterface::ICON_WARNING); + CClientUIInterface::ICON_WARNING); } event->acceptProposedAction(); @@ -756,11 +757,6 @@ void BitcoinGUI::handlePaymentRequest(const SendCoinsRecipient& recipient) walletFrame->handlePaymentRequest(recipient); } -void BitcoinGUI::showPaymentACK(const QString& msg) -{ - message(tr("Payment acknowledged"), GUIUtil::HtmlEscape(msg), CClientUIInterface::MODAL); -} - void BitcoinGUI::setEncryptionStatus(int status) { switch(status) diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 5710b827ad..a5a3ce83bf 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -135,6 +135,7 @@ public slots: @param[in] ret pointer to a bool that will be modified to whether Ok was clicked (modal only) */ void message(const QString &title, const QString &message, unsigned int style, bool *ret = NULL); + /** Asks the user whether to pay the transaction fee or to cancel the transaction. It is currently not possible to pass a return value to another thread through BlockingQueuedConnection, so an indirected pointer is used. @@ -146,7 +147,6 @@ public slots: void askFee(qint64 nFeeRequired, bool *payFee); void handlePaymentRequest(const SendCoinsRecipient& recipient); - void showPaymentACK(const QString& msg); /** Show incoming transaction notification for new transactions. */ void incomingTransaction(const QString& date, int unit, qint64 amount, const QString& type, const QString& address); diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index af75d6b4e5..43c4bdd191 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -250,7 +250,12 @@ bool PaymentServer::ipcSendCommandLine(int argc, char* argv[]) return fResult; } -PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : QObject(parent), saveURIs(true) +PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : + QObject(parent), + saveURIs(true), + uriServer(0), + netManager(0), + optionsModel(0) { // Verify that the version of the library that we linked against is // compatible with the version of the headers we compiled against. @@ -258,7 +263,7 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : QObject(p // Install global event filter to catch QFileOpenEvents // on Mac: sent when you click bitcoin: links - // other OSes: helpful when dealing with payment-request files (in the future) + // other OSes: helpful when dealing with payment request files (in the future) if (parent) parent->installEventFilter(this); @@ -273,8 +278,10 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : QObject(p if (!uriServer->listen(name)) qDebug() << "PaymentServer::PaymentServer : Cannot start bitcoin: click-to-pay handler"; - else + else { connect(uriServer, SIGNAL(newConnection()), this, SLOT(handleURIConnection())); + connect(this, SIGNAL(receivedPaymentACK(QString)), this, SLOT(handlePaymentACK(QString))); + } } // netManager is null until uiReady() is called @@ -316,7 +323,7 @@ void PaymentServer::initNetManager() // netManager is used to fetch paymentrequests given in bitcoin: URIs netManager = new QNetworkAccessManager(this); - // Use proxy settings from optionsModel: + // Use proxy settings from optionsModel QString proxyIP; quint16 proxyPort; if (optionsModel->getProxySettings(proxyIP, proxyPort)) @@ -452,7 +459,7 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, QList<Sen foreach(const PAIRTYPE(CScript, qint64)& sendingTo, sendingTos) { CTxOut txOut(sendingTo.second, sendingTo.first); if (txOut.IsDust(CTransaction::nMinRelayTxFee)) { - QString msg = QObject::tr("Requested payment amount (%1) too small") + QString msg = tr("Requested payment amount of %1 is too small (considered dust).") .arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second)); qDebug() << "PaymentServer::processPaymentRequest : " << msg; @@ -532,7 +539,7 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipien payment.add_transactions(transaction.data(), transaction.size()); // Create a new refund address, or re-use: - QString account = tr("Refund from") + QString(" ") + recipient.authenticatedMerchant; + QString account = tr("Refund from %1").arg(recipient.authenticatedMerchant); std::string strAccount = account.toStdString(); set<CTxDestination> refundAddresses = wallet->GetAccountAddresses(strAccount); if (!refundAddresses.empty()) { @@ -574,9 +581,10 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply) reply->deleteLater(); if (reply->error() != QNetworkReply::NoError) { - QString msg = QObject::tr("Error communicating with %1: %2") + QString msg = tr("Error communicating with %1: %2") .arg(reply->request().url().toString()) .arg(reply->errorString()); + qDebug() << "PaymentServer::netRequestFinished : " << msg; emit message(tr("Network request error"), msg, CClientUIInterface::MSG_ERROR); return; @@ -590,12 +598,13 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply) PaymentRequestPlus request; QList<SendCoinsRecipient> recipients; if (request.parse(data) && processPaymentRequest(request, recipients)) { - foreach (const SendCoinsRecipient& recipient, recipients){ + foreach (const SendCoinsRecipient& recipient, recipients) { emit receivedPaymentRequest(recipient); } } else qDebug() << "PaymentServer::netRequestFinished : Error processing payment request"; + return; } else if (requestType == "PaymentACK") @@ -603,13 +612,14 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply) payments::PaymentACK paymentACK; if (!paymentACK.ParseFromArray(data.data(), data.size())) { - QString msg = QObject::tr("Bad response from server %1") + QString msg = tr("Bad response from server %1") .arg(reply->request().url().toString()); + qDebug() << "PaymentServer::netRequestFinished : " << msg; emit message(tr("Network request error"), msg, CClientUIInterface::MSG_ERROR); } else { - emit receivedPaymentACK(QString::fromStdString(paymentACK.memo())); + emit receivedPaymentACK(GUIUtil::HtmlEscape(paymentACK.memo())); } } } @@ -630,3 +640,9 @@ void PaymentServer::setOptionsModel(OptionsModel *optionsModel) { this->optionsModel = optionsModel; } + +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); +} diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h index 042c41ef64..9f43571edc 100644 --- a/src/qt/paymentserver.h +++ b/src/qt/paymentserver.h @@ -88,7 +88,7 @@ signals: void receivedPaymentRequest(SendCoinsRecipient); // Fired when a valid PaymentACK is received - void receivedPaymentACK(QString); + void receivedPaymentACK(const QString &paymentACKMsg); // Fired when a message should be reported to the user void message(const QString &title, const QString &message, unsigned int style); @@ -105,6 +105,7 @@ private slots: void handleURIConnection(); void netRequestFinished(QNetworkReply*); void reportSslErrors(QNetworkReply*, const QList<QSslError> &); + void handlePaymentACK(const QString& paymentACKMsg); private: static bool readPaymentRequest(const QString& filename, PaymentRequestPlus& request); diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 93fc8cab22..63a72c4553 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -234,7 +234,10 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u } if (wtx.IsCoinBase()) - strHTML += "<br>" + tr("Generated coins must mature 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.") + "<br>"; + { + quint32 numBlocksToMaturity = COINBASE_MATURITY + 1; + strHTML += "<br>" + tr("Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.").arg(QString::number(numBlocksToMaturity)) + "<br>"; + } // // Debug view diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 3c92739852..5d87a2449f 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -27,7 +27,7 @@ Value ping(const Array& params, bool fHelp) "Requests that a ping be sent to all other nodes, to measure ping time.\n" "Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n" "Ping command is handled in queue with all other commands, so it measures processing backlog, not just network ping."); - + // Request that each node send a ping during next message processing pass LOCK(cs_vNodes); BOOST_FOREACH(CNode* pNode, vNodes) { @@ -120,13 +120,13 @@ Value addnode(const Array& params, bool fHelp) if (strCommand == "add") { if (it != vAddedNodes.end()) - throw JSONRPCError(-23, "Error: Node already added"); + throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added"); vAddedNodes.push_back(strNode); } else if(strCommand == "remove") { if (it == vAddedNodes.end()) - throw JSONRPCError(-24, "Error: Node has not been added."); + throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added."); vAddedNodes.erase(it); } @@ -163,7 +163,7 @@ Value getaddednodeinfo(const Array& params, bool fHelp) break; } if (laddedNodes.size() == 0) - throw JSONRPCError(-24, "Error: Node has not been added."); + throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added."); } if (!fDns) diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 7aae9ddb73..fe22dfe54c 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -1271,7 +1271,7 @@ Value keypoolrefill(const Array& params, bool fHelp) unsigned int kpSize = max(GetArg("-keypool", 100), 0LL); if (params.size() > 0) { if (params[0].get_int() < 0) - throw JSONRPCError(-8, "Invalid parameter, expected valid size"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size"); kpSize = (unsigned int) params[0].get_int(); } @@ -1301,6 +1301,8 @@ Value walletpassphrase(const Array& params, bool fHelp) "Stores the wallet decryption key in memory for <timeout> seconds."); if (fHelp) return true; + if (!fServer) + throw JSONRPCError(RPC_SERVER_NOT_STARTED, "Error: RPC server was not started, use server=1 to change this."); if (!pwalletMain->IsCrypted()) throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called."); diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 35eabed0e2..25849054eb 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -168,4 +168,35 @@ BOOST_AUTO_TEST_CASE(rpc_rawsign) BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == true); } +BOOST_AUTO_TEST_CASE(rpc_format_monetary_values) +{ + BOOST_CHECK(write_string(ValueFromAmount(0LL), false) == "0.00000000"); + BOOST_CHECK(write_string(ValueFromAmount(1LL), false) == "0.00000001"); + BOOST_CHECK(write_string(ValueFromAmount(17622195LL), false) == "0.17622195"); + BOOST_CHECK(write_string(ValueFromAmount(50000000LL), false) == "0.50000000"); + BOOST_CHECK(write_string(ValueFromAmount(89898989LL), false) == "0.89898989"); + BOOST_CHECK(write_string(ValueFromAmount(100000000LL), false) == "1.00000000"); + BOOST_CHECK(write_string(ValueFromAmount(2099999999999990LL), false) == "20999999.99999990"); + BOOST_CHECK(write_string(ValueFromAmount(2099999999999999LL), false) == "20999999.99999999"); +} + +static Value ValueFromString(const std::string &str) +{ + Value value; + BOOST_CHECK(read_string(str, value)); + return value; +} + +BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values) +{ + BOOST_CHECK(AmountFromValue(ValueFromString("0.00000001")) == 1LL); + BOOST_CHECK(AmountFromValue(ValueFromString("0.17622195")) == 17622195LL); + BOOST_CHECK(AmountFromValue(ValueFromString("0.5")) == 50000000LL); + BOOST_CHECK(AmountFromValue(ValueFromString("0.50000000")) == 50000000LL); + BOOST_CHECK(AmountFromValue(ValueFromString("0.89898989")) == 89898989LL); + BOOST_CHECK(AmountFromValue(ValueFromString("1.00000000")) == 100000000LL); + BOOST_CHECK(AmountFromValue(ValueFromString("20999999.9999999")) == 2099999999999990LL); + BOOST_CHECK(AmountFromValue(ValueFromString("20999999.99999999")) == 2099999999999999LL); +} + BOOST_AUTO_TEST_SUITE_END() |