Merge pull request #560 from rnicoll/1.7.2-dev-payment

Re-enable payment protocol
This commit is contained in:
langerhans 2014-06-29 15:37:19 +02:00
commit e3eeb47d1d
4 changed files with 85 additions and 68 deletions

View file

@ -173,7 +173,7 @@ public:
#ifdef ENABLE_WALLET
/// Create payment server
// void createPaymentServer();
void createPaymentServer();
#endif
/// Create options model
void createOptionsModel();
@ -212,7 +212,7 @@ private:
BitcoinGUI *window;
QTimer *pollShutdownTimer;
#ifdef ENABLE_WALLET
// PaymentServer* paymentServer;
PaymentServer* paymentServer;
WalletModel *walletModel;
#endif
int returnValue;
@ -279,7 +279,7 @@ BitcoinApplication::BitcoinApplication(int &argc, char **argv):
window(0),
pollShutdownTimer(0),
#ifdef ENABLE_WALLET
// paymentServer(0),
paymentServer(0),
walletModel(0),
#endif
returnValue(0)
@ -298,20 +298,18 @@ BitcoinApplication::~BitcoinApplication()
delete window;
window = 0;
#ifdef ENABLE_WALLET
// delete paymentServer;
// paymentServer = 0;
delete paymentServer;
paymentServer = 0;
#endif
delete optionsModel;
optionsModel = 0;
}
#ifdef ENABLE_WALLET
/*
void BitcoinApplication::createPaymentServer()
{
paymentServer = new PaymentServer(this);
}
*/
#endif
void BitcoinApplication::createOptionsModel()
@ -394,12 +392,10 @@ void BitcoinApplication::initializeResult(int retval)
returnValue = retval ? 0 : 1;
if(retval)
{
/*
#ifdef ENABLE_WALLET
PaymentServer::LoadRootCAs();
paymentServer->setOptionsModel(optionsModel);
#endif
*/
emit splashFinished(window);
@ -414,10 +410,8 @@ void BitcoinApplication::initializeResult(int retval)
window->addWallet("~Default", walletModel);
window->setCurrentWallet("~Default");
/*
connect(walletModel, SIGNAL(coinsSent(CWallet*,SendCoinsRecipient,QByteArray)),
paymentServer, SLOT(fetchPaymentACK(CWallet*,const SendCoinsRecipient&,QByteArray)));
*/
}
#endif
@ -431,11 +425,8 @@ void BitcoinApplication::initializeResult(int retval)
window->show();
}
#ifdef ENABLE_WALLET
// Payment server disabled pending future work on specifications
// Now that initialization/startup is done, process any command-line
// dogecoin: URIs or payment requests:
/*
connect(paymentServer, SIGNAL(receivedPaymentRequest(SendCoinsRecipient)),
window, SLOT(handlePaymentRequest(SendCoinsRecipient)));
connect(window, SIGNAL(receivedURI(QString)),
@ -443,7 +434,6 @@ void BitcoinApplication::initializeResult(int retval)
connect(paymentServer, SIGNAL(message(QString,QString,unsigned int)),
window, SLOT(message(QString,QString,unsigned int)));
QTimer::singleShot(100, paymentServer, SLOT(uiReady()));
*/
#endif
} else {
quit(); // Exit main loop
@ -578,7 +568,7 @@ int main(int argc, char *argv[])
// Start up the payment server early, too, so impatient users that click on
// dogecoin: links repeatedly have their payment requests routed to this process:
// app.createPaymentServer();
app.createPaymentServer();
#endif
/// 9. Main GUI initialization

View file

@ -1,22 +1,23 @@
//
// Simple Bitcoin Payment Protocol messages
// Simple Dogecoin Payment Protocol messages
// Derived fromthe Bitcoin Payment Protocol
//
// Use fields 100+ for extensions;
// to avoid conflicts, register extensions at:
// https://en.bitcoin.it/wiki/Payment_Request
// to avoid conflicts, register extensions via pull-req at:
// https://github.com/dogecoin/dips
//
package payments;
option java_package = "org.bitcoin.protocols.payments";
option java_package = "com.dogecoin.protocols.payments";
option java_outer_classname = "Protos";
// Generalized form of "send payment to this/these bitcoin addresses"
// Generalized form of "send payment to this/these dogecoin addresses"
message Output {
optional uint64 amount = 1 [default = 0]; // amount is integer-number-of-satoshis
required bytes script = 2; // usually one of the standard Script forms
optional uint64 amount = 1 [default = 0]; // amount is integer-number-of-satoshis
required bytes script = 2; // usually one of the standard Script forms
}
message PaymentDetails {
optional string network = 1 [default = "main"]; // "main" or "test"
optional string genesis = 1 [default = "1a91e3dace36e2be3bf030a65679fe821aa1d6ef92e7c9902eb318182c355691"]; // Hash of the network genesis block
repeated Output outputs = 2; // Where payment should be sent
required uint64 time = 3; // Timestamp; when payment request created
optional uint64 expires = 4; // Timestamp; when this request should be considered invalid

View file

@ -178,6 +178,9 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
// and the items in savedPaymentRequest will be handled
// when uiReady() is called.
//
// Warning: ipcSendCommandLine() is called early in init,
// so don't use "emit message()", but "QMessageBox::"!
//
bool PaymentServer::ipcParseCommandLine(int argc, char* argv[])
{
for (int i = 1; i < argc; i++)
@ -205,14 +208,19 @@ bool PaymentServer::ipcParseCommandLine(int argc, char* argv[])
else if (QFile::exists(arg)) // Filename
{
savedPaymentRequests.append(arg);
PaymentRequestPlus request;
if (readPaymentRequest(arg, request))
{
if (request.getDetails().network() == "main")
if (request.getDetails().genesis() == "1a91e3dace36e2be3bf030a65679fe821aa1d6ef92e7c9902eb318182c355691")
{
SelectParams(CChainParams::MAIN);
else
}
else if (request.getDetails().genesis() == "bb0a78264637406b6360aad926284d544d7049f45189db5664f3c4d07350559e")
{
SelectParams(CChainParams::TESTNET);
}
}
}
else
@ -411,7 +419,15 @@ void PaymentServer::handleURIOrFile(const QString& s)
{
SendCoinsRecipient recipient;
if (GUIUtil::parseBitcoinURI(s, &recipient))
emit receivedPaymentRequest(recipient);
{
CBitcoinAddress address(recipient.address.toStdString());
if (!address.IsValid()) {
emit message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address),
CClientUIInterface::MSG_ERROR);
}
else
emit receivedPaymentRequest(recipient);
}
else
emit message(tr("URI handling"),
tr("URI can not be parsed! This can be caused by an invalid Dogecoin address or malformed URI parameters."),
@ -425,12 +441,14 @@ void PaymentServer::handleURIOrFile(const QString& s)
{
PaymentRequestPlus request;
SendCoinsRecipient recipient;
if (readPaymentRequest(s, request) && processPaymentRequest(request, recipient))
emit receivedPaymentRequest(recipient);
else
if (!readPaymentRequest(s, request))
{
emit message(tr("Payment request file handling"),
tr("Payment request file can not be read or processed! This can be caused by an invalid payment request file."),
tr("Payment request file can not be read! This can be caused by an invalid payment request file."),
CClientUIInterface::ICON_WARNING);
}
else if (processPaymentRequest(request, recipient))
emit receivedPaymentRequest(recipient);
return;
}
@ -482,6 +500,35 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins
if (!optionsModel)
return false;
if (request.IsInitialized()) {
const payments::PaymentDetails& details = request.getDetails();
// Payment request network matches client network?
if ((details.genesis() == "1a91e3dace36e2be3bf030a65679fe821aa1d6ef92e7c9902eb318182c355691" && TestNet()) ||
(details.genesis() == "bb0a78264637406b6360aad926284d544d7049f45189db5664f3c4d07350559e" && !TestNet()))
{
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."),
CClientUIInterface::MSG_ERROR);
return false;
}
}
else {
emit message(tr("Payment request error"), tr("Payment request is not initialized."),
CClientUIInterface::MSG_ERROR);
return false;
}
recipient.paymentRequest = request;
recipient.message = GUIUtil::HtmlEscape(request.getDetails().memo());
@ -497,11 +544,11 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins
// Append destination address
addresses.append(QString::fromStdString(CBitcoinAddress(dest).ToString()));
}
else if (!recipient.authenticatedMerchant.isEmpty()){
else if (!recipient.authenticatedMerchant.isEmpty()) {
// Insecure payments to custom bitcoin addresses are not supported
// (there is no good way to tell the user where they are paying in a way
// they'd have a chance of understanding).
emit message(tr("Payment request error"),
emit message(tr("Payment request rejected"),
tr("Unverified payment requests to custom payment scripts are unsupported."),
CClientUIInterface::MSG_ERROR);
return false;
@ -510,11 +557,10 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins
// Extract and check amounts
CTxOut txOut(sendingTo.second, sendingTo.first);
if (txOut.IsDust(CTransaction::nMinRelayTxFee)) {
QString msg = tr("Requested payment amount of %1 is too small (considered dust).")
.arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second));
emit message(tr("Payment request error"), tr("Requested payment amount of %1 is too small (considered dust).")
.arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second)),
CClientUIInterface::MSG_ERROR);
qDebug() << "PaymentServer::processPaymentRequest : " << msg;
emit message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR);
return false;
}
@ -581,8 +627,8 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipien
refund_to->set_script(&s[0], s.size());
}
else {
// This should never happen, because sending coins should have just unlocked the wallet
// and refilled the keypool
// This should never happen, because sending coins should have
// just unlocked the wallet and refilled the keypool.
qDebug() << "PaymentServer::fetchPaymentACK : Error getting refund key, refund_to not set";
}
}
@ -594,7 +640,7 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipien
netManager->post(netRequest, serData);
}
else {
// This should never happen, either:
// This should never happen, either.
qDebug() << "PaymentServer::fetchPaymentACK : Error serializing payment message";
}
}
@ -620,17 +666,15 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply)
{
PaymentRequestPlus request;
SendCoinsRecipient recipient;
if (request.parse(data) && processPaymentRequest(request, recipient))
if (!request.parse(data))
{
emit receivedPaymentRequest(recipient);
}
else
{
qDebug() << "PaymentServer::netRequestFinished : Error processing payment request";
qDebug() << "PaymentServer::netRequestFinished : Error parsing payment request";
emit message(tr("Payment request error"),
tr("Payment request can not be parsed or processed!"),
tr("Payment request can not be parsed!"),
CClientUIInterface::MSG_ERROR);
}
else if (processPaymentRequest(request, recipient))
emit receivedPaymentRequest(recipient);
return;
}

View file

@ -377,26 +377,8 @@ void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv)
bool SendCoinsDialog::handlePaymentRequest(const SendCoinsRecipient &rv)
{
QString strSendCoins = tr("Send Coins");
if (rv.paymentRequest.IsInitialized()) {
// Expired payment request?
const payments::PaymentDetails& details = rv.paymentRequest.getDetails();
if (details.has_expires() && (int64_t)details.expires() < GetTime())
{
emit message(strSendCoins, tr("Payment request expired"),
CClientUIInterface::MSG_WARNING);
return false;
}
}
else {
CBitcoinAddress address(rv.address.toStdString());
if (!address.IsValid()) {
emit message(strSendCoins, tr("Invalid payment address %1").arg(rv.address),
CClientUIInterface::MSG_WARNING);
return false;
}
}
// Just paste the entry, all pre-checks
// are done in paymentserver.cpp.
pasteEntry(rv);
return true;
}