aboutsummaryrefslogtreecommitdiff
path: root/src/qt/walletmodel.cpp
diff options
context:
space:
mode:
authorGavin Andresen <gavinandresen@gmail.com>2013-07-22 16:50:39 +1000
committerGavin Andresen <gavinandresen@gmail.com>2013-08-22 16:18:25 +1000
commita41d5fe01947f2f878c055670986a165af800f9a (patch)
tree40eeada1ebc180f8e3669a7d164104686dc0c618 /src/qt/walletmodel.cpp
parent47d0534368fbf0e3fb2cad7d05d60501d29f62aa (diff)
Payment Protocol: X509-validated payment requests
Add support for a Payment Protocol to Bitcoin-Qt. Payment messages are protocol-buffer encoded and communicated over http(s), so this adds a dependency on the Google protocol buffer library, and requires Qt with OpenSSL support.
Diffstat (limited to 'src/qt/walletmodel.cpp')
-rw-r--r--src/qt/walletmodel.cpp96
1 files changed, 69 insertions, 27 deletions
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index d3c3ddcab1..61357647b7 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -127,31 +127,60 @@ bool WalletModel::validateAddress(const QString &address)
WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipient> &recipients)
{
qint64 total = 0;
- QSet<QString> setAddress;
- QString hex;
+ std::vector<std::pair<CScript, int64> > vecSend;
+ QByteArray transaction;
if(recipients.empty())
{
return OK;
}
+ QSet<QString> setAddress; // Used to detect duplicates
+ int nAddresses = 0;
+
// Pre-check input data for validity
foreach(const SendCoinsRecipient &rcp, recipients)
{
- if(!validateAddress(rcp.address))
- {
- return InvalidAddress;
+ if (rcp.paymentRequest.IsInitialized())
+ { // PaymentRequest...
+ int64 subtotal = 0;
+ const payments::PaymentDetails& details = rcp.paymentRequest.getDetails();
+ for (int i = 0; i < details.outputs_size(); i++)
+ {
+ const payments::Output& out = details.outputs(i);
+ if (out.amount() <= 0) continue;
+ subtotal += out.amount();
+ const unsigned char* scriptStr = (const unsigned char*)out.script().data();
+ CScript scriptPubKey(scriptStr, scriptStr+out.script().size());
+ vecSend.push_back(std::pair<CScript, int64>(scriptPubKey, out.amount()));
+ }
+ if (subtotal <= 0)
+ {
+ return InvalidAmount;
+ }
+ total += subtotal;
}
- setAddress.insert(rcp.address);
+ else
+ { // User-entered bitcoin address / amount:
+ if(!validateAddress(rcp.address))
+ {
+ return InvalidAddress;
+ }
+ if(rcp.amount <= 0)
+ {
+ return InvalidAmount;
+ }
+ setAddress.insert(rcp.address);
+ ++nAddresses;
- if(rcp.amount <= 0)
- {
- return InvalidAmount;
+ CScript scriptPubKey;
+ scriptPubKey.SetDestination(CBitcoinAddress(rcp.address.toStdString()).Get());
+ vecSend.push_back(std::pair<CScript, int64>(scriptPubKey, rcp.amount));
+
+ total += rcp.amount;
}
- total += rcp.amount;
}
-
- if(recipients.size() > setAddress.size())
+ if(setAddress.size() != nAddresses)
{
return DuplicateAddress;
}
@@ -169,19 +198,10 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipie
{
LOCK2(cs_main, wallet->cs_wallet);
- // Sendmany
- std::vector<std::pair<CScript, int64> > vecSend;
- foreach(const SendCoinsRecipient &rcp, recipients)
- {
- CScript scriptPubKey;
- scriptPubKey.SetDestination(CBitcoinAddress(rcp.address.toStdString()).Get());
- vecSend.push_back(make_pair(scriptPubKey, rcp.amount));
- }
-
- CWalletTx wtx;
CReserveKey keyChange(wallet);
int64 nFeeRequired = 0;
std::string strFailReason;
+ CWalletTx wtx;
bool fCreated = wallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, strFailReason);
if(!fCreated)
@@ -194,6 +214,18 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipie
CClientUIInterface::MSG_ERROR);
return TransactionCreationFailed;
}
+ // Store PaymentRequests in wtx.vOrderForm in wallet.
+ foreach(const SendCoinsRecipient &rcp, recipients)
+ {
+ if (rcp.paymentRequest.IsInitialized())
+ {
+ std::string key("PaymentRequest");
+ std::string value;
+ rcp.paymentRequest.SerializeToString(&value);
+ wtx.vOrderForm.push_back(make_pair(key, value));
+ }
+ }
+
if(!uiInterface.ThreadSafeAskFee(nFeeRequired))
{
return Aborted;
@@ -202,10 +234,15 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipie
{
return TransactionCommitFailed;
}
- hex = QString::fromStdString(wtx.GetHash().GetHex());
+
+ CTransaction* t = (CTransaction*)&wtx;
+ CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
+ ssTx << *t;
+ transaction.append(&(ssTx[0]), ssTx.size());
}
- // Add addresses / update labels that we've sent to to the address book
+ // Add addresses / update labels that we've sent to to the address book,
+ // and emit coinsSent signal
foreach(const SendCoinsRecipient &rcp, recipients)
{
std::string strAddress = rcp.address.toStdString();
@@ -217,14 +254,19 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipie
std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(dest);
// Check if we have a new address or an updated label
- if (mi == wallet->mapAddressBook.end() || mi->second.name != strLabel)
+ if (mi == wallet->mapAddressBook.end())
+ {
+ wallet->SetAddressBook(dest, strLabel, "send");
+ }
+ else if (mi->second.name != strLabel)
{
- wallet->SetAddressBookName(dest, strLabel);
+ wallet->SetAddressBook(dest, strLabel, ""); // "" means don't change purpose
}
}
+ emit coinsSent(wallet, rcp, transaction);
}
- return SendCoinsReturn(OK, 0, hex);
+ return SendCoinsReturn(OK, 0);
}
OptionsModel *WalletModel::getOptionsModel()