[Qt] Permanently store requested payments in wallet
This commit is contained in:
parent
b10e147096
commit
8476d5d407
5 changed files with 142 additions and 4 deletions
|
@ -12,6 +12,13 @@ RecentRequestsTableModel::RecentRequestsTableModel(CWallet *wallet, WalletModel
|
|||
walletModel(parent)
|
||||
{
|
||||
Q_UNUSED(wallet);
|
||||
nReceiveRequestsMaxId = 0;
|
||||
|
||||
// Load entries from wallet
|
||||
std::vector<std::string> vReceiveRequests;
|
||||
parent->loadReceiveRequests(vReceiveRequests);
|
||||
BOOST_FOREACH(const std::string& request, vReceiveRequests)
|
||||
addNewRequest(request);
|
||||
|
||||
/* These columns must match the indices in the ColumnIndex enumeration */
|
||||
columns << tr("Date") << tr("Label") << tr("Message") << tr("Amount");
|
||||
|
@ -104,6 +111,14 @@ bool RecentRequestsTableModel::removeRows(int row, int count, const QModelIndex
|
|||
|
||||
if(count > 0 && row >= 0 && (row+count) <= list.size())
|
||||
{
|
||||
const RecentRequestEntry *rec;
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
rec = &list[row+i];
|
||||
if (!walletModel->saveReceiveRequest(rec->recipient.address.toStdString(), rec->id, ""))
|
||||
return false;
|
||||
}
|
||||
|
||||
beginRemoveRows(parent, row, row + count - 1);
|
||||
list.erase(list.begin() + row, list.begin() + row + count);
|
||||
endRemoveRows();
|
||||
|
@ -118,12 +133,45 @@ Qt::ItemFlags RecentRequestsTableModel::flags(const QModelIndex &index) const
|
|||
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
||||
}
|
||||
|
||||
// called when adding a request from the GUI
|
||||
void RecentRequestsTableModel::addNewRequest(const SendCoinsRecipient &recipient)
|
||||
{
|
||||
RecentRequestEntry newEntry;
|
||||
newEntry.id = ++nReceiveRequestsMaxId;
|
||||
newEntry.date = QDateTime::currentDateTime();
|
||||
newEntry.recipient = recipient;
|
||||
|
||||
CDataStream ss(SER_DISK, CLIENT_VERSION);
|
||||
ss << newEntry;
|
||||
|
||||
if (!walletModel->saveReceiveRequest(recipient.address.toStdString(), newEntry.id, ss.str()))
|
||||
return;
|
||||
|
||||
addNewRequest(newEntry);
|
||||
}
|
||||
|
||||
// called from ctor when loading from wallet
|
||||
void RecentRequestsTableModel::addNewRequest(const std::string &recipient)
|
||||
{
|
||||
std::vector<char> data(recipient.begin(), recipient.end());
|
||||
CDataStream ss(data, SER_DISK, CLIENT_VERSION);
|
||||
|
||||
RecentRequestEntry entry;
|
||||
ss >> entry;
|
||||
|
||||
if (entry.id == 0) // should not happen
|
||||
return;
|
||||
|
||||
if (entry.id > nReceiveRequestsMaxId)
|
||||
nReceiveRequestsMaxId = entry.id;
|
||||
|
||||
addNewRequest(entry);
|
||||
}
|
||||
|
||||
// actually add to table in GUI
|
||||
void RecentRequestsTableModel::addNewRequest(RecentRequestEntry &recipient)
|
||||
{
|
||||
beginInsertRows(QModelIndex(), 0, 0);
|
||||
list.prepend(newEntry);
|
||||
list.prepend(recipient);
|
||||
endInsertRows();
|
||||
}
|
||||
|
|
|
@ -13,10 +13,32 @@
|
|||
|
||||
class CWallet;
|
||||
|
||||
struct RecentRequestEntry
|
||||
class RecentRequestEntry
|
||||
{
|
||||
public:
|
||||
RecentRequestEntry() : nVersion(RecentRequestEntry::CURRENT_VERSION), id(0) { }
|
||||
|
||||
static const int CURRENT_VERSION=1;
|
||||
int nVersion;
|
||||
int64_t id;
|
||||
QDateTime date;
|
||||
SendCoinsRecipient recipient;
|
||||
|
||||
IMPLEMENT_SERIALIZE
|
||||
(
|
||||
RecentRequestEntry* pthis = const_cast<RecentRequestEntry*>(this);
|
||||
|
||||
unsigned int nDate = date.toTime_t();
|
||||
|
||||
READWRITE(pthis->nVersion);
|
||||
nVersion = pthis->nVersion;
|
||||
READWRITE(id);
|
||||
READWRITE(nDate);
|
||||
READWRITE(recipient);
|
||||
|
||||
if (fRead)
|
||||
pthis->date = QDateTime::fromTime_t(nDate);
|
||||
)
|
||||
};
|
||||
|
||||
/** Model for list of recently generated payment requests / bitcoin URIs.
|
||||
|
@ -51,11 +73,14 @@ public:
|
|||
|
||||
const RecentRequestEntry &entry(int row) const { return list[row]; }
|
||||
void addNewRequest(const SendCoinsRecipient &recipient);
|
||||
void addNewRequest(const std::string &recipient);
|
||||
void addNewRequest(RecentRequestEntry &recipient);
|
||||
|
||||
private:
|
||||
WalletModel *walletModel;
|
||||
QStringList columns;
|
||||
QList<RecentRequestEntry> list;
|
||||
int64_t nReceiveRequestsMaxId;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -554,3 +554,27 @@ void WalletModel::listLockedCoins(std::vector<COutPoint>& vOutpts)
|
|||
LOCK(wallet->cs_wallet);
|
||||
wallet->ListLockedCoins(vOutpts);
|
||||
}
|
||||
|
||||
void WalletModel::loadReceiveRequests(std::vector<std::string>& vReceiveRequests)
|
||||
{
|
||||
LOCK(wallet->cs_wallet);
|
||||
BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, wallet->mapAddressBook)
|
||||
BOOST_FOREACH(const PAIRTYPE(std::string, std::string)& item2, item.second.destdata)
|
||||
if (item2.first.size() > 2 && item2.first.substr(0,2) == "rr") // receive request
|
||||
vReceiveRequests.push_back(item2.second);
|
||||
}
|
||||
|
||||
bool WalletModel::saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest)
|
||||
{
|
||||
CTxDestination dest = CBitcoinAddress(sAddress).Get();
|
||||
|
||||
std::stringstream ss;
|
||||
ss << nId;
|
||||
std::string key = "rr" + ss.str(); // "rr" prefix = "receive request" in destdata
|
||||
|
||||
LOCK(wallet->cs_wallet);
|
||||
if (sRequest.empty())
|
||||
return wallet->EraseDestData(dest, key);
|
||||
else
|
||||
return wallet->AddDestData(dest, key, sRequest);
|
||||
}
|
||||
|
|
|
@ -36,9 +36,9 @@ QT_END_NAMESPACE
|
|||
class SendCoinsRecipient
|
||||
{
|
||||
public:
|
||||
explicit SendCoinsRecipient() : amount(0) { }
|
||||
explicit SendCoinsRecipient() : amount(0), nVersion(SendCoinsRecipient::CURRENT_VERSION) { }
|
||||
explicit SendCoinsRecipient(const QString &addr, const QString &label, quint64 amount, const QString &message):
|
||||
address(addr), label(label), amount(amount), message(message) {}
|
||||
address(addr), label(label), amount(amount), message(message), nVersion(SendCoinsRecipient::CURRENT_VERSION) {}
|
||||
|
||||
// If from an insecure payment request, this is used for storing
|
||||
// the addresses, e.g. address-A<br />address-B<br />address-C.
|
||||
|
@ -55,6 +55,41 @@ public:
|
|||
PaymentRequestPlus paymentRequest;
|
||||
// Empty if no authentication or invalid signature/cert/etc.
|
||||
QString authenticatedMerchant;
|
||||
|
||||
static const int CURRENT_VERSION=1;
|
||||
int nVersion;
|
||||
|
||||
IMPLEMENT_SERIALIZE
|
||||
(
|
||||
SendCoinsRecipient* pthis = const_cast<SendCoinsRecipient*>(this);
|
||||
|
||||
std::string sAddress = pthis->address.toStdString();
|
||||
std::string sLabel = pthis->label.toStdString();
|
||||
std::string sMessage = pthis->message.toStdString();
|
||||
std::string sPaymentRequest;
|
||||
if (!fRead && pthis->paymentRequest.IsInitialized())
|
||||
pthis->paymentRequest.SerializeToString(&sPaymentRequest);
|
||||
std::string sAuthenticatedMerchant = pthis->authenticatedMerchant.toStdString();
|
||||
|
||||
READWRITE(pthis->nVersion);
|
||||
nVersion = pthis->nVersion;
|
||||
READWRITE(sAddress);
|
||||
READWRITE(sLabel);
|
||||
READWRITE(amount);
|
||||
READWRITE(sMessage);
|
||||
READWRITE(sPaymentRequest);
|
||||
READWRITE(sAuthenticatedMerchant);
|
||||
|
||||
if (fRead)
|
||||
{
|
||||
pthis->address = QString::fromStdString(sAddress);
|
||||
pthis->label = QString::fromStdString(sLabel);
|
||||
pthis->message = QString::fromStdString(sMessage);
|
||||
if (!sPaymentRequest.empty())
|
||||
pthis->paymentRequest.parse(QByteArray::fromRawData(sPaymentRequest.data(), sPaymentRequest.size()));
|
||||
pthis->authenticatedMerchant = QString::fromStdString(sAuthenticatedMerchant);
|
||||
}
|
||||
)
|
||||
};
|
||||
|
||||
/** Interface to Bitcoin wallet from Qt view code. */
|
||||
|
@ -152,6 +187,9 @@ public:
|
|||
void unlockCoin(COutPoint& output);
|
||||
void listLockedCoins(std::vector<COutPoint>& vOutpts);
|
||||
|
||||
void loadReceiveRequests(std::vector<std::string>& vReceiveRequests);
|
||||
bool saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest);
|
||||
|
||||
private:
|
||||
CWallet *wallet;
|
||||
|
||||
|
|
|
@ -2023,6 +2023,9 @@ void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const {
|
|||
|
||||
bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
|
||||
{
|
||||
if (boost::get<CNoDestination>(&dest))
|
||||
return false;
|
||||
|
||||
mapAddressBook[dest].destdata.insert(std::make_pair(key, value));
|
||||
if (!fFileBacked)
|
||||
return true;
|
||||
|
|
Loading…
Reference in a new issue