Skip to content

Commit 8476d5d

Browse files
committed
[Qt] Permanently store requested payments in wallet
1 parent b10e147 commit 8476d5d

File tree

5 files changed

+142
-4
lines changed

5 files changed

+142
-4
lines changed

src/qt/recentrequeststablemodel.cpp

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ RecentRequestsTableModel::RecentRequestsTableModel(CWallet *wallet, WalletModel
1212
walletModel(parent)
1313
{
1414
Q_UNUSED(wallet);
15+
nReceiveRequestsMaxId = 0;
16+
17+
// Load entries from wallet
18+
std::vector<std::string> vReceiveRequests;
19+
parent->loadReceiveRequests(vReceiveRequests);
20+
BOOST_FOREACH(const std::string& request, vReceiveRequests)
21+
addNewRequest(request);
1522

1623
/* These columns must match the indices in the ColumnIndex enumeration */
1724
columns << tr("Date") << tr("Label") << tr("Message") << tr("Amount");
@@ -104,6 +111,14 @@ bool RecentRequestsTableModel::removeRows(int row, int count, const QModelIndex
104111

105112
if(count > 0 && row >= 0 && (row+count) <= list.size())
106113
{
114+
const RecentRequestEntry *rec;
115+
for (int i = 0; i < count; ++i)
116+
{
117+
rec = &list[row+i];
118+
if (!walletModel->saveReceiveRequest(rec->recipient.address.toStdString(), rec->id, ""))
119+
return false;
120+
}
121+
107122
beginRemoveRows(parent, row, row + count - 1);
108123
list.erase(list.begin() + row, list.begin() + row + count);
109124
endRemoveRows();
@@ -118,12 +133,45 @@ Qt::ItemFlags RecentRequestsTableModel::flags(const QModelIndex &index) const
118133
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
119134
}
120135

136+
// called when adding a request from the GUI
121137
void RecentRequestsTableModel::addNewRequest(const SendCoinsRecipient &recipient)
122138
{
123139
RecentRequestEntry newEntry;
140+
newEntry.id = ++nReceiveRequestsMaxId;
124141
newEntry.date = QDateTime::currentDateTime();
125142
newEntry.recipient = recipient;
143+
144+
CDataStream ss(SER_DISK, CLIENT_VERSION);
145+
ss << newEntry;
146+
147+
if (!walletModel->saveReceiveRequest(recipient.address.toStdString(), newEntry.id, ss.str()))
148+
return;
149+
150+
addNewRequest(newEntry);
151+
}
152+
153+
// called from ctor when loading from wallet
154+
void RecentRequestsTableModel::addNewRequest(const std::string &recipient)
155+
{
156+
std::vector<char> data(recipient.begin(), recipient.end());
157+
CDataStream ss(data, SER_DISK, CLIENT_VERSION);
158+
159+
RecentRequestEntry entry;
160+
ss >> entry;
161+
162+
if (entry.id == 0) // should not happen
163+
return;
164+
165+
if (entry.id > nReceiveRequestsMaxId)
166+
nReceiveRequestsMaxId = entry.id;
167+
168+
addNewRequest(entry);
169+
}
170+
171+
// actually add to table in GUI
172+
void RecentRequestsTableModel::addNewRequest(RecentRequestEntry &recipient)
173+
{
126174
beginInsertRows(QModelIndex(), 0, 0);
127-
list.prepend(newEntry);
175+
list.prepend(recipient);
128176
endInsertRows();
129177
}

src/qt/recentrequeststablemodel.h

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,32 @@
1313

1414
class CWallet;
1515

16-
struct RecentRequestEntry
16+
class RecentRequestEntry
1717
{
18+
public:
19+
RecentRequestEntry() : nVersion(RecentRequestEntry::CURRENT_VERSION), id(0) { }
20+
21+
static const int CURRENT_VERSION=1;
22+
int nVersion;
23+
int64_t id;
1824
QDateTime date;
1925
SendCoinsRecipient recipient;
26+
27+
IMPLEMENT_SERIALIZE
28+
(
29+
RecentRequestEntry* pthis = const_cast<RecentRequestEntry*>(this);
30+
31+
unsigned int nDate = date.toTime_t();
32+
33+
READWRITE(pthis->nVersion);
34+
nVersion = pthis->nVersion;
35+
READWRITE(id);
36+
READWRITE(nDate);
37+
READWRITE(recipient);
38+
39+
if (fRead)
40+
pthis->date = QDateTime::fromTime_t(nDate);
41+
)
2042
};
2143

2244
/** Model for list of recently generated payment requests / bitcoin URIs.
@@ -51,11 +73,14 @@ class RecentRequestsTableModel: public QAbstractTableModel
5173

5274
const RecentRequestEntry &entry(int row) const { return list[row]; }
5375
void addNewRequest(const SendCoinsRecipient &recipient);
76+
void addNewRequest(const std::string &recipient);
77+
void addNewRequest(RecentRequestEntry &recipient);
5478

5579
private:
5680
WalletModel *walletModel;
5781
QStringList columns;
5882
QList<RecentRequestEntry> list;
83+
int64_t nReceiveRequestsMaxId;
5984
};
6085

6186
#endif

src/qt/walletmodel.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,3 +554,27 @@ void WalletModel::listLockedCoins(std::vector<COutPoint>& vOutpts)
554554
LOCK(wallet->cs_wallet);
555555
wallet->ListLockedCoins(vOutpts);
556556
}
557+
558+
void WalletModel::loadReceiveRequests(std::vector<std::string>& vReceiveRequests)
559+
{
560+
LOCK(wallet->cs_wallet);
561+
BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, wallet->mapAddressBook)
562+
BOOST_FOREACH(const PAIRTYPE(std::string, std::string)& item2, item.second.destdata)
563+
if (item2.first.size() > 2 && item2.first.substr(0,2) == "rr") // receive request
564+
vReceiveRequests.push_back(item2.second);
565+
}
566+
567+
bool WalletModel::saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest)
568+
{
569+
CTxDestination dest = CBitcoinAddress(sAddress).Get();
570+
571+
std::stringstream ss;
572+
ss << nId;
573+
std::string key = "rr" + ss.str(); // "rr" prefix = "receive request" in destdata
574+
575+
LOCK(wallet->cs_wallet);
576+
if (sRequest.empty())
577+
return wallet->EraseDestData(dest, key);
578+
else
579+
return wallet->AddDestData(dest, key, sRequest);
580+
}

src/qt/walletmodel.h

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ QT_END_NAMESPACE
3636
class SendCoinsRecipient
3737
{
3838
public:
39-
explicit SendCoinsRecipient() : amount(0) { }
39+
explicit SendCoinsRecipient() : amount(0), nVersion(SendCoinsRecipient::CURRENT_VERSION) { }
4040
explicit SendCoinsRecipient(const QString &addr, const QString &label, quint64 amount, const QString &message):
41-
address(addr), label(label), amount(amount), message(message) {}
41+
address(addr), label(label), amount(amount), message(message), nVersion(SendCoinsRecipient::CURRENT_VERSION) {}
4242

4343
// If from an insecure payment request, this is used for storing
4444
// the addresses, e.g. address-A<br />address-B<br />address-C.
@@ -55,6 +55,41 @@ class SendCoinsRecipient
5555
PaymentRequestPlus paymentRequest;
5656
// Empty if no authentication or invalid signature/cert/etc.
5757
QString authenticatedMerchant;
58+
59+
static const int CURRENT_VERSION=1;
60+
int nVersion;
61+
62+
IMPLEMENT_SERIALIZE
63+
(
64+
SendCoinsRecipient* pthis = const_cast<SendCoinsRecipient*>(this);
65+
66+
std::string sAddress = pthis->address.toStdString();
67+
std::string sLabel = pthis->label.toStdString();
68+
std::string sMessage = pthis->message.toStdString();
69+
std::string sPaymentRequest;
70+
if (!fRead && pthis->paymentRequest.IsInitialized())
71+
pthis->paymentRequest.SerializeToString(&sPaymentRequest);
72+
std::string sAuthenticatedMerchant = pthis->authenticatedMerchant.toStdString();
73+
74+
READWRITE(pthis->nVersion);
75+
nVersion = pthis->nVersion;
76+
READWRITE(sAddress);
77+
READWRITE(sLabel);
78+
READWRITE(amount);
79+
READWRITE(sMessage);
80+
READWRITE(sPaymentRequest);
81+
READWRITE(sAuthenticatedMerchant);
82+
83+
if (fRead)
84+
{
85+
pthis->address = QString::fromStdString(sAddress);
86+
pthis->label = QString::fromStdString(sLabel);
87+
pthis->message = QString::fromStdString(sMessage);
88+
if (!sPaymentRequest.empty())
89+
pthis->paymentRequest.parse(QByteArray::fromRawData(sPaymentRequest.data(), sPaymentRequest.size()));
90+
pthis->authenticatedMerchant = QString::fromStdString(sAuthenticatedMerchant);
91+
}
92+
)
5893
};
5994

6095
/** Interface to Bitcoin wallet from Qt view code. */
@@ -152,6 +187,9 @@ class WalletModel : public QObject
152187
void unlockCoin(COutPoint& output);
153188
void listLockedCoins(std::vector<COutPoint>& vOutpts);
154189

190+
void loadReceiveRequests(std::vector<std::string>& vReceiveRequests);
191+
bool saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest);
192+
155193
private:
156194
CWallet *wallet;
157195

src/wallet.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2023,6 +2023,9 @@ void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const {
20232023

20242024
bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
20252025
{
2026+
if (boost::get<CNoDestination>(&dest))
2027+
return false;
2028+
20262029
mapAddressBook[dest].destdata.insert(std::make_pair(key, value));
20272030
if (!fFileBacked)
20282031
return true;

0 commit comments

Comments
 (0)