]> Git Repo - VerusCoin.git/blame - src/wallet/wallet.cpp
Fix multi-currency sencurrency, initial VDXF start files
[VerusCoin.git] / src / wallet / wallet.cpp
CommitLineData
b2120e22 1// Copyright (c) 2009-2010 Satoshi Nakamoto
f914f1a7 2// Copyright (c) 2009-2014 The Bitcoin Core developers
5b40d886 3// Distributed under the MIT software license, see the accompanying
bc909a7a 4// file COPYING or https://www.opensource.org/licenses/mit-license.php .
e8ef3da7 5
50c72f23 6#include "wallet/wallet.h"
51ed9ec9 7
81a45d69 8#include "asyncrpcqueue.h"
3e1cf9b6 9#include "checkpoints.h"
6a86c24d 10#include "coincontrol.h"
81a45d69 11#include "core_io.h"
be126699 12#include "consensus/upgrades.h"
da29ecbc 13#include "consensus/validation.h"
9bb37bf0 14#include "consensus/consensus.h"
02e67455 15#include "init.h"
3d31e09c 16#include "key_io.h"
8a893c94 17#include "main.h"
b2a98c42 18#include "mmr.h"
0689f46c 19#include "net.h"
fcab001b 20#include "rpc/protocol.h"
81a45d69 21#include "rpc/server.h"
e088d65a 22#include "script/script.h"
23#include "script/sign.h"
14f888ca 24#include "timedata.h"
ad49c256 25#include "utilmoneystr.h"
02e67455 26#include "zcash/Note.hpp"
73699cea 27#include "crypter.h"
4a4e912b 28#include "coins.h"
81a45d69 29#include "wallet/asyncrpcoperation_saplingmigration.h"
70b4ad2d 30#include "zcash/zip32.h"
ca4a5f26 31#include "cc/StakeGuard.h"
b7c685b8 32#include "pbaas/identity.h"
e7e14f44 33#include "pbaas/pbaas.h"
1fae37f6 34
d0c4197e
PK
35#include <assert.h>
36
cae686d3 37#include <boost/algorithm/string/replace.hpp>
2bb1c877 38#include <boost/filesystem.hpp>
ad49c256 39#include <boost/thread.hpp>
e8ef3da7
WL
40
41using namespace std;
c1c45943 42using namespace libzcash;
e8ef3da7 43
5b40d886
MF
44/**
45 * Settings
46 */
c6cb21d1 47CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
aa279d61 48CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
77ed59df 49unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;
1bbca249 50bool bSpendZeroConfChange = true;
c1c9d5b4 51bool fSendFreeTransactions = false;
ed3e5e46 52bool fPayAtLeastCustomFee = true;
bdc72415 53#include "komodo_defs.h"
54
06f41160 55extern int32_t USE_EXTERNAL_PUBKEY;
56extern std::string NOTARY_PUBKEY;
6ad13d7c 57extern int32_t KOMODO_EXCHANGEWALLET;
7c130297 58extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
b2a98c42 59extern uint160 ASSETCHAINS_CHAINID;
1fae37f6 60extern int32_t VERUS_MIN_STAKEAGE;
1f722359 61CBlockIndex *komodo_chainactive(int32_t height);
a55973ae 62extern std::string DONATION_PUBKEY;
a20f2622 63extern BlockMap mapBlockIndex;
e8ef3da7 64
7e6d23b1
CD
65/**
66 * Fees smaller than this (in satoshi) are considered zero fee (for transaction creation)
5b40d886
MF
67 * Override with -mintxfee
68 */
9b1627d1 69CFeeRate CWallet::minTxFee = CFeeRate(1000);
13fc83c7 70
5b40d886
MF
71/** @defgroup mapWallet
72 *
73 * @{
74 */
e8ef3da7 75
d650f96d
CM
76struct CompareValueOnly
77{
a372168e
MF
78 bool operator()(const pair<CAmount, pair<const CWalletTx*, unsigned int> >& t1,
79 const pair<CAmount, pair<const CWalletTx*, unsigned int> >& t2) const
d650f96d
CM
80 {
81 return t1.first < t2.first;
82 }
83};
84
2ec1b02c 85struct CompareValueMap
56fe75cb 86{
2ec1b02c 87 bool operator()(const CCurrencyValueMap &m1,
88 const CCurrencyValueMap &m2) const
89 {
90 if (m1 < m2 && m2 < m1)
91 {
92 // this is used for sorting
93 // what we care about most in this case is that we always give the same answer,
94 // so, run a repeatable check, regardless of the order of operands. we'd also want
95 // to be as close to right as possible.
96 CCurrencyValueMap checkMap1 = m1.IntersectingValues(m2);
97 CCurrencyValueMap checkMap2;
98 // where they intersect, they are empty, no way to know which is less for sorting
99 if (!(checkMap2 < checkMap1))
100 {
101 return false;
102 }
103 checkMap2 = checkMap1 - m2.IntersectingValues(m1);
104 CAmount total = 0;
105 for (auto &oneCur : checkMap2.valueMap)
106 {
107 total += oneCur.second;
108 }
109 if (total < 0)
110 {
111 return true;
112 }
113 else
114 {
115 return false;
116 }
117 }
118 return m1 < m2;
119 }
56fe75cb 120 bool operator()(const pair<CCurrencyValueMap, pair<const CWalletTx*, unsigned int> >& t1,
121 const pair<CCurrencyValueMap, pair<const CWalletTx*, unsigned int> >& t2) const
122 {
2ec1b02c 123 if (t1.first < t2.first && t2.first < t1.first)
124 {
125 // this is used for sorting
126 // what we care about most in this case is that we always give the same answer,
127 // so, run a repeatable check, regardless of the order of operands. we'd also want
128 // to be as close to right as possible.
129 CCurrencyValueMap checkMap1 = t1.first.IntersectingValues(t2.first);
130 CCurrencyValueMap checkMap2;
131 // where they intersect, they are empty, no way to know which is less for sorting
132 if (!(checkMap2 < checkMap1))
133 {
134 return false;
135 }
136 checkMap2 = checkMap1 - t2.first.IntersectingValues(t1.first);
137 CAmount total = 0;
138 for (auto &oneCur : checkMap2.valueMap)
139 {
140 total += oneCur.second;
141 }
142 if (total < 0)
143 {
144 return true;
145 }
146 else
147 {
148 return false;
149 }
150 }
151 return t1.first < t2.first;
56fe75cb 152 }
153};
154
02e67455
JG
155std::string JSOutPoint::ToString() const
156{
157 return strprintf("JSOutPoint(%s, %d, %d)", hash.ToString().substr(0,10), js, n);
158}
159
ad49c256
WL
160std::string COutput::ToString() const
161{
805344dc 162 return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->vout[i].nValue));
ad49c256
WL
163}
164
93a18a36
GA
165const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
166{
167 LOCK(cs_wallet);
168 std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(hash);
169 if (it == mapWallet.end())
170 return NULL;
171 return &(it->second);
172}
173
c1c45943 174// Generate a new spending key and return its public payment address
d6ad8cef 175libzcash::SproutPaymentAddress CWallet::GenerateNewSproutZKey()
c1c45943 176{
d6b31d59 177 AssertLockHeld(cs_wallet); // mapSproutZKeyMetadata
d6ad8cef 178
e5eab182 179 auto k = SproutSpendingKey::random();
c1c45943
S
180 auto addr = k.address();
181
182 // Check for collision, even though it is unlikely to ever occur
25d5e80c 183 if (CCryptoKeyStore::HaveSproutSpendingKey(addr))
92fc29a3 184 throw std::runtime_error("CWallet::GenerateNewSproutZKey(): Collision detected");
c1c45943
S
185
186 // Create new metadata
187 int64_t nCreationTime = GetTime();
d6b31d59 188 mapSproutZKeyMetadata[addr] = CKeyMetadata(nCreationTime);
c1c45943 189
a0783bb9 190 if (!AddSproutZKey(k))
92fc29a3 191 throw std::runtime_error("CWallet::GenerateNewSproutZKey(): AddSproutZKey failed");
80ed13d5 192 return addr;
c1c45943
S
193}
194
efb7662d
JG
195// Generate a new Sapling spending key and return its public payment address
196SaplingPaymentAddress CWallet::GenerateNewSaplingZKey()
197{
8e91ebf7 198 AssertLockHeld(cs_wallet); // mapSaplingZKeyMetadata
70b4ad2d 199
f82a864d
JG
200 // Create new metadata
201 int64_t nCreationTime = GetTime();
70b4ad2d
JG
202 CKeyMetadata metadata(nCreationTime);
203
204 // Try to get the seed
205 HDSeed seed;
206 if (!GetHDSeed(seed))
207 throw std::runtime_error("CWallet::GenerateNewSaplingZKey(): HD seed not found");
208
209 auto m = libzcash::SaplingExtendedSpendingKey::Master(seed);
b6d1af89 210 uint32_t bip44CoinType = Params().BIP44CoinType();
70b4ad2d
JG
211
212 // We use a fixed keypath scheme of m/32'/coin_type'/account'
213 // Derive m/32'
214 auto m_32h = m.Derive(32 | ZIP32_HARDENED_KEY_LIMIT);
215 // Derive m/32'/coin_type'
b6d1af89 216 auto m_32h_cth = m_32h.Derive(bip44CoinType | ZIP32_HARDENED_KEY_LIMIT);
70b4ad2d
JG
217
218 // Derive account key at next index, skip keys already known to the wallet
219 libzcash::SaplingExtendedSpendingKey xsk;
220 do
221 {
222 xsk = m_32h_cth.Derive(hdChain.saplingAccountCounter | ZIP32_HARDENED_KEY_LIMIT);
b6d1af89
JS
223 metadata.hdKeypath = "m/32'/" + std::to_string(bip44CoinType) + "'/" + std::to_string(hdChain.saplingAccountCounter) + "'";
224 metadata.seedFp = hdChain.seedFp;
70b4ad2d
JG
225 // Increment childkey index
226 hdChain.saplingAccountCounter++;
227 } while (HaveSaplingSpendingKey(xsk.expsk.full_viewing_key()));
228
229 // Update the chain model in the database
230 if (fFileBacked && !CWalletDB(strWalletFile).WriteHDChain(hdChain))
231 throw std::runtime_error("CWallet::GenerateNewSaplingZKey(): Writing HD chain model failed");
232
233 auto ivk = xsk.expsk.full_viewing_key().in_viewing_key();
234 mapSaplingZKeyMetadata[ivk] = metadata;
a4ac4fc3 235
70b4ad2d
JG
236 auto addr = xsk.DefaultAddress();
237 if (!AddSaplingZKey(xsk, addr)) {
f82a864d 238 throw std::runtime_error("CWallet::GenerateNewSaplingZKey(): AddSaplingZKey failed");
efb7662d 239 }
f82a864d
JG
240 // return default sapling payment address.
241 return addr;
efb7662d
JG
242}
243
244// Add spending key to keystore
5175a7f0 245bool CWallet::AddSaplingZKey(
70b4ad2d 246 const libzcash::SaplingExtendedSpendingKey &sk,
83c4e360 247 const libzcash::SaplingPaymentAddress &defaultAddr)
efb7662d
JG
248{
249 AssertLockHeld(cs_wallet); // mapSaplingZKeyMetadata
efb7662d 250
5175a7f0 251 if (!CCryptoKeyStore::AddSaplingSpendingKey(sk, defaultAddr)) {
efb7662d
JG
252 return false;
253 }
f4207d0c
JG
254
255 if (!fFileBacked) {
256 return true;
257 }
efb7662d 258
c2dc091e 259 if (!IsCrypted()) {
260 auto ivk = sk.expsk.full_viewing_key().in_viewing_key();
261 return CWalletDB(strWalletFile).WriteSaplingZKey(ivk, sk, mapSaplingZKeyMetadata[ivk]);
262 }
f82a864d 263
efb7662d
JG
264 return true;
265}
266
c2dc091e 267// Add payment address -> incoming viewing key map entry
268bool CWallet::AddSaplingIncomingViewingKey(
269 const libzcash::SaplingIncomingViewingKey &ivk,
270 const libzcash::SaplingPaymentAddress &addr)
271{
272 AssertLockHeld(cs_wallet); // mapSaplingZKeyMetadata
273
274 if (!CCryptoKeyStore::AddSaplingIncomingViewingKey(ivk, addr)) {
275 return false;
276 }
277
278 if (!fFileBacked) {
279 return true;
280 }
281
282 if (!IsCrypted()) {
283 return CWalletDB(strWalletFile).WriteSaplingPaymentAddress(addr, ivk);
284 }
285
286 return true;
287}
288
efb7662d 289
c1c45943 290// Add spending key to keystore and persist to disk
a0783bb9 291bool CWallet::AddSproutZKey(const libzcash::SproutSpendingKey &key)
c1c45943 292{
d6b31d59 293 AssertLockHeld(cs_wallet); // mapSproutZKeyMetadata
c1c45943
S
294 auto addr = key.address();
295
25d5e80c 296 if (!CCryptoKeyStore::AddSproutSpendingKey(key))
c1c45943
S
297 return false;
298
167cd333 299 // check if we need to remove from viewing keys
4c775177
JG
300 if (HaveSproutViewingKey(addr))
301 RemoveSproutViewingKey(key.viewing_key());
167cd333 302
c1c45943
S
303 if (!fFileBacked)
304 return true;
305
306 if (!IsCrypted()) {
307 return CWalletDB(strWalletFile).WriteZKey(addr,
308 key,
d6b31d59 309 mapSproutZKeyMetadata[addr]);
c1c45943
S
310 }
311 return true;
312}
313
fd61d6f5 314CPubKey CWallet::GenerateNewKey()
9976cf07 315{
95691680 316 AssertLockHeld(cs_wallet); // mapKeyMetadata
439e1497 317 bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
38067c18 318
dfa23b94
PW
319 CKey secret;
320 secret.MakeNewKey(fCompressed);
38067c18
PW
321
322 // Compressed public keys were introduced in version 0.6.0
323 if (fCompressed)
439e1497 324 SetMinVersion(FEATURE_COMPRPUBKEY);
38067c18 325
dfa23b94 326 CPubKey pubkey = secret.GetPubKey();
d0c41a73 327 assert(secret.VerifyPubKey(pubkey));
4addb2c0
PW
328
329 // Create new metadata
51ed9ec9 330 int64_t nCreationTime = GetTime();
4addb2c0
PW
331 mapKeyMetadata[pubkey.GetID()] = CKeyMetadata(nCreationTime);
332 if (!nTimeFirstKey || nCreationTime < nTimeFirstKey)
333 nTimeFirstKey = nCreationTime;
334
dfa23b94 335 if (!AddKeyPubKey(secret, pubkey))
5262fde0 336 throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed");
dfa23b94 337 return pubkey;
9976cf07 338}
e8ef3da7 339
4addb2c0 340bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
e8ef3da7 341{
95691680 342 AssertLockHeld(cs_wallet); // mapKeyMetadata
dfa23b94 343 if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey))
acd65016 344 return false;
ccca27a7
CL
345
346 // check if we need to remove from watch-only
347 CScript script;
348 script = GetScriptForDestination(pubkey.GetID());
349 if (HaveWatchOnly(script))
350 RemoveWatchOnly(script);
351
e8ef3da7
WL
352 if (!fFileBacked)
353 return true;
dfa23b94 354 if (!IsCrypted()) {
3869fb89
JG
355 return CWalletDB(strWalletFile).WriteKey(pubkey,
356 secret.GetPrivKey(),
4addb2c0 357 mapKeyMetadata[pubkey.GetID()]);
dfa23b94 358 }
84c3c2eb 359 return true;
4e87d341
MC
360}
361
3869fb89 362bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
4addb2c0 363 const vector<unsigned char> &vchCryptedSecret)
4e87d341 364{
efb7662d 365
4e87d341
MC
366 if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
367 return false;
368 if (!fFileBacked)
369 return true;
96f34cd5 370 {
f8dcd5ca 371 LOCK(cs_wallet);
96f34cd5 372 if (pwalletdbEncryption)
3869fb89
JG
373 return pwalletdbEncryption->WriteCryptedKey(vchPubKey,
374 vchCryptedSecret,
4addb2c0 375 mapKeyMetadata[vchPubKey.GetID()]);
96f34cd5 376 else
3869fb89
JG
377 return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey,
378 vchCryptedSecret,
4addb2c0 379 mapKeyMetadata[vchPubKey.GetID()]);
96f34cd5 380 }
0767e691 381 return false;
4e87d341
MC
382}
383
73699cea 384
25d5e80c
JG
385bool CWallet::AddCryptedSproutSpendingKey(
386 const libzcash::SproutPaymentAddress &address,
387 const libzcash::ReceivingKey &rk,
388 const std::vector<unsigned char> &vchCryptedSecret)
73699cea 389{
25d5e80c 390 if (!CCryptoKeyStore::AddCryptedSproutSpendingKey(address, rk, vchCryptedSecret))
73699cea
S
391 return false;
392 if (!fFileBacked)
393 return true;
394 {
395 LOCK(cs_wallet);
82bd9ee8 396 if (pwalletdbEncryption) {
73699cea 397 return pwalletdbEncryption->WriteCryptedZKey(address,
642a1caf 398 rk,
73699cea 399 vchCryptedSecret,
d6b31d59 400 mapSproutZKeyMetadata[address]);
82bd9ee8 401 } else {
73699cea 402 return CWalletDB(strWalletFile).WriteCryptedZKey(address,
642a1caf 403 rk,
73699cea 404 vchCryptedSecret,
d6b31d59 405 mapSproutZKeyMetadata[address]);
82bd9ee8 406 }
73699cea
S
407 }
408 return false;
409}
410
c2dc091e 411bool CWallet::AddCryptedSaplingSpendingKey(const libzcash::SaplingExtendedFullViewingKey &extfvk,
5175a7f0 412 const std::vector<unsigned char> &vchCryptedSecret,
83c4e360 413 const libzcash::SaplingPaymentAddress &defaultAddr)
bc6344b3 414{
c2dc091e 415 if (!CCryptoKeyStore::AddCryptedSaplingSpendingKey(extfvk, vchCryptedSecret, defaultAddr))
bc6344b3
JG
416 return false;
417 if (!fFileBacked)
418 return true;
419 {
c2dc091e 420 LOCK(cs_wallet);
421 if (pwalletdbEncryption) {
422 return pwalletdbEncryption->WriteCryptedSaplingZKey(extfvk,
423 vchCryptedSecret,
424 mapSaplingZKeyMetadata[extfvk.fvk.in_viewing_key()]);
425 } else {
426 return CWalletDB(strWalletFile).WriteCryptedSaplingZKey(extfvk,
427 vchCryptedSecret,
428 mapSaplingZKeyMetadata[extfvk.fvk.in_viewing_key()]);
429 }
bc6344b3
JG
430 }
431 return false;
432}
433
4addb2c0
PW
434bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta)
435{
95691680 436 AssertLockHeld(cs_wallet); // mapKeyMetadata
4addb2c0
PW
437 if (meta.nCreateTime && (!nTimeFirstKey || meta.nCreateTime < nTimeFirstKey))
438 nTimeFirstKey = meta.nCreateTime;
439
440 mapKeyMetadata[pubkey.GetID()] = meta;
441 return true;
442}
443
e5eab182 444bool CWallet::LoadZKeyMetadata(const SproutPaymentAddress &addr, const CKeyMetadata &meta)
c1c45943 445{
d6b31d59
EOW
446 AssertLockHeld(cs_wallet); // mapSproutZKeyMetadata
447 mapSproutZKeyMetadata[addr] = meta;
c1c45943
S
448 return true;
449}
450
2f15e86a
GA
451bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
452{
453 return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
454}
455
e5eab182 456bool CWallet::LoadCryptedZKey(const libzcash::SproutPaymentAddress &addr, const libzcash::ReceivingKey &rk, const std::vector<unsigned char> &vchCryptedSecret)
73699cea 457{
25d5e80c 458 return CCryptoKeyStore::AddCryptedSproutSpendingKey(addr, rk, vchCryptedSecret);
73699cea
S
459}
460
c2dc091e 461bool CWallet::LoadCryptedSaplingZKey(
462 const libzcash::SaplingExtendedFullViewingKey &extfvk,
463 const std::vector<unsigned char> &vchCryptedSecret)
464{
465 return CCryptoKeyStore::AddCryptedSaplingSpendingKey(extfvk, vchCryptedSecret, extfvk.DefaultAddress());
466}
467
468bool CWallet::LoadSaplingZKeyMetadata(const libzcash::SaplingIncomingViewingKey &ivk, const CKeyMetadata &meta)
469{
470 AssertLockHeld(cs_wallet); // mapSaplingZKeyMetadata
471 mapSaplingZKeyMetadata[ivk] = meta;
472 return true;
473}
474
475bool CWallet::LoadSaplingZKey(const libzcash::SaplingExtendedSpendingKey &key)
476{
477 return CCryptoKeyStore::AddSaplingSpendingKey(key, key.DefaultAddress());
478}
479
480bool CWallet::LoadSaplingPaymentAddress(
481 const libzcash::SaplingPaymentAddress &addr,
482 const libzcash::SaplingIncomingViewingKey &ivk)
483{
484 return CCryptoKeyStore::AddSaplingIncomingViewingKey(ivk, addr);
485}
486
e5eab182 487bool CWallet::LoadZKey(const libzcash::SproutSpendingKey &key)
c1c45943 488{
25d5e80c 489 return CCryptoKeyStore::AddSproutSpendingKey(key);
c1c45943
S
490}
491
4c775177 492bool CWallet::AddSproutViewingKey(const libzcash::SproutViewingKey &vk)
167cd333 493{
4c775177 494 if (!CCryptoKeyStore::AddSproutViewingKey(vk)) {
167cd333 495 return false;
bec22351 496 }
167cd333 497 nTimeFirstKey = 1; // No birthday information for viewing keys.
bec22351 498 if (!fFileBacked) {
167cd333 499 return true;
bec22351 500 }
4c775177 501 return CWalletDB(strWalletFile).WriteSproutViewingKey(vk);
167cd333
JG
502}
503
4c775177 504bool CWallet::RemoveSproutViewingKey(const libzcash::SproutViewingKey &vk)
167cd333
JG
505{
506 AssertLockHeld(cs_wallet);
4c775177 507 if (!CCryptoKeyStore::RemoveSproutViewingKey(vk)) {
167cd333 508 return false;
bec22351
JG
509 }
510 if (fFileBacked) {
4c775177 511 if (!CWalletDB(strWalletFile).EraseSproutViewingKey(vk)) {
167cd333 512 return false;
bec22351
JG
513 }
514 }
167cd333
JG
515
516 return true;
517}
518
4c775177 519bool CWallet::LoadSproutViewingKey(const libzcash::SproutViewingKey &vk)
167cd333 520{
4c775177 521 return CCryptoKeyStore::AddSproutViewingKey(vk);
167cd333
JG
522}
523
922e8e29 524bool CWallet::AddCScript(const CScript& redeemScript)
e679ec96 525{
b7c685b8 526 // if this is an identity, which we currently need to check, we
527 // store the ID as a script in the wallet script storage, but instead of using the
528 // hash of the script, we store it under the name ID
922e8e29 529 if (!CCryptoKeyStore::AddCScript(redeemScript))
e679ec96
GA
530 return false;
531 if (!fFileBacked)
532 return true;
b7c685b8 533 return CWalletDB(strWalletFile).WriteCScript(ScriptOrIdentityID(redeemScript), redeemScript);
e679ec96
GA
534}
535
18116b06
WL
536bool CWallet::LoadCScript(const CScript& redeemScript)
537{
538 /* A sanity check was added in pull #3843 to avoid adding redeemScripts
539 * that never can be redeemed. However, old wallets may still contain
540 * these. Do not add them to the wallet and warn. */
a4f9bc97 541 if (redeemScript.size() > CScript::MAX_SCRIPT_ELEMENT_SIZE)
18116b06 542 {
b7c685b8 543 std::string strAddr = EncodeDestination(ScriptOrIdentityID(redeemScript));
18116b06 544 LogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n",
a4f9bc97 545 __func__, redeemScript.size(), CScript::MAX_SCRIPT_ELEMENT_SIZE, strAddr);
18116b06
WL
546 return true;
547 }
548
549 return CCryptoKeyStore::AddCScript(redeemScript);
550}
551
5bc89dab 552bool CWallet::AddIdentity(const CIdentityMapKey &mapKey, const CIdentityMapValue &identity)
e14c324c 553{
554 // if this is an identity, which we currently need to check, we
555 // store the ID as a script in the wallet script storage, but instead of using the
556 // hash of the script, we store it under the name ID
5bc89dab 557 if (!CCryptoKeyStore::AddIdentity(mapKey, identity))
e14c324c 558 return false;
559 if (!fFileBacked)
560 return true;
5bc89dab 561 return CWalletDB(strWalletFile).WriteIdentity(mapKey, identity);
e14c324c 562}
563
5bc89dab 564bool CWallet::UpdateIdentity(const CIdentityMapKey &mapKey, const CIdentityMapValue &identity)
e14c324c 565{
5bc89dab 566 // if this is an identity, which we currently need to check, we
567 // store the ID as a script in the wallet script storage, but instead of using the
568 // hash of the script, we store it under the name ID
569 if (!CCryptoKeyStore::UpdateIdentity(mapKey, identity))
e14c324c 570 return false;
5bc89dab 571 if (!fFileBacked)
572 return true;
573 return CWalletDB(strWalletFile).WriteIdentity(mapKey, identity);
e14c324c 574}
575
5bc89dab 576bool CWallet::AddUpdateIdentity(const CIdentityMapKey &mapKey, const CIdentityMapValue &identity)
e14c324c 577{
578 // if this is an identity, which we currently need to check, we
579 // store the ID as a script in the wallet script storage, but instead of using the
580 // hash of the script, we store it under the name ID
5bc89dab 581 if (!CCryptoKeyStore::AddUpdateIdentity(mapKey, identity))
e14c324c 582 return false;
583 if (!fFileBacked)
584 return true;
5bc89dab 585 return CWalletDB(strWalletFile).WriteIdentity(mapKey, identity);
586}
587
e5ace0f4 588void CWallet::ClearIdentities()
589{
590 if (fFileBacked)
591 {
592 for (auto idPair : mapIdentities)
593 {
594 CWalletDB(strWalletFile).EraseIdentity(idPair.first);
595 }
596 }
597
598 CCryptoKeyStore::ClearIdentities();
599}
600
5bc89dab 601bool CWallet::RemoveIdentity(const CIdentityMapKey &mapKey, const uint256 &txid)
602{
603 CIdentityMapKey localKey = mapKey;
604 std::vector<std::pair<CIdentityMapKey, CIdentityMapValue>> toErase;
605 if (localKey.blockHeight == 0)
606 {
e54e3c24 607 localKey.blockHeight = INT_MAX;
5bc89dab 608 }
609 if (!GetIdentity(mapKey, localKey, toErase))
610 {
611 return false;
612 }
613 if (!txid.IsNull())
614 {
615 std::pair<CIdentityMapKey, CIdentityMapValue> idEntry;
616 for (auto id : toErase)
617 {
618 if (id.second.txid == txid)
619 {
620 idEntry = id;
621 }
622 }
623 toErase.clear();
624 if (idEntry.first.IsValid() && idEntry.second.IsValid())
625 {
626 toErase.push_back(idEntry);
627 }
628 }
629 if (!CCryptoKeyStore::RemoveIdentity(mapKey, txid))
630 return false;
631 if (!fFileBacked)
632 return true;
633
634 bool error = false;
635 for (auto idPair : toErase)
636 {
637 error = CWalletDB(strWalletFile).EraseIdentity(idPair.first) ? error : true;
638 }
639 return error;
e14c324c 640}
641
5bc89dab 642bool CWallet::LoadIdentity(const CIdentityMapKey &mapKey, const CIdentityMapValue &identity)
e14c324c 643{
5bc89dab 644 return CCryptoKeyStore::AddUpdateIdentity(mapKey, identity);
e14c324c 645}
646
248084b7 647// returns all key IDs that are destinations for UTXOs in the wallet
648std::set<CKeyID> CWallet::GetTransactionDestinationIDs()
649{
650 std::vector<COutput> vecOutputs;
651 std::set<CKeyID> setKeyIDs;
652
20bcd9ba 653 AvailableCoins(vecOutputs, false, NULL, true, true, true, true);
248084b7 654
655 for (int i = 0; i < vecOutputs.size(); i++)
656 {
657 auto &txout = vecOutputs[i];
658 txnouttype outType;
659 std::vector<CTxDestination> dests;
660 int nRequiredSigs;
661
662 if (ExtractDestinations(txout.tx->vout[txout.i].scriptPubKey, outType, dests, nRequiredSigs))
663 {
29c07a8f 664 CScript scriptPubKey;
665 if (outType != TX_SCRIPTHASH ||
666 (dests.size() &&
667 GetCScript(GetDestinationID(dests[0]), scriptPubKey) &&
668 ExtractDestinations(scriptPubKey, outType, dests, nRequiredSigs)))
248084b7 669 {
29c07a8f 670 for (auto &dest : dests)
248084b7 671 {
29c07a8f 672 if (dest.which() == COptCCParams::ADDRTYPE_PK || dest.which() == COptCCParams::ADDRTYPE_PKH)
673 {
674 setKeyIDs.insert(GetDestinationID(dest));
675 }
248084b7 676 }
677 }
678 }
679 }
680 return setKeyIDs;
681}
682
d5087d1b 683bool CWallet::AddWatchOnly(const CScript &dest)
c8988460
PW
684{
685 if (!CCryptoKeyStore::AddWatchOnly(dest))
686 return false;
687 nTimeFirstKey = 1; // No birthday information for watch-only keys.
939ed973 688 NotifyWatchonlyChanged(true);
c8988460
PW
689 if (!fFileBacked)
690 return true;
691 return CWalletDB(strWalletFile).WriteWatchOnly(dest);
692}
693
ccca27a7
CL
694bool CWallet::RemoveWatchOnly(const CScript &dest)
695{
696 AssertLockHeld(cs_wallet);
697 if (!CCryptoKeyStore::RemoveWatchOnly(dest))
698 return false;
699 if (!HaveWatchOnly())
700 NotifyWatchonlyChanged(false);
701 if (fFileBacked)
702 if (!CWalletDB(strWalletFile).EraseWatchOnly(dest))
703 return false;
704
705 return true;
706}
707
d5087d1b 708bool CWallet::LoadWatchOnly(const CScript &dest)
c8988460 709{
c8988460
PW
710 return CCryptoKeyStore::AddWatchOnly(dest);
711}
712
94f778bd 713bool CWallet::Unlock(const SecureString& strWalletPassphrase)
4e87d341 714{
6cc4a62c
GA
715 CCrypter crypter;
716 CKeyingMaterial vMasterKey;
4e87d341 717
f8dcd5ca
PW
718 {
719 LOCK(cs_wallet);
4e87d341
MC
720 BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
721 {
722 if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
723 return false;
724 if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
92f2c1fe 725 continue; // try another master key
1f561f32
JG
726 if (CCryptoKeyStore::Unlock(vMasterKey)) {
727 // Now that the wallet is decrypted, ensure we have an HD seed.
728 // https://github.com/zcash/zcash/issues/3607
729 if (!this->HaveHDSeed()) {
730 this->GenerateNewSeed();
731 }
4e87d341 732 return true;
1f561f32 733 }
4e87d341 734 }
f8dcd5ca 735 }
4e87d341
MC
736 return false;
737}
738
94f778bd 739bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase)
4e87d341 740{
6cc4a62c 741 bool fWasLocked = IsLocked();
4e87d341 742
6cc4a62c 743 {
f8dcd5ca 744 LOCK(cs_wallet);
4e87d341
MC
745 Lock();
746
747 CCrypter crypter;
748 CKeyingMaterial vMasterKey;
749 BOOST_FOREACH(MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
750 {
751 if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
752 return false;
6cc4a62c 753 if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
4e87d341
MC
754 return false;
755 if (CCryptoKeyStore::Unlock(vMasterKey))
756 {
51ed9ec9 757 int64_t nStartTime = GetTimeMillis();
ddebdd9a
MC
758 crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
759 pMasterKey.second.nDeriveIterations = pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime)));
760
761 nStartTime = GetTimeMillis();
762 crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
763 pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
764
765 if (pMasterKey.second.nDeriveIterations < 25000)
766 pMasterKey.second.nDeriveIterations = 25000;
767
881a85a2 768 LogPrintf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
ddebdd9a 769
4e87d341
MC
770 if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
771 return false;
772 if (!crypter.Encrypt(vMasterKey, pMasterKey.second.vchCryptedKey))
773 return false;
774 CWalletDB(strWalletFile).WriteMasterKey(pMasterKey.first, pMasterKey.second);
775 if (fWasLocked)
776 Lock();
777 return true;
778 }
779 }
780 }
6cc4a62c 781
4e87d341
MC
782 return false;
783}
784
162bfc3a
E
785void CWallet::ChainTipAdded(const CBlockIndex *pindex,
786 const CBlock *pblock,
787 SproutMerkleTree sproutTree,
788 SaplingMerkleTree saplingTree)
789{
790 IncrementNoteWitnesses(pindex, pblock, sproutTree, saplingTree);
791 UpdateSaplingNullifierNoteMapForBlock(pblock);
792}
793
f86ee1c2
EOW
794void CWallet::ChainTip(const CBlockIndex *pindex,
795 const CBlock *pblock,
4fc309f0
EOW
796 SproutMerkleTree sproutTree,
797 SaplingMerkleTree saplingTree,
f86ee1c2 798 bool added)
769e031c
JG
799{
800 if (added) {
162bfc3a 801 ChainTipAdded(pindex, pblock, sproutTree, saplingTree);
6921c81b
S
802 // Prevent migration transactions from being created when node is syncing after launch,
803 // and also when node wakes up from suspension/hibernation and incoming blocks are old.
3ffc29b8 804 if (!IsInitialBlockDownload(Params()) &&
6921c81b
S
805 pblock->GetBlockTime() > GetAdjustedTime() - 3 * 60 * 60)
806 {
88d014d0 807 RunSaplingMigration(pindex->GetHeight());
6921c81b 808 }
769e031c 809 } else {
40ef121e 810 DecrementNoteWitnesses(pindex);
162bfc3a 811 UpdateSaplingNullifierNoteMapForBlock(pblock);
769e031c
JG
812 }
813}
814
81a45d69 815void CWallet::RunSaplingMigration(int blockHeight) {
2c6c5526 816 if (!Params().GetConsensus().NetworkUpgradeActive(blockHeight, Consensus::UPGRADE_SAPLING)) {
81a45d69
E
817 return;
818 }
819 LOCK(cs_wallet);
162bfc3a
E
820 if (!fSaplingMigrationEnabled) {
821 return;
822 }
81a45d69
E
823 // The migration transactions to be sent in a particular batch can take
824 // significant time to generate, and this time depends on the speed of the user's
825 // computer. If they were generated only after a block is seen at the target
826 // height minus 1, then this could leak information. Therefore, for target
827 // height N, implementations SHOULD start generating the transactions at around
828 // height N-5
829 if (blockHeight % 500 == 495) {
d48c3efc 830 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
7470ae88 831 std::shared_ptr<AsyncRPCOperation> lastOperation = q->getOperationForId(saplingMigrationOperationId);
d48c3efc
E
832 if (lastOperation != nullptr) {
833 lastOperation->cancel();
81a45d69
E
834 }
835 pendingSaplingMigrationTxs.clear();
81a45d69 836 std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_saplingmigration(blockHeight + 5));
d48c3efc 837 saplingMigrationOperationId = operation->getId();
81a45d69
E
838 q->addOperation(operation);
839 } else if (blockHeight % 500 == 499) {
d48c3efc 840 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
7470ae88 841 std::shared_ptr<AsyncRPCOperation> lastOperation = q->getOperationForId(saplingMigrationOperationId);
d48c3efc
E
842 if (lastOperation != nullptr) {
843 lastOperation->cancel();
7c4ad6e2 844 }
81a45d69 845 for (const CTransaction& transaction : pendingSaplingMigrationTxs) {
81a45d69 846 // Send the transaction
3220d993
E
847 CWalletTx wtx(this, transaction);
848 CommitTransaction(wtx, boost::none);
81a45d69
E
849 }
850 pendingSaplingMigrationTxs.clear();
851 }
852}
853
854void CWallet::AddPendingSaplingMigrationTx(const CTransaction& tx) {
7c4ad6e2 855 LOCK(cs_wallet);
81a45d69 856 pendingSaplingMigrationTxs.push_back(tx);
769e031c
JG
857}
858
ed6d0b5f
PW
859void CWallet::SetBestChain(const CBlockLocator& loc)
860{
861 CWalletDB walletdb(strWalletFile);
03f83b9b 862 SetBestChainINTERNAL(walletdb, loc);
ed6d0b5f 863}
7414733b 864
e4f0d6a8
LR
865std::set<std::pair<libzcash::PaymentAddress, uint256>> CWallet::GetNullifiersForAddresses(
866 const std::set<libzcash::PaymentAddress> & addresses)
0646f749
EOW
867{
868 std::set<std::pair<libzcash::PaymentAddress, uint256>> nullifierSet;
e4f0d6a8
LR
869 // Sapling ivk -> list of addrs map
870 // (There may be more than one diversified address for a given ivk.)
871 std::map<libzcash::SaplingIncomingViewingKey, std::vector<libzcash::SaplingPaymentAddress>> ivkMap;
872 for (const auto & addr : addresses) {
873 auto saplingAddr = boost::get<libzcash::SaplingPaymentAddress>(&addr);
874 if (saplingAddr != nullptr) {
875 libzcash::SaplingIncomingViewingKey ivk;
876 this->GetSaplingIncomingViewingKey(*saplingAddr, ivk);
877 ivkMap[ivk].push_back(*saplingAddr);
878 }
879 }
0646f749 880 for (const auto & txPair : mapWallet) {
e4f0d6a8 881 // Sprout
2f0b2a25 882 for (const auto & noteDataPair : txPair.second.mapSproutNoteData) {
e4f0d6a8
LR
883 auto & noteData = noteDataPair.second;
884 auto & nullifier = noteData.nullifier;
885 auto & address = noteData.address;
886 if (nullifier && addresses.count(address)) {
887 nullifierSet.insert(std::make_pair(address, nullifier.get()));
888 }
889 }
890 // Sapling
891 for (const auto & noteDataPair : txPair.second.mapSaplingNoteData) {
892 auto & noteData = noteDataPair.second;
893 auto & nullifier = noteData.nullifier;
894 auto & ivk = noteData.ivk;
895 if (nullifier && ivkMap.count(ivk)) {
896 for (const auto & addr : ivkMap[ivk]) {
897 nullifierSet.insert(std::make_pair(addr, nullifier.get()));
898 }
0646f749
EOW
899 }
900 }
901 }
902 return nullifierSet;
903}
904
e4f0d6a8
LR
905bool CWallet::IsNoteSproutChange(
906 const std::set<std::pair<libzcash::PaymentAddress, uint256>> & nullifierSet,
907 const PaymentAddress & address,
908 const JSOutPoint & jsop)
0646f749
EOW
909{
910 // A Note is marked as "change" if the address that received it
911 // also spent Notes in the same transaction. This will catch,
912 // for instance:
913 // - Change created by spending fractions of Notes (because
914 // z_sendmany sends change to the originating z-address).
915 // - "Chaining Notes" used to connect JoinSplits together.
916 // - Notes created by consolidation transactions (e.g. using
917 // z_mergetoaddress).
918 // - Notes sent from one address to itself.
f57f76d7 919 for (const JSDescription & jsd : mapWallet[jsop.hash].vJoinSplit) {
0646f749
EOW
920 for (const uint256 & nullifier : jsd.nullifiers) {
921 if (nullifierSet.count(std::make_pair(address, nullifier))) {
922 return true;
923 }
924 }
925 }
926 return false;
927}
928
e4f0d6a8
LR
929bool CWallet::IsNoteSaplingChange(const std::set<std::pair<libzcash::PaymentAddress, uint256>> & nullifierSet,
930 const libzcash::PaymentAddress & address,
931 const SaplingOutPoint & op)
932{
933 // A Note is marked as "change" if the address that received it
934 // also spent Notes in the same transaction. This will catch,
935 // for instance:
936 // - Change created by spending fractions of Notes (because
937 // z_sendmany sends change to the originating z-address).
938 // - Notes created by consolidation transactions (e.g. using
939 // z_mergetoaddress).
940 // - Notes sent from one address to itself.
941 for (const SpendDescription &spend : mapWallet[op.hash].vShieldedSpend) {
942 if (nullifierSet.count(std::make_pair(address, spend.nullifier))) {
943 return true;
944 }
945 }
946 return false;
947}
948
439e1497 949bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, bool fExplicit)
0b807a41 950{
ca4cf5cf 951 LOCK(cs_wallet); // nWalletVersion
0b807a41
PW
952 if (nWalletVersion >= nVersion)
953 return true;
954
439e1497
PW
955 // when doing an explicit upgrade, if we pass the max version permitted, upgrade all the way
956 if (fExplicit && nVersion > nWalletMaxVersion)
957 nVersion = FEATURE_LATEST;
958
0b807a41
PW
959 nWalletVersion = nVersion;
960
439e1497
PW
961 if (nVersion > nWalletMaxVersion)
962 nWalletMaxVersion = nVersion;
963
0b807a41
PW
964 if (fFileBacked)
965 {
966 CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(strWalletFile);
0b807a41
PW
967 if (nWalletVersion > 40000)
968 pwalletdb->WriteMinVersion(nWalletVersion);
969 if (!pwalletdbIn)
970 delete pwalletdb;
971 }
972
973 return true;
974}
975
439e1497
PW
976bool CWallet::SetMaxVersion(int nVersion)
977{
ca4cf5cf 978 LOCK(cs_wallet); // nWalletVersion, nWalletMaxVersion
439e1497
PW
979 // cannot downgrade below current version
980 if (nWalletVersion > nVersion)
981 return false;
982
983 nWalletMaxVersion = nVersion;
984
985 return true;
986}
987
3015e0bc 988set<uint256> CWallet::GetConflicts(const uint256& txid) const
731b89b8
GA
989{
990 set<uint256> result;
991 AssertLockHeld(cs_wallet);
992
993 std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(txid);
994 if (it == mapWallet.end())
995 return result;
996 const CWalletTx& wtx = it->second;
997
93a18a36 998 std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
731b89b8
GA
999
1000 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
1001 {
93a18a36
GA
1002 if (mapTxSpends.count(txin.prevout) <= 1)
1003 continue; // No conflict if zero or one spends
1004 range = mapTxSpends.equal_range(txin.prevout);
1005 for (TxSpends::const_iterator it = range.first; it != range.second; ++it)
3015e0bc 1006 result.insert(it->second);
731b89b8 1007 }
0f106047
JG
1008
1009 std::pair<TxNullifiers::const_iterator, TxNullifiers::const_iterator> range_n;
1010
f57f76d7 1011 for (const JSDescription& jsdesc : wtx.vJoinSplit) {
0f106047 1012 for (const uint256& nullifier : jsdesc.nullifiers) {
3438e26c 1013 if (mapTxSproutNullifiers.count(nullifier) <= 1) {
0f106047
JG
1014 continue; // No conflict if zero or one spends
1015 }
3438e26c 1016 range_n = mapTxSproutNullifiers.equal_range(nullifier);
0f106047
JG
1017 for (TxNullifiers::const_iterator it = range_n.first; it != range_n.second; ++it) {
1018 result.insert(it->second);
1019 }
1020 }
1021 }
3afc6ce2
S
1022
1023 std::pair<TxNullifiers::const_iterator, TxNullifiers::const_iterator> range_o;
1024
1025 for (const SpendDescription &spend : wtx.vShieldedSpend) {
1026 uint256 nullifier = spend.nullifier;
1027 if (mapTxSaplingNullifiers.count(nullifier) <= 1) {
1028 continue; // No conflict if zero or one spends
1029 }
1030 range_o = mapTxSaplingNullifiers.equal_range(nullifier);
1031 for (TxNullifiers::const_iterator it = range_o.first; it != range_o.second; ++it) {
1032 result.insert(it->second);
1033 }
0f106047 1034 }
731b89b8
GA
1035 return result;
1036}
1037
2bb1c877
JS
1038void CWallet::Flush(bool shutdown)
1039{
1040 bitdb.Flush(shutdown);
1041}
1042
341e2385 1043bool CWallet::Verify(const string& walletFile, string& warningString, string& errorString)
2bb1c877
JS
1044{
1045 if (!bitdb.Open(GetDataDir()))
1046 {
1047 // try moving the database env out of the way
1048 boost::filesystem::path pathDatabase = GetDataDir() / "database";
1049 boost::filesystem::path pathDatabaseBak = GetDataDir() / strprintf("database.%d.bak", GetTime());
1050 try {
1051 boost::filesystem::rename(pathDatabase, pathDatabaseBak);
1052 LogPrintf("Moved old %s to %s. Retrying.\n", pathDatabase.string(), pathDatabaseBak.string());
1053 } catch (const boost::filesystem::filesystem_error&) {
1054 // failure is ok (well, not really, but it's not worse than what we started with)
1055 }
efb7662d 1056
2bb1c877
JS
1057 // try again
1058 if (!bitdb.Open(GetDataDir())) {
1059 // if it still fails, it probably means we can't even create the database env
1060 string msg = strprintf(_("Error initializing wallet database environment %s!"), GetDataDir());
1061 errorString += msg;
1062 return true;
1063 }
1064 }
efb7662d 1065
2bb1c877
JS
1066 if (GetBoolArg("-salvagewallet", false))
1067 {
1068 // Recover readable keypairs:
1069 if (!CWalletDB::Recover(bitdb, walletFile, true))
1070 return false;
1071 }
efb7662d 1072
2bb1c877
JS
1073 if (boost::filesystem::exists(GetDataDir() / walletFile))
1074 {
1075 CDBEnv::VerifyResult r = bitdb.Verify(walletFile, CWalletDB::Recover);
1076 if (r == CDBEnv::RECOVER_OK)
1077 {
1078 warningString += strprintf(_("Warning: wallet.dat corrupt, data salvaged!"
1079 " Original wallet.dat saved as wallet.{timestamp}.bak in %s; if"
1080 " your balance or transactions are incorrect you should"
1081 " restore from a backup."), GetDataDir());
1082 }
1083 if (r == CDBEnv::RECOVER_FAIL)
1084 errorString += _("wallet.dat corrupt, salvage failed");
1085 }
efb7662d 1086
2bb1c877
JS
1087 return true;
1088}
1089
0f106047
JG
1090template <class T>
1091void CWallet::SyncMetaData(pair<typename TxSpendMap<T>::iterator, typename TxSpendMap<T>::iterator> range)
731b89b8
GA
1092{
1093 // We want all the wallet transactions in range to have the same metadata as
1094 // the oldest (smallest nOrderPos).
1095 // So: find smallest nOrderPos:
1096
1097 int nMinOrderPos = std::numeric_limits<int>::max();
1098 const CWalletTx* copyFrom = NULL;
0f106047 1099 for (typename TxSpendMap<T>::iterator it = range.first; it != range.second; ++it)
731b89b8
GA
1100 {
1101 const uint256& hash = it->second;
1102 int n = mapWallet[hash].nOrderPos;
1103 if (n < nMinOrderPos)
1104 {
1105 nMinOrderPos = n;
1106 copyFrom = &mapWallet[hash];
1107 }
1108 }
1109 // Now copy data from copyFrom to rest:
0f106047 1110 for (typename TxSpendMap<T>::iterator it = range.first; it != range.second; ++it)
731b89b8
GA
1111 {
1112 const uint256& hash = it->second;
1113 CWalletTx* copyTo = &mapWallet[hash];
1114 if (copyFrom == copyTo) continue;
1115 copyTo->mapValue = copyFrom->mapValue;
303f80fb 1116 // mapSproutNoteData and mapSaplingNoteData not copied on purpose
c3a7307a 1117 // (it is always set correctly for each CWalletTx)
731b89b8
GA
1118 copyTo->vOrderForm = copyFrom->vOrderForm;
1119 // fTimeReceivedIsTxTime not copied on purpose
1120 // nTimeReceived not copied on purpose
1121 copyTo->nTimeSmart = copyFrom->nTimeSmart;
1122 copyTo->fFromMe = copyFrom->fFromMe;
1123 copyTo->strFromAccount = copyFrom->strFromAccount;
731b89b8
GA
1124 // nOrderPos not copied on purpose
1125 // cached members not copied on purpose
1126 }
1127}
1128
5b40d886
MF
1129/**
1130 * Outpoint is spent if any non-conflicted transaction
1131 * spends it:
1132 */
93a18a36 1133bool CWallet::IsSpent(const uint256& hash, unsigned int n) const
731b89b8 1134{
93a18a36
GA
1135 const COutPoint outpoint(hash, n);
1136 pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
1137 range = mapTxSpends.equal_range(outpoint);
731b89b8 1138
93a18a36 1139 for (TxSpends::const_iterator it = range.first; it != range.second; ++it)
731b89b8 1140 {
93a18a36
GA
1141 const uint256& wtxid = it->second;
1142 std::map<uint256, CWalletTx>::const_iterator mit = mapWallet.find(wtxid);
1143 if (mit != mapWallet.end() && mit->second.GetDepthInMainChain() >= 0)
1144 return true; // Spent
731b89b8 1145 }
93a18a36
GA
1146 return false;
1147}
1148
0f106047
JG
1149/**
1150 * Note is spent if any non-conflicted transaction
1151 * spends it:
1152 */
3b6dd486 1153bool CWallet::IsSproutSpent(const uint256& nullifier) const {
0f106047 1154 pair<TxNullifiers::const_iterator, TxNullifiers::const_iterator> range;
3438e26c 1155 range = mapTxSproutNullifiers.equal_range(nullifier);
0f106047
JG
1156
1157 for (TxNullifiers::const_iterator it = range.first; it != range.second; ++it) {
1158 const uint256& wtxid = it->second;
1159 std::map<uint256, CWalletTx>::const_iterator mit = mapWallet.find(wtxid);
1160 if (mit != mapWallet.end() && mit->second.GetDepthInMainChain() >= 0) {
1161 return true; // Spent
1162 }
1163 }
1164 return false;
1165}
1166
3b6dd486
S
1167bool CWallet::IsSaplingSpent(const uint256& nullifier) const {
1168 pair<TxNullifiers::const_iterator, TxNullifiers::const_iterator> range;
edfc6a78
S
1169 range = mapTxSaplingNullifiers.equal_range(nullifier);
1170
1171 for (TxNullifiers::const_iterator it = range.first; it != range.second; ++it) {
1172 const uint256& wtxid = it->second;
0f106047
JG
1173 std::map<uint256, CWalletTx>::const_iterator mit = mapWallet.find(wtxid);
1174 if (mit != mapWallet.end() && mit->second.GetDepthInMainChain() >= 0) {
1175 return true; // Spent
1176 }
1177 }
1178 return false;
1179}
1180
d5e490d9 1181void CWallet::AddToTransparentSpends(const COutPoint& outpoint, const uint256& wtxid)
93a18a36
GA
1182{
1183 mapTxSpends.insert(make_pair(outpoint, wtxid));
1184
1185 pair<TxSpends::iterator, TxSpends::iterator> range;
1186 range = mapTxSpends.equal_range(outpoint);
0f106047 1187 SyncMetaData<COutPoint>(range);
93a18a36
GA
1188}
1189
d5e490d9 1190void CWallet::AddToSproutSpends(const uint256& nullifier, const uint256& wtxid)
0f106047 1191{
3438e26c 1192 mapTxSproutNullifiers.insert(make_pair(nullifier, wtxid));
0f106047
JG
1193
1194 pair<TxNullifiers::iterator, TxNullifiers::iterator> range;
3438e26c 1195 range = mapTxSproutNullifiers.equal_range(nullifier);
0f106047
JG
1196 SyncMetaData<uint256>(range);
1197}
93a18a36 1198
c343e2db
S
1199void CWallet::AddToSaplingSpends(const uint256& nullifier, const uint256& wtxid)
1200{
1201 mapTxSaplingNullifiers.insert(make_pair(nullifier, wtxid));
1202
1203 pair<TxNullifiers::iterator, TxNullifiers::iterator> range;
1204 range = mapTxSaplingNullifiers.equal_range(nullifier);
0f106047
JG
1205 SyncMetaData<uint256>(range);
1206}
93a18a36
GA
1207
1208void CWallet::AddToSpends(const uint256& wtxid)
1209{
1210 assert(mapWallet.count(wtxid));
1211 CWalletTx& thisTx = mapWallet[wtxid];
1212 if (thisTx.IsCoinBase()) // Coinbases don't spend anything!
1213 return;
1214
0f106047 1215 for (const CTxIn& txin : thisTx.vin) {
d5e490d9 1216 AddToTransparentSpends(txin.prevout, wtxid);
0f106047 1217 }
f57f76d7 1218 for (const JSDescription& jsdesc : thisTx.vJoinSplit) {
0f106047 1219 for (const uint256& nullifier : jsdesc.nullifiers) {
d5e490d9 1220 AddToSproutSpends(nullifier, wtxid);
0f106047
JG
1221 }
1222 }
52332fb4
S
1223 for (const SpendDescription &spend : thisTx.vShieldedSpend) {
1224 AddToSaplingSpends(spend.nullifier, wtxid);
1225 }
731b89b8
GA
1226}
1227
76b22658
JG
1228void CWallet::ClearNoteWitnessCache()
1229{
1230 LOCK(cs_wallet);
1231 for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
005f3ad1 1232 for (mapSproutNoteData_t::value_type& item : wtxItem.second.mapSproutNoteData) {
40600f50 1233 item.second.witnesses.clear();
a4ef3aa9 1234 item.second.witnessHeight = -1;
76b22658 1235 }
403b9b4e 1236 for (mapSaplingNoteData_t::value_type& item : wtxItem.second.mapSaplingNoteData) {
40600f50 1237 item.second.witnesses.clear();
a4ef3aa9 1238 item.second.witnessHeight = -1;
76b22658
JG
1239 }
1240 }
a4ef3aa9 1241 nWitnessCacheSize = 0;
a7f86bc7 1242 //fprintf(stderr,"Clear witness cache\n");
76b22658
JG
1243}
1244
b5380248
EOW
1245template<typename NoteDataMap>
1246void CopyPreviousWitnesses(NoteDataMap& noteDataMap, int indexHeight, int64_t nWitnessCacheSize)
1247{
1248 for (auto& item : noteDataMap) {
1249 auto* nd = &(item.second);
1250 // Only increment witnesses that are behind the current height
1251 if (nd->witnessHeight < indexHeight) {
1252 // Check the validity of the cache
1253 // The only time a note witnessed above the current height
1254 // would be invalid here is during a reindex when blocks
1255 // have been decremented, and we are incrementing the blocks
1256 // immediately after.
1257 assert(nWitnessCacheSize >= nd->witnesses.size());
1258 // Witnesses being incremented should always be either -1
1259 // (never incremented or decremented) or one below indexHeight
1260 assert((nd->witnessHeight == -1) || (nd->witnessHeight == indexHeight - 1));
1261 // Copy the witness for the previous block if we have one
1262 if (nd->witnesses.size() > 0) {
1263 nd->witnesses.push_front(nd->witnesses.front());
1264 }
1265 if (nd->witnesses.size() > WITNESS_CACHE_SIZE) {
1266 nd->witnesses.pop_back();
be74c80d
JG
1267 }
1268 }
b5380248
EOW
1269 }
1270}
1271
f6d0d5ec
EOW
1272template<typename NoteDataMap>
1273void AppendNoteCommitment(NoteDataMap& noteDataMap, int indexHeight, int64_t nWitnessCacheSize, const uint256& note_commitment)
1274{
1275 for (auto& item : noteDataMap) {
1276 auto* nd = &(item.second);
1277 if (nd->witnessHeight < indexHeight && nd->witnesses.size() > 0) {
1278 // Check the validity of the cache
1279 // See comment in CopyPreviousWitnesses about validity.
1280 assert(nWitnessCacheSize >= nd->witnesses.size());
1281 nd->witnesses.front().append(note_commitment);
8a7d37be 1282 }
f6d0d5ec
EOW
1283 }
1284}
be74c80d 1285
f6d0d5ec
EOW
1286template<typename OutPoint, typename NoteData, typename Witness>
1287void WitnessNoteIfMine(std::map<OutPoint, NoteData>& noteDataMap, int indexHeight, int64_t nWitnessCacheSize, const OutPoint& key, const Witness& witness)
1288{
1289 if (noteDataMap.count(key) && noteDataMap[key].witnessHeight < indexHeight) {
1290 auto* nd = &(noteDataMap[key]);
1291 if (nd->witnesses.size() > 0) {
1292 // We think this can happen because we write out the
1293 // witness cache state after every block increment or
1294 // decrement, but the block index itself is written in
1295 // batches. So if the node crashes in between these two
1296 // operations, it is possible for IncrementNoteWitnesses
1297 // to be called again on previously-cached blocks. This
1298 // doesn't affect existing cached notes because of the
1299 // NoteData::witnessHeight checks. See #1378 for details.
1300 LogPrintf("Inconsistent witness cache state found for %s\n- Cache size: %d\n- Top (height %d): %s\n- New (height %d): %s\n",
1301 key.ToString(), nd->witnesses.size(),
1302 nd->witnessHeight,
1303 nd->witnesses.front().root().GetHex(),
1304 indexHeight,
1305 witness.root().GetHex());
1306 nd->witnesses.clear();
be74c80d 1307 }
f6d0d5ec
EOW
1308 nd->witnesses.push_front(witness);
1309 // Set height to one less than pindex so it gets incremented
1310 nd->witnessHeight = indexHeight - 1;
1311 // Check the validity of the cache
1312 assert(nWitnessCacheSize >= nd->witnesses.size());
1313 }
1314}
be74c80d 1315
be74c80d 1316
4a0bc604
EOW
1317template<typename NoteDataMap>
1318void UpdateWitnessHeights(NoteDataMap& noteDataMap, int indexHeight, int64_t nWitnessCacheSize)
1319{
1320 for (auto& item : noteDataMap) {
1321 auto* nd = &(item.second);
1322 if (nd->witnessHeight < indexHeight) {
1323 nd->witnessHeight = indexHeight;
1324 // Check the validity of the cache
1325 // See comment in CopyPreviousWitnesses about validity.
1326 assert(nWitnessCacheSize >= nd->witnesses.size());
1327 }
1328 }
1329}
be74c80d 1330
be74c80d
JG
1331void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex,
1332 const CBlock* pblockIn,
4fc309f0
EOW
1333 SproutMerkleTree& sproutTree,
1334 SaplingMerkleTree& saplingTree)
be74c80d 1335{
49695a97
EOW
1336 LOCK(cs_wallet);
1337 for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
4b729ec5 1338 ::CopyPreviousWitnesses(wtxItem.second.mapSproutNoteData, pindex->GetHeight(), nWitnessCacheSize);
1339 ::CopyPreviousWitnesses(wtxItem.second.mapSaplingNoteData, pindex->GetHeight(), nWitnessCacheSize);
49695a97 1340 }
b5380248 1341
49695a97
EOW
1342 if (nWitnessCacheSize < WITNESS_CACHE_SIZE) {
1343 nWitnessCacheSize += 1;
1344 }
be74c80d 1345
49695a97
EOW
1346 const CBlock* pblock {pblockIn};
1347 CBlock block;
1348 if (!pblock) {
71cf6ba9 1349 ReadBlockFromDisk(block, pindex, Params().GetConsensus());
49695a97
EOW
1350 pblock = &block;
1351 }
be74c80d 1352
49695a97
EOW
1353 for (const CTransaction& tx : pblock->vtx) {
1354 auto hash = tx.GetHash();
1355 bool txIsOurs = mapWallet.count(hash);
45de2eda 1356 // Sprout
f57f76d7
DA
1357 for (size_t i = 0; i < tx.vJoinSplit.size(); i++) {
1358 const JSDescription& jsdesc = tx.vJoinSplit[i];
49695a97
EOW
1359 for (uint8_t j = 0; j < jsdesc.commitments.size(); j++) {
1360 const uint256& note_commitment = jsdesc.commitments[j];
f86ee1c2 1361 sproutTree.append(note_commitment);
be74c80d 1362
49695a97
EOW
1363 // Increment existing witnesses
1364 for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
4b729ec5 1365 ::AppendNoteCommitment(wtxItem.second.mapSproutNoteData, pindex->GetHeight(), nWitnessCacheSize, note_commitment);
be74c80d 1366 }
b6961fc1 1367
49695a97
EOW
1368 // If this is our note, witness it
1369 if (txIsOurs) {
1370 JSOutPoint jsoutpt {hash, i, j};
4b729ec5 1371 ::WitnessNoteIfMine(mapWallet[hash].mapSproutNoteData, pindex->GetHeight(), nWitnessCacheSize, jsoutpt, sproutTree.witness());
be74c80d
JG
1372 }
1373 }
1374 }
45de2eda
EOW
1375 // Sapling
1376 for (uint32_t i = 0; i < tx.vShieldedOutput.size(); i++) {
1377 const uint256& note_commitment = tx.vShieldedOutput[i].cm;
1378 saplingTree.append(note_commitment);
1379
1380 // Increment existing witnesses
1381 for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
4b729ec5 1382 ::AppendNoteCommitment(wtxItem.second.mapSaplingNoteData, pindex->GetHeight(), nWitnessCacheSize, note_commitment);
45de2eda 1383 }
b6961fc1 1384
45de2eda
EOW
1385 // If this is our note, witness it
1386 if (txIsOurs) {
1387 SaplingOutPoint outPoint {hash, i};
4b729ec5 1388 ::WitnessNoteIfMine(mapWallet[hash].mapSaplingNoteData, pindex->GetHeight(), nWitnessCacheSize, outPoint, saplingTree.witness());
83d7b5b6
JG
1389 }
1390 }
49695a97 1391 }
b6961fc1 1392
49695a97
EOW
1393 // Update witness heights
1394 for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
4b729ec5 1395 ::UpdateWitnessHeights(wtxItem.second.mapSproutNoteData, pindex->GetHeight(), nWitnessCacheSize);
1396 ::UpdateWitnessHeights(wtxItem.second.mapSaplingNoteData, pindex->GetHeight(), nWitnessCacheSize);
be74c80d 1397 }
49695a97
EOW
1398
1399 // For performance reasons, we write out the witness cache in
1400 // CWallet::SetBestChain() (which also ensures that overall consistency
1401 // of the wallet.dat is maintained).
be74c80d
JG
1402}
1403
9d804cc6 1404template<typename NoteDataMap>
47ab0926 1405bool DecrementNoteWitnesses(NoteDataMap& noteDataMap, int indexHeight, int64_t nWitnessCacheSize)
be74c80d 1406{
8ba45413 1407 extern int32_t KOMODO_REWIND;
9feb4b9e 1408
9d804cc6
EOW
1409 for (auto& item : noteDataMap) {
1410 auto* nd = &(item.second);
1411 // Only decrement witnesses that are not above the current height
1412 if (nd->witnessHeight <= indexHeight) {
49695a97 1413 // Check the validity of the cache
9d804cc6
EOW
1414 // See comment below (this would be invalid if there were a
1415 // prior decrement).
1416 assert(nWitnessCacheSize >= nd->witnesses.size());
1417 // Witnesses being decremented should always be either -1
1418 // (never incremented or decremented) or equal to the height
1419 // of the block being removed (indexHeight)
47ab0926 1420 if (!((nd->witnessHeight == -1) || (nd->witnessHeight == indexHeight)))
1421 {
1422 printf("at height %d\n", indexHeight);
1423 return false;
1424 }
9d804cc6
EOW
1425 if (nd->witnesses.size() > 0) {
1426 nd->witnesses.pop_front();
be74c80d 1427 }
9d804cc6
EOW
1428 // indexHeight is the height of the block being removed, so
1429 // the new witness cache height is one below it.
1430 nd->witnessHeight = indexHeight - 1;
be74c80d 1431 }
9d804cc6
EOW
1432 // Check the validity of the cache
1433 // Technically if there are notes witnessed above the current
1434 // height, their cache will now be invalid (relative to the new
1435 // value of nWitnessCacheSize). However, this would only occur
1436 // during a reindex, and by the time the reindex reaches the tip
1437 // of the chain again, the existing witness caches will be valid
1438 // again.
1439 // We don't set nWitnessCacheSize to zero at the start of the
1440 // reindex because the on-disk blocks had already resulted in a
1441 // chain that didn't trigger the assertion below.
1442 if (nd->witnessHeight < indexHeight) {
1443 // Subtract 1 to compare to what nWitnessCacheSize will be after
1444 // decrementing.
1445 assert((nWitnessCacheSize - 1) >= nd->witnesses.size());
4c73b58b 1446 }
be74c80d 1447 }
9feb4b9e 1448 assert(KOMODO_REWIND != 0 || nWitnessCacheSize > 0);
47ab0926 1449 return true;
9d804cc6
EOW
1450}
1451
1452void CWallet::DecrementNoteWitnesses(const CBlockIndex* pindex)
1453{
1454 LOCK(cs_wallet);
1455 for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
47ab0926 1456 if (!::DecrementNoteWitnesses(wtxItem.second.mapSproutNoteData, pindex->GetHeight(), nWitnessCacheSize))
1457 needsRescan = true;
1458 if (!::DecrementNoteWitnesses(wtxItem.second.mapSaplingNoteData, pindex->GetHeight(), nWitnessCacheSize))
1459 needsRescan = true;
9d804cc6 1460 }
6a23bf78 1461 if (nWitnessCacheSize != 0)
1462 {
1463 nWitnessCacheSize -= 1;
1464 // TODO: If nWitnessCache is zero, we need to regenerate the caches (#1302)
1465 if (nWitnessCacheSize == 0)
1466 {
1467 ClearNoteWitnessCache();
1468 }
1469 //assert(nWitnessCacheSize > 0);
1470 }
49695a97
EOW
1471
1472 // For performance reasons, we write out the witness cache in
1473 // CWallet::SetBestChain() (which also ensures that overall consistency
1474 // of the wallet.dat is maintained).
be74c80d
JG
1475}
1476
94f778bd 1477bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
4e87d341 1478{
6cc4a62c
GA
1479 if (IsCrypted())
1480 return false;
4e87d341 1481
6cc4a62c 1482 CKeyingMaterial vMasterKey;
4e87d341 1483
6cc4a62c 1484 vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
65e3a1e7 1485 GetRandBytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
4e87d341 1486
6cc4a62c 1487 CMasterKey kMasterKey;
001a53d7 1488
6cc4a62c 1489 kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
65e3a1e7 1490 GetRandBytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
4e87d341 1491
6cc4a62c 1492 CCrypter crypter;
51ed9ec9 1493 int64_t nStartTime = GetTimeMillis();
6cc4a62c
GA
1494 crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
1495 kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime));
ddebdd9a 1496
6cc4a62c
GA
1497 nStartTime = GetTimeMillis();
1498 crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
1499 kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
ddebdd9a 1500
6cc4a62c
GA
1501 if (kMasterKey.nDeriveIterations < 25000)
1502 kMasterKey.nDeriveIterations = 25000;
ddebdd9a 1503
881a85a2 1504 LogPrintf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations);
ddebdd9a 1505
6cc4a62c
GA
1506 if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod))
1507 return false;
1508 if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey))
1509 return false;
4e87d341 1510
6cc4a62c 1511 {
f8dcd5ca 1512 LOCK(cs_wallet);
4e87d341
MC
1513 mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
1514 if (fFileBacked)
1515 {
870da77d 1516 assert(!pwalletdbEncryption);
96f34cd5 1517 pwalletdbEncryption = new CWalletDB(strWalletFile);
870da77d
PK
1518 if (!pwalletdbEncryption->TxnBegin()) {
1519 delete pwalletdbEncryption;
1520 pwalletdbEncryption = NULL;
0fb78eae 1521 return false;
870da77d 1522 }
96f34cd5 1523 pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
4e87d341
MC
1524 }
1525
1526 if (!EncryptKeys(vMasterKey))
96f34cd5 1527 {
870da77d 1528 if (fFileBacked) {
96f34cd5 1529 pwalletdbEncryption->TxnAbort();
870da77d
PK
1530 delete pwalletdbEncryption;
1531 }
1532 // We now probably have half of our keys encrypted in memory, and half not...
7e6d23b1 1533 // die and let the user reload the unencrypted wallet.
d0c4197e 1534 assert(false);
96f34cd5
MC
1535 }
1536
0b807a41 1537 // Encryption was introduced in version 0.4.0
439e1497 1538 SetMinVersion(FEATURE_WALLETCRYPT, pwalletdbEncryption, true);
0b807a41 1539
96f34cd5
MC
1540 if (fFileBacked)
1541 {
870da77d
PK
1542 if (!pwalletdbEncryption->TxnCommit()) {
1543 delete pwalletdbEncryption;
5b40d886 1544 // We now have keys encrypted in memory, but not on disk...
7e6d23b1 1545 // die to avoid confusion and let the user reload the unencrypted wallet.
d0c4197e 1546 assert(false);
870da77d 1547 }
96f34cd5 1548
fcfd7ff8 1549 delete pwalletdbEncryption;
96f34cd5
MC
1550 pwalletdbEncryption = NULL;
1551 }
4e87d341 1552
37971fcc
GA
1553 Lock();
1554 Unlock(strWalletPassphrase);
1555 NewKeyPool();
4e87d341 1556 Lock();
6cc4a62c 1557
d764d916
GA
1558 // Need to completely rewrite the wallet file; if we don't, bdb might keep
1559 // bits of the unencrypted private key in slack space in the database file.
b2d3b2d6 1560 CDB::Rewrite(strWalletFile);
fe4a6550 1561
d764d916 1562 }
ab1b288f 1563 NotifyStatusChanged(this);
9e9869d0 1564
4e87d341 1565 return true;
e8ef3da7
WL
1566}
1567
51ed9ec9 1568int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb)
da7b8c12 1569{
95691680 1570 AssertLockHeld(cs_wallet); // nOrderPosNext
51ed9ec9 1571 int64_t nRet = nOrderPosNext++;
4291e8fe
PW
1572 if (pwalletdb) {
1573 pwalletdb->WriteOrderPosNext(nOrderPosNext);
1574 } else {
1575 CWalletDB(strWalletFile).WriteOrderPosNext(nOrderPosNext);
1576 }
da7b8c12
LD
1577 return nRet;
1578}
1579
ddb709e9 1580CWallet::TxItems CWallet::OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount)
c3f95ef1 1581{
95691680 1582 AssertLockHeld(cs_wallet); // mapWallet
c3f95ef1
LD
1583 CWalletDB walletdb(strWalletFile);
1584
1585 // First: get all CWalletTx and CAccountingEntry into a sorted-by-order multimap.
1586 TxItems txOrdered;
1587
1588 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1589 // would make this much faster for applications that do this a lot.
1590 for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
1591 {
1592 CWalletTx* wtx = &((*it).second);
1593 txOrdered.insert(make_pair(wtx->nOrderPos, TxPair(wtx, (CAccountingEntry*)0)));
1594 }
ddb709e9 1595 acentries.clear();
c3f95ef1
LD
1596 walletdb.ListAccountCreditDebit(strAccount, acentries);
1597 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1598 {
1599 txOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry)));
1600 }
1601
1602 return txOrdered;
1603}
1604
1f722359
MT
1605// looks through all wallet UTXOs and checks to see if any qualify to stake the block at the current height. it always returns the qualified
1606// UTXO with the smallest coin age if there is more than one, as larger coin age will win more often and is worth saving
1607// each attempt consists of taking a VerusHash of the following values:
1608// ASSETCHAINS_MAGIC, nHeight, txid, voutNum
17d0160a 1609bool CWallet::VerusSelectStakeOutput(CBlock *pBlock, arith_uint256 &hashResult, CTransaction &stakeSource, int32_t &voutNum, int32_t nHeight, uint32_t &bnTarget) const
1f722359 1610{
c5325a32 1611 arith_uint256 target;
1f722359 1612 arith_uint256 curHash;
1f722359 1613 COutput *pwinner = NULL;
0cc87e8f 1614 CWalletTx winnerWtx;
1615
1fae37f6
MT
1616 txnouttype whichType;
1617 std:vector<std::vector<unsigned char>> vSolutions;
1f722359 1618
12217420 1619 pBlock->nNonce.SetPOSTarget(bnTarget, pBlock->nVersion);
c5325a32
MT
1620 target.SetCompact(bnTarget);
1621
b95cb937
MT
1622 auto consensusParams = Params().GetConsensus();
1623 CValidationState state;
1624
672414d7 1625 std::vector<COutput> vecOutputs;
1626 std::vector<CWalletTx> vwtx;
0cc87e8f 1627 CAmount totalStakingAmount = 0;
1628
5dde9d7e 1629 uint32_t solutionVersion = CConstVerusSolutionVector::GetVersionByHeight(nHeight);
1630 bool extendedStake = solutionVersion >= CActivationHeight::ACTIVATE_EXTENDEDSTAKE;
1631
0cc87e8f 1632 {
0cc87e8f 1633 LOCK2(cs_main, cs_wallet);
fbafcefe 1634 pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, true, false);
0cc87e8f 1635
fbafcefe 1636 int newSize = 0;
1637
1638 for (int i = 0; i < vecOutputs.size(); i++)
0cc87e8f 1639 {
fbafcefe 1640 auto &txout = vecOutputs[i];
5dde9d7e 1641 COptCCParams p;
fbafcefe 1642
0cc87e8f 1643 if (txout.tx &&
3416e9be 1644 txout.i < txout.tx->vout.size() &&
0cc87e8f 1645 txout.tx->vout[txout.i].nValue > 0 &&
1646 txout.fSpendable &&
1647 (txout.nDepth >= VERUS_MIN_STAKEAGE) &&
6e7fb01d 1648 ((txout.tx->vout[txout.i].scriptPubKey.IsPayToCryptoCondition(p) &&
1649 extendedStake &&
50c7c41c 1650 p.IsValid() &&
1651 txout.tx->vout[txout.i].scriptPubKey.IsSpendableOutputType(p)) ||
1652 (!p.IsValid() &&
1653 Solver(txout.tx->vout[txout.i].scriptPubKey, whichType, vSolutions) &&
1654 (whichType == TX_PUBKEY || whichType == TX_PUBKEYHASH))))
0cc87e8f 1655 {
1656 totalStakingAmount += txout.tx->vout[txout.i].nValue;
fbafcefe 1657 // if all are valid, no change, else compress
1658 if (newSize != i)
1659 {
1660 vecOutputs[newSize] = txout;
1661 }
1662 newSize++;
1663 }
1664 }
1665
1666 if (newSize)
1667 {
1668 // no reallocations to move objects. do all at once, so we can release the wallet lock
1669 vecOutputs.resize(newSize);
1670 vwtx.resize(newSize);
1671 for (int i = 0; i < vecOutputs.size(); i++)
1672 {
1673 vwtx[i] = *vecOutputs[i].tx;
1674 vecOutputs[i].tx = &vwtx[i];
0cc87e8f 1675 }
1676 }
1677 }
1678
1679 if (totalStakingAmount)
1680 {
6e7fb01d 1681 LogPrintf("Staking with %s VRSC\n", ValueFromAmount(totalStakingAmount).write().c_str());
0cc87e8f 1682 }
1683 else
1684 {
6e7fb01d 1685 LogPrintf("No VRSC staking\n");
0cc87e8f 1686 return false;
1687 }
1f722359 1688
af521e42 1689 // we get these sources of entropy to prove all sources in the header
1690 int posHeight = -1, powHeight = -1, altHeight = -1;
1691 uint256 pastHash;
1692 {
1693 LOCK(cs_main);
1694 pastHash = chainActive.GetVerusEntropyHash(nHeight, &posHeight, &powHeight, &altHeight);
6e62f837 1695 if (extendedStake && (altHeight == -1 && (powHeight == -1 || posHeight == -1)))
5fd488ca 1696 {
1697 printf("Error retrieving entropy hash at height %d, posHeight: %d, powHeight: %d, altHeight: %d\n", nHeight, posHeight, powHeight, altHeight);
1698 LogPrintf("Error retrieving entropy hash at height %d, posHeight: %d, powHeight: %d, altHeight: %d\n", nHeight, posHeight, powHeight, altHeight);
1699 return false;
1700 }
af521e42 1701 }
1702
6e62f837 1703 // secondBlockHeight is either less than first or -1 if there isn't one
1704 int secondBlockHeight = altHeight != -1 ?
1705 altHeight :
1706 posHeight == -1 ?
1707 posHeight :
1708 powHeight == -1 ?
1709 powHeight :
1710 (posHeight > powHeight ?
1711 powHeight :
1712 posHeight);
1713
7f5a0ec7 1714 int proveBlockHeight = posHeight > secondBlockHeight ? posHeight : ((powHeight == -1) ? posHeight : powHeight);
af521e42 1715
6e62f837 1716 if (proveBlockHeight == -1)
1717 {
1718 printf("No block suitable for proof for height %d, posHeight: %d, powHeight: %d, altHeight: %d\n", nHeight, posHeight, powHeight, altHeight);
1719 LogPrintf("No block suitable for proof for height %d, posHeight: %d, powHeight: %d, altHeight: %d\n", nHeight, posHeight, powHeight, altHeight);
1720 }
1721 else
1f722359 1722 {
17d0160a 1723 CPOSNonce curNonce;
b2a98c42 1724 uint32_t srcIndex;
1f722359 1725
12d157e4 1726 CCoinsViewCache view(pcoinsTip);
1727 CMutableTransaction checkStakeTx = CreateNewContextualCMutableTransaction(consensusParams, nHeight);
e54e3c24 1728 std::vector<CTxDestination> addressRet;
1729 int nRequiredRet;
12d157e4 1730
1f722359
MT
1731 BOOST_FOREACH(COutput &txout, vecOutputs)
1732 {
5dde9d7e 1733 COptCCParams p;
1734 std::vector<CTxDestination> destinations;
1735 int nRequired = 0;
1736 bool canSign = false, canSpend = false;
1737
0cc87e8f 1738 if (UintToArith256(txout.tx->GetVerusPOSHash(&(pBlock->nNonce), txout.i, nHeight, pastHash)) <= target &&
5dde9d7e 1739 ExtractDestinations(txout.tx->vout[txout.i].scriptPubKey, whichType, destinations, nRequired, this, &canSign, &canSpend) &&
6e7fb01d 1740 ((txout.tx->vout[txout.i].scriptPubKey.IsPayToCryptoCondition(p) &&
1741 extendedStake &&
5dde9d7e 1742 canSpend) ||
6e7fb01d 1743 (!p.IsValid() && (whichType == TX_PUBKEY || whichType == TX_PUBKEYHASH) && ::IsMine(*this, destinations[0]))))
1f722359 1744 {
285c3564 1745 uint256 txHash = txout.tx->GetHash();
a4777f81 1746 checkStakeTx.vin.push_back(CTxIn(COutPoint(txHash, txout.i)));
285c3564 1747
56fe75cb 1748 LOCK2(cs_main, cs_wallet);
0cc87e8f 1749
6e7fb01d 1750 if ((!pwinner || UintToArith256(curNonce) < UintToArith256(pBlock->nNonce)) &&
717f1db6 1751 !cheatList.IsUTXOInList(COutPoint(txHash, txout.i), nHeight <= 100 ? 1 : nHeight-100))
c68ca1a2 1752 {
717f1db6 1753 if (view.HaveCoins(txHash) && Consensus::CheckTxInputs(checkStakeTx, state, view, nHeight, consensusParams))
1754 {
1755 //printf("Found PoS block\nnNonce: %s\n", pBlock->nNonce.GetHex().c_str());
1756 pwinner = &txout;
1757 curNonce = pBlock->nNonce;
af521e42 1758 srcIndex = nHeight - txout.nDepth;
717f1db6 1759 }
1760 else
1761 {
1762 LogPrintf("Transaction %s failed to stake due to %s\n", txout.tx->GetHash().GetHex().c_str(),
1763 view.HaveCoins(txHash) ? "bad inputs" : "unavailable coins");
1764 }
c68ca1a2 1765 }
12d157e4 1766
1767 checkStakeTx.vin.pop_back();
1f722359
MT
1768 }
1769 }
1770 if (pwinner)
1771 {
0cc87e8f 1772 stakeSource = static_cast<CTransaction>(*pwinner->tx);
31609f35 1773
1774 // arith_uint256 post;
1775 // post.SetCompact(pBlock->GetVerusPOSTarget());
1776 // printf("Found stake transaction\n");
1777 // printf("POS hash: %s \ntarget: %s\n\n",
1778 // stakeSource.GetVerusPOSHash(&(pBlock->nNonce), pwinner->i, nHeight, pastHash).GetHex().c_str(),
1779 // ArithToUint256(post).GetHex().c_str());
1780
1f722359 1781 voutNum = pwinner->i;
17d0160a 1782 pBlock->nNonce = curNonce;
ec1c84a0 1783
7695dab4 1784 if (solutionVersion >= CActivationHeight::ACTIVATE_STAKEHEADER)
ec1c84a0 1785 {
56fe75cb 1786 CDataStream headerStream = CDataStream(SER_NETWORK, PROTOCOL_VERSION);
ec1c84a0 1787
b2a98c42
MT
1788 // store:
1789 // 1. PBaaS header for this block
1790 // 2. source transaction
1791 // 3. block index of base MMR being used
1792 // 4. source tx block index for proof
1793 // 5. full merkle proof of source tx up to prior MMR root
1794 // 6. block hash of block of entropyhash
1795 // 7. proof of block hash (not full header) in the MMR for the block height of the entropy hash block
1796 // all that data includes enough information to verify
1797 // prior MMR, blockhash, transaction, entropy hash, and block indexes match
1798 // also checks root match & block power
0cc87e8f 1799 auto mmrView = chainActive.GetMMV();
56fe75cb 1800 pBlock->SetPrevMMRRoot(mmrView.GetRoot());
1801 pBlock->AddUpdatePBaaSHeader();
ec1c84a0 1802
56fe75cb 1803 // get map and MMR for stake source transaction
1804 CTransactionMap txMap(stakeSource);
1805 TransactionMMView txView(txMap.transactionMMR);
af521e42 1806 uint256 txRoot = txView.GetRoot();
ec1c84a0 1807
f39725dc 1808 std::vector<CTransactionComponentProof> txProofVec;
0ab273d2 1809 txProofVec.emplace_back(txView, txMap, stakeSource, CTransactionHeader::TX_HEADER, 0);
1810 txProofVec.emplace_back(txView, txMap, stakeSource, CTransactionHeader::TX_OUTPUT, pwinner->i);
b2a98c42 1811
56fe75cb 1812 // now, both the header and stake output are dependent on the transaction MMR root being provable up
1813 // through the block MMR, and since we don't cache the new MMR proof for transactions yet, we need the block to create the proof.
1814 // when we switch to the new MMR in place of a merkle tree, we can keep that in the wallet as well
1815 CBlock block;
1816 if (!ReadBlockFromDisk(block, chainActive[srcIndex], Params().GetConsensus(), false))
1817 {
af521e42 1818 LogPrintf("%s: ERROR: could not read block number %u from disk\n", __func__, srcIndex);
56fe75cb 1819 return false;
1820 }
b2a98c42 1821
2d88a342 1822 BlockMMRange blockMMR(block.GetBlockMMRTree());
56fe75cb 1823 BlockMMView blockView(blockMMR);
b2a98c42 1824
af521e42 1825 int txIndexPos;
1826 for (txIndexPos = 0; txIndexPos < blockMMR.size(); txIndexPos++)
1827 {
1828 uint256 txRootHashFromMMR = blockMMR[txIndexPos].hash;
1829 if (txRootHashFromMMR == txRoot)
1830 {
1831 //printf("tx with root %s found in block\n", txRootHashFromMMR.GetHex().c_str());
1832 break;
1833 }
1834 }
f39725dc 1835
af521e42 1836 if (txIndexPos == blockMMR.size())
56fe75cb 1837 {
af521e42 1838 LogPrintf("%s: ERROR: could not find source transaction root in block %u\n", __func__, srcIndex);
56fe75cb 1839 return false;
1840 }
b2a98c42 1841
af521e42 1842 // prove the tx up to the MMR root, which also contains the block hash
f39725dc 1843 CMMRProof txRootProof;
af521e42 1844 if (!blockView.GetProof(txRootProof, txIndexPos))
56fe75cb 1845 {
af521e42 1846 LogPrintf("%s: ERROR: could not create proof of source transaction in block %u\n", __func__, srcIndex);
56fe75cb 1847 return false;
1848 }
1849
af521e42 1850 mmrView.resize(proveBlockHeight + 1);
1851 chainActive.GetMerkleProof(mmrView, txRootProof, srcIndex);
1852
1853 headerStream << CPartialTransactionProof(txRootProof, txProofVec);
56fe75cb 1854
af521e42 1855 CMMRProof blockHeaderProof1;
1856 if (!chainActive.GetBlockProof(mmrView, blockHeaderProof1, proveBlockHeight))
56fe75cb 1857 {
af521e42 1858 LogPrintf("%s: ERROR: could not create block proof for block %u\n", __func__, srcIndex);
56fe75cb 1859 return false;
1860 }
af521e42 1861 headerStream << CBlockHeaderProof(blockHeaderProof1, chainActive[proveBlockHeight]->GetBlockHeader());
b2a98c42 1862
af521e42 1863 CMMRProof blockHeaderProof2;
1864 if (!chainActive.GetBlockProof(mmrView, blockHeaderProof2, secondBlockHeight))
1865 {
1866 LogPrintf("%s: ERROR: could not create block proof for second entropy source block %u\n", __func__, srcIndex);
5fd488ca 1867 chainActive.GetBlockProof(mmrView, blockHeaderProof2, secondBlockHeight); // repeat for debugging
af521e42 1868 return false;
1869 }
1870 headerStream << CBlockHeaderProof(blockHeaderProof2, chainActive[secondBlockHeight]->GetBlockHeader());
b2a98c42 1871
56fe75cb 1872 std::vector<unsigned char> stx(headerStream.begin(), headerStream.end());
b2a98c42 1873
af521e42 1874 // printf("\nFound Stake transaction... all proof serialized size == %lu\n", stx.size());
b2a98c42 1875
b2a98c42
MT
1876 CVerusSolutionVector(pBlock->nSolution).ResizeExtraData(stx.size());
1877
1878 pBlock->SetExtraData(stx.data(), stx.size());
f39725dc 1879
1880 //CBlockHeader blkHeader(*pBlock);
1881 //CDataStream s(SER_NETWORK, PROTOCOL_VERSION);
1882 //printf("Staking block header size %ld\n", GetSerializeSize(s, blkHeader));
ec1c84a0 1883 }
1f722359
MT
1884 return true;
1885 }
1886 }
1887 return false;
1888}
1889
855714b0 1890int32_t CWallet::VerusStakeTransaction(CBlock *pBlock, CMutableTransaction &txNew, uint32_t &bnTarget, arith_uint256 &hashResult, std::vector<unsigned char> &utxosig, CTxDestination &rewardDest) const
1f722359 1891{
1f722359
MT
1892 CTransaction stakeSource;
1893 int32_t voutNum, siglen = 0;
1894 int64_t nValue;
1fae37f6
MT
1895 txnouttype whichType;
1896 std::vector<std::vector<unsigned char>> vSolutions;
1f722359 1897
3bfa5e22 1898 CBlockIndex *tipindex = chainActive.LastTip();
1899 uint32_t stakeHeight = tipindex->GetHeight() + 1;
56fe75cb 1900 bool extendedStake = CConstVerusSolutionVector::GetVersionByHeight(stakeHeight) >= CActivationHeight::ACTIVATE_EXTENDEDSTAKE;
8a727a26 1901
1f722359 1902 bnTarget = lwmaGetNextPOSRequired(tipindex, Params().GetConsensus());
1f722359 1903
adb5cebb 1904 if (!VerusSelectStakeOutput(pBlock, hashResult, stakeSource, voutNum, stakeHeight, bnTarget))
1f722359 1905 {
0cc87e8f 1906 //LogPrintf("Searched for eligible staking transactions, no winners found\n");
1f722359
MT
1907 return 0;
1908 }
1909
1f722359
MT
1910 bool signSuccess;
1911 SignatureData sigdata;
86e31e3d 1912 uint64_t txfee;
86e31e3d 1913 auto consensusBranchId = CurrentEpochBranchId(stakeHeight, Params().GetConsensus());
1f722359
MT
1914
1915 const CKeyStore& keystore = *pwalletMain;
1916 txNew.vin.resize(1);
1917 txNew.vout.resize(1);
88d014d0 1918 txfee = 0;
1f722359
MT
1919 txNew.vin[0].prevout.hash = stakeSource.GetHash();
1920 txNew.vin[0].prevout.n = voutNum;
1921
adb5cebb 1922 COptCCParams p;
1923 if (stakeSource.vout[voutNum].scriptPubKey.IsPayToCryptoCondition(p) && p.IsValid())
1fae37f6 1924 {
855714b0 1925 if (!p.vKeys.size())
1926 {
1927 LogPrintf("%s: Please report - no destination on stake source\n");
1928 return 0;
1929 }
1930
adb5cebb 1931 // send output to same destination as source, convert stakeguard into normal output, since
1932 // that is a spendable output that only works in coinbases. preserve all recipients and
1933 // min sigs
1934 if (p.evalCode == EVAL_STAKEGUARD)
1935 {
855714b0 1936 // "CIdentity" is a dummy object type since an obj is not passed, and it does not make this an identity output
1937 txNew.vout[0].scriptPubKey = MakeMofNCCScript(CConditionObj<CIdentity>(0, p.vKeys, p.m));
adb5cebb 1938 }
1939 else
8a727a26 1940 {
adb5cebb 1941 txNew.vout[0].scriptPubKey = stakeSource.vout[voutNum].scriptPubKey;
8a727a26 1942 }
855714b0 1943 rewardDest = p.vKeys[0];
1fae37f6 1944 }
adb5cebb 1945 else if (Solver(stakeSource.vout[voutNum].scriptPubKey, whichType, vSolutions))
e54e3c24 1946 {
adb5cebb 1947 if (whichType == TX_PUBKEY)
1948 {
1949 txNew.vout[0].scriptPubKey << ToByteVector(vSolutions[0]) << OP_CHECKSIG;
855714b0 1950 rewardDest = CPubKey(vSolutions[0]);
adb5cebb 1951 }
1952 else if (whichType == TX_PUBKEYHASH)
1953 {
1954 txNew.vout[0].scriptPubKey << OP_DUP << OP_HASH160 << ToByteVector(vSolutions[0]) << OP_EQUALVERIFY << OP_CHECKSIG;
855714b0 1955 rewardDest = CKeyID(uint160(vSolutions[0]));
adb5cebb 1956 }
1957 else
1958 {
1959 LogPrintf("%s: Please report - found stake source that is not valid\n");
1960 return 0;
1961 }
e54e3c24 1962 }
1fae37f6 1963 else
e54e3c24 1964 {
1fae37f6 1965 return 0;
e54e3c24 1966 }
1f722359 1967
855714b0 1968 // set expiry to time out after 100 blocks, so we can remove the transaction if it orphans
1969 txNew.nExpiryHeight = stakeHeight + 100;
7a993143 1970
855714b0 1971 uint256 srcBlock = uint256();
1972 CBlockIndex *pSrcIndex;
8a727a26 1973
855714b0 1974 txNew.vout.push_back(CTxOut());
1975 CTxOut &txOut1 = txNew.vout[1];
1976 txOut1.nValue = 0;
1977 if (!GetTransaction(stakeSource.GetHash(), stakeSource, srcBlock))
1978 return 0;
1979
1980 BlockMap::const_iterator it = mapBlockIndex.find(srcBlock);
1981 if (it == mapBlockIndex.end() || (pSrcIndex = it->second) == 0)
1982 return 0;
8a727a26 1983
855714b0 1984 // !! DISABLE THIS FOR RELEASE: THIS MAKES A CHEAT TRANSACTION FOR EVERY STAKE FOR TESTING
1985 //CMutableTransaction cheat;
1986 //cheat = CMutableTransaction(txNew);
1987 //printf("TESTING ONLY: THIS SHOULD NOT BE ENABLED FOR RELEASE - MAKING CHEAT TRANSACTION FOR TESTING\n");
1988 //cheat.vout[1].scriptPubKey << OP_RETURN
1989 // << CStakeParams(pSrcIndex->GetHeight(), tipindex->GetHeight() + 1, pSrcIndex->GetBlockHash(), pk).AsVector();
1990 // !! DOWN TO HERE
43260416 1991
855714b0 1992 if (USE_EXTERNAL_PUBKEY)
1993 {
1994 rewardDest = CPubKey(ParseHex(NOTARY_PUBKEY));
1995 }
1996 else if (!VERUS_DEFAULTID.IsNull())
1997 {
1998 rewardDest = VERUS_DEFAULTID;
1999 }
8a727a26 2000
855714b0 2001 if (rewardDest.which() == COptCCParams::ADDRTYPE_INVALID)
2002 {
2003 printf("%s: Invalid reward destinaton for stake\n", __func__);
2004 return 0;
41e9e058 2005 }
43260416 2006
855714b0 2007 txOut1.scriptPubKey << OP_RETURN
2008 << CStakeParams(pSrcIndex->GetHeight(), tipindex->GetHeight() + 1, tipindex->GetBlockHash(), rewardDest).AsVector();
2009
2010 // !! DISABLE THIS FOR RELEASE: REMOVE THIS TOO
2011 //nValue = cheat.vout[0].nValue = stakeSource.vout[voutNum].nValue - txfee;
2012 //cheat.nLockTime = 0;
2013 //CTransaction cheatConst(cheat);
2014 //SignatureData cheatSig;
2015 //if (!ProduceSignature(TransactionSignatureCreator(&keystore, &cheatConst, 0, nValue, SIGHASH_ALL), stakeSource.vout[voutNum].scriptPubKey, cheatSig, consensusBranchId))
2016 // fprintf(stderr,"failed to create cheat test signature\n");
2017 //else
2018 //{
2019 // uint8_t *ptr;
2020 // UpdateTransaction(cheat,0,cheatSig);
2021 // cheatList.Add(CTxHolder(CTransaction(cheat), tipindex->GetHeight() + 1));
2022 //}
2023 // !! DOWN TO HERE
2024
31bbe234 2025 nValue = txNew.vout[0].nValue = stakeSource.vout[voutNum].nValue - txfee;
3bfa5e22 2026
1f722359
MT
2027 txNew.nLockTime = 0;
2028 CTransaction txNewConst(txNew);
a4f9bc97 2029 signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, nValue, stakeSource.vout[voutNum].scriptPubKey), stakeSource.vout[voutNum].scriptPubKey, sigdata, consensusBranchId);
1f722359 2030 if (!signSuccess)
b2a59a12 2031 {
1f722359 2032 fprintf(stderr,"failed to create signature\n");
b2a59a12 2033 utxosig.clear();
2034 }
1f722359
MT
2035 else
2036 {
2037 uint8_t *ptr;
b2a59a12 2038 UpdateTransaction(txNew, 0, sigdata);
2039 utxosig.resize(sigdata.scriptSig.size());
2040 memcpy(&(utxosig[0]), &(sigdata.scriptSig[0]), utxosig.size());
1f722359 2041 }
b2a59a12 2042 return(utxosig.size());
1f722359
MT
2043}
2044
95d888a6
PW
2045void CWallet::MarkDirty()
2046{
95d888a6 2047 {
f8dcd5ca 2048 LOCK(cs_wallet);
95d888a6
PW
2049 BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
2050 item.second.MarkDirty();
2051 }
2052}
2053
1a62587e 2054/**
9a2b8ae5
JG
2055 * Ensure that every note in the wallet (for which we possess a spending key)
2056 * has a cached nullifier.
1a62587e
JG
2057 */
2058bool CWallet::UpdateNullifierNoteMap()
2059{
2060 {
2061 LOCK(cs_wallet);
2062
2063 if (IsLocked())
2064 return false;
2065
2066 ZCNoteDecryption dec;
2067 for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
005f3ad1 2068 for (mapSproutNoteData_t::value_type& item : wtxItem.second.mapSproutNoteData) {
1a62587e 2069 if (!item.second.nullifier) {
9a2b8ae5
JG
2070 if (GetNoteDecryptor(item.second.address, dec)) {
2071 auto i = item.first.js;
f57f76d7 2072 auto hSig = wtxItem.second.vJoinSplit[i].h_sig(
9a2b8ae5 2073 *pzcashParams, wtxItem.second.joinSplitPubKey);
618206c7 2074 item.second.nullifier = GetSproutNoteNullifier(
f57f76d7 2075 wtxItem.second.vJoinSplit[i],
9a2b8ae5
JG
2076 item.second.address,
2077 dec,
2078 hSig,
2079 item.first.n);
2080 }
1a62587e
JG
2081 }
2082 }
ad1e90dd
S
2083
2084 // TODO: Sapling. This method is only called from RPC walletpassphrase, which is currently unsupported
2085 // as RPC encryptwallet is hidden behind two flags: -developerencryptwallet -experimentalfeatures
2086
6e263a5f 2087 UpdateNullifierNoteMapWithTx(wtxItem.second);
1a62587e
JG
2088 }
2089 }
2090 return true;
2091}
2092
6e263a5f 2093/**
ad1e90dd
S
2094 * Update mapSproutNullifiersToNotes and mapSaplingNullifiersToNotes
2095 * with the cached nullifiers in this tx.
6e263a5f
JG
2096 */
2097void CWallet::UpdateNullifierNoteMapWithTx(const CWalletTx& wtx)
8db7e25c
JG
2098{
2099 {
2100 LOCK(cs_wallet);
005f3ad1 2101 for (const mapSproutNoteData_t::value_type& item : wtx.mapSproutNoteData) {
1a62587e 2102 if (item.second.nullifier) {
f41bf503 2103 mapSproutNullifiersToNotes[*item.second.nullifier] = item.first;
1a62587e 2104 }
8db7e25c 2105 }
ad1e90dd
S
2106
2107 for (const mapSaplingNoteData_t::value_type& item : wtx.mapSaplingNoteData) {
1a62587e 2108 if (item.second.nullifier) {
ad1e90dd 2109 mapSaplingNullifiersToNotes[*item.second.nullifier] = item.first;
1a62587e 2110 }
8db7e25c
JG
2111 }
2112 }
2113}
2114
ad1e90dd
S
2115/**
2116 * Update mapSaplingNullifiersToNotes, computing the nullifier from a cached witness if necessary.
2117 */
2118void CWallet::UpdateSaplingNullifierNoteMapWithTx(CWalletTx& wtx) {
2119 LOCK(cs_wallet);
2120
2121 for (mapSaplingNoteData_t::value_type &item : wtx.mapSaplingNoteData) {
2122 SaplingOutPoint op = item.first;
2123 SaplingNoteData nd = item.second;
2124
c343e2db 2125 if (nd.witnesses.empty()) {
ad1e90dd
S
2126 // If there are no witnesses, erase the nullifier and associated mapping.
2127 if (item.second.nullifier) {
2128 mapSaplingNullifiersToNotes.erase(item.second.nullifier.get());
2129 }
2130 item.second.nullifier = boost::none;
2131 }
c343e2db 2132 else {
ad1e90dd
S
2133 uint64_t position = nd.witnesses.front().position();
2134 SaplingFullViewingKey fvk = mapSaplingFullViewingKeys.at(nd.ivk);
2135 OutputDescription output = wtx.vShieldedOutput[op.n];
2136 auto optPlaintext = SaplingNotePlaintext::decrypt(output.encCiphertext, nd.ivk, output.ephemeralKey, output.cm);
2137 if (!optPlaintext) {
2138 // An item in mapSaplingNoteData must have already been successfully decrypted,
2139 // otherwise the item would not exist in the first place.
2140 assert(false);
2141 }
2142 auto optNote = optPlaintext.get().note(nd.ivk);
2143 if (!optNote) {
2144 assert(false);
2145 }
2146 auto optNullifier = optNote.get().nullifier(fvk, position);
2147 if (!optNullifier) {
2148 // This should not happen. If it does, maybe the position has been corrupted or miscalculated?
2149 assert(false);
2150 }
2151 uint256 nullifier = optNullifier.get();
2152 mapSaplingNullifiersToNotes[nullifier] = op;
2153 item.second.nullifier = nullifier;
2154 }
2155 }
2156}
2157
2158/**
2159 * Iterate over transactions in a block and update the cached Sapling nullifiers
2160 * for transactions which belong to the wallet.
2161 */
2162void CWallet::UpdateSaplingNullifierNoteMapForBlock(const CBlock *pblock) {
2163 LOCK(cs_wallet);
2164
2165 for (const CTransaction& tx : pblock->vtx) {
2166 auto hash = tx.GetHash();
2167 bool txIsOurs = mapWallet.count(hash);
2168 if (txIsOurs) {
2169 UpdateSaplingNullifierNoteMapWithTx(mapWallet[hash]);
2170 }
8db7e25c
JG
2171 }
2172}
2173
44bc988e 2174bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb)
e8ef3da7 2175{
805344dc 2176 uint256 hash = wtxIn.GetHash();
731b89b8
GA
2177
2178 if (fFromLoadWallet)
2179 {
2180 mapWallet[hash] = wtxIn;
09ec3af1 2181 mapWallet[hash].BindWallet(this);
6e263a5f 2182 UpdateNullifierNoteMapWithTx(mapWallet[hash]);
93a18a36 2183 AddToSpends(hash);
731b89b8
GA
2184 }
2185 else
e8ef3da7 2186 {
f8dcd5ca 2187 LOCK(cs_wallet);
e8ef3da7
WL
2188 // Inserts only if not already there, returns tx inserted or tx found
2189 pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
2190 CWalletTx& wtx = (*ret.first).second;
4c6e2295 2191 wtx.BindWallet(this);
6e263a5f 2192 UpdateNullifierNoteMapWithTx(wtx);
e8ef3da7
WL
2193 bool fInsertedNew = ret.second;
2194 if (fInsertedNew)
9c7722b7 2195 {
e8ef3da7 2196 wtx.nTimeReceived = GetAdjustedTime();
44bc988e 2197 wtx.nOrderPos = IncOrderPosNext(pwalletdb);
c3f95ef1
LD
2198
2199 wtx.nTimeSmart = wtx.nTimeReceived;
4f152496 2200 if (!wtxIn.hashBlock.IsNull())
c3f95ef1
LD
2201 {
2202 if (mapBlockIndex.count(wtxIn.hashBlock))
2203 {
209377a7 2204 int64_t latestNow = wtx.nTimeReceived;
2205 int64_t latestEntry = 0;
c3f95ef1
LD
2206 {
2207 // Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future
51ed9ec9 2208 int64_t latestTolerated = latestNow + 300;
ddb709e9
LD
2209 std::list<CAccountingEntry> acentries;
2210 TxItems txOrdered = OrderedTxItems(acentries);
c3f95ef1
LD
2211 for (TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
2212 {
2213 CWalletTx *const pwtx = (*it).second.first;
2214 if (pwtx == &wtx)
2215 continue;
2216 CAccountingEntry *const pacentry = (*it).second.second;
51ed9ec9 2217 int64_t nSmartTime;
c3f95ef1
LD
2218 if (pwtx)
2219 {
2220 nSmartTime = pwtx->nTimeSmart;
2221 if (!nSmartTime)
2222 nSmartTime = pwtx->nTimeReceived;
2223 }
2224 else
2225 nSmartTime = pacentry->nTime;
2226 if (nSmartTime <= latestTolerated)
2227 {
2228 latestEntry = nSmartTime;
2229 if (nSmartTime > latestNow)
2230 latestNow = nSmartTime;
2231 break;
2232 }
2233 }
2234 }
2235
209377a7 2236 int64_t blocktime = mapBlockIndex[wtxIn.hashBlock]->GetBlockTime();
c3f95ef1
LD
2237 wtx.nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
2238 }
2239 else
5262fde0 2240 LogPrintf("AddToWallet(): found %s in block %s not in index\n",
805344dc 2241 wtxIn.GetHash().ToString(),
7d9d134b 2242 wtxIn.hashBlock.ToString());
c3f95ef1 2243 }
93a18a36 2244 AddToSpends(hash);
9c7722b7 2245 }
e8ef3da7
WL
2246
2247 bool fUpdated = false;
2248 if (!fInsertedNew)
2249 {
2250 // Merge
4f152496 2251 if (!wtxIn.hashBlock.IsNull() && wtxIn.hashBlock != wtx.hashBlock)
e8ef3da7
WL
2252 {
2253 wtx.hashBlock = wtxIn.hashBlock;
2254 fUpdated = true;
2255 }
2256 if (wtxIn.nIndex != -1 && (wtxIn.vMerkleBranch != wtx.vMerkleBranch || wtxIn.nIndex != wtx.nIndex))
2257 {
2258 wtx.vMerkleBranch = wtxIn.vMerkleBranch;
2259 wtx.nIndex = wtxIn.nIndex;
2260 fUpdated = true;
2261 }
ac1c9435 2262 if (UpdatedNoteData(wtxIn, wtx)) {
c3a7307a
JG
2263 fUpdated = true;
2264 }
e8ef3da7
WL
2265 if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
2266 {
2267 wtx.fFromMe = wtxIn.fFromMe;
2268 fUpdated = true;
2269 }
e8ef3da7
WL
2270 }
2271
0cc87e8f 2272 //// debug log out
2273 if (fDebug)
2274 {
2275 LogPrintf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
2276 }
e8ef3da7
WL
2277
2278 // Write to disk
2279 if (fInsertedNew || fUpdated)
44bc988e 2280 if (!wtx.WriteToDisk(pwalletdb))
e8ef3da7 2281 return false;
ee4b170c 2282
93a18a36
GA
2283 // Break debit/credit balance caches:
2284 wtx.MarkDirty();
e8ef3da7 2285
fe4a6550
WL
2286 // Notify UI of new or updated transaction
2287 NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
cae686d3 2288
2289 // notify an external script when a wallet transaction comes in or is updated
2290 std::string strCmd = GetArg("-walletnotify", "");
2291
2292 if ( !strCmd.empty())
2293 {
805344dc 2294 boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
cae686d3 2295 boost::thread t(runCommand, strCmd); // thread runs free
2296 }
2297
fe4a6550 2298 }
e8ef3da7
WL
2299 return true;
2300}
2301
ac1c9435
JG
2302bool CWallet::UpdatedNoteData(const CWalletTx& wtxIn, CWalletTx& wtx)
2303{
3a83e7c9
S
2304 bool unchangedSproutFlag = (wtxIn.mapSproutNoteData.empty() || wtxIn.mapSproutNoteData == wtx.mapSproutNoteData);
2305 if (!unchangedSproutFlag) {
2306 auto tmp = wtxIn.mapSproutNoteData;
2307 // Ensure we keep any cached witnesses we may already have
2308 for (const std::pair <JSOutPoint, SproutNoteData> nd : wtx.mapSproutNoteData) {
2309 if (tmp.count(nd.first) && nd.second.witnesses.size() > 0) {
2310 tmp.at(nd.first).witnesses.assign(
2311 nd.second.witnesses.cbegin(), nd.second.witnesses.cend());
2312 }
2313 tmp.at(nd.first).witnessHeight = nd.second.witnessHeight;
2314 }
2315 // Now copy over the updated note data
2316 wtx.mapSproutNoteData = tmp;
ac1c9435 2317 }
3a83e7c9
S
2318
2319 bool unchangedSaplingFlag = (wtxIn.mapSaplingNoteData.empty() || wtxIn.mapSaplingNoteData == wtx.mapSaplingNoteData);
2320 if (!unchangedSaplingFlag) {
2321 auto tmp = wtxIn.mapSaplingNoteData;
2322 // Ensure we keep any cached witnesses we may already have
2323
2324 for (const std::pair <SaplingOutPoint, SaplingNoteData> nd : wtx.mapSaplingNoteData) {
2325 if (tmp.count(nd.first) && nd.second.witnesses.size() > 0) {
2326 tmp.at(nd.first).witnesses.assign(
2327 nd.second.witnesses.cbegin(), nd.second.witnesses.cend());
2328 }
2329 tmp.at(nd.first).witnessHeight = nd.second.witnessHeight;
ac1c9435 2330 }
3a83e7c9
S
2331
2332 // Now copy over the updated note data
2333 wtx.mapSaplingNoteData = tmp;
ac1c9435 2334 }
3a83e7c9
S
2335
2336 return !unchangedSproutFlag || !unchangedSaplingFlag;
ac1c9435
JG
2337}
2338
b27ae18a 2339std::pair<bool, bool> CWallet::CheckAuthority(const CIdentity &identity)
5bc89dab 2340{
14f010d8 2341 std::pair<bool, bool> canSignCanSpend({false, false});
b27ae18a 2342 if (!identity.IsValidUnrevoked())
2343 {
2344 return canSignCanSpend;
2345 }
5bc89dab 2346 std::set<CIdentityID> keySet;
2347
2348 // determine our status of cansign or canspend for this new ID
b27ae18a 2349 for (auto key : identity.primaryAddresses)
5bc89dab 2350 {
2351 CKeyID keyID = CKeyID(GetDestinationID(key));
2352 if (HaveKey(keyID))
2353 {
2354 keySet.insert(keyID);
2355 }
2356 }
2357
2358 // if we have enough keys to fully authorize, it is ours
b27ae18a 2359 if (keySet.size() >= identity.minSigs)
5bc89dab 2360 {
2361 canSignCanSpend.first = true;
2362 canSignCanSpend.second = true;
2363 }
2364 else if (keySet.size())
2365 {
2366 canSignCanSpend.first = true;
5bc89dab 2367 }
2368 return canSignCanSpend;
2369}
2370
2371bool CWallet::MarkIdentityDirty(const CIdentityID &idID)
2372{
2373 bool found = false;
2374 // if we already had signing authority, but not spending, enumerate wallet transactions sent to this ID and mark them dirty
2375 // for proper balance calculation
2376 for (auto &txidAndWtx : mapWallet)
2377 {
2378 bool dirty = false;
2379 txnouttype txType;
2380 std::vector<CTxDestination> addresses;
2381 int minSigs;
2382 for (auto txout : txidAndWtx.second.vout)
2383 {
2384 if (txout.scriptPubKey.IsPayToCryptoCondition() && ExtractDestinations(txout.scriptPubKey, txType, addresses, minSigs))
2385 {
2386 for (auto dest : addresses)
2387 {
2388 if (GetDestinationID(dest) == idID)
2389 {
2390 dirty = true;
2391 found = true;
2392 break;
2393 }
2394 }
2395 }
2396 }
2397 if (dirty)
2398 {
2399 txidAndWtx.second.MarkDirty();
2400 }
2401 }
2402 return found;
2403}
2404
5b40d886
MF
2405/**
2406 * Add a transaction to the wallet, or update it.
2407 * pblock is optional, but should be provided if the transaction is known to be in a block.
2408 * If fUpdate is true, existing transactions will be updated.
3ff68c50
JG
2409 *
2410 * If pblock is null, this transaction has either recently entered the mempool from the
2411 * network, is re-entering the mempool after a block was disconnected, or is exiting the
2412 * mempool because it conflicts with another transaction. In all these cases, if there is
2413 * an existing wallet transaction, the wallet transaction's Merkle branch data is _not_
2414 * updated; instead, the transaction being in the mempool or conflicted is determined on
2415 * the fly in CMerkleTx::GetDepthInMainChain().
5b40d886 2416 */
d38da59b 2417bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate)
e8ef3da7 2418{
e8ef3da7 2419 {
53d56881 2420 AssertLockHeld(cs_wallet);
e2c86312 2421 AssertLockHeld(cs_main);
a20f2622 2422 uint256 txHash = tx.GetHash();
44ac8ad4 2423
d00f15b4 2424 bool fExisted = mapWallet.count(txHash) != 0;
6cc4a62c 2425 if (fExisted && !fUpdate) return false;
78584ef7 2426 auto sproutNoteData = FindMySproutNotes(tx);
a4ecd0fa
EOW
2427 auto saplingNoteDataAndAddressesToAdd = FindMySaplingNotes(tx);
2428 auto saplingNoteData = saplingNoteDataAndAddressesToAdd.first;
2429 auto addressesToAdd = saplingNoteDataAndAddressesToAdd.second;
2430 for (const auto &addressToAdd : addressesToAdd) {
2431 if (!AddSaplingIncomingViewingKey(addressToAdd.second, addressToAdd.first)) {
2432 return false;
2433 }
2434 }
b3ea772e 2435
efecad16 2436 uint32_t nHeight = 0;
2437 if (pblock)
2438 {
2439 auto blkIndexIt = mapBlockIndex.find(pblock->GetHash());
2440 if (blkIndexIt != mapBlockIndex.end())
2441 {
2442 nHeight = blkIndexIt->second->GetHeight();
2443 }
2444 else
2445 {
2446 // this should never happen
2447 assert(false);
2448 }
2449 }
2450
b3ea772e 2451 for (auto output : tx.vout)
2452 {
2453 bool canSpend = false;
2454 COptCCParams p;
2455
2f537fa1 2456 if (output.scriptPubKey.IsPayToCryptoCondition(p) && p.IsValid() && p.version >= p.VERSION_V3)
b3ea772e 2457 {
5bc89dab 2458 CIdentityMapValue identity;
e14c324c 2459
5bc89dab 2460 if (p.evalCode == EVAL_IDENTITY_PRIMARY && p.vData.size() && (*(CIdentity *)&identity = CIdentity(p.vData[0])).IsValid())
b3ea772e 2461 {
e2c86312 2462 identity.txid = txHash;
22adf258 2463 CIdentityMapKey idMapKey = CIdentityMapKey(identity.GetID(),
5ae5090d 2464 nHeight,
2465 1,
2466 CIdentityMapKey::VALID);
5bc89dab 2467
b3ea772e 2468 std::set<CKeyID> keySet;
22adf258 2469 CIdentityID idID(identity.GetID());
5ae5090d 2470 int blockOrder = 1;
5bc89dab 2471 bool doneWithID = false;
2472
2473 std::pair<CIdentityMapKey, CIdentityMapValue> idHistory;
2474
e2c86312 2475 // if adding, current is what it will be, idHistory is what it was
2476 // if we are deleting, current identity is what it was, idHistory is what it will be
5bc89dab 2477 std::pair<bool, bool> wasCanSignCanSpend({false, false});
e54e3c24 2478 std::pair<bool, bool> canSignCanSpend(CheckAuthority(identity));
b3ea772e 2479
e2c86312 2480 // if the new identity is revoked, the recovery identity holds can sign/can spend authority
d26748d5 2481 if (identity.IsRevoked())
2482 {
e2c86312 2483 // if it's revoked, default is no authority for primary addresses, but we will have authority if
2484 // we have control over the recovery identity
d26748d5 2485 std::pair<CIdentityMapKey, CIdentityMapValue> recoveryAuthority;
2486 if (GetIdentity(identity.recoveryAuthority, recoveryAuthority, nHeight ? nHeight : INT_MAX))
2487 {
2488 canSignCanSpend = CheckAuthority(recoveryAuthority.second);
2489 }
2490 }
2491
e54e3c24 2492 // does identity already exist in this wallet?
5bc89dab 2493 if (GetIdentity(idID, idHistory, nHeight ? nHeight : INT_MAX))
b3ea772e 2494 {
e54e3c24 2495 wasCanSignCanSpend = CheckAuthority(idHistory.second);
2496
e2c86312 2497 if (idHistory.second.IsRevoked())
420019f6 2498 {
2499 std::pair<CIdentityMapKey, CIdentityMapValue> oldRecoveryAuthority;
2500 std::pair<bool, bool> auxCSCS;
2501 // if we hold the recovery authority in our wallet, then set wasCanSignCanSpend pair to true
2502 if (GetIdentity(idHistory.second.recoveryAuthority,
2503 oldRecoveryAuthority,
2504 nHeight ? nHeight : INT_MAX))
2505 {
2506 auxCSCS = CheckAuthority(oldRecoveryAuthority.second);
2507 wasCanSignCanSpend = std::pair<bool, bool>({wasCanSignCanSpend.first || auxCSCS.first,
2508 wasCanSignCanSpend.second || auxCSCS.second});
2509 }
2510 }
2511
e2c86312 2512 // if this is an add of the initial registration, delete all other instances of the ID
d00f15b4 2513 if (CNameReservation(tx).IsValid())
2514 {
2515 while (GetIdentity(idID, idHistory))
2516 {
e2c86312 2517 // any definition of this identity in this wallet must be
2518 // invalid now
d00f15b4 2519 RemoveIdentity(idHistory.first, idHistory.second.txid);
e2c86312 2520 if (idHistory.second.txid != txHash)
2521 {
2522 // any definition of this ID in this wallet that is not this definition
2523 // must also be on an invalid transaction
2524 EraseFromWallet(idHistory.second.txid);
2525 }
e54e3c24 2526 // set wasCanSignCanSpend to true, true to delete any dependent transactions
2527 wasCanSignCanSpend = {true, true};
d00f15b4 2528 }
2529 idHistory = std::pair<CIdentityMapKey, CIdentityMapValue>();
e2c86312 2530 wasCanSignCanSpend = std::pair<bool, bool>({false, false});
d00f15b4 2531 }
2532 else if (nHeight && idHistory.first.blockHeight == nHeight && idHistory.second.txid != identity.txid)
e14c324c 2533 {
e54e3c24 2534 // this is one of more than one identity records in the same block
22adf258 2535 std::vector<std::pair<CIdentityMapKey, CIdentityMapValue>> thisHeightIdentities;
2536 CIdentityMapKey heightKey(idID, nHeight);
2537 GetIdentity(heightKey, heightKey, thisHeightIdentities);
2538
93459a00 2539 std::map<uint256, std::pair<CIdentityMapKey, CIdentityMapValue>> firstIDMap;
22adf258 2540 for (auto &foundID : thisHeightIdentities)
2541 {
2542 firstIDMap[foundID.second.txid] = foundID;
2543 }
2544
93459a00 2545 if (firstIDMap.count(identity.txid))
2546 {
e54e3c24 2547 doneWithID = true;
93459a00 2548 }
2549 else
2550 {
2551 blockOrder = thisHeightIdentities.size() + 1;
2552 firstIDMap.insert(make_pair(identity.txid,
2553 make_pair(CIdentityMapKey(idID,
2554 nHeight,
2555 blockOrder,
d26748d5 2556 (canSignCanSpend.first ? CIdentityMapKey::CAN_SIGN : 0) + canSignCanSpend.second ? CIdentityMapKey::CAN_SPEND : 0),
93459a00 2557 identity)));
93459a00 2558
e54e3c24 2559 // now we have all the entries of the specified height, including those from before and the new one in the firstIDMap
2560 // the #1 in the block is one that has none of its input txes in the map. the last is not present in any input tx
2561 // to sort, we make a new map, indexed by the one that it spends, then follow the chain
2562 std::map<uint256, std::pair<CIdentityMapKey, CIdentityMapValue>> indexedByPrior;
2563 std::pair<CIdentityMapKey, CIdentityMapValue> firstInBlock;
22adf258 2564
e54e3c24 2565 for (auto &idEntry : firstIDMap)
22adf258 2566 {
e54e3c24 2567 uint256 spendsTxId;
2568 CTransaction entryTx;
2569 uint256 blkHash;
2570 if (!myGetTransaction(idEntry.first, entryTx, blkHash))
22adf258 2571 {
e54e3c24 2572 LogPrint("%s - error: cannot retrieve transaction %s during sort of identity transactions in block, blockchain state may be corrupt and need resynchronization\n", __func__, idEntry.first.GetHex().c_str());
22adf258 2573 }
e54e3c24 2574 else
22adf258 2575 {
e54e3c24 2576 bool isFirst = true;
2577 for (auto &input : entryTx.vin)
22adf258 2578 {
e54e3c24 2579 auto idMapIt = firstIDMap.find(input.prevout.hash);
2580 if (idMapIt != firstIDMap.end())
2581 {
2582 indexedByPrior[input.prevout.hash] = idEntry.second;
2583 isFirst = false;
2584 }
2585 }
2586 if (isFirst)
2587 {
2588 // this should first be added solo, so #1 should always be set
2589 if (idEntry.second.first.blockOrder != 1)
2590 {
2591 LogPrint("%s - error: unexpected block order in %s\n", __func__, idEntry.first.GetHex().c_str());
2592 }
2593 firstInBlock = idEntry.second;
22adf258 2594 }
22adf258 2595 }
2596 }
22adf258 2597
e54e3c24 2598 if (!firstInBlock.first.IsValid())
22adf258 2599 {
e54e3c24 2600 LogPrint("%s - error: missing first in block\n", __func__);
2601 }
2602 else
2603 {
2604 // now validate that from 1st to last, we have order correct
2605 std::pair<CIdentityMapKey, CIdentityMapValue> *pCurID;
2606 int i = 1;
2607 for (pCurID = &firstInBlock; pCurID; i++)
22adf258 2608 {
e54e3c24 2609 if (pCurID->first.blockOrder != i)
2610 {
2611 LogPrint("%s - error: incorrect block order in entry %s\n", __func__, pCurID->second.txid.GetHex().c_str());
2612 printf("%s - error: incorrect block order in entry %s\n", __func__, pCurID->second.txid.GetHex().c_str());
2613 }
22adf258 2614 }
2615 }
2616 }
e14c324c 2617 }
d00f15b4 2618 else if (nHeight && idHistory.first.blockHeight == nHeight)
b3ea772e 2619 {
e54e3c24 2620 // nHeight means this is an add, it has the same txid as an ID already present in the wallet, so we can ignore
2621 doneWithID = true;
5bc89dab 2622 }
e54e3c24 2623 else
5bc89dab 2624 {
2625 if (idHistory.first.flags & idHistory.first.CAN_SPEND)
2626 {
2627 wasCanSignCanSpend.first = true;
2628 wasCanSignCanSpend.second = true;
2629 }
2630 else if ((idHistory.first.flags & idHistory.first.CAN_SIGN))
2631 {
2632 wasCanSignCanSpend.first = true;
2633 }
e54e3c24 2634 // if we are supposed to remove the last entry, do so
2635 if (!pblock && txHash == idHistory.second.txid)
2636 {
2637 RemoveIdentity(idHistory.first, idHistory.second.txid);
2638 }
5bc89dab 2639 }
b3ea772e 2640 }
5bc89dab 2641 else if (!pblock)
b3ea772e 2642 {
5bc89dab 2643 // not present, nothing to delete
2644 doneWithID = true;
b3ea772e 2645 }
e14c324c 2646
5bc89dab 2647 if (!doneWithID)
b3ea772e 2648 {
5bc89dab 2649 if (pblock)
e14c324c 2650 {
956ab931 2651 // if we used to be able to sign with this identity, can now, or we put it on a manual hold, and it's not invalid or blacklisted, store it
2652 if ((wasCanSignCanSpend.first || canSignCanSpend.first || (idHistory.first.flags & idHistory.first.MANUAL_HOLD)) && !(idHistory.first.flags & idHistory.first.BLACKLIST))
e14c324c 2653 {
956ab931 2654 idMapKey = CIdentityMapKey(identity.GetID(),
2655 nHeight,
2656 blockOrder,
2657 idHistory.first.VALID |
2658 ((idHistory.second.IsValid() ? idHistory.first.flags : 0) & idHistory.first.MANUAL_HOLD) |
2659 (canSignCanSpend.first ? idHistory.first.CAN_SIGN : 0) |
2660 (canSignCanSpend.second ? idHistory.first.CAN_SPEND : 0));
c0724caf 2661 AddUpdateIdentity(idMapKey, identity);
e14c324c 2662 }
2663 }
5bc89dab 2664 else
e14c324c 2665 {
e54e3c24 2666 std::pair<bool, bool> swapBools = canSignCanSpend;
2667 canSignCanSpend = wasCanSignCanSpend;
2668 wasCanSignCanSpend = swapBools;
e14c324c 2669 }
5bc89dab 2670
996f6c33 2671 // store transitions as needed in the wallet
a20f2622 2672 if (canSignCanSpend.first != wasCanSignCanSpend.first || canSignCanSpend.second != wasCanSignCanSpend.second)
e14c324c 2673 {
dcc9eba2 2674 // mark all transactions dirty to recalculate numbers
2675 for (auto &txidAndWtx : mapWallet)
2676 {
2677 // mark the whole wallet dirty. if this is an issue, we can optimize.
2678 txidAndWtx.second.MarkDirty();
2679 }
2680
5bc89dab 2681 if (canSignCanSpend.first != wasCanSignCanSpend.first)
2682 {
2f537fa1 2683 if (canSignCanSpend.first)
2684 {
7428b90b 2685 // add all UTXOs sent to this ID to this wallet
2686 // and also check any other outputs that are sent to this ID to see if they have
2687 // been spent, and if so, add them as spends as well
a20f2622 2688 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue>> unspentOutputs;
2a7946a4 2689 std::set<uint256> unspentTxSet;
2690 GetAddressUnspent(idID, CScript::P2ID, unspentOutputs);
2691
2692 // first, put all the txids of the UTXOs in a set to check intersection with wallet txes
2693 // that may already include outputs to the newly controlled ID. we also need to check wallet
2694 // txes that are not UTXOs to record spends, rather than considering them UTXOs
2695 for (auto &newOut : unspentOutputs)
a20f2622 2696 {
2a7946a4 2697 unspentTxSet.insert(newOut.first.txhash);
2698 }
e54e3c24 2699
2a7946a4 2700 // now, look through existing wallet txes for outputs to the ID, which we did not, but now will
2701 // consider as ours and add them to the outputs that need to be checked
2702 for (auto &wtx : mapWallet)
2703 {
2704 // if it's not in the chain, or already in the unspent set to check, we don't need to add it to
2705 // anything
2706 if (!wtx.second.IsInMainChain() ||
2707 unspentTxSet.count(wtx.first))
2708 {
2709 continue;
2710 }
2711 int unspentOutputsSize = unspentOutputs.size();
2712 for (int k = 0; k < wtx.second.vout.size(); k++)
2713 {
2714 const CTxOut &oneOut = wtx.second.vout[k];
adbb6236 2715 txnouttype newTypeRet;
2716 std::vector<CTxDestination> newAddressRet;
2717 int newNRequired;
2718 bool newCanSign, newCanSpend;
2a7946a4 2719 // if we think this output isn't spent and we couldn't sign for it, but the ID enables us to,
2720 // then we need to check it further to see if we need to add other spending txes now
2721 if (IsSpent(wtx.first, k) ||
2722 (ExtractDestinations(oneOut.scriptPubKey, newTypeRet, newAddressRet, newNRequired, this, &newCanSign, &newCanSpend, nHeight == 0 ? INT_MAX : nHeight) && newCanSign))
2723 {
2724 continue;
2725 }
2726 for (auto &oneDest : newAddressRet)
a20f2622 2727 {
2a7946a4 2728 if (oneDest.which() == COptCCParams::ADDRTYPE_ID && GetDestinationID(oneDest) == idID)
a20f2622 2729 {
2a7946a4 2730 CAddressUnspentKey unspentKey(CScript::P2ID, idID, wtx.first, k);
2731 CBlockIndex *pIndex = mapBlockIndex[wtx.second.hashBlock];
2732 unspentOutputs.push_back(
2733 make_pair(unspentKey, CAddressUnspentValue(oneOut.nValue, oneOut.scriptPubKey, pIndex->GetHeight())));
2734 // if we add one on a tx, no need to check more here
2735 break;
a20f2622 2736 }
2a7946a4 2737 }
2738 // we only need to add one output to check all outputs below
2739 if (unspentOutputsSize < unspentOutputs.size())
2740 {
2741 break;
2742 }
2743 }
2744 if (unspentOutputsSize < unspentOutputs.size())
2745 {
2746 continue;
2747 }
2748 }
a20f2622 2749
2a7946a4 2750 auto consensus = Params().GetConsensus();
2751 for (auto &newOut : unspentOutputs)
2752 {
2753 // Do not flush the wallet here for performance reasons
2754 // this is safe, as in case of a crash, we rescan the necessary blocks on startup through our SetBestChain-mechanism
2755 CWalletDB walletdb(strWalletFile, "r+", false);
2756
2757 txnouttype newTypeRet;
2758 std::vector<CTxDestination> newAddressRet;
2759 int newNRequired;
2760 bool newCanSign, newCanSpend;
2761 const CWalletTx *pWtx = GetWalletTx(newOut.first.txhash);
2762
2763 // check if already present and if its a CC output, so we know it can be sent to an identity
2764 if (pWtx == nullptr && newOut.second.script.IsPayToCryptoCondition())
2765 {
2766 CWalletTx wtx;
2767 if (!(ExtractDestinations(newOut.second.script, newTypeRet, newAddressRet, newNRequired, this, &newCanSign, &newCanSpend, nHeight == 0 ? INT_MAX : nHeight + 1) && newCanSign))
2768 {
2769 continue;
2770 }
2771 uint256 blkHash;
2772 CTransaction newTx;
2773 if (myGetTransaction(newOut.first.txhash, newTx, blkHash))
2774 {
2775 wtx = CWalletTx(this, newTx);
2776
2777 // Get merkle branch if transaction was found in a block
2778 CBlock block;
2779 auto blkIndexIt = mapBlockIndex.find(blkHash);
2780 if (!blkHash.IsNull() && blkIndexIt != mapBlockIndex.end() && chainActive.Contains(blkIndexIt->second))
2781 {
2782 // if it's supposed to be in a block, but can't be loaded, don't add without merkle
2783 if (!ReadBlockFromDisk(block, blkIndexIt->second, consensus))
a20f2622 2784 {
2a7946a4 2785 continue;
a20f2622 2786 }
2a7946a4 2787 wtx.SetMerkleBranch(block);
adbb6236 2788 }
2a7946a4 2789
2790 AddToWallet(wtx, false, &walletdb);
2791 pWtx = GetWalletTx(newOut.first.txhash);
adbb6236 2792 }
2a7946a4 2793 }
2794 else if (pWtx = GetWalletTx(newOut.first.txhash))
2795 {
2796 if (!(ExtractDestinations(newOut.second.script, newTypeRet, newAddressRet, newNRequired, this, &newCanSign, &newCanSpend, nHeight == 0 ? INT_MAX : nHeight + 1) && newCanSign))
adbb6236 2797 {
2a7946a4 2798 continue;
adbb6236 2799 }
2a7946a4 2800 }
7428b90b 2801
2a7946a4 2802 // if we were or are now in the wallet, we need to see if we should record new spends
2803 if (pWtx != nullptr && newOut.second.script.IsPayToCryptoCondition())
2804 {
2805 // while we know there is an unspent index to this ID on the new transaction output, we don't know
2806 // if there are other outputs to this ID on the transaction, which are already spent.
2807 // if so, we need to record the spends in the wallet as well, or it will add them but
2808 // not consider them spent.
2809 uint256 spendBlkHash;
2810 CTransaction spendTx;
2811 std::vector<CTxOut> checkIfSpent = pWtx->vout;
2812 for (int i = 0; i < checkIfSpent.size(); i++)
adbb6236 2813 {
2a7946a4 2814 // if it really came from the unspent index and is the same output, don't bother looking for a spend
2815 if (unspentTxSet.count(newOut.first.txhash) && newOut.first.index == i)
adbb6236 2816 {
2a7946a4 2817 continue;
2818 }
7428b90b 2819
2a7946a4 2820 // if we can't spend it, no need to check for spends
2821 if (!(ExtractDestinations(checkIfSpent[i].scriptPubKey,
2822 newTypeRet,
2823 newAddressRet,
2824 newNRequired,
2825 this,
2826 &newCanSign,
2827 &newCanSpend,
2828 nHeight == 0 ? INT_MAX : nHeight + 1) && newCanSign))
2829 {
2830 continue;
2831 }
7428b90b 2832
2a7946a4 2833 CSpentIndexValue spentInfo;
2834 CSpentIndexKey spentKey(newOut.first.txhash, i);
2835 if (GetSpentIndex(spentKey, spentInfo))
2836 {
2837 if (GetWalletTx(spentInfo.txid) == nullptr &&
2838 spentInfo.blockHeight <= nHeight &&
2839 myGetTransaction(spentInfo.txid, spendTx, spendBlkHash) && !spendBlkHash.IsNull())
adbb6236 2840 {
2a7946a4 2841 CWalletTx spendWtx(this, spendTx);
2842
2843 // Get merkle branch if transaction was found in a block
2844 CBlock spendBlock;
2845 auto spendBlkIndexIt = mapBlockIndex.find(spendBlkHash);
2846 if (spendBlkIndexIt != mapBlockIndex.end() &&
2847 chainActive.Contains(spendBlkIndexIt->second) &&
2848 ReadBlockFromDisk(spendBlock, spendBlkIndexIt->second, consensus))
7428b90b 2849 {
2a7946a4 2850 spendWtx.SetMerkleBranch(spendBlock);
2851 AddToWallet(spendWtx, false, &walletdb);
2852
2853 // add these outputs to the outputs we need to check if spent
2854 // as long as we are adding spending transactions that are earlier
2855 // or up to this height, we follow the spends
2856 checkIfSpent.insert(checkIfSpent.end(), spendTx.vout.begin(), spendTx.vout.end());
7428b90b 2857 }
2858 }
a20f2622 2859 }
2860 }
2861 }
2862 }
2f537fa1 2863 }
2864 else
5bc89dab 2865 {
2866 // we have gone from canSign to no control over this ID, either by deletion of tx or removal from signers. this will take effect retroactively on deletion and next block on addition
2867 // 1. remove all transactions that have UTXOs sent to this ID and are no longer can sign or can spend for us from the wallet
2868 // 2. if deletion, remove all transactions since the last idHistory that are in the wallet due to this ID
2869 // 3. remove all IDs from the wallet that are found in those removed transactions, are neither canSpend nor canSign, and are neither on manual hold nor present on any remaining transactions
7428b90b 2870 // 4. remove any transactions that are only in the wallet because they spend an output that was sent to this ID
5bc89dab 2871
7428b90b 2872 std::set<CIdentityID> idsToCheck = std::set<CIdentityID>();
2873
2874 if (!pblock)
2875 {
2876 idsToCheck.insert(idID);
2877 }
5bc89dab 2878
2879 // first and last blocks to consider when deleting spent transactions from the wallet
956ab931 2880 uint32_t deleteSpentFrom;
5bc89dab 2881
2882 if (!pblock)
2883 {
956ab931 2884 deleteSpentFrom = idHistory.first.blockHeight + 1;
5bc89dab 2885 }
2886 else
2887 {
956ab931 2888 deleteSpentFrom = idMapKey.blockHeight + 1;
5bc89dab 2889 }
2890
7428b90b 2891 std::map<const uint256 *, CWalletTx *> txesToErase;
c6782713 2892
5bc89dab 2893 for (auto &txidAndWtx : mapWallet)
2894 {
956ab931 2895 const CBlockIndex *pIndex;
996f6c33 2896 if (txidAndWtx.second.GetDepthInMainChain(pIndex) > 0 && pIndex->GetHeight() <= deleteSpentFrom)
5bc89dab 2897 {
956ab931 2898 continue;
5bc89dab 2899 }
2900
5bc89dab 2901 txnouttype txType;
2902 std::vector<CTxDestination> addresses;
2903 int minSigs;
2904 bool eraseTx = true;
5bc89dab 2905 int i = 0;
2906 uint256 hashTx = txidAndWtx.second.GetHash();
2907
e2c86312 2908 // if we still have z-address notes on the transaction, don't delete
2909 auto sprNoteData = FindMySproutNotes(txidAndWtx.second);
2910 auto sapNoteDataAndAddressesToAdd = FindMySaplingNotes(txidAndWtx.second);
2911 if (sprNoteData.size() || sapNoteDataAndAddressesToAdd.first.size())
2912 {
2913 // don't erase the tx, but check to erase IDs
2914 eraseTx = false;
2915 }
2916
7428b90b 2917 // if the tx is spending from another in this wallet, we will not erase it
2918 // but check destinations before deciding not to erase IDs
adbb6236 2919 if (IsFromMe(txidAndWtx.second, deleteSpentFrom - 1))
e2c86312 2920 {
2921 eraseTx = false;
2922 }
2923
7428b90b 2924 // look for a reason not to delete this tx or IDs it is sent to
5bc89dab 2925 for (auto txout : txidAndWtx.second.vout)
2926 {
2927 // we only want to remove UTXOs that are sent to this ID, used to be ours, and are no longer cansign
2928 if (!txout.scriptPubKey.IsPayToCryptoCondition() || IsSpent(hashTx, i))
2929 {
7428b90b 2930 // if this is ours, we will not erase the tx
2931 // we already checked IsFromMe
5bc89dab 2932 if (IsMine(txout))
2933 {
2934 eraseTx = false;
7428b90b 2935 continue;
5bc89dab 2936 }
5bc89dab 2937 }
2938 bool canSignOut = false;
2939 bool canSpendOut = false;
2940
adbb6236 2941 if (ExtractDestinations(txout.scriptPubKey, txType, addresses, minSigs, this, &canSignOut, &canSpendOut, nHeight == 0 ? INT_MAX : nHeight + 1))
5bc89dab 2942 {
2943 if (canSignOut || canSpendOut)
2944 {
2945 // we should keep this transaction anyhow, check next
2946 eraseTx = false;
e2c86312 2947 continue;
5bc89dab 2948 }
7428b90b 2949
5bc89dab 2950 for (auto &dest : addresses)
2951 {
2952 if (dest.which() == COptCCParams::ADDRTYPE_ID)
2953 {
e2c86312 2954 idsToCheck.insert(GetDestinationID(dest));
5bc89dab 2955 }
2956 }
2957 }
2958
2959 i++;
2960 }
2961 if (eraseTx)
2962 {
7428b90b 2963 txesToErase.insert(make_pair(&txidAndWtx.first, &txidAndWtx.second));
5bc89dab 2964 }
2965 }
c6782713 2966
7428b90b 2967 for (auto &oneTx : txesToErase)
c6782713 2968 {
7428b90b 2969 EraseFromWallet(*oneTx.first);
c6782713 2970 }
5bc89dab 2971
996f6c33 2972 if (pblock && idsToCheck.count(idID))
2973 {
2974 // do not remove the current identity that was just added to take away our authority
2975 // that is an important record to keep
2976 idsToCheck.erase(idID);
2977 }
2978
2979 // now, we've deleted all transactions that were only in the wallet due to our ability to sign with the ID we just lost
5bc89dab 2980 // loop through all transactions and remove all IDs found in the remaining transactions from our idsToCheck set after we
2981 // have gone through all wallet transactions, we can delete all IDs remaining in the idsToCheck set
2982 // that are not on manual hold
2983 for (auto &txidAndWtx : mapWallet)
2984 {
2985 for (auto txout : txidAndWtx.second.vout)
2986 {
2987 if (!txout.scriptPubKey.IsPayToCryptoCondition())
2988 {
2989 continue;
2990 }
2991 bool canSignOut = false;
2992 bool canSpendOut = false;
2993 txnouttype txType;
2994 std::vector<CTxDestination> addresses;
2995 int minSigs;
adbb6236 2996 if (ExtractDestinations(txout.scriptPubKey, txType, addresses, minSigs, this, &canSignOut, &canSpendOut, nHeight == 0 ? INT_MAX : nHeight + 1))
5bc89dab 2997 {
2998 if (canSignOut || canSpendOut)
2999 {
3000 for (auto &dest : addresses)
3001 {
3002 if (dest.which() == COptCCParams::ADDRTYPE_ID)
3003 {
3004 idsToCheck.erase(GetDestinationID(dest));
3005 if (!idsToCheck.size())
3006 {
3007 break;
3008 }
3009 }
3010 }
e54e3c24 3011 }
5bc89dab 3012 }
3013 if (!idsToCheck.size())
3014 {
3015 break;
3016 }
3017 }
3018 if (!idsToCheck.size())
3019 {
3020 break;
3021 }
3022 }
996f6c33 3023
5bc89dab 3024 // delete all remaining IDs that are not held for manual hold
3025 for (auto &idToRemove : idsToCheck)
3026 {
3027 std::pair<CIdentityMapKey, CIdentityMapValue> identityToRemove;
3028
3029 // if not cansign or canspend, no transactions we care about relating to it and no manual hold, delete the ID from the wallet
956ab931 3030 // also keep the first transition after one we will keep
5bc89dab 3031 if (GetIdentity(idToRemove, identityToRemove) &&
3032 !((identityToRemove.first.flags & (identityToRemove.first.CAN_SIGN + identityToRemove.first.CAN_SPEND)) || identityToRemove.first.flags & identityToRemove.first.MANUAL_HOLD))
3033 {
d26748d5 3034 std::pair<CIdentityMapKey, CIdentityMapValue> priorIdentity;
3035
996f6c33 3036 if (!GetPriorIdentity(identityToRemove.first, priorIdentity) ||
3037 !((priorIdentity.first.flags & (priorIdentity.first.CAN_SIGN + priorIdentity.first.CAN_SPEND)) || identityToRemove.first.flags & identityToRemove.first.MANUAL_HOLD))
956ab931 3038 {
d26748d5 3039 // if we don't have recovery on a revoked ID in our wallet, then remove it
3040 std::pair<CIdentityMapKey, CIdentityMapValue> recoveryIdentity;
3041 if (!identityToRemove.second.IsRevoked() || !GetIdentity(identityToRemove.second.recoveryAuthority, recoveryIdentity) || !(recoveryIdentity.first.flags & recoveryIdentity.first.CAN_SIGN))
3042 {
3043 RemoveIdentity(CIdentityMapKey(idToRemove));
3044 }
956ab931 3045 }
5bc89dab 3046 }
3047 }
3048 }
3049 }
e14c324c 3050 }
b3ea772e 3051 }
3052 }
b3ea772e 3053 }
3054 }
3055
efecad16 3056 // for IsMine, the default height is max, not 0
3057 nHeight = nHeight == 0 ? INT_MAX : nHeight;
3058 if (fExisted || IsMine(tx, nHeight) || IsFromMe(tx, nHeight) || sproutNoteData.size() > 0 || saplingNoteData.size() > 0)
6cc4a62c 3059 {
2f537fa1 3060 CWalletTx wtx(this, tx);
44bc988e 3061
78584ef7
S
3062 if (sproutNoteData.size() > 0) {
3063 wtx.SetSproutNoteData(sproutNoteData);
3064 }
3065
3066 if (saplingNoteData.size() > 0) {
3067 wtx.SetSaplingNoteData(saplingNoteData);
be74c80d 3068 }
c3a7307a 3069
6cc4a62c
GA
3070 // Get merkle branch if transaction was found in a block
3071 if (pblock)
4b0deb3b 3072 wtx.SetMerkleBranch(*pblock);
44bc988e
CL
3073
3074 // Do not flush the wallet here for performance reasons
3075 // this is safe, as in case of a crash, we rescan the necessary blocks on startup through our SetBestChain-mechanism
3076 CWalletDB walletdb(strWalletFile, "r+", false);
3077
3078 return AddToWallet(wtx, false, &walletdb);
6cc4a62c 3079 }
e8ef3da7 3080 }
e8ef3da7
WL
3081 return false;
3082}
3083
d38da59b 3084void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock)
93a18a36 3085{
7c8111f3 3086 LOCK(cs_wallet);
d38da59b 3087 if (!AddToWalletIfInvolvingMe(tx, pblock, true))
93a18a36
GA
3088 return; // Not one of ours
3089
ac1c9435
JG
3090 MarkAffectedTransactionsDirty(tx);
3091}
3092
3093void CWallet::MarkAffectedTransactionsDirty(const CTransaction& tx)
3094{
93a18a36
GA
3095 // If a transaction changes 'conflicted' state, that changes the balance
3096 // available of the outputs it spends. So force those to be
3097 // recomputed, also:
3098 BOOST_FOREACH(const CTxIn& txin, tx.vin)
3099 {
3100 if (mapWallet.count(txin.prevout.hash))
3101 mapWallet[txin.prevout.hash].MarkDirty();
3102 }
f57f76d7 3103 for (const JSDescription& jsdesc : tx.vJoinSplit) {
8db7e25c 3104 for (const uint256& nullifier : jsdesc.nullifiers) {
f41bf503 3105 if (mapSproutNullifiersToNotes.count(nullifier) &&
dae1c420 3106 mapWallet.count(mapSproutNullifiersToNotes[nullifier].hash)) {
f41bf503 3107 mapWallet[mapSproutNullifiersToNotes[nullifier].hash].MarkDirty();
8db7e25c
JG
3108 }
3109 }
3110 }
dae1c420
S
3111
3112 for (const SpendDescription &spend : tx.vShieldedSpend) {
3113 uint256 nullifier = spend.nullifier;
3114 if (mapSaplingNullifiersToNotes.count(nullifier) &&
3115 mapWallet.count(mapSaplingNullifiersToNotes[nullifier].hash)) {
3116 mapWallet[mapSaplingNullifiersToNotes[nullifier].hash].MarkDirty();
3117 }
3118 }
00588c3f
PW
3119}
3120
3121void CWallet::EraseFromWallet(const uint256 &hash)
e8ef3da7
WL
3122{
3123 if (!fFileBacked)
00588c3f 3124 return;
e8ef3da7 3125 {
f8dcd5ca 3126 LOCK(cs_wallet);
e8ef3da7
WL
3127 if (mapWallet.erase(hash))
3128 CWalletDB(strWalletFile).EraseTx(hash);
3129 }
00588c3f 3130 return;
e8ef3da7
WL
3131}
3132
47ab0926 3133void CWallet::RescanWallet()
3134{
3135 if (needsRescan)
3136 {
3137 CBlockIndex *start = chainActive.Height() > 0 ? chainActive[1] : NULL;
3138 if (start)
3139 ScanForWalletTransactions(start, true);
3140 needsRescan = false;
3141 }
3142}
3143
e8ef3da7 3144
1a62587e
JG
3145/**
3146 * Returns a nullifier if the SpendingKey is available
3147 * Throws std::runtime_error if the decryptor doesn't match this note
3148 */
618206c7
S
3149boost::optional<uint256> CWallet::GetSproutNoteNullifier(const JSDescription &jsdesc,
3150 const libzcash::SproutPaymentAddress &address,
3151 const ZCNoteDecryption &dec,
3152 const uint256 &hSig,
3153 uint8_t n) const
1a62587e
JG
3154{
3155 boost::optional<uint256> ret;
5020a936 3156 auto note_pt = libzcash::SproutNotePlaintext::decrypt(
1a62587e
JG
3157 dec,
3158 jsdesc.ciphertexts[n],
3159 jsdesc.ephemeralKey,
3160 hSig,
3161 (unsigned char) n);
3162 auto note = note_pt.note(address);
c1009374
SB
3163
3164 // Check note plaintext against note commitment
3165 if (note.cm() != jsdesc.commitments[n]) {
3166 throw libzcash::note_decryption_failed();
3167 }
3168
9a2b8ae5
JG
3169 // SpendingKeys are only available if:
3170 // - We have them (this isn't a viewing key)
3171 // - The wallet is unlocked
e5eab182 3172 libzcash::SproutSpendingKey key;
25d5e80c 3173 if (GetSproutSpendingKey(address, key)) {
1a62587e
JG
3174 ret = note.nullifier(key);
3175 }
3176 return ret;
3177}
3178
e492d986
JG
3179/**
3180 * Finds all output notes in the given transaction that have been sent to
3181 * PaymentAddresses in this wallet.
3182 *
3183 * It should never be necessary to call this method with a CWalletTx, because
57faf44e 3184 * the result of FindMySproutNotes (for the addresses available at the time) will
005f3ad1 3185 * already have been cached in CWalletTx.mapSproutNoteData.
e492d986 3186 */
57faf44e 3187mapSproutNoteData_t CWallet::FindMySproutNotes(const CTransaction &tx) const
02e67455 3188{
3fac1020 3189 LOCK(cs_SpendingKeyStore);
fa511e10 3190 uint256 hash = tx.GetHash();
02e67455 3191
005f3ad1 3192 mapSproutNoteData_t noteData;
f57f76d7
DA
3193 for (size_t i = 0; i < tx.vJoinSplit.size(); i++) {
3194 auto hSig = tx.vJoinSplit[i].h_sig(*pzcashParams, tx.joinSplitPubKey);
3195 for (uint8_t j = 0; j < tx.vJoinSplit[i].ciphertexts.size(); j++) {
3fac1020 3196 for (const NoteDecryptorMap::value_type& item : mapNoteDecryptors) {
02e67455 3197 try {
02e67455 3198 auto address = item.first;
02e67455 3199 JSOutPoint jsoutpt {hash, i, j};
618206c7 3200 auto nullifier = GetSproutNoteNullifier(
f57f76d7 3201 tx.vJoinSplit[i],
1a62587e
JG
3202 address,
3203 item.second,
3204 hSig, j);
3205 if (nullifier) {
005f3ad1 3206 SproutNoteData nd {address, *nullifier};
1a62587e
JG
3207 noteData.insert(std::make_pair(jsoutpt, nd));
3208 } else {
005f3ad1 3209 SproutNoteData nd {address};
1a62587e
JG
3210 noteData.insert(std::make_pair(jsoutpt, nd));
3211 }
02e67455 3212 break;
51fde9ea 3213 } catch (const note_decryption_failed &err) {
1a62587e 3214 // Couldn't decrypt with this decryptor
32a103aa
JG
3215 } catch (const std::exception &exc) {
3216 // Unexpected failure
57faf44e 3217 LogPrintf("FindMySproutNotes(): Unexpected error while testing decrypt:\n");
32a103aa 3218 LogPrintf("%s\n", exc.what());
02e67455
JG
3219 }
3220 }
3221 }
3222 }
3223 return noteData;
3224}
3225
78584ef7
S
3226
3227/**
3228 * Finds all output notes in the given transaction that have been sent to
3229 * SaplingPaymentAddresses in this wallet.
3230 *
3231 * It should never be necessary to call this method with a CWalletTx, because
3232 * the result of FindMySaplingNotes (for the addresses available at the time) will
3233 * already have been cached in CWalletTx.mapSaplingNoteData.
3234 */
a4ecd0fa 3235std::pair<mapSaplingNoteData_t, SaplingIncomingViewingKeyMap> CWallet::FindMySaplingNotes(const CTransaction &tx) const
78584ef7
S
3236{
3237 LOCK(cs_SpendingKeyStore);
3238 uint256 hash = tx.GetHash();
3239
3240 mapSaplingNoteData_t noteData;
a4ecd0fa 3241 SaplingIncomingViewingKeyMap viewingKeysToAdd;
78584ef7
S
3242
3243 // Protocol Spec: 4.19 Block Chain Scanning (Sapling)
3244 for (uint32_t i = 0; i < tx.vShieldedOutput.size(); ++i) {
3245 const OutputDescription output = tx.vShieldedOutput[i];
ec064abb
S
3246 for (auto it = mapSaplingFullViewingKeys.begin(); it != mapSaplingFullViewingKeys.end(); ++it) {
3247 SaplingIncomingViewingKey ivk = it->first;
78584ef7
S
3248 auto result = SaplingNotePlaintext::decrypt(output.encCiphertext, ivk, output.ephemeralKey, output.cm);
3249 if (!result) {
3250 continue;
3251 }
a4ecd0fa
EOW
3252 auto address = ivk.address(result.get().d);
3253 if (address && mapSaplingIncomingViewingKeys.count(address.get()) == 0) {
3254 viewingKeysToAdd[address.get()] = ivk;
3255 }
78584ef7
S
3256 // We don't cache the nullifier here as computing it requires knowledge of the note position
3257 // in the commitment tree, which can only be determined when the transaction has been mined.
3258 SaplingOutPoint op {hash, i};
3259 SaplingNoteData nd;
3260 nd.ivk = ivk;
3261 noteData.insert(std::make_pair(op, nd));
3262 break;
3263 }
3264 }
3265
a4ecd0fa 3266 return std::make_pair(noteData, viewingKeysToAdd);
78584ef7
S
3267}
3268
037cacf2 3269bool CWallet::IsSproutNullifierFromMe(const uint256& nullifier) const
1551db87
JG
3270{
3271 {
3272 LOCK(cs_wallet);
f41bf503
S
3273 if (mapSproutNullifiersToNotes.count(nullifier) &&
3274 mapWallet.count(mapSproutNullifiersToNotes.at(nullifier).hash)) {
1551db87
JG
3275 return true;
3276 }
3277 }
3278 return false;
3279}
3280
d7cf640b 3281bool CWallet::IsSaplingNullifierFromMe(const uint256& nullifier) const
be74c80d
JG
3282{
3283 {
3284 LOCK(cs_wallet);
d7cf640b
S
3285 if (mapSaplingNullifiersToNotes.count(nullifier) &&
3286 mapWallet.count(mapSaplingNullifiersToNotes.at(nullifier).hash)) {
3287 return true;
3288 }
3289 }
3290 return false;
3291}
3292
8e8279e7 3293void CWallet::GetSproutNoteWitnesses(std::vector<JSOutPoint> notes,
8ea8ef98 3294 std::vector<boost::optional<SproutWitness>>& witnesses,
8e8279e7 3295 uint256 &final_anchor)
be74c80d 3296{
29523dc7
EOW
3297 LOCK(cs_wallet);
3298 witnesses.resize(notes.size());
3299 boost::optional<uint256> rt;
3300 int i = 0;
3301 for (JSOutPoint note : notes) {
3302 if (mapWallet.count(note.hash) &&
3303 mapWallet[note.hash].mapSproutNoteData.count(note) &&
3304 mapWallet[note.hash].mapSproutNoteData[note].witnesses.size() > 0) {
3305 witnesses[i] = mapWallet[note.hash].mapSproutNoteData[note].witnesses.front();
3306 if (!rt) {
3307 rt = witnesses[i]->root();
3308 } else {
3309 assert(*rt == witnesses[i]->root());
be74c80d 3310 }
be74c80d 3311 }
29523dc7
EOW
3312 i++;
3313 }
3314 // All returned witnesses have the same anchor
3315 if (rt) {
3316 final_anchor = *rt;
be74c80d
JG
3317 }
3318}
3319
e6b0a8b9 3320void CWallet::GetSaplingNoteWitnesses(std::vector<SaplingOutPoint> notes,
8ea8ef98 3321 std::vector<boost::optional<SaplingWitness>>& witnesses,
e6b0a8b9
EOW
3322 uint256 &final_anchor)
3323{
3324 LOCK(cs_wallet);
3325 witnesses.resize(notes.size());
3326 boost::optional<uint256> rt;
3327 int i = 0;
3328 for (SaplingOutPoint note : notes) {
3329 if (mapWallet.count(note.hash) &&
3330 mapWallet[note.hash].mapSaplingNoteData.count(note) &&
3331 mapWallet[note.hash].mapSaplingNoteData[note].witnesses.size() > 0) {
3332 witnesses[i] = mapWallet[note.hash].mapSaplingNoteData[note].witnesses.front();
3333 if (!rt) {
3334 rt = witnesses[i]->root();
3335 } else {
3336 assert(*rt == witnesses[i]->root());
3337 }
be74c80d 3338 }
e6b0a8b9
EOW
3339 i++;
3340 }
3341 // All returned witnesses have the same anchor
3342 if (rt) {
3343 final_anchor = *rt;
be74c80d
JG
3344 }
3345}
3346
efecad16 3347isminetype CWallet::IsMine(const CTxIn &txin, uint32_t nHeight) const
e8ef3da7 3348{
e8ef3da7 3349 {
f8dcd5ca 3350 LOCK(cs_wallet);
e8ef3da7
WL
3351 map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
3352 if (mi != mapWallet.end())
3353 {
3354 const CWalletTx& prev = (*mi).second;
3355 if (txin.prevout.n < prev.vout.size())
efecad16 3356 return (::IsMine(*this, prev.vout[txin.prevout.n].scriptPubKey, nHeight));
e8ef3da7
WL
3357 }
3358 }
a3e192a3 3359 return ISMINE_NO;
e8ef3da7
WL
3360}
3361
efecad16 3362CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter, uint32_t nHeight) const
e8ef3da7 3363{
e8ef3da7 3364 {
f8dcd5ca 3365 LOCK(cs_wallet);
e8ef3da7
WL
3366 map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
3367 if (mi != mapWallet.end())
3368 {
3369 const CWalletTx& prev = (*mi).second;
3370 if (txin.prevout.n < prev.vout.size())
efecad16 3371 if (::IsMine(*this, prev.vout[txin.prevout.n].scriptPubKey, nHeight) & filter)
47658758 3372 return prev.vout[txin.prevout.n].nValue; // komodo_interest?
e8ef3da7
WL
3373 }
3374 }
3375 return 0;
3376}
3377
efecad16 3378CCurrencyValueMap CWallet::GetReserveDebit(const CTxIn &txin, const isminefilter& filter, uint32_t nHeight) const
56fe75cb 3379{
3380 {
3381 LOCK(cs_wallet);
3382 map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
3383 if (mi != mapWallet.end())
3384 {
3385 const CWalletTx& prev = (*mi).second;
3386 if (txin.prevout.n < prev.vout.size())
efecad16 3387 if (::IsMine(*this, prev.vout[txin.prevout.n].scriptPubKey, nHeight) & filter)
56fe75cb 3388 return prev.vout[txin.prevout.n].ReserveOutValue();
3389 }
3390 }
3391 return CCurrencyValueMap();
3392}
3393
efecad16 3394isminetype CWallet::IsMine(const CTxOut& txout, uint32_t nHeight) const
eca0b1ea 3395{
efecad16 3396 return ::IsMine(*this, txout.scriptPubKey, nHeight);
eca0b1ea
JT
3397}
3398
efecad16 3399CAmount CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter, uint32_t nHeight) const
eca0b1ea
JT
3400{
3401 if (!MoneyRange(txout.nValue))
3402 throw std::runtime_error("CWallet::GetCredit(): value out of range");
efecad16 3403 return ((IsMine(txout, nHeight) & filter) ? txout.nValue : 0);
eca0b1ea
JT
3404}
3405
e679ec96
GA
3406bool CWallet::IsChange(const CTxOut& txout) const
3407{
2a45a494 3408 // TODO: fix handling of 'change' outputs. The assumption is that any
d5087d1b 3409 // payment to a script that is ours, but is not in the address book
2a45a494
GA
3410 // is change. That assumption is likely to break when we implement multisignature
3411 // wallets that return change back into a multi-signature-protected address;
3412 // a better way of identifying which outputs are 'the send' and which are
3413 // 'the change' will need to be implemented (maybe extend CWalletTx to remember
3414 // which output, if any, was change).
d5087d1b 3415 if (::IsMine(*this, txout.scriptPubKey))
f8dcd5ca 3416 {
d5087d1b
PW
3417 CTxDestination address;
3418 if (!ExtractDestination(txout.scriptPubKey, address))
3419 return true;
3420
f8dcd5ca
PW
3421 LOCK(cs_wallet);
3422 if (!mapAddressBook.count(address))
3423 return true;
3424 }
e679ec96
GA
3425 return false;
3426}
3427
eca0b1ea
JT
3428CAmount CWallet::GetChange(const CTxOut& txout) const
3429{
3430 if (!MoneyRange(txout.nValue))
3431 throw std::runtime_error("CWallet::GetChange(): value out of range");
3432 return (IsChange(txout) ? txout.nValue : 0);
3433}
3434
ea340a14 3435typedef vector<unsigned char> valtype;
3436unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore);
3437
efecad16 3438bool CWallet::IsMine(const CTransaction& tx, uint32_t nHeight)
eca0b1ea 3439{
90e75021 3440 for (int i = 0; i < tx.vout.size(); i++)
3441 {
efecad16 3442 isminetype mine;
3443 IsMine(tx, i, mine, nHeight);
3444 if (mine)
eca0b1ea 3445 return true;
90e75021 3446 }
3447 return false;
3448}
3449
29bd53a1
MT
3450// special case handling for non-standard/Verus OP_RETURN script outputs, which need the transaction
3451// to determine ownership
efecad16 3452void CWallet::IsMine(const CTransaction& tx, uint32_t voutNum, isminetype &mine, uint32_t nHeight)
29bd53a1
MT
3453{
3454 vector<valtype> vSolutions;
3455 txnouttype whichType;
0d7fed99 3456 CScript scriptPubKey = tx.vout[voutNum].scriptPubKey;
29bd53a1 3457
0d7fed99 3458 if (scriptPubKey.IsCheckLockTimeVerify())
b7c685b8 3459 {
0d7fed99 3460 uint8_t pushOp = scriptPubKey[0];
3461 uint32_t scriptStart = pushOp + 3;
b7c685b8 3462
0d7fed99 3463 // continue with post CLTV script
3464 scriptPubKey = CScript(scriptPubKey.size() > scriptStart ? scriptPubKey.begin() + scriptStart : scriptPubKey.end(), scriptPubKey.end());
3465 }
3466
3467 COptCCParams p;
3468 if (scriptPubKey.IsPayToCryptoCondition(p) && p.IsValid())
3469 {
3470 std::vector<CTxDestination> dests;
3471 int minSigs;
3472 bool canSign = false;
3473 bool canSpend = false;
b7c685b8 3474
efecad16 3475 if (ExtractDestinations(scriptPubKey, whichType, dests, minSigs, this, &canSign, &canSpend, nHeight))
0d7fed99 3476 {
3477 if (canSpend)
b7c685b8 3478 {
efecad16 3479 mine = ISMINE_SPENDABLE;
3480 return;
b7c685b8 3481 }
0d7fed99 3482 else if (canSign)
b7c685b8 3483 {
efecad16 3484 mine = ISMINE_WATCH_ONLY;
3485 return;
b7c685b8 3486 }
2f537fa1 3487 else
3488 {
efecad16 3489 mine = ISMINE_NO;
3490 return;
2f537fa1 3491 }
b7c685b8 3492 }
3493 else
3494 {
efecad16 3495 mine = ISMINE_NO;
3496 return;
b7c685b8 3497 }
3498 }
3499 else if (!Solver(scriptPubKey, whichType, vSolutions))
3500 {
29bd53a1 3501 if (this->HaveWatchOnly(scriptPubKey))
efecad16 3502 {
3503 mine = ISMINE_WATCH_ONLY;
3504 return;
3505 }
3506 mine = ISMINE_NO;
3507 return;
29bd53a1
MT
3508 }
3509
3510 CKeyID keyID;
90e75021 3511 CScriptID scriptID;
29bd53a1
MT
3512 CScriptExt subscript;
3513 int voutNext = voutNum + 1;
3514
3515 switch (whichType)
3516 {
3517 case TX_NONSTANDARD:
3518 case TX_NULL_DATA:
3519 break;
3520
68b9a352 3521 case TX_CRYPTOCONDITION:
ac53126c 3522 // for now, default is that the first value returned will be the target address, subsequent values will be
3523 // pubkeys. if we have the first in our wallet, we consider it spendable for now
3524 if (vSolutions[0].size() == 33)
68b9a352 3525 {
ac53126c 3526 keyID = CPubKey(vSolutions[0]).GetID();
3527 }
3528 else if (vSolutions[0].size() == 20)
3529 {
3530 keyID = CKeyID(uint160(vSolutions[0]));
3531 }
3532 if (!keyID.IsNull() && HaveKey(keyID))
3533 {
efecad16 3534 mine = ISMINE_SPENDABLE;
3535 return;
68b9a352 3536 }
3537 break;
3538
29bd53a1
MT
3539 case TX_PUBKEY:
3540 keyID = CPubKey(vSolutions[0]).GetID();
3541 if (this->HaveKey(keyID))
efecad16 3542 {
3543 mine = ISMINE_SPENDABLE;
3544 return;
3545 }
29bd53a1
MT
3546 break;
3547
3548 case TX_PUBKEYHASH:
3549 keyID = CKeyID(uint160(vSolutions[0]));
3550 if (this->HaveKey(keyID))
efecad16 3551 {
3552 mine = ISMINE_SPENDABLE;
3553 return;
3554 }
29bd53a1
MT
3555 break;
3556
3557 case TX_SCRIPTHASH:
90e75021 3558 scriptID = CScriptID(uint160(vSolutions[0]));
29bd53a1
MT
3559 if (this->GetCScript(scriptID, subscript))
3560 {
3561 // if this is a CLTV, handle it differently
ef70c5b2 3562 if (subscript.IsCheckLockTimeVerify())
29bd53a1 3563 {
efecad16 3564 mine = (::IsMine(*this, subscript));
3565 return;
29bd53a1
MT
3566 }
3567 else
3568 {
3569 isminetype ret = ::IsMine(*this, subscript);
3570 if (ret == ISMINE_SPENDABLE)
efecad16 3571 {
3572 mine = ret;
3573 return;
3574 }
29bd53a1
MT
3575 }
3576 }
ebee7b5b
MT
3577 else if (tx.vout.size() > (voutNum + 1) &&
3578 tx.vout.back().scriptPubKey.size() > 7 &&
3579 tx.vout.back().scriptPubKey[0] == OP_RETURN)
29bd53a1
MT
3580 {
3581 // get the opret script from next vout, verify that the front is CLTV and hash matches
3582 // if so, remove it and use the solver
3583 opcodetype op;
3584 std::vector<uint8_t> opretData;
ebee7b5b
MT
3585 CScript::const_iterator it = tx.vout.back().scriptPubKey.begin() + 1;
3586 if (tx.vout.back().scriptPubKey.GetOp2(it, op, &opretData))
29bd53a1 3587 {
9feb4b9e 3588 if (opretData.size() > 0 && opretData[0] == OPRETTYPE_TIMELOCK)
29bd53a1 3589 {
9feb4b9e 3590 CScript opretScript = CScript(opretData.begin() + 1, opretData.end());
29bd53a1
MT
3591
3592 if (CScriptID(opretScript) == scriptID &&
ef70c5b2 3593 opretScript.IsCheckLockTimeVerify())
29bd53a1 3594 {
ea340a14 3595 // if we find that this is ours, we need to add this script to the wallet,
3596 // and we can then recognize this transaction
3597 isminetype t = ::IsMine(*this, opretScript);
3598 if (t != ISMINE_NO)
3599 {
3600 this->AddCScript(opretScript);
3601 }
efecad16 3602 mine = t;
3603 return;
29bd53a1
MT
3604 }
3605 }
3606 }
3607 }
3608 break;
3609
3610 case TX_MULTISIG:
3611 // Only consider transactions "mine" if we own ALL the
3612 // keys involved. Multi-signature transactions that are
3613 // partially owned (somebody else has a key that can spend
3614 // them) enable spend-out-from-under-you attacks, especially
3615 // in shared-wallet situations.
3616 vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
3617 if (HaveKeys(keys, *this) == keys.size())
efecad16 3618 {
3619 mine = ISMINE_SPENDABLE;
3620 return;
3621 }
29bd53a1
MT
3622 break;
3623 }
3624
3625 if (this->HaveWatchOnly(scriptPubKey))
efecad16 3626 {
3627 mine = ISMINE_WATCH_ONLY;
3628 return;
3629 }
29bd53a1 3630
efecad16 3631 mine = ISMINE_NO;
29bd53a1
MT
3632}
3633
efecad16 3634bool CWallet::IsFromMe(const CTransaction& tx, uint32_t height) const
eca0b1ea 3635{
4a5b9f74 3636 {
3637 LOCK(cs_wallet);
3638 for (auto &txin : tx.vin)
3639 {
3640 map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
3641 if (mi != mapWallet.end())
3642 {
3643 const CWalletTx& prev = (*mi).second;
3644 if (txin.prevout.n < prev.vout.size())
adbb6236 3645 {
efecad16 3646 if (::IsMine(*this, prev.vout[txin.prevout.n].scriptPubKey, height) & ISMINE_ALL)
4a5b9f74 3647 return true;
adbb6236 3648 }
4a5b9f74 3649 }
3650 }
1551db87 3651 }
f57f76d7 3652 for (const JSDescription& jsdesc : tx.vJoinSplit) {
1551db87 3653 for (const uint256& nullifier : jsdesc.nullifiers) {
037cacf2 3654 if (IsSproutNullifierFromMe(nullifier)) {
1551db87
JG
3655 return true;
3656 }
3657 }
3658 }
d7cf640b
S
3659 for (const SpendDescription &spend : tx.vShieldedSpend) {
3660 if (IsSaplingNullifierFromMe(spend.nullifier)) {
3661 return true;
3662 }
3663 }
1551db87 3664 return false;
eca0b1ea
JT
3665}
3666
efecad16 3667CAmount CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter, uint32_t nHeight) const
eca0b1ea
JT
3668{
3669 CAmount nDebit = 0;
3670 BOOST_FOREACH(const CTxIn& txin, tx.vin)
3671 {
efecad16 3672 nDebit += GetDebit(txin, filter, nHeight);
eca0b1ea
JT
3673 if (!MoneyRange(nDebit))
3674 throw std::runtime_error("CWallet::GetDebit(): value out of range");
3675 }
3676 return nDebit;
3677}
3678
efecad16 3679CCurrencyValueMap CWallet::GetReserveDebit(const CTransaction& tx, const isminefilter& filter, uint32_t nHeight) const
56fe75cb 3680{
3681 CCurrencyValueMap retVal;
3682 BOOST_FOREACH(const CTxIn& txin, tx.vin)
3683 {
efecad16 3684 retVal += GetReserveDebit(txin, filter, nHeight);
56fe75cb 3685 }
3686 return retVal;
3687}
3688
efecad16 3689CAmount CWallet::GetCredit(const CTransaction& tx, const int32_t &voutNum, const isminefilter& filter, uint32_t nHeight) const
fab1429d 3690{
3691 if (voutNum >= tx.vout.size() || !MoneyRange(tx.vout[voutNum].nValue))
3692 throw std::runtime_error("CWallet::GetCredit(): value out of range");
efecad16 3693 return ((IsMine(tx.vout[voutNum], nHeight) & filter) ? tx.vout[voutNum].nValue : 0);
fab1429d 3694}
3695
56fe75cb 3696CCurrencyValueMap CWallet::GetReserveCredit(const CTransaction& tx, int32_t voutNum, const isminefilter& filter) const
3a27113e 3697{
56fe75cb 3698 return ((IsMine(tx.vout[voutNum]) & filter) ? tx.vout[voutNum].ReserveOutValue() : CCurrencyValueMap());
3a27113e 3699}
3700
56fe75cb 3701CCurrencyValueMap CWallet::GetReserveCredit(const CTransaction& tx, const isminefilter& filter) const
3a27113e 3702{
56fe75cb 3703 CCurrencyValueMap nCredit;
3a27113e 3704 for (int i = 0; i < tx.vout.size(); i++)
3705 {
3706 nCredit += GetReserveCredit(tx, i, filter);
3707 }
3708 return nCredit;
3709}
3710
efecad16 3711CAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter, uint32_t nHeight) const
eca0b1ea
JT
3712{
3713 CAmount nCredit = 0;
fab1429d 3714 for (int i = 0; i < tx.vout.size(); i++)
eca0b1ea 3715 {
efecad16 3716 nCredit += GetCredit(tx, i, filter, nHeight);
eca0b1ea
JT
3717 }
3718 return nCredit;
3719}
3720
3721CAmount CWallet::GetChange(const CTransaction& tx) const
3722{
3723 CAmount nChange = 0;
3724 BOOST_FOREACH(const CTxOut& txout, tx.vout)
3725 {
3726 nChange += GetChange(txout);
3727 if (!MoneyRange(nChange))
3728 throw std::runtime_error("CWallet::GetChange(): value out of range");
3729 }
3730 return nChange;
3731}
3732
e2416930
JG
3733bool CWallet::IsHDFullyEnabled() const
3734{
3735 // Only Sapling addresses are HD for now
3736 return false;
3737}
3738
3739void CWallet::GenerateNewSeed()
3740{
3741 LOCK(cs_wallet);
3742
3743 auto seed = HDSeed::Random(HD_WALLET_SEED_LENGTH);
3744
3745 int64_t nCreationTime = GetTime();
3746
3747 // If the wallet is encrypted and locked, this will fail.
3748 if (!SetHDSeed(seed))
3749 throw std::runtime_error(std::string(__func__) + ": SetHDSeed failed");
3750
3751 // store the key creation time together with
3752 // the child index counter in the database
3753 // as a hdchain object
3754 CHDChain newHdChain;
3755 newHdChain.nVersion = CHDChain::VERSION_HD_BASE;
3756 newHdChain.seedFp = seed.Fingerprint();
3757 newHdChain.nCreateTime = nCreationTime;
3758 SetHDChain(newHdChain, false);
3759}
3760
3761bool CWallet::SetHDSeed(const HDSeed& seed)
c3a7307a 3762{
e2416930
JG
3763 if (!CCryptoKeyStore::SetHDSeed(seed)) {
3764 return false;
3765 }
3766
3767 if (!fFileBacked) {
3768 return true;
3769 }
3770
3771 {
3772 LOCK(cs_wallet);
3773 if (!IsCrypted()) {
3774 return CWalletDB(strWalletFile).WriteHDSeed(seed);
3775 }
3776 }
3777 return true;
3778}
3779
3780bool CWallet::SetCryptedHDSeed(const uint256& seedFp, const std::vector<unsigned char> &vchCryptedSecret)
3781{
3782 if (!CCryptoKeyStore::SetCryptedHDSeed(seedFp, vchCryptedSecret)) {
3783 return false;
3784 }
3785
3786 if (!fFileBacked) {
3787 return true;
3788 }
3789
3790 {
3791 LOCK(cs_wallet);
3792 if (pwalletdbEncryption)
3793 return pwalletdbEncryption->WriteCryptedHDSeed(seedFp, vchCryptedSecret);
3794 else
3795 return CWalletDB(strWalletFile).WriteCryptedHDSeed(seedFp, vchCryptedSecret);
3796 }
3797 return false;
3798}
3799
52cfa9c1
E
3800HDSeed CWallet::GetHDSeedForRPC() const {
3801 HDSeed seed;
3802 if (!pwalletMain->GetHDSeed(seed)) {
3803 throw JSONRPCError(RPC_WALLET_ERROR, "HD seed not found");
3804 }
3805 return seed;
3806}
3807
e2416930
JG
3808void CWallet::SetHDChain(const CHDChain& chain, bool memonly)
3809{
3810 LOCK(cs_wallet);
3811 if (!memonly && fFileBacked && !CWalletDB(strWalletFile).WriteHDChain(chain))
3812 throw std::runtime_error(std::string(__func__) + ": writing chain failed");
3813
3814 hdChain = chain;
3815}
3816
3817bool CWallet::LoadHDSeed(const HDSeed& seed)
3818{
3819 return CBasicKeyStore::SetHDSeed(seed);
3820}
3821
3822bool CWallet::LoadCryptedHDSeed(const uint256& seedFp, const std::vector<unsigned char>& seed)
3823{
3824 return CCryptoKeyStore::SetCryptedHDSeed(seedFp, seed);
3825}
3826
8e8279e7 3827void CWalletTx::SetSproutNoteData(mapSproutNoteData_t &noteData)
c3a7307a 3828{
005f3ad1
EOW
3829 mapSproutNoteData.clear();
3830 for (const std::pair<JSOutPoint, SproutNoteData> nd : noteData) {
f57f76d7
DA
3831 if (nd.first.js < vJoinSplit.size() &&
3832 nd.first.n < vJoinSplit[nd.first.js].ciphertexts.size()) {
c3a7307a 3833 // Store the address and nullifier for the Note
005f3ad1 3834 mapSproutNoteData[nd.first] = nd.second;
c3a7307a 3835 } else {
57faf44e 3836 // If FindMySproutNotes() was used to obtain noteData,
c3a7307a 3837 // this should never happen
8e8279e7 3838 throw std::logic_error("CWalletTx::SetSproutNoteData(): Invalid note");
c3a7307a
JG
3839 }
3840 }
3841}
3842
e6b0a8b9
EOW
3843void CWalletTx::SetSaplingNoteData(mapSaplingNoteData_t &noteData)
3844{
3845 mapSaplingNoteData.clear();
3846 for (const std::pair<SaplingOutPoint, SaplingNoteData> nd : noteData) {
3847 if (nd.first.n < vShieldedOutput.size()) {
3848 mapSaplingNoteData[nd.first] = nd.second;
3849 } else {
3850 throw std::logic_error("CWalletTx::SetSaplingNoteData(): Invalid note");
c3a7307a
JG
3851 }
3852 }
3853}
3854
79cd5c96 3855std::pair<SproutNotePlaintext, SproutPaymentAddress> CWalletTx::DecryptSproutNote(
3856 JSOutPoint jsop) const
3857{
3858 LOCK(pwallet->cs_wallet);
3859
3860 auto nd = this->mapSproutNoteData.at(jsop);
3861 SproutPaymentAddress pa = nd.address;
3862
3863 // Get cached decryptor
3864 ZCNoteDecryption decryptor;
3865 if (!pwallet->GetNoteDecryptor(pa, decryptor)) {
3866 // Note decryptors are created when the wallet is loaded, so it should always exist
3867 throw std::runtime_error(strprintf(
3868 "Could not find note decryptor for payment address %s",
3869 EncodePaymentAddress(pa)));
3870 }
3871
3872 auto hSig = this->vJoinSplit[jsop.js].h_sig(*pzcashParams, this->joinSplitPubKey);
3873 try {
3874 SproutNotePlaintext plaintext = SproutNotePlaintext::decrypt(
3875 decryptor,
3876 this->vJoinSplit[jsop.js].ciphertexts[jsop.n],
3877 this->vJoinSplit[jsop.js].ephemeralKey,
3878 hSig,
3879 (unsigned char) jsop.n);
3880
3881 return std::make_pair(plaintext, pa);
3882 } catch (const note_decryption_failed &err) {
3883 // Couldn't decrypt with this spending key
3884 throw std::runtime_error(strprintf(
3885 "Could not decrypt note for payment address %s",
3886 EncodePaymentAddress(pa)));
3887 } catch (const std::exception &exc) {
3888 // Unexpected failure
3889 throw std::runtime_error(strprintf(
3890 "Error while decrypting note for payment address %s: %s",
3891 EncodePaymentAddress(pa), exc.what()));
3892 }
3893}
3894
3895boost::optional<std::pair<
3896 SaplingNotePlaintext,
3897 SaplingPaymentAddress>> CWalletTx::DecryptSaplingNote(SaplingOutPoint op) const
3898{
3899 // Check whether we can decrypt this SaplingOutPoint
3900 if (this->mapSaplingNoteData.count(op) == 0) {
3901 return boost::none;
3902 }
3903
3904 auto output = this->vShieldedOutput[op.n];
3905 auto nd = this->mapSaplingNoteData.at(op);
3906
3907 auto maybe_pt = SaplingNotePlaintext::decrypt(
3908 output.encCiphertext,
3909 nd.ivk,
3910 output.ephemeralKey,
3911 output.cm);
3912 assert(static_cast<bool>(maybe_pt));
3913 auto notePt = maybe_pt.get();
3914
3915 auto maybe_pa = nd.ivk.address(notePt.d);
3916 assert(static_cast<bool>(maybe_pa));
3917 auto pa = maybe_pa.get();
3918
3919 return std::make_pair(notePt, pa);
3920}
3921
3922boost::optional<std::pair<
3923 SaplingNotePlaintext,
3924 SaplingPaymentAddress>> CWalletTx::RecoverSaplingNote(
3925 SaplingOutPoint op, std::set<uint256>& ovks) const
3926{
3927 auto output = this->vShieldedOutput[op.n];
3928
3929 for (auto ovk : ovks) {
3930 auto outPt = SaplingOutgoingPlaintext::decrypt(
3931 output.outCiphertext,
3932 ovk,
3933 output.cv,
3934 output.cm,
3935 output.ephemeralKey);
3936 if (!outPt) {
3937 continue;
3938 }
3939
3940 auto maybe_pt = SaplingNotePlaintext::decrypt(
3941 output.encCiphertext,
3942 output.ephemeralKey,
3943 outPt->esk,
3944 outPt->pk_d,
3945 output.cm);
3946 assert(static_cast<bool>(maybe_pt));
3947 auto notePt = maybe_pt.get();
3948
3949 return std::make_pair(notePt, SaplingPaymentAddress(notePt.d, outPt->pk_d));
3950 }
3951
3952 // Couldn't recover with any of the provided OutgoingViewingKeys
3953 return boost::none;
3954}
3955
51ed9ec9 3956int64_t CWalletTx::GetTxTime() const
e8ef3da7 3957{
51ed9ec9 3958 int64_t n = nTimeSmart;
c3f95ef1 3959 return n ? n : nTimeReceived;
e8ef3da7
WL
3960}
3961
3962int CWalletTx::GetRequestCount() const
3963{
3964 // Returns -1 if it wasn't being tracked
3965 int nRequests = -1;
e8ef3da7 3966 {
f8dcd5ca 3967 LOCK(pwallet->cs_wallet);
e8ef3da7
WL
3968 if (IsCoinBase())
3969 {
3970 // Generated block
4f152496 3971 if (!hashBlock.IsNull())
e8ef3da7
WL
3972 {
3973 map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
3974 if (mi != pwallet->mapRequestCount.end())
3975 nRequests = (*mi).second;
3976 }
3977 }
3978 else
3979 {
3980 // Did anyone request this transaction?
805344dc 3981 map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash());
e8ef3da7
WL
3982 if (mi != pwallet->mapRequestCount.end())
3983 {
3984 nRequests = (*mi).second;
3985
3986 // How about the block it's in?
4f152496 3987 if (nRequests == 0 && !hashBlock.IsNull())
e8ef3da7
WL
3988 {
3989 map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
3990 if (mi != pwallet->mapRequestCount.end())
3991 nRequests = (*mi).second;
3992 else
3993 nRequests = 1; // If it's in someone else's block it must have got out
3994 }
3995 }
3996 }
3997 }
3998 return nRequests;
3999}
4000
86cf60b5 4001// GetAmounts will determine the transparent debits and credits for a given wallet tx.
1b4568cb 4002void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
a372168e 4003 list<COutputEntry>& listSent, CAmount& nFee, string& strSentAccount, const isminefilter& filter) const
e8ef3da7 4004{
e07c8e91 4005 nFee = 0;
e8ef3da7
WL
4006 listReceived.clear();
4007 listSent.clear();
4008 strSentAccount = strFromAccount;
4009
86cf60b5 4010 // Is this tx sent/signed by me?
a372168e 4011 CAmount nDebit = GetDebit(filter);
44ac8ad4 4012
4013 bool isFromMyTaddr = false;
4014
4015 for (auto &txin : vin)
4016 {
4017 map<uint256, CWalletTx>::const_iterator mi = pwallet->mapWallet.find(txin.prevout.hash);
4018 if (mi != pwallet->mapWallet.end())
4019 {
4020 const CWalletTx& prev = (*mi).second;
4021 if (txin.prevout.n < prev.vout.size())
4022 {
4023 if (::IsMine(*pwallet, prev.vout[txin.prevout.n].scriptPubKey) & filter)
4024 {
4025 isFromMyTaddr = true;
4026 break;
4027 }
4028 }
4029 }
4030 }
4031
4032 //bool isFromMyTaddr = pwallet->IsFromMe(*this); // IsFromMe(filter); // debit>0 means we signed/sent this transaction
86cf60b5 4033
86cf60b5
S
4034 // Compute fee if we sent this transaction.
4035 if (isFromMyTaddr) {
f6863889
S
4036 CAmount nValueOut = GetValueOut(); // transparent outputs plus all Sprout vpub_old and negative Sapling valueBalance
4037 CAmount nValueIn = GetShieldedValueIn();
86cf60b5
S
4038 nFee = nDebit - nValueOut + nValueIn;
4039 }
4040
4041 // Create output entry for vpub_old/new, if we sent utxos from this transaction
4042 if (isFromMyTaddr) {
4043 CAmount myVpubOld = 0;
4044 CAmount myVpubNew = 0;
f57f76d7 4045 for (const JSDescription& js : vJoinSplit) {
86cf60b5
S
4046 bool fMyJSDesc = false;
4047
4048 // Check input side
4049 for (const uint256& nullifier : js.nullifiers) {
037cacf2 4050 if (pwallet->IsSproutNullifierFromMe(nullifier)) {
86cf60b5
S
4051 fMyJSDesc = true;
4052 break;
4053 }
4054 }
4055
4056 // Check output side
4057 if (!fMyJSDesc) {
005f3ad1 4058 for (const std::pair<JSOutPoint, SproutNoteData> nd : this->mapSproutNoteData) {
f57f76d7 4059 if (nd.first.js < vJoinSplit.size() && nd.first.n < vJoinSplit[nd.first.js].ciphertexts.size()) {
86cf60b5
S
4060 fMyJSDesc = true;
4061 break;
4062 }
4063 }
4064 }
4065
4066 if (fMyJSDesc) {
4067 myVpubOld += js.vpub_old;
4068 myVpubNew += js.vpub_new;
4069 }
4070
4071 if (!MoneyRange(js.vpub_old) || !MoneyRange(js.vpub_new) || !MoneyRange(myVpubOld) || !MoneyRange(myVpubNew)) {
4072 throw std::runtime_error("CWalletTx::GetAmounts: value out of range");
4073 }
4074 }
4075
4076 // Create an output for the value taken from or added to the transparent value pool by JoinSplits
4077 if (myVpubOld > myVpubNew) {
4078 COutputEntry output = {CNoDestination(), myVpubOld - myVpubNew, (int)vout.size()};
4079 listSent.push_back(output);
4080 } else if (myVpubNew > myVpubOld) {
4081 COutputEntry output = {CNoDestination(), myVpubNew - myVpubOld, (int)vout.size()};
4082 listReceived.push_back(output);
4083 }
e8ef3da7
WL
4084 }
4085
f9816408
S
4086 // If we sent utxos from this transaction, create output for value taken from (negative valueBalance)
4087 // or added (positive valueBalance) to the transparent value pool by Sapling shielding and unshielding.
4088 if (isFromMyTaddr) {
4089 if (valueBalance < 0) {
4090 COutputEntry output = {CNoDestination(), -valueBalance, (int) vout.size()};
4091 listSent.push_back(output);
4092 } else if (valueBalance > 0) {
4093 COutputEntry output = {CNoDestination(), valueBalance, (int) vout.size()};
4094 listReceived.push_back(output);
4095 }
4096 }
4097
e679ec96 4098 // Sent/received.
5bb76550 4099 for (unsigned int i = 0; i < vout.size(); ++i)
e8ef3da7 4100 {
1b4568cb 4101 const CTxOut& txout = vout[i];
a5c6c5d6 4102 isminetype fIsMine = pwallet->IsMine(txout);
96ed6821
LD
4103 // Only need to handle txouts if AT LEAST one of these is true:
4104 // 1) they debit from us (sent)
4105 // 2) the output is to us (received)
4106 if (nDebit > 0)
4107 {
4108 // Don't report 'change' txouts
73b4d696 4109 if (!(filter & ISMINE_CHANGE) && pwallet->IsChange(txout))
96ed6821 4110 continue;
96ed6821 4111 }
a5c6c5d6 4112 else if (!(fIsMine & filter))
96ed6821
LD
4113 continue;
4114
4115 // In either case, we need to get the destination address
10254401 4116 CTxDestination address;
10254401 4117 if (!ExtractDestination(txout.scriptPubKey, address))
e8ef3da7 4118 {
7d306d64 4119 //LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",this->GetHash().ToString()); complains on the opreturns
96ed6821 4120 address = CNoDestination();
e8ef3da7
WL
4121 }
4122
5bb76550 4123 COutputEntry output = {address, txout.nValue, (int)i};
1b4568cb 4124
96ed6821 4125 // If we are debited by the transaction, add the output as a "sent" entry
e8ef3da7 4126 if (nDebit > 0)
1b4568cb 4127 listSent.push_back(output);
e8ef3da7 4128
96ed6821 4129 // If we are receiving the output, add it as a "received" entry
d512534c 4130 if (fIsMine & filter)
1b4568cb 4131 listReceived.push_back(output);
e8ef3da7 4132 }
e8ef3da7
WL
4133}
4134
a372168e
MF
4135void CWalletTx::GetAccountAmounts(const string& strAccount, CAmount& nReceived,
4136 CAmount& nSent, CAmount& nFee, const isminefilter& filter) const
e8ef3da7 4137{
e07c8e91 4138 nReceived = nSent = nFee = 0;
e8ef3da7 4139
a372168e 4140 CAmount allFee;
e8ef3da7 4141 string strSentAccount;
1b4568cb
CL
4142 list<COutputEntry> listReceived;
4143 list<COutputEntry> listSent;
d4640d7d 4144 GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
e8ef3da7 4145
e8ef3da7
WL
4146 if (strAccount == strSentAccount)
4147 {
1b4568cb
CL
4148 BOOST_FOREACH(const COutputEntry& s, listSent)
4149 nSent += s.amount;
e8ef3da7
WL
4150 nFee = allFee;
4151 }
e8ef3da7 4152 {
f8dcd5ca 4153 LOCK(pwallet->cs_wallet);
1b4568cb 4154 BOOST_FOREACH(const COutputEntry& r, listReceived)
e8ef3da7 4155 {
1b4568cb 4156 if (pwallet->mapAddressBook.count(r.destination))
e8ef3da7 4157 {
1b4568cb 4158 map<CTxDestination, CAddressBookData>::const_iterator mi = pwallet->mapAddressBook.find(r.destination);
61885513 4159 if (mi != pwallet->mapAddressBook.end() && (*mi).second.name == strAccount)
1b4568cb 4160 nReceived += r.amount;
e8ef3da7
WL
4161 }
4162 else if (strAccount.empty())
4163 {
1b4568cb 4164 nReceived += r.amount;
e8ef3da7
WL
4165 }
4166 }
4167 }
4168}
4169
722fa283 4170
44bc988e 4171bool CWalletTx::WriteToDisk(CWalletDB *pwalletdb)
e8ef3da7 4172{
805344dc 4173 return pwalletdb->WriteTx(GetHash(), *this);
e8ef3da7
WL
4174}
4175
4bc00dc1 4176void CWallet::WitnessNoteCommitment(std::vector<uint256> commitments,
8ea8ef98 4177 std::vector<boost::optional<SproutWitness>>& witnesses,
4bc00dc1 4178 uint256 &final_anchor)
a8ac403d 4179{
2dc35992 4180 witnesses.resize(commitments.size());
a8ac403d 4181 CBlockIndex* pindex = chainActive.Genesis();
4fc309f0 4182 SproutMerkleTree tree;
a8ac403d
SB
4183
4184 while (pindex) {
4185 CBlock block;
88d014d0 4186 ReadBlockFromDisk(block, pindex, Params().GetConsensus(), 1);
a8ac403d
SB
4187
4188 BOOST_FOREACH(const CTransaction& tx, block.vtx)
4189 {
f57f76d7 4190 BOOST_FOREACH(const JSDescription& jsdesc, tx.vJoinSplit)
a8ac403d 4191 {
22de1602 4192 BOOST_FOREACH(const uint256 &note_commitment, jsdesc.commitments)
a8ac403d 4193 {
4bc00dc1 4194 tree.append(note_commitment);
1760b3cd 4195
8ea8ef98 4196 BOOST_FOREACH(boost::optional<SproutWitness>& wit, witnesses) {
2dc35992 4197 if (wit) {
4bc00dc1 4198 wit->append(note_commitment);
2dc35992
SB
4199 }
4200 }
4201
4202 size_t i = 0;
4203 BOOST_FOREACH(uint256& commitment, commitments) {
4bc00dc1 4204 if (note_commitment == commitment) {
2dc35992 4205 witnesses.at(i) = tree.witness();
1760b3cd 4206 }
2dc35992 4207 i++;
a8ac403d
SB
4208 }
4209 }
4210 }
4211 }
4212
ccb439c5 4213 uint256 current_anchor = tree.root();
a8ac403d
SB
4214
4215 // Consistency check: we should be able to find the current tree
4216 // in our CCoins view.
4fc309f0 4217 SproutMerkleTree dummy_tree;
008f4ee8 4218 assert(pcoinsTip->GetSproutAnchorAt(current_anchor, dummy_tree));
a8ac403d
SB
4219
4220 pindex = chainActive.Next(pindex);
4221 }
4222
ccb439c5
SB
4223 // TODO: #93; Select a root via some heuristic.
4224 final_anchor = tree.root();
a8ac403d 4225
8ea8ef98 4226 BOOST_FOREACH(boost::optional<SproutWitness>& wit, witnesses) {
2dc35992
SB
4227 if (wit) {
4228 assert(final_anchor == wit->root());
4229 }
1760b3cd 4230 }
a8ac403d
SB
4231}
4232
5b40d886
MF
4233/**
4234 * Scan the block chain (starting in pindexStart) for transactions
4235 * from or to us. If fUpdate is true, found transactions that already
4236 * exist in the wallet will be updated.
4237 */
e8ef3da7
WL
4238int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
4239{
4240 int ret = 0;
75b8953a 4241 int64_t nNow = GetTime();
11982d36 4242 const CChainParams& chainParams = Params();
e8ef3da7
WL
4243
4244 CBlockIndex* pindex = pindexStart;
cd10562c
S
4245
4246 std::vector<uint256> myTxHashes;
4247
e8ef3da7 4248 {
55a1db4f 4249 LOCK2(cs_main, cs_wallet);
39278369
CL
4250
4251 // no need to read and scan block, if block was created before
4252 // our wallet birthday (as adjusted for block time variability)
209377a7 4253 while (pindex && nTimeFirstKey && (pindex->GetBlockTime() < (nTimeFirstKey - 7200)))
39278369
CL
4254 pindex = chainActive.Next(pindex);
4255
4256 ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
11982d36 4257 double dProgressStart = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex, false);
86131275 4258 double dProgressTip = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.LastTip(), false);
e8ef3da7
WL
4259 while (pindex)
4260 {
4b729ec5 4261 if (pindex->GetHeight() % 100 == 0 && dProgressTip - dProgressStart > 0.0)
11982d36 4262 ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex, false) - dProgressStart) / (dProgressTip - dProgressStart) * 100))));
8da9dd07 4263
e8ef3da7 4264 CBlock block;
71cf6ba9 4265 ReadBlockFromDisk(block, pindex, Params().GetConsensus());
e8ef3da7
WL
4266 BOOST_FOREACH(CTransaction& tx, block.vtx)
4267 {
cd10562c
S
4268 if (AddToWalletIfInvolvingMe(tx, &block, fUpdate)) {
4269 myTxHashes.push_back(tx.GetHash());
e8ef3da7 4270 ret++;
cd10562c 4271 }
e8ef3da7 4272 }
b6961fc1 4273
4fc309f0
EOW
4274 SproutMerkleTree sproutTree;
4275 SaplingMerkleTree saplingTree;
b6961fc1
JG
4276 // This should never fail: we should always be able to get the tree
4277 // state on the path to the tip of our chain
f86ee1c2
EOW
4278 assert(pcoinsTip->GetSproutAnchorAt(pindex->hashSproutAnchor, sproutTree));
4279 if (pindex->pprev) {
88d014d0 4280 if (Params().GetConsensus().NetworkUpgradeActive(pindex->pprev->GetHeight(), Consensus::UPGRADE_SAPLING)) {
d9fe33b8
S
4281 assert(pcoinsTip->GetSaplingAnchorAt(pindex->pprev->hashFinalSaplingRoot, saplingTree));
4282 }
f86ee1c2 4283 }
b6961fc1 4284 // Increment note witness caches
162bfc3a 4285 ChainTipAdded(pindex, &block, sproutTree, saplingTree);
b6961fc1 4286
4c6d41b8 4287 pindex = chainActive.Next(pindex);
75b8953a
B
4288 if (GetTime() >= nNow + 60) {
4289 nNow = GetTime();
4b729ec5 4290 LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->GetHeight(), Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex));
75b8953a 4291 }
e8ef3da7 4292 }
cd10562c
S
4293
4294 // After rescanning, persist Sapling note data that might have changed, e.g. nullifiers.
4295 // Do not flush the wallet here for performance reasons.
4296 CWalletDB walletdb(strWalletFile, "r+", false);
4297 for (auto hash : myTxHashes) {
4298 CWalletTx wtx = mapWallet[hash];
4299 if (!wtx.mapSaplingNoteData.empty()) {
4300 if (!wtx.WriteToDisk(&walletdb)) {
4301 LogPrintf("Rescanning... WriteToDisk failed to update Sapling note data for: %s\n", hash.ToString());
4302 }
4303 }
4304 }
4305
39278369 4306 ShowProgress(_("Rescanning..."), 100); // hide progress dialog in GUI
e8ef3da7
WL
4307 }
4308 return ret;
4309}
4310
4311void CWallet::ReacceptWalletTransactions()
4312{
7e6d23b1 4313 // If transactions aren't being broadcasted, don't let them into local mempool either
6f252627
WL
4314 if (!fBroadcastTransactions)
4315 return;
55a1db4f 4316 LOCK2(cs_main, cs_wallet);
e9c3215b 4317 std::map<int64_t, CWalletTx*> mapSorted;
4318
4319 // Sort pending wallet transactions based on their initial wallet insertion order
93a18a36 4320 BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
e8ef3da7 4321 {
93a18a36
GA
4322 const uint256& wtxid = item.first;
4323 CWalletTx& wtx = item.second;
805344dc 4324 assert(wtx.GetHash() == wtxid);
e8ef3da7 4325
93a18a36
GA
4326 int nDepth = wtx.GetDepthInMainChain();
4327
e9c3215b 4328 if (!wtx.IsCoinBase() && nDepth < 0) {
4329 mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx));
e8ef3da7
WL
4330 }
4331 }
e9c3215b 4332
43260416 4333 std::vector<uint256> vwtxh;
4334
e9c3215b 4335 // Try to add wallet transactions to memory pool
4336 BOOST_FOREACH(PAIRTYPE(const int64_t, CWalletTx*)& item, mapSorted)
4337 {
4338 CWalletTx& wtx = *(item.second);
4339
4340 LOCK(mempool.cs);
271326fa 4341 CValidationState state;
4342 // attempt to add them, but don't set any DOS level
085c3640 4343 if (!::AcceptToMemoryPool(mempool, state, wtx, false, NULL, true, 0))
4344 {
4345 int nDoS;
4346 bool invalid = state.IsInvalid(nDoS);
4347
4348 // log rejection and deletion
4349 // printf("ERROR reaccepting wallet transaction %s to mempool, reason: %s, DoS: %d\n", wtx.GetHash().ToString().c_str(), state.GetRejectReason().c_str(), nDoS);
4350
4351 if (!wtx.IsCoinBase() && invalid && nDoS > 0)
4352 {
d738023b 4353 LogPrintf("erasing transaction %s\n", wtx.GetHash().GetHex().c_str());
43260416 4354 vwtxh.push_back(wtx.GetHash());
085c3640 4355 }
4356 }
e9c3215b 4357 }
43260416 4358 for (auto hash : vwtxh)
4359 {
4360 EraseFromWallet(hash);
4361 }
e8ef3da7
WL
4362}
4363
0f5954c4 4364bool CWalletTx::RelayWalletTransaction()
e8ef3da7 4365{
7000ef1a 4366 if ( pwallet == 0 )
4367 {
4368 fprintf(stderr,"unexpected null pwallet in RelayWalletTransaction\n");
4369 return(false);
4370 }
6f252627 4371 assert(pwallet->GetBroadcastTransactions());
e8ef3da7
WL
4372 if (!IsCoinBase())
4373 {
bd070d8b 4374 if (GetDepthInMainChain() == 0)
4375 {
4376 // if tx is expired, dont relay
805344dc 4377 LogPrintf("Relaying wtx %s\n", GetHash().ToString());
d38da59b 4378 RelayTransaction((CTransaction)*this);
0f5954c4 4379 return true;
e8ef3da7
WL
4380 }
4381 }
0f5954c4 4382 return false;
e8ef3da7
WL
4383}
4384
3015e0bc 4385set<uint256> CWalletTx::GetConflicts() const
731b89b8
GA
4386{
4387 set<uint256> result;
4388 if (pwallet != NULL)
4389 {
805344dc 4390 uint256 myHash = GetHash();
3015e0bc 4391 result = pwallet->GetConflicts(myHash);
731b89b8
GA
4392 result.erase(myHash);
4393 }
4394 return result;
4395}
4396
bbacd882
CF
4397CAmount CWalletTx::GetDebit(const isminefilter& filter) const
4398{
4399 if (vin.empty())
4400 return 0;
4401
4402 CAmount debit = 0;
4403 if(filter & ISMINE_SPENDABLE)
4404 {
4405 if (fDebitCached)
4406 debit += nDebitCached;
4407 else
4408 {
efecad16 4409 int depth = this->GetDepthInMainChain();
4410 uint32_t height = chainActive.Height() - --depth;
4411 nDebitCached = pwallet->GetDebit(*this, ISMINE_SPENDABLE, height);
bbacd882
CF
4412 fDebitCached = true;
4413 debit += nDebitCached;
4414 }
4415 }
4416 if(filter & ISMINE_WATCH_ONLY)
4417 {
4418 if(fWatchDebitCached)
4419 debit += nWatchDebitCached;
4420 else
4421 {
efecad16 4422 int depth = this->GetDepthInMainChain();
4423 uint32_t height = chainActive.Height() - --depth;
4424 nWatchDebitCached = pwallet->GetDebit(*this, ISMINE_WATCH_ONLY, height);
bbacd882
CF
4425 fWatchDebitCached = true;
4426 debit += nWatchDebitCached;
4427 }
4428 }
4429 return debit;
4430}
4431
56fe75cb 4432CCurrencyValueMap CWalletTx::GetReserveDebit(const isminefilter& filter) const
3a27113e 4433{
4434 if (vin.empty())
56fe75cb 4435 return CCurrencyValueMap();
3a27113e 4436
efecad16 4437 int depth = this->GetDepthInMainChain();
4438 uint32_t height = chainActive.Height() - --depth;
4439
4440 return pwallet->GetReserveDebit(*this, filter, height);
3a27113e 4441}
4442
bbacd882
CF
4443CAmount CWalletTx::GetCredit(const isminefilter& filter) const
4444{
4445 // Must wait until coinbase is safely deep enough in the chain before valuing it
4446 if (IsCoinBase() && GetBlocksToMaturity() > 0)
4447 return 0;
4448
4449 int64_t credit = 0;
4450 if (filter & ISMINE_SPENDABLE)
4451 {
4452 // GetBalance can assume transactions in mapWallet won't change
4453 if (fCreditCached)
4454 credit += nCreditCached;
4455 else
4456 {
efecad16 4457 int depth = this->GetDepthInMainChain();
4458 uint32_t height = chainActive.Height() - --depth;
4459
4460 nCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE, height);
bbacd882
CF
4461 fCreditCached = true;
4462 credit += nCreditCached;
4463 }
4464 }
4465 if (filter & ISMINE_WATCH_ONLY)
4466 {
4467 if (fWatchCreditCached)
4468 credit += nWatchCreditCached;
4469 else
4470 {
efecad16 4471 int depth = this->GetDepthInMainChain();
4472 uint32_t height = chainActive.Height() - --depth;
4473
4474 nWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY, height);
bbacd882
CF
4475 fWatchCreditCached = true;
4476 credit += nWatchCreditCached;
4477 }
4478 }
4479 return credit;
4480}
4481
a78c55ad 4482bool CWalletTx::HasMatureCoins() const
4483{
4484 // Must wait until coinbase is safely deep enough in the chain before valuing it
4485 if (!(IsCoinBase() && GetBlocksToMaturity() > 0))
4486 {
4487 return true;
4488 }
4489 else
4490 {
4491 for (auto oneout : vout)
4492 {
4493 if (oneout.scriptPubKey.IsInstantSpend())
4494 {
4495 return true;
4496 }
4497 }
4498 return false;
4499 }
4500}
4501
56fe75cb 4502CCurrencyValueMap CWalletTx::GetReserveCredit(const isminefilter& filter) const
3a27113e 4503{
4504 // Must wait until coinbase is safely deep enough in the chain before valuing it
4505 if (IsCoinBase() && GetBlocksToMaturity() > 0)
56fe75cb 4506 return CCurrencyValueMap();
3a27113e 4507
56fe75cb 4508 return pwallet->GetReserveCredit(*this, filter);
3a27113e 4509}
4510
bbacd882
CF
4511CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const
4512{
4513 if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
4514 {
4515 if (fUseCache && fImmatureCreditCached)
4516 return nImmatureCreditCached;
4517 nImmatureCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE);
4518 fImmatureCreditCached = true;
4519 return nImmatureCreditCached;
4520 }
4521
4522 return 0;
4523}
4524
56fe75cb 4525CCurrencyValueMap CWalletTx::GetImmatureReserveCredit(bool fUseCache) const
3a27113e 4526{
4527 if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
4528 {
56fe75cb 4529 pwallet->GetReserveCredit(*this, ISMINE_SPENDABLE);
3a27113e 4530 }
4531
56fe75cb 4532 return CCurrencyValueMap();
3a27113e 4533}
4534
bbacd882
CF
4535CAmount CWalletTx::GetAvailableCredit(bool fUseCache) const
4536{
4537 if (pwallet == 0)
4538 return 0;
4539
4540 // Must wait until coinbase is safely deep enough in the chain before valuing it
4541 if (IsCoinBase() && GetBlocksToMaturity() > 0)
4542 return 0;
4543
4544 if (fUseCache && fAvailableCreditCached)
4545 return nAvailableCreditCached;
4546
4547 CAmount nCredit = 0;
805344dc 4548 uint256 hashTx = GetHash();
bbacd882
CF
4549 for (unsigned int i = 0; i < vout.size(); i++)
4550 {
a88b514e 4551 if (!pwallet->IsSpent(hashTx, i) && vout[i].scriptPubKey.IsSpendableOutputType())
bbacd882 4552 {
fab1429d 4553 nCredit += pwallet->GetCredit(*this, i, ISMINE_SPENDABLE);
bbacd882
CF
4554 }
4555 }
4556
4557 nAvailableCreditCached = nCredit;
4558 fAvailableCreditCached = true;
4559 return nCredit;
4560}
4561
56fe75cb 4562CCurrencyValueMap CWalletTx::GetAvailableReserveCredit(bool fUseCache) const
3a27113e 4563{
56fe75cb 4564 CCurrencyValueMap retVal;
3a27113e 4565 if (pwallet == 0)
56fe75cb 4566 return retVal;
3a27113e 4567
4568 // Must wait until coinbase is safely deep enough in the chain before valuing it
4569 if (IsCoinBase() && GetBlocksToMaturity() > 0)
56fe75cb 4570 return retVal;
3a27113e 4571
3a27113e 4572 uint256 hashTx = GetHash();
4573 for (unsigned int i = 0; i < vout.size(); i++)
4574 {
a88b514e 4575 if (!pwallet->IsSpent(hashTx, i) && vout[i].scriptPubKey.IsSpendableOutputType())
3a27113e 4576 {
56fe75cb 4577 retVal += pwallet->GetReserveCredit(*this, i, ISMINE_SPENDABLE);
3a27113e 4578 }
4579 }
56fe75cb 4580 return retVal;
3a27113e 4581}
4582
bbacd882
CF
4583CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool& fUseCache) const
4584{
4585 if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
4586 {
4587 if (fUseCache && fImmatureWatchCreditCached)
4588 return nImmatureWatchCreditCached;
4589 nImmatureWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY);
4590 fImmatureWatchCreditCached = true;
4591 return nImmatureWatchCreditCached;
4592 }
4593
4594 return 0;
4595}
4596
56fe75cb 4597CCurrencyValueMap CWalletTx::GetImmatureWatchOnlyReserveCredit(const bool& fUseCache) const
3a27113e 4598{
4599 if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
4600 {
56fe75cb 4601 return pwallet->GetReserveCredit(*this, ISMINE_WATCH_ONLY);
3a27113e 4602 }
4603
56fe75cb 4604 return CCurrencyValueMap();
3a27113e 4605}
4606
bbacd882
CF
4607CAmount CWalletTx::GetAvailableWatchOnlyCredit(const bool& fUseCache) const
4608{
4609 if (pwallet == 0)
4610 return 0;
4611
4612 // Must wait until coinbase is safely deep enough in the chain before valuing it
4613 if (IsCoinBase() && GetBlocksToMaturity() > 0)
4614 return 0;
4615
4616 if (fUseCache && fAvailableWatchCreditCached)
4617 return nAvailableWatchCreditCached;
4618
4619 CAmount nCredit = 0;
4620 for (unsigned int i = 0; i < vout.size(); i++)
4621 {
805344dc 4622 if (!pwallet->IsSpent(GetHash(), i))
bbacd882 4623 {
fab1429d 4624 nCredit += pwallet->GetCredit(*this, i, ISMINE_WATCH_ONLY);
bbacd882
CF
4625 if (!MoneyRange(nCredit))
4626 throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
4627 }
4628 }
4629
4630 nAvailableWatchCreditCached = nCredit;
4631 fAvailableWatchCreditCached = true;
4632 return nCredit;
4633}
4634
56fe75cb 4635CCurrencyValueMap CWalletTx::GetAvailableWatchOnlyReserveCredit(const bool& fUseCache) const
3a27113e 4636{
56fe75cb 4637 CCurrencyValueMap retVal;
3a27113e 4638 if (pwallet == 0)
56fe75cb 4639 return retVal;
3a27113e 4640
4641 // Must wait until coinbase is safely deep enough in the chain before valuing it
4642 if (IsCoinBase() && GetBlocksToMaturity() > 0)
56fe75cb 4643 return retVal;
3a27113e 4644
3a27113e 4645 for (unsigned int i = 0; i < vout.size(); i++)
4646 {
4647 if (!pwallet->IsSpent(GetHash(), i))
4648 {
56fe75cb 4649 retVal += pwallet->GetReserveCredit(*this, i, ISMINE_WATCH_ONLY);
3a27113e 4650 }
4651 }
4652
56fe75cb 4653 return retVal;
3a27113e 4654}
4655
bbacd882
CF
4656CAmount CWalletTx::GetChange() const
4657{
4658 if (fChangeCached)
4659 return nChangeCached;
4660 nChangeCached = pwallet->GetChange(*this);
4661 fChangeCached = true;
4662 return nChangeCached;
4663}
4664
4665bool CWalletTx::IsTrusted() const
4666{
4667 // Quick answer in most cases
75a4d512 4668 if (!CheckFinalTx(*this))
bbacd882
CF
4669 return false;
4670 int nDepth = GetDepthInMainChain();
4671 if (nDepth >= 1)
4672 return true;
4673 if (nDepth < 0)
4674 return false;
4675 if (!bSpendZeroConfChange || !IsFromMe(ISMINE_ALL)) // using wtx's cached debit
4676 return false;
4677
4678 // Trusted if all inputs are from us and are in the mempool:
4679 BOOST_FOREACH(const CTxIn& txin, vin)
4680 {
4681 // Transactions not sent by us: not trusted
4682 const CWalletTx* parent = pwallet->GetWalletTx(txin.prevout.hash);
4683 if (parent == NULL)
4684 return false;
bf412e62 4685 if (!parent->vout.size())
4686 {
420019f6 4687 LogPrintf("%s: No spendable output in wallet for input to %s, num %d\n", __func__, txin.prevout.hash.GetHex().c_str(), txin.prevout.n);
bf412e62 4688 return false;
4689 }
bbacd882
CF
4690 const CTxOut& parentOut = parent->vout[txin.prevout.n];
4691 if (pwallet->IsMine(parentOut) != ISMINE_SPENDABLE)
4692 return false;
4693 }
4694 return true;
4695}
4696
0f5954c4
GA
4697std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
4698{
4699 std::vector<uint256> result;
4700
4701 LOCK(cs_wallet);
4702 // Sort them in chronological order
4703 multimap<unsigned int, CWalletTx*> mapSorted;
bd070d8b 4704 uint32_t now = (uint32_t)time(NULL);
47ab0926 4705 std::vector<uint256> vwtxh;
0f5954c4
GA
4706 BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
4707 {
4708 CWalletTx& wtx = item.second;
4709 // Don't rebroadcast if newer than nTime:
4710 if (wtx.nTimeReceived > nTime)
4711 continue;
3abeed2c 4712 if ( (wtx.nLockTime >= LOCKTIME_THRESHOLD && wtx.nLockTime < now-KOMODO_MAXMEMPOOLTIME) || wtx.hashBlock.IsNull() )
bd070d8b 4713 {
1aa576ad 4714 //LogPrintf("skip Relaying wtx %s nLockTime %u vs now.%u\n", wtx.GetHash().ToString(),(uint32_t)wtx.nLockTime,now);
d738023b 4715 //vwtxh.push_back(wtx.GetHash());
3abeed2c 4716 continue;
bd070d8b 4717 }
0f5954c4
GA
4718 mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
4719 }
4720 BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
4721 {
7000ef1a 4722 if ( item.second != 0 )
4723 {
3872e9cb 4724 CWalletTx &wtx = *item.second;
7000ef1a 4725 if (wtx.RelayWalletTransaction())
4726 result.push_back(wtx.GetHash());
4727 }
0f5954c4 4728 }
47ab0926 4729 for (auto hash : vwtxh)
4730 {
d738023b 4731 EraseFromWallets(hash);
47ab0926 4732 }
0f5954c4
GA
4733 return result;
4734}
4735
4736void CWallet::ResendWalletTransactions(int64_t nBestBlockTime)
e8ef3da7
WL
4737{
4738 // Do this infrequently and randomly to avoid giving away
4739 // that these are our transactions.
6f252627 4740 if (GetTime() < nNextResend || !fBroadcastTransactions)
e8ef3da7 4741 return;
203d1ae6
LD
4742 bool fFirst = (nNextResend == 0);
4743 nNextResend = GetTime() + GetRand(30 * 60);
e8ef3da7
WL
4744 if (fFirst)
4745 return;
4746
4747 // Only do it if there's been a new block since last time
0f5954c4 4748 if (nBestBlockTime < nLastResend)
e8ef3da7 4749 return;
203d1ae6 4750 nLastResend = GetTime();
e8ef3da7 4751
0f5954c4
GA
4752 // Rebroadcast unconfirmed txes older than 5 minutes before the last
4753 // block was found:
4754 std::vector<uint256> relayed = ResendWalletTransactionsBefore(nBestBlockTime-5*60);
4755 if (!relayed.empty())
4756 LogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, relayed.size());
e8ef3da7
WL
4757}
4758
5b40d886 4759/** @} */ // end of mapWallet
e8ef3da7
WL
4760
4761
4762
4763
5b40d886
MF
4764/** @defgroup Actions
4765 *
4766 * @{
4767 */
e8ef3da7
WL
4768
4769
a372168e 4770CAmount CWallet::GetBalance() const
e8ef3da7 4771{
a372168e 4772 CAmount nTotal = 0;
e8ef3da7 4773 {
55a1db4f 4774 LOCK2(cs_main, cs_wallet);
e8ef3da7
WL
4775 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4776 {
4777 const CWalletTx* pcoin = &(*it).second;
0542619d 4778 if (pcoin->IsTrusted())
8fdb7e10 4779 nTotal += pcoin->GetAvailableCredit();
e8ef3da7
WL
4780 }
4781 }
4782
e8ef3da7
WL
4783 return nTotal;
4784}
4785
56fe75cb 4786CCurrencyValueMap CWallet::GetReserveBalance() const
3a27113e 4787{
56fe75cb 4788 CCurrencyValueMap retVal;
3a27113e 4789 {
4790 LOCK2(cs_main, cs_wallet);
4791 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4792 {
4793 const CWalletTx* pcoin = &(*it).second;
4794 if (pcoin->IsTrusted())
56fe75cb 4795 retVal += pcoin->GetAvailableReserveCredit();
3a27113e 4796 }
4797 }
4798
56fe75cb 4799 return retVal;
3a27113e 4800}
4801
a372168e 4802CAmount CWallet::GetUnconfirmedBalance() const
df5ccbd2 4803{
a372168e 4804 CAmount nTotal = 0;
df5ccbd2 4805 {
55a1db4f 4806 LOCK2(cs_main, cs_wallet);
df5ccbd2
WL
4807 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4808 {
4809 const CWalletTx* pcoin = &(*it).second;
75a4d512 4810 if (!CheckFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
8fdb7e10 4811 nTotal += pcoin->GetAvailableCredit();
4812 }
4813 }
4814 return nTotal;
4815}
4816
56fe75cb 4817CCurrencyValueMap CWallet::GetUnconfirmedReserveBalance() const
3a27113e 4818{
56fe75cb 4819 CCurrencyValueMap retVal;
3a27113e 4820 {
4821 LOCK2(cs_main, cs_wallet);
4822 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4823 {
4824 const CWalletTx* pcoin = &(*it).second;
4825 if (!CheckFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
56fe75cb 4826 retVal += pcoin->GetAvailableReserveCredit();
3a27113e 4827 }
4828 }
56fe75cb 4829 return retVal;
3a27113e 4830}
4831
a372168e 4832CAmount CWallet::GetImmatureBalance() const
8fdb7e10 4833{
a372168e 4834 CAmount nTotal = 0;
8fdb7e10 4835 {
55a1db4f 4836 LOCK2(cs_main, cs_wallet);
8fdb7e10 4837 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4838 {
966a0e8c
PK
4839 const CWalletTx* pcoin = &(*it).second;
4840 nTotal += pcoin->GetImmatureCredit();
df5ccbd2
WL
4841 }
4842 }
4843 return nTotal;
4844}
e8ef3da7 4845
56fe75cb 4846CCurrencyValueMap CWallet::GetImmatureReserveBalance() const
3a27113e 4847{
56fe75cb 4848 CCurrencyValueMap retVal;
3a27113e 4849 {
4850 LOCK2(cs_main, cs_wallet);
4851 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4852 {
4853 const CWalletTx* pcoin = &(*it).second;
56fe75cb 4854 retVal += pcoin->GetImmatureReserveCredit();
3a27113e 4855 }
4856 }
56fe75cb 4857 return retVal;
3a27113e 4858}
4859
a372168e 4860CAmount CWallet::GetWatchOnlyBalance() const
ffd40da3 4861{
a372168e 4862 CAmount nTotal = 0;
ffd40da3 4863 {
39cc4922 4864 LOCK2(cs_main, cs_wallet);
ffd40da3
J
4865 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4866 {
4867 const CWalletTx* pcoin = &(*it).second;
4868 if (pcoin->IsTrusted())
4869 nTotal += pcoin->GetAvailableWatchOnlyCredit();
4870 }
4871 }
870da77d 4872
ffd40da3
J
4873 return nTotal;
4874}
4875
56fe75cb 4876CCurrencyValueMap CWallet::GetWatchOnlyReserveBalance() const
3a27113e 4877{
56fe75cb 4878 CCurrencyValueMap retVal;
3a27113e 4879 {
4880 LOCK2(cs_main, cs_wallet);
4881 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4882 {
4883 const CWalletTx* pcoin = &(*it).second;
4884 if (pcoin->IsTrusted())
56fe75cb 4885 retVal += pcoin->GetAvailableWatchOnlyReserveCredit();
3a27113e 4886 }
4887 }
4888
56fe75cb 4889 return retVal;
3a27113e 4890}
4891
a372168e 4892CAmount CWallet::GetUnconfirmedWatchOnlyBalance() const
ffd40da3 4893{
a372168e 4894 CAmount nTotal = 0;
ffd40da3 4895 {
39cc4922 4896 LOCK2(cs_main, cs_wallet);
ffd40da3
J
4897 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4898 {
4899 const CWalletTx* pcoin = &(*it).second;
75a4d512 4900 if (!CheckFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
ffd40da3
J
4901 nTotal += pcoin->GetAvailableWatchOnlyCredit();
4902 }
4903 }
4904 return nTotal;
4905}
4906
56fe75cb 4907CCurrencyValueMap CWallet::GetUnconfirmedWatchOnlyReserveBalance() const
3a27113e 4908{
56fe75cb 4909 CCurrencyValueMap retVal;
3a27113e 4910 {
4911 LOCK2(cs_main, cs_wallet);
4912 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4913 {
4914 const CWalletTx* pcoin = &(*it).second;
4915 if (!CheckFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
56fe75cb 4916 retVal += pcoin->GetAvailableWatchOnlyReserveCredit();
3a27113e 4917 }
4918 }
56fe75cb 4919 return retVal;
3a27113e 4920}
4921
a372168e 4922CAmount CWallet::GetImmatureWatchOnlyBalance() const
ffd40da3 4923{
a372168e 4924 CAmount nTotal = 0;
ffd40da3 4925 {
39cc4922 4926 LOCK2(cs_main, cs_wallet);
ffd40da3
J
4927 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4928 {
4929 const CWalletTx* pcoin = &(*it).second;
4930 nTotal += pcoin->GetImmatureWatchOnlyCredit();
4931 }
4932 }
4933 return nTotal;
4934}
4935
56fe75cb 4936CCurrencyValueMap CWallet::GetImmatureWatchOnlyReserveBalance() const
3a27113e 4937{
56fe75cb 4938 CCurrencyValueMap retVal;
3a27113e 4939 {
4940 LOCK2(cs_main, cs_wallet);
4941 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4942 {
4943 const CWalletTx* pcoin = &(*it).second;
56fe75cb 4944 retVal += pcoin->GetImmatureWatchOnlyReserveCredit();
3a27113e 4945 }
4946 }
56fe75cb 4947 return retVal;
3a27113e 4948}
4949
5b40d886
MF
4950/**
4951 * populate vCoins with vector of available COutputs.
4952 */
79383e0a 4953uint64_t komodo_interestnew(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
c60397dd 4954uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight);
0ad6a463 4955
20bcd9ba 4956void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeZeroValue, bool fIncludeCoinBase, bool fIncludeProtectedCoinbase, bool fIncludeImmatureCoins) const
9b0369c7 4957{
5c439232 4958 uint64_t interest,*ptr;
9b0369c7
CM
4959 vCoins.clear();
4960
4961 {
ea3acaf3 4962 LOCK2(cs_main, cs_wallet);
1e435b54 4963 uint32_t nHeight = chainActive.Height() + 1;
9b0369c7
CM
4964 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4965 {
93a18a36 4966 const uint256& wtxid = it->first;
9b0369c7
CM
4967 const CWalletTx* pcoin = &(*it).second;
4968
75a4d512 4969 if (!CheckFinalTx(*pcoin))
a2709fad
GA
4970 continue;
4971
0542619d 4972 if (fOnlyConfirmed && !pcoin->IsTrusted())
9b0369c7
CM
4973 continue;
4974
1e435b54 4975 bool isCoinbase = pcoin->IsCoinBase();
29c07a8f 4976 if (!fIncludeCoinBase && isCoinbase)
2b1cda3b 4977 continue;
1e435b54 4978
29c07a8f 4979 if (!fIncludeImmatureCoins && isCoinbase && pcoin->GetBlocksToMaturity() > 0)
9b0369c7
CM
4980 continue;
4981
2b72d46f
GA
4982 int nDepth = pcoin->GetDepthInMainChain();
4983 if (nDepth < 0)
4984 continue;
53dce971 4985
1e435b54 4986 uint32_t coinHeight = nHeight - nDepth;
4987 // even if we should include coinbases, we may opt to exclude protected coinbases, which must only be included when shielding
af521e42 4988 if (isCoinbase &&
4989 !fIncludeProtectedCoinbase &&
4990 Params().GetConsensus().fCoinbaseMustBeProtected &&
4991 CConstVerusSolutionVector::GetVersionByHeight(coinHeight) < CActivationHeight::SOLUTION_VERUSV4 &&
4992 CConstVerusSolutionVector::GetVersionByHeight(nHeight) < CActivationHeight::SOLUTION_VERUSV5)
1e435b54 4993 continue;
4994
fab1429d 4995 for (int i = 0; i < pcoin->vout.size(); i++)
0ad6a463 4996 {
ea340a14 4997 isminetype mine = IsMine(pcoin->vout[i]);
a3e192a3 4998 if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO &&
219953ce 4999 !IsLockedCoin((*it).first, i) && (pcoin->vout[i].nValue > 0 || fIncludeZeroValue) &&
6a86c24d 5000 (!coinControl || !coinControl->HasSelected() || coinControl->IsSelected((*it).first, i)))
0ad6a463 5001 {
6ad13d7c 5002 if ( KOMODO_EXCHANGEWALLET == 0 )
0ad6a463 5003 {
6ad13d7c 5004 uint32_t locktime; int32_t txheight; CBlockIndex *tipindex;
4b729ec5 5005 if ( ASSETCHAINS_SYMBOL[0] == 0 && chainActive.LastTip() != 0 && chainActive.LastTip()->GetHeight() >= 60000 )
0ad6a463 5006 {
6ad13d7c 5007 if ( pcoin->vout[i].nValue >= 10*COIN )
9d92c93d 5008 {
86131275 5009 if ( (tipindex= chainActive.LastTip()) != 0 )
6ad13d7c 5010 {
4b729ec5 5011 komodo_accrued_interest(&txheight,&locktime,wtxid,i,0,pcoin->vout[i].nValue,(int32_t)tipindex->GetHeight());
79383e0a 5012 interest = komodo_interestnew(txheight,pcoin->vout[i].nValue,locktime,tipindex->nTime);
6ad13d7c 5013 } else interest = 0;
4b729ec5 5014 //interest = komodo_interestnew(chainActive.LastTip()->GetHeight()+1,pcoin->vout[i].nValue,pcoin->nLockTime,chainActive.LastTip()->nTime);
6ad13d7c 5015 if ( interest != 0 )
5016 {
5017 //printf("wallet nValueRet %.8f += interest %.8f ht.%d lock.%u/%u tip.%u\n",(double)pcoin->vout[i].nValue/COIN,(double)interest/COIN,txheight,locktime,pcoin->nLockTime,tipindex->nTime);
4b729ec5 5018 //fprintf(stderr,"wallet nValueRet %.8f += interest %.8f ht.%d lock.%u tip.%u\n",(double)pcoin->vout[i].nValue/COIN,(double)interest/COIN,chainActive.LastTip()->GetHeight()+1,pcoin->nLockTime,chainActive.LastTip()->nTime);
6ad13d7c 5019 //ptr = (uint64_t *)&pcoin->vout[i].nValue;
5020 //(*ptr) += interest;
5021 ptr = (uint64_t *)&pcoin->vout[i].interest;
5022 (*ptr) = interest;
5023 //pcoin->vout[i].nValue += interest;
5024 }
5025 else
5026 {
5027 ptr = (uint64_t *)&pcoin->vout[i].interest;
5028 (*ptr) = 0;
5029 }
e9e8044e 5030 }
258748f5 5031 else
5032 {
5033 ptr = (uint64_t *)&pcoin->vout[i].interest;
5034 (*ptr) = 0;
5035 }
0ad6a463 5036 }
258748f5 5037 else
5038 {
5039 ptr = (uint64_t *)&pcoin->vout[i].interest;
5040 (*ptr) = 0;
5041 }
5042 }
0ad6a463 5043 vCoins.push_back(COutput(pcoin, i, nDepth, (mine & ISMINE_SPENDABLE) != ISMINE_NO));
5044 }
fdbb537d 5045 }
9b0369c7
CM
5046 }
5047 }
5048}
5049
56fe75cb 5050void CWallet::AvailableReserveCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeCoinBase, bool fIncludeNative, const CTxDestination *pOnlyFromDest, const CCurrencyValueMap *pOnlyTheseCurrencies) const
989b1de1
MT
5051{
5052 vCoins.clear();
5053
5054 {
5055 LOCK2(cs_main, cs_wallet);
5056 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
5057 {
5058 const uint256& wtxid = it->first;
5059 const CWalletTx* pcoin = &(*it).second;
5060
5061 if (!CheckFinalTx(*pcoin))
5062 continue;
5063
5064 if (fOnlyConfirmed && !pcoin->IsTrusted())
5065 continue;
5066
5067 if (pcoin->IsCoinBase() && !fIncludeCoinBase)
5068 continue;
5069
5070 if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
5071 continue;
5072
5073 int nDepth = pcoin->GetDepthInMainChain();
5074 if (nDepth < 0)
5075 continue;
5076
5077 for (int i = 0; i < pcoin->vout.size(); i++)
5078 {
989b1de1 5079 isminetype mine = IsMine(pcoin->vout[i]);
2f416b17 5080 if (!(IsSpent(wtxid, i)) &&
5081 mine != ISMINE_NO &&
56fe75cb 5082 !IsLockedCoin((*it).first, i) &&
989b1de1
MT
5083 (!coinControl || !coinControl->HasSelected() || coinControl->IsSelected((*it).first, i)))
5084 {
5085 COptCCParams p;
15197dca 5086 CCurrencyValueMap rOut = pcoin->vout[i].scriptPubKey.ReserveOutValue(p, true);
a88b514e 5087
15197dca 5088 if (p.IsValid() && !pcoin->vout[i].scriptPubKey.IsSpendableOutputType(p))
5089 {
5090 continue;
5091 }
56fe75cb 5092 if (pOnlyFromDest)
989b1de1 5093 {
56fe75cb 5094 if (p.IsValid())
5095 {
5096 bool found = false;
5097 for (auto &oneDest : p.vKeys)
5098 {
5099 if (GetDestinationID(oneDest) == GetDestinationID(*pOnlyFromDest))
5100 {
5101 found = true;
5102 break;
5103 }
5104 }
5105 if (!found)
5106 {
5107 continue;
5108 }
5109 }
5110 else
5111 {
5112 // support P2PK or P2PKH
5113 CTxDestination dest;
5114 if (!ExtractDestination(pcoin->vout[i].scriptPubKey, dest) || GetDestinationID(dest) != GetDestinationID(*pOnlyFromDest))
5115 {
5116 continue;
5117 }
5118 }
5119 }
5120 // don't return zero valued outputs
15197dca 5121 if (rOut.CanonicalMap().valueMap.size() || pcoin->vout[i].nValue)
56fe75cb 5122 {
2f416b17 5123 if ((rOut.valueMap.size() && (!pOnlyTheseCurrencies || (pOnlyTheseCurrencies && pOnlyTheseCurrencies->Intersects(rOut)))) ||
5124 (fIncludeNative && pcoin->vout[i].nValue))
56fe75cb 5125 {
5126 vCoins.push_back(COutput(pcoin, i, nDepth, (mine & ISMINE_SPENDABLE) != ISMINE_NO));
5127 }
989b1de1
MT
5128 }
5129 }
5130 }
5131 }
5132 }
5133}
5134
eed98728 5135bool CWallet::GetAndValidateSaplingZAddress(const std::string &addressStr, libzcash::PaymentAddress &zaddress)
5136{
5137 std::string addrCopy = addressStr;
5138 std::vector<std::string> addressParts;
5139 boost::split(addressParts, addrCopy, boost::is_any_of(":"));
5140
5141 if (addressParts.size() == 2 && addressParts[1] == "private")
5142 {
5143 // look up to see if this is the private address of an ID. if not, or if the ID does not have a valid, Sapling address, it is invalid
5144 CTxDestination destination = DecodeDestination(addressParts[0]);
5145 if (destination.which() == COptCCParams::ADDRTYPE_ID)
5146 {
5147 AssertLockHeld(cs_main);
5148 CIdentity idSource = CIdentity::LookupIdentity(GetDestinationID(destination));
5149 if (idSource.IsValid() && idSource.privateAddresses.size() > 0)
5150 {
5151 zaddress = idSource.privateAddresses[0];
1f5cde4e 5152 return true;
eed98728 5153 }
eed98728 5154 }
1f5cde4e 5155 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid ID or ID that does not have valid z-address specified");
eed98728 5156 }
5157
5158 zaddress = DecodePaymentAddress(addrCopy);
5159 bool hasZSource = boost::get<libzcash::SaplingPaymentAddress>(&zaddress) != nullptr;
5160 if (!hasZSource && boost::get<libzcash::SproutPaymentAddress>(&zaddress) != nullptr)
5161 {
1f5cde4e 5162 throw JSONRPCError(RPC_INVALID_PARAMETER, "Legacy Sprout address not supported. Use a transparent or Sapling compatible address");
eed98728 5163 }
5164 return hasZSource;
5165}
5166
0ad6a463 5167static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,unsigned int> > >vValue, const CAmount& nTotalLower, const CAmount& nTargetValue,vector<char>& vfBest, CAmount& nBest, int iterations = 1000)
831f59ce
CM
5168{
5169 vector<char> vfIncluded;
5170
5171 vfBest.assign(vValue.size(), true);
5172 nBest = nTotalLower;
5173
907a2aa4
GM
5174 seed_insecure_rand();
5175
831f59ce
CM
5176 for (int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++)
5177 {
5178 vfIncluded.assign(vValue.size(), false);
a372168e 5179 CAmount nTotal = 0;
831f59ce
CM
5180 bool fReachedTarget = false;
5181 for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
5182 {
5183 for (unsigned int i = 0; i < vValue.size(); i++)
5184 {
907a2aa4
GM
5185 //The solver here uses a randomized algorithm,
5186 //the randomness serves no real security purpose but is just
5187 //needed to prevent degenerate behavior and it is important
5b40d886 5188 //that the rng is fast. We do not use a constant random sequence,
907a2aa4
GM
5189 //because there may be some privacy improvement by making
5190 //the selection random.
5191 if (nPass == 0 ? insecure_rand()&1 : !vfIncluded[i])
831f59ce
CM
5192 {
5193 nTotal += vValue[i].first;
5194 vfIncluded[i] = true;
5195 if (nTotal >= nTargetValue)
5196 {
5197 fReachedTarget = true;
5198 if (nTotal < nBest)
5199 {
5200 nBest = nTotal;
5201 vfBest = vfIncluded;
5202 }
5203 nTotal -= vValue[i].first;
5204 vfIncluded[i] = false;
5205 }
5206 }
5207 }
5208 }
5209 }
5210}
5211
2ec1b02c 5212// returns true if the selection contributes to getting any closer to the target. for example,
5213// if a candidate value map contains more of currencies already present and none of those that are needed
5214// but not present, it will return false. if it contains currencies that are needed, it will return
5215// true.
5216bool CloserToTarget(const CCurrencyValueMap &target, const CCurrencyValueMap &current, const CCurrencyValueMap &candidate)
5217{
5218 CCurrencyValueMap workingTarget = target.SubtractToZero(current); // whatever is left is what we still need
5219 //printf("with candidate: \n%s\nprior target: %s\n", workingTarget.SubtractToZero(candidate).ToUniValue().write(1,2).c_str(),
5220 // workingTarget.ToUniValue().write(1,2).c_str());
5221 return workingTarget.SubtractToZero(candidate) < workingTarget;
5222}
5223
56fe75cb 5224static void ApproximateBestReserveSubset(vector<pair<CCurrencyValueMap, pair<const CWalletTx*,unsigned int> > >vValue,
ee7656e8 5225 const CCurrencyValueMap &totalToOptimize,
2ec1b02c 5226 const CCurrencyValueMap &targetValues,
56fe75cb 5227 vector<char>& vfBest,
5228 CCurrencyValueMap& bestTotals,
5229 int iterations = 1000)
5230{
5231 vector<char> vfIncluded;
5232
5233 vfBest.assign(vValue.size(), true);
ee7656e8 5234 bestTotals = totalToOptimize;
56fe75cb 5235
5236 seed_insecure_rand();
5237
5238 for (int nRep = 0; nRep < iterations && bestTotals != targetValues; nRep++)
5239 {
5240 vfIncluded.assign(vValue.size(), false);
5241 CCurrencyValueMap totals;
5242 bool fReachedTarget = false;
5243 for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
5244 {
5245 for (unsigned int i = 0; i < vValue.size(); i++)
5246 {
5247 //The solver here uses a randomized algorithm,
5248 //the randomness serves no real security purpose but is just
5249 //needed to prevent degenerate behavior and it is important
5250 //that the rng is fast. We do not use a constant random sequence,
5251 //because there may be some privacy improvement by making
5252 //the selection random.
2ec1b02c 5253 /*
5254 printf("targetValues\n%s\ntotals\n%s\nvValue[i].first\n%s\n", targetValues.ToUniValue().write(1,2).c_str(),
5255 totals.ToUniValue().write(1,2).c_str(),
5256 vValue[i].first.ToUniValue().write(1,2).c_str());
5257 printf("iscloser: %d\n", CloserToTarget(targetValues, totals, vValue[i].first));
5258 */
5259 if ((nPass == 0 ? insecure_rand()&1 : !vfIncluded[i]) && CloserToTarget(targetValues, totals, vValue[i].first))
56fe75cb 5260 {
5261 totals += vValue[i].first;
5262 vfIncluded[i] = true;
56a7b665 5263 // we reached the target if we fulfill all currencies
5264 CCurrencyValueMap curLeft = totals - targetValues;
5265 if (!curLeft.HasNegative())
56fe75cb 5266 {
5267 fReachedTarget = true;
2ec1b02c 5268 if (CompareValueMap()(totals, bestTotals))
56fe75cb 5269 {
5270 bestTotals = totals;
5271 vfBest = vfIncluded;
5272 }
5273 totals -= vValue[i].first;
5274 vfIncluded[i] = false;
5275 }
5276 }
5277 }
5278 }
5279 }
5280}
5281
79383e0a 5282bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, vector<COutput> vCoins,set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const
e8ef3da7 5283{
79383e0a 5284 int32_t count = 0; //uint64_t lowest_interest = 0;
e8ef3da7 5285 setCoinsRet.clear();
79383e0a 5286 //memset(interests,0,sizeof(interests));
e8ef3da7 5287 nValueRet = 0;
e8ef3da7 5288 // List of values less than target
a372168e
MF
5289 pair<CAmount, pair<const CWalletTx*,unsigned int> > coinLowestLarger;
5290 coinLowestLarger.first = std::numeric_limits<CAmount>::max();
e8ef3da7 5291 coinLowestLarger.second.first = NULL;
a372168e
MF
5292 vector<pair<CAmount, pair<const CWalletTx*,unsigned int> > > vValue;
5293 CAmount nTotalLower = 0;
e8ef3da7 5294
e333ab56
CM
5295 random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
5296
c8988460 5297 BOOST_FOREACH(const COutput &output, vCoins)
e8ef3da7 5298 {
c8988460
PW
5299 if (!output.fSpendable)
5300 continue;
5301
b80aa0c7 5302 if (output.tx->vout[output.i].nValue == 0)
5303 {
5304 continue;
5305 }
5306
9b0369c7 5307 const CWalletTx *pcoin = output.tx;
e8ef3da7 5308
a3e192a3 5309 if (output.nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? nConfMine : nConfTheirs))
9b0369c7 5310 continue;
e8ef3da7 5311
9b0369c7 5312 int i = output.i;
a372168e 5313 CAmount n = pcoin->vout[i].nValue;
e8ef3da7 5314
a372168e 5315 pair<CAmount,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin, i));
e8ef3da7 5316
9b0369c7
CM
5317 if (n == nTargetValue)
5318 {
5319 setCoinsRet.insert(coin.second);
5320 nValueRet += coin.first;
79383e0a 5321 //if ( KOMODO_EXCHANGEWALLET == 0 )
5322 // *interestp += pcoin->vout[i].interest;
9b0369c7
CM
5323 return true;
5324 }
5325 else if (n < nTargetValue + CENT)
5326 {
5327 vValue.push_back(coin);
5328 nTotalLower += n;
79383e0a 5329 //if ( KOMODO_EXCHANGEWALLET == 0 && count < sizeof(interests)/sizeof(*interests) )
5330 //{
9067057a 5331 //fprintf(stderr,"count.%d %.8f\n",count,(double)pcoin->vout[i].interest/COIN);
79383e0a 5332 //interests[count++] = pcoin->vout[i].interest;
5333 //}
5334 if ( nTotalLower > 4*nTargetValue + CENT )
92c2aa6b 5335 {
eaba9a27 5336 //fprintf(stderr,"why bother with all the utxo if we have double what is needed?\n");
92c2aa6b 5337 break;
5338 }
9b0369c7
CM
5339 }
5340 else if (n < coinLowestLarger.first)
5341 {
5342 coinLowestLarger = coin;
79383e0a 5343 //if ( KOMODO_EXCHANGEWALLET == 0 )
5344 // lowest_interest = pcoin->vout[i].interest;
e8ef3da7
WL
5345 }
5346 }
5347
831f59ce 5348 if (nTotalLower == nTargetValue)
e8ef3da7 5349 {
c376ac35 5350 for (unsigned int i = 0; i < vValue.size(); ++i)
e8ef3da7
WL
5351 {
5352 setCoinsRet.insert(vValue[i].second);
5353 nValueRet += vValue[i].first;
79383e0a 5354 //if ( KOMODO_EXCHANGEWALLET == 0 && i < count )
5355 // *interestp += interests[i];
e8ef3da7
WL
5356 }
5357 return true;
5358 }
5359
831f59ce 5360 if (nTotalLower < nTargetValue)
e8ef3da7
WL
5361 {
5362 if (coinLowestLarger.second.first == NULL)
5363 return false;
5364 setCoinsRet.insert(coinLowestLarger.second);
5365 nValueRet += coinLowestLarger.first;
79383e0a 5366 //if ( KOMODO_EXCHANGEWALLET == 0 )
5367 // *interestp += lowest_interest;
e8ef3da7
WL
5368 return true;
5369 }
5370
e8ef3da7 5371 // Solve subset sum by stochastic approximation
d650f96d 5372 sort(vValue.rbegin(), vValue.rend(), CompareValueOnly());
831f59ce 5373 vector<char> vfBest;
a372168e 5374 CAmount nBest;
e8ef3da7 5375
831f59ce
CM
5376 ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest, 1000);
5377 if (nBest != nTargetValue && nTotalLower >= nTargetValue + CENT)
5378 ApproximateBestSubset(vValue, nTotalLower, nTargetValue + CENT, vfBest, nBest, 1000);
e8ef3da7 5379
831f59ce
CM
5380 // If we have a bigger coin and (either the stochastic approximation didn't find a good solution,
5381 // or the next bigger coin is closer), return the bigger coin
5382 if (coinLowestLarger.second.first &&
5383 ((nBest != nTargetValue && nBest < nTargetValue + CENT) || coinLowestLarger.first <= nBest))
e8ef3da7
WL
5384 {
5385 setCoinsRet.insert(coinLowestLarger.second);
5386 nValueRet += coinLowestLarger.first;
79383e0a 5387 //if ( KOMODO_EXCHANGEWALLET == 0 )
5388 // *interestp += lowest_interest;
e8ef3da7
WL
5389 }
5390 else {
c376ac35 5391 for (unsigned int i = 0; i < vValue.size(); i++)
e8ef3da7
WL
5392 if (vfBest[i])
5393 {
5394 setCoinsRet.insert(vValue[i].second);
5395 nValueRet += vValue[i].first;
79383e0a 5396 //if ( KOMODO_EXCHANGEWALLET == 0 && i < count )
5397 // *interestp += interests[i];
e8ef3da7
WL
5398 }
5399
faaeae1e 5400 LogPrint("selectcoins", "SelectCoins() best subset: ");
c376ac35 5401 for (unsigned int i = 0; i < vValue.size(); i++)
e8ef3da7 5402 if (vfBest[i])
4f0f864d 5403 LogPrint("selectcoins", "%s", FormatMoney(vValue[i].first));
7d9d134b 5404 LogPrint("selectcoins", "total %s\n", FormatMoney(nBest));
e8ef3da7
WL
5405 }
5406
5407 return true;
5408}
5409
1e435b54 5410bool CWallet::SelectCoins(const CAmount& nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, bool& fOnlyProtectedCoinbaseCoinsRet, bool& fNeedProtectedCoinbaseCoinsRet, const CCoinControl* coinControl) const
e8ef3da7 5411{
1e435b54 5412 // Output parameter fOnlyProtectedCoinbaseCoinsRet is set to true when the only available coins are coinbase utxos.
79383e0a 5413 uint64_t tmp; int32_t retval;
5414 //if ( interestp == 0 )
5415 //{
5416 // interestp = &tmp;
5417 // *interestp = 0;
5418 //}
2b1cda3b 5419 vector<COutput> vCoinsNoCoinbase, vCoinsWithCoinbase;
1e435b54 5420 AvailableCoins(vCoinsNoCoinbase, true, coinControl, false, true, false);
5421 AvailableCoins(vCoinsWithCoinbase, true, coinControl, false, true, true);
5422 fOnlyProtectedCoinbaseCoinsRet = vCoinsNoCoinbase.size() == 0 && vCoinsWithCoinbase.size() > 0;
2b1cda3b
S
5423
5424 // If coinbase utxos can only be sent to zaddrs, exclude any coinbase utxos from coin selection.
5425 bool fProtectCoinbase = Params().GetConsensus().fCoinbaseMustBeProtected;
5426 vector<COutput> vCoins = (fProtectCoinbase) ? vCoinsNoCoinbase : vCoinsWithCoinbase;
5427
1e435b54 5428 // Output parameter fNeedProtectedCoinbaseCoinsRet is set to true if coinbase utxos that must be shielded need to be spent to meet target amount
2b1cda3b
S
5429 if (fProtectCoinbase && vCoinsWithCoinbase.size() > vCoinsNoCoinbase.size()) {
5430 CAmount value = 0;
5431 for (const COutput& out : vCoinsNoCoinbase) {
5432 if (!out.fSpendable) {
5433 continue;
5434 }
5435 value += out.tx->vout[out.i].nValue;
f87150f4 5436 if ( KOMODO_EXCHANGEWALLET == 0 )
5437 value += out.tx->vout[out.i].interest;
2b1cda3b
S
5438 }
5439 if (value <= nTargetValue) {
5440 CAmount valueWithCoinbase = 0;
5441 for (const COutput& out : vCoinsWithCoinbase) {
5442 if (!out.fSpendable) {
5443 continue;
5444 }
5445 valueWithCoinbase += out.tx->vout[out.i].nValue;
f87150f4 5446 if ( KOMODO_EXCHANGEWALLET == 0 )
5447 valueWithCoinbase += out.tx->vout[out.i].interest;
2b1cda3b 5448 }
1e435b54 5449 fNeedProtectedCoinbaseCoinsRet = (valueWithCoinbase >= nTargetValue);
2b1cda3b
S
5450 }
5451 }
6a86c24d 5452 // coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
aa30f655 5453 if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs)
6a86c24d
CL
5454 {
5455 BOOST_FOREACH(const COutput& out, vCoins)
5456 {
aa30f655
MC
5457 if (!out.fSpendable)
5458 continue;
6a86c24d 5459 nValueRet += out.tx->vout[out.i].nValue;
79383e0a 5460 //if ( KOMODO_EXCHANGEWALLET == 0 )
5461 // *interestp += out.tx->vout[out.i].interest;
6a86c24d
CL
5462 setCoinsRet.insert(make_pair(out.tx, out.i));
5463 }
5464 return (nValueRet >= nTargetValue);
5465 }
aa30f655
MC
5466 // calculate value from preset inputs and store them
5467 set<pair<const CWalletTx*, uint32_t> > setPresetCoins;
5468 CAmount nValueFromPresetInputs = 0;
5469
5470 std::vector<COutPoint> vPresetInputs;
5471 if (coinControl)
5472 coinControl->ListSelected(vPresetInputs);
5473 BOOST_FOREACH(const COutPoint& outpoint, vPresetInputs)
5474 {
5475 map<uint256, CWalletTx>::const_iterator it = mapWallet.find(outpoint.hash);
5476 if (it != mapWallet.end())
5477 {
5478 const CWalletTx* pcoin = &it->second;
5479 // Clearly invalid input, fail
5480 if (pcoin->vout.size() <= outpoint.n)
5481 return false;
5482 nValueFromPresetInputs += pcoin->vout[outpoint.n].nValue;
945f015d 5483 if ( KOMODO_EXCHANGEWALLET == 0 )
5484 nValueFromPresetInputs += pcoin->vout[outpoint.n].interest;
aa30f655
MC
5485 setPresetCoins.insert(make_pair(pcoin, outpoint.n));
5486 } else
5487 return false; // TODO: Allow non-wallet inputs
5488 }
5489
5490 // remove preset inputs from vCoins
5491 for (vector<COutput>::iterator it = vCoins.begin(); it != vCoins.end() && coinControl && coinControl->HasSelected();)
5492 {
5493 if (setPresetCoins.count(make_pair(it->tx, it->i)))
5494 it = vCoins.erase(it);
5495 else
5496 ++it;
5497 }
945f015d 5498 retval = false;
5499 if ( nTargetValue <= nValueFromPresetInputs )
5500 retval = true;
79383e0a 5501 else if ( SelectCoinsMinConf(nTargetValue, 1, 6, vCoins, setCoinsRet, nValueRet) != 0 )
945f015d 5502 retval = true;
79383e0a 5503 else if ( SelectCoinsMinConf(nTargetValue, 1, 1, vCoins, setCoinsRet, nValueRet) != 0 )
945f015d 5504 retval = true;
79383e0a 5505 else if ( bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue, 0, 1, vCoins, setCoinsRet, nValueRet) != 0 )
945f015d 5506 retval = true;
aa30f655
MC
5507 // because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset
5508 setCoinsRet.insert(setPresetCoins.begin(), setPresetCoins.end());
aa30f655
MC
5509 // add preset inputs to the total value selected
5510 nValueRet += nValueFromPresetInputs;
945f015d 5511 return retval;
e8ef3da7
WL
5512}
5513
56fe75cb 5514bool CWallet::SelectReserveCoinsMinConf(const CCurrencyValueMap& targetValues,
5515 CAmount targetNativeValue,
5516 int nConfMine,
5517 int nConfTheirs,
5518 std::vector<COutput> vCoins,
5519 std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet,
5520 CCurrencyValueMap& valueRet,
5521 CAmount &nativeValueRet) const
989b1de1
MT
5522{
5523 int32_t count = 0; //uint64_t lowest_interest = 0;
5524 setCoinsRet.clear();
7beb1c0b 5525 valueRet.valueMap.clear();
5526 nativeValueRet = 0;
989b1de1 5527 //memset(interests,0,sizeof(interests));
56fe75cb 5528
ee7656e8 5529 // for each currency type being looked for, store the lowest larger outputs found in order, up to a maximum of the number of
5530 // different currencies being looked for
5531 std::map<uint160, std::multimap<CAmount, CReserveOutSelectionInfo>> coinsLowestLarger;
5532 std::set<const COutput *> largerOuts; // all those that are >= than amount requested in at least one currency
5533 std::multimap<int, std::pair<std::vector<uint160>, CReserveOutSelectionInfo>> multiSatisfy; // for outputs that satisfy >= one currency
5534 CCurrencyValueMap largerTotal;
5535 std::map<uint160, std::multimap<CAmount, CReserveOutSelectionInfo>> coinsLargestLower;
5536 std::set<const COutput *> lowerOuts; // all those that are lower in all requested amounts
5537 CCurrencyValueMap lowerTotal;
5538
5539 CCurrencyValueMap nativeCent(std::vector<uint160>({ASSETCHAINS_CHAINID}), std::vector<CAmount>({CENT}));
5540
5541 CCurrencyValueMap totalToOptimize;
5542 std::vector<std::pair<CCurrencyValueMap, std::pair<const CWalletTx*, unsigned int>>> vOutputsToOptimize;
989b1de1
MT
5543
5544 random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
5545
ee7656e8 5546 CCurrencyValueMap nTotalTarget = (targetValues + CCurrencyValueMap(std::vector<uint160>({ASSETCHAINS_CHAINID}), std::vector<CAmount>({targetNativeValue}))).CanonicalMap();
a88b514e 5547
a1a85fd6 5548 //printf("totaltarget: %s\n", nTotalTarget.ToUniValue().write().c_str());
56a7b665 5549
989b1de1
MT
5550 BOOST_FOREACH(const COutput &output, vCoins)
5551 {
5552 if (!output.fSpendable)
5553 continue;
5554
5555 const CWalletTx *pcoin = output.tx;
5556
5557 if (output.nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? nConfMine : nConfTheirs))
5558 continue;
5559
5560 int i = output.i;
ee7656e8 5561 CCurrencyValueMap nAll(pcoin->vout[i].scriptPubKey.ReserveOutValue()); // all currencies, whether in target or not
a88b514e 5562 CCurrencyValueMap n = nAll.IntersectingValues(targetValues); // get only those reserve currencies that are also in target
ee7656e8 5563 CCurrencyValueMap nTotal = n; // nTotal will be all currencies, including native, that are also in target
56fe75cb 5564 CAmount nativeN = pcoin->vout[i].nValue;
56a7b665 5565 if (nativeN)
5566 {
5567 nAll.valueMap[ASSETCHAINS_CHAINID] = nativeN;
5568 if (targetNativeValue)
5569 {
5570 nTotal.valueMap[ASSETCHAINS_CHAINID] = nativeN;
5571 }
5572 }
989b1de1 5573
56a7b665 5574 // if it has no output types we care about, next
ee7656e8 5575 if (!nTotal.valueMap.size())
56fe75cb 5576 {
5577 continue;
5578 }
989b1de1 5579
a88b514e 5580 //printf("nTotal: %s\n", nTotal.ToUniValue().write().c_str());
5581
ee7656e8 5582 vOutputsToOptimize.push_back(std::make_pair(nAll, std::make_pair(output.tx, output.i)));
5583
5584 CReserveOutSelectionInfo coin(pcoin, i, nAll);
5585
5586 // if all values are equivalent to targets, we've found the perfect output, no more searching needed
eed98728 5587 // TODO: should we early out, even if we have extra currencies? If so, use nTotal to commpare
56a7b665 5588 if (nAll == nTotalTarget)
989b1de1 5589 {
ee7656e8 5590 setCoinsRet.insert(std::make_pair(coin.pWtx, coin.n));
7beb1c0b 5591 valueRet = pcoin->vout[i].scriptPubKey.ReserveOutValue();
5592 nativeValueRet = nativeN;
989b1de1
MT
5593 return true;
5594 }
56a7b665 5595
ee7656e8 5596 // now, we need to loop through all targets to see if this satisfies any single currency requirement completely
5597 // if so, we will include it in the largest lower list for that currency
5598 int numLarger = 0;
5599 std::vector<uint160> multiCurrencies;
5600 for (auto &oneCur : nTotal.valueMap)
989b1de1 5601 {
ee7656e8 5602 // see if we are larger than or equal to at least one required currency,
5603 // we can get duplicates in multiple currency lists this way, and we will reconcile that later
5604 if (oneCur.second >= nTotalTarget.valueMap[oneCur.first])
989b1de1 5605 {
ee7656e8 5606 if (coinsLowestLarger.count(oneCur.first))
5607 {
5608 coinsLowestLarger[oneCur.first].emplace(std::make_pair(oneCur.second, coin));
5609 }
5610 else
5611 {
5612 coinsLowestLarger.emplace(std::make_pair(oneCur.first,
5613 std::multimap<CAmount, CReserveOutSelectionInfo>({{oneCur.second, coin}})));
5614 }
5615 numLarger++;
5616 multiCurrencies.push_back(oneCur.first);
989b1de1
MT
5617 }
5618 }
ee7656e8 5619
5620 // if any currencies here are larger than or equal to what is needed for one currency
5621 if (numLarger)
989b1de1 5622 {
ee7656e8 5623 largerOuts.insert(&output);
5624 largerTotal += nTotal;
5625 multiSatisfy.insert(std::make_pair(numLarger, std::make_pair(multiCurrencies, coin)));
5626 }
5627 else
5628 {
5629 for (auto &oneCur : nTotal.valueMap)
56a7b665 5630 {
ee7656e8 5631 if (coinsLargestLower.count(oneCur.first))
5632 {
5633 coinsLargestLower[oneCur.first].emplace(std::make_pair(oneCur.second, coin));
5634 }
5635 else
5636 {
5637 coinsLargestLower.emplace(std::make_pair(oneCur.first,
5638 std::multimap<CAmount, CReserveOutSelectionInfo>({{oneCur.second, coin}})));
5639 }
56a7b665 5640 }
ee7656e8 5641 lowerOuts.insert(&output);
5642 lowerTotal += nTotal;
5643 if (lowerTotal > ((nTotalTarget * 4) + nativeCent))
56a7b665 5644 {
ee7656e8 5645 //fprintf(stderr,"why bother with other utxos if we have much more than what is needed?\n");
5646 break;
56a7b665 5647 }
989b1de1
MT
5648 }
5649 }
5650
ee7656e8 5651 // if our lower total + larger total are not enough, no way we have enough
5652 if ((lowerTotal + largerTotal) < nTotalTarget)
5653 {
5654 return false;
5655 }
2ec1b02c 5656
a88b514e 5657 //printf("lowerTotal:\n%s\nlargerTotal:\n%s\n", lowerTotal.ToUniValue().write().c_str(), largerTotal.ToUniValue().write().c_str());
5658
ee7656e8 5659 // if all the lower amounts are just what we need, and we don't add too many inputs in the process, use them all
eed98728 5660 size_t numInputsLimit = (size_t)GetArg("-mempooltxinputlimit", MAX_NUM_INPUTS_LIMIT);
5661
5662 if ((lowerTotal >= nTotalTarget && lowerTotal <= (nTotalTarget + nativeCent)) && lowerOuts.size() <= numInputsLimit)
989b1de1 5663 {
ee7656e8 5664 for (auto oneOut : lowerOuts)
989b1de1 5665 {
ee7656e8 5666 setCoinsRet.insert(std::make_pair(oneOut->tx, oneOut->i));
5667 valueRet += oneOut->tx->vout[oneOut->i].ReserveOutValue();
5668 nativeValueRet += oneOut->tx->vout[oneOut->i].nValue;
989b1de1
MT
5669 }
5670 return true;
5671 }
5672
ee7656e8 5673 std::map<std::pair<const CWalletTx *, int>, CReserveOutSelectionInfo> added;
5674 CCurrencyValueMap totalAdded;
5675 CCurrencyValueMap adjustedTarget = nTotalTarget;
5676 std::set<uint160> satisfied;
5677
5678 // short circuit best fit check with any exact amounts we may have
5679 if (multiSatisfy.size())
989b1de1 5680 {
ee7656e8 5681 // each output for each currency will satisfy one or more currency requirements
5682 // first check those that satisfy more than one currency, then select those which are lowest value in currencies they satisfy
56a7b665 5683
ee7656e8 5684 // check in reverse to check those that satisfy most first
5685 for (auto multiIt = multiSatisfy.rbegin(); multiIt != multiSatisfy.rend(); multiIt++)
5686 {
5687 // if we have 0 left, we're done
5688 if ((nTotalTarget.valueMap.size() - satisfied.size()) == 0)
5689 {
5690 break;
5691 }
5692
eed98728 5693 // consider "satisfying" an exact match of any currency in the adjusted request, otherwise, we should fall through to the best fit solver
ee7656e8 5694 int newFound = 0;
5695 for (auto &oneCurID : multiIt->second.first)
5696 {
5697 if (!satisfied.count(oneCurID) &&
5698 multiIt->second.second.outVal.valueMap[oneCurID] == adjustedTarget.valueMap[oneCurID])
5699 {
5700 satisfied.insert(oneCurID);
5701 newFound++;
5702 }
5703 }
5704
5705 // if we don't satisfy any new currency with this output, don't add it as we care more if singles are lower as a priotity
5706 if (!newFound)
5707 {
5708 continue;
5709 }
5710
5711 // this satisfies at least 1 new currency, so use it and also reduce other currencies by all amounts that it includes
5712 // don't check it again when looking later
5713 added.insert(std::make_pair(std::make_pair(multiIt->second.second.pWtx, multiIt->second.second.n), multiIt->second.second));
5714
5715 // add all currency values in the transaction, as some may partially satisfy, and we should early out when we have enough
5716 totalAdded += multiIt->second.second.outVal.IntersectingValues(nTotalTarget);
5717
5718 adjustedTarget.SubtractToZero(totalAdded);
5719 // loop through all those that have been zeroed in the adjusted target, and mark as satisfied
5720 for (auto &oneCur : nTotalTarget.NonIntersectingValues(adjustedTarget).valueMap)
5721 {
5722 satisfied.insert(oneCur.first);
5723 }
5724 }
5725 }
5726
5727 // if we've satisfied all currency requirements with larger outputs that fit well, use what we have and be done
5728 if (satisfied.size() == nTotalTarget.valueMap.size())
5729 {
5730 for (auto &oneOut : added)
5731 {
5732 setCoinsRet.insert(std::make_pair(oneOut.second.pWtx, oneOut.second.n));
5733 valueRet += oneOut.second.outVal;
5734 }
5735 auto vRetIt = valueRet.valueMap.find(ASSETCHAINS_CHAINID);
5736 if (vRetIt != valueRet.valueMap.end())
5737 {
5738 nativeValueRet = vRetIt->second;
5739 valueRet.valueMap.erase(vRetIt);
5740 }
989b1de1
MT
5741 return true;
5742 }
5743
ee7656e8 5744 // make new vector without those we have added due to exact fit, and use remaining and adjusted target to satisfy requests
5745 std::vector<int> vOutputsToRemove;
5746 CCurrencyValueMap removedValue;
5747 for (int i = 0; i < vOutputsToOptimize.size(); i++)
5748 {
5749 if (added.count(vOutputsToOptimize[i].second))
5750 {
5751 vOutputsToRemove.push_back(i);
5752 removedValue += vOutputsToOptimize[i].first;
5753 }
5754 }
56fe75cb 5755
ee7656e8 5756 // remove all that we've already added leaving a vector of those that we need to optimize
5757 for (int i = vOutputsToRemove.size() - 1; i >= 0; i--)
2ec1b02c 5758 {
ee7656e8 5759 vOutputsToOptimize.erase(vOutputsToOptimize.begin() + vOutputsToRemove[i]);
2ec1b02c 5760 }
2ec1b02c 5761
ee7656e8 5762 totalToOptimize = largerTotal.SubtractToZero(removedValue) + lowerTotal;
5763 CCurrencyValueMap newOptimizationTarget = nTotalTarget.SubtractToZero(removedValue);
56a7b665 5764
a88b514e 5765 /* printf("totalToOptimize:\n%s\nnewOptimizationTarget:\n%s\n", totalToOptimize.ToUniValue().write().c_str(), newOptimizationTarget.ToUniValue().write().c_str());
5766 for (int i = 0; i < vOutputsToOptimize.size(); i++)
5767 {
5768 printf("output #%d:\nreserves:\n%s\nnative:\n%s\n",
5769 i,
5770 vOutputsToOptimize[i].first.ToUniValue().write().c_str(),
5771 ValueFromAmount(vOutputsToOptimize[i].second.first->vout[vOutputsToOptimize[i].second.second].nValue).write().c_str());
5772 } */
5773
989b1de1 5774 vector<char> vfBest;
56fe75cb 5775 CCurrencyValueMap bestTotals;
989b1de1 5776
ee7656e8 5777 ApproximateBestReserveSubset(vOutputsToOptimize, totalToOptimize, newOptimizationTarget, vfBest, bestTotals, 1000);
5778 if (bestTotals != targetValues && totalToOptimize >= targetValues + nativeCent)
a88b514e 5779 {
ee7656e8 5780 ApproximateBestReserveSubset(vOutputsToOptimize, totalToOptimize, newOptimizationTarget + nativeCent, vfBest, bestTotals, 1000);
a88b514e 5781 }
989b1de1 5782
ee7656e8 5783 for (unsigned int i = 0; i < vOutputsToOptimize.size(); i++)
989b1de1 5784 {
56a7b665 5785 if (vfBest[i])
5786 {
ee7656e8 5787 setCoinsRet.insert(vOutputsToOptimize[i].second);
5788 valueRet += vOutputsToOptimize[i].second.first->vout[vOutputsToOptimize[i].second.second].ReserveOutValue();
5789 nativeValueRet += vOutputsToOptimize[i].second.first->vout[vOutputsToOptimize[i].second.second].nValue;
56a7b665 5790 }
989b1de1 5791 }
989b1de1 5792
ee7656e8 5793 valueRet.valueMap[ASSETCHAINS_CHAINID] = nativeValueRet;
a88b514e 5794 CCurrencyValueMap checkReturn(valueRet);
5795
5796 //printf("valueRet:\n%s\n", valueRet.ToUniValue().write().c_str());
5797
ee7656e8 5798 if (checkReturn.IntersectingValues(nTotalTarget) < nTotalTarget)
5799 {
5800 return false;
5801 }
5802
56a7b665 5803 LogPrint("selectcoins", "SelectCoins() best subset: ");
ee7656e8 5804 for (unsigned int i = 0; i < vOutputsToOptimize.size(); i++)
56a7b665 5805 {
5806 if (vfBest[i])
5807 {
ee7656e8 5808 LogPrint("selectcoins", "%s", FormatMoney(vOutputsToOptimize[i].first.valueMap[targetValues.valueMap.begin()->first]));
56a7b665 5809 }
989b1de1 5810 }
56a7b665 5811 LogPrint("selectcoins", "total %s\n", FormatMoney(bestTotals.valueMap[targetValues.valueMap.begin()->first]));
989b1de1
MT
5812
5813 return true;
5814}
5815
56fe75cb 5816bool CWallet::SelectReserveCoins(const CCurrencyValueMap& targetReserveValues,
5817 CAmount targetNativeValue,
5818 set<pair<const CWalletTx*,unsigned int> >& setCoinsRet,
5819 CCurrencyValueMap &valueRet,
5820 CAmount &nativeRet,
5821 bool& fOnlyCoinbaseCoinsRet,
5822 bool& fNeedCoinbaseCoinsRet,
5823 const CCoinControl* coinControl,
5824 const CTxDestination *pOnlyFromDest) const
989b1de1
MT
5825{
5826 // Output parameter fOnlyCoinbaseCoinsRet is set to true when the only available coins are coinbase utxos.
56a7b665 5827
989b1de1 5828 vector<COutput> vCoinsNoCoinbase, vCoinsWithCoinbase;
56a7b665 5829 AvailableReserveCoins(vCoinsNoCoinbase, true, coinControl, false, true, pOnlyFromDest, &targetReserveValues);
5830 AvailableReserveCoins(vCoinsWithCoinbase, true, coinControl, true, true, pOnlyFromDest, &targetReserveValues);
989b1de1
MT
5831 fOnlyCoinbaseCoinsRet = vCoinsNoCoinbase.size() == 0 && vCoinsWithCoinbase.size() > 0;
5832
1188acf6 5833 // coinbase protection forcing them to be spent only to z-addresses ended
5834 // when identities were released
5835 bool fProtectCoinbase = false;
989b1de1 5836
56a7b665 5837 vector<COutput> vCoins = (fProtectCoinbase) ? vCoinsNoCoinbase : vCoinsWithCoinbase;
c83e4936 5838
989b1de1
MT
5839 // Output parameter fNeedCoinbaseCoinsRet is set to true if coinbase utxos need to be spent to meet target amount
5840 if (fProtectCoinbase && vCoinsWithCoinbase.size() > vCoinsNoCoinbase.size()) {
c83e4936 5841 CCurrencyValueMap reserveValues;
56fe75cb 5842 CAmount nativeValue = 0;
989b1de1
MT
5843 for (const COutput& out : vCoinsNoCoinbase) {
5844 if (!out.fSpendable) {
5845 continue;
5846 }
56fe75cb 5847 nativeValue += out.tx->vout[out.i].nValue;
c83e4936 5848 reserveValues += out.tx->vout[out.i].ReserveOutValue();
989b1de1 5849 }
c83e4936 5850 if (reserveValues < targetReserveValues || nativeValue < targetNativeValue) {
5851 CCurrencyValueMap reserveValuesWithCoinbase;
56fe75cb 5852 CAmount nativeValueWithCoinbase = 0;
989b1de1
MT
5853 for (const COutput& out : vCoinsWithCoinbase) {
5854 if (!out.fSpendable) {
5855 continue;
5856 }
c83e4936 5857 reserveValuesWithCoinbase += out.tx->vout[out.i].ReserveOutValue();
56fe75cb 5858 nativeValueWithCoinbase += out.tx->vout[out.i].nValue;
989b1de1 5859 }
c83e4936 5860 fNeedCoinbaseCoinsRet = (reserveValuesWithCoinbase >= targetReserveValues) && (nativeValueWithCoinbase >= targetNativeValue);
989b1de1
MT
5861 }
5862 }
56fe75cb 5863
989b1de1
MT
5864 // coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
5865 if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs)
5866 {
5867 BOOST_FOREACH(const COutput& out, vCoins)
5868 {
5869 if (!out.fSpendable)
5870 continue;
56fe75cb 5871 valueRet += out.tx->vout[out.i].ReserveOutValue();
5872 nativeRet += out.tx->vout[out.i].nValue;
989b1de1
MT
5873 setCoinsRet.insert(make_pair(out.tx, out.i));
5874 }
56fe75cb 5875 return (valueRet >= targetReserveValues) && (nativeRet >= targetNativeValue);
989b1de1 5876 }
56fe75cb 5877
989b1de1
MT
5878 // calculate value from preset inputs and store them
5879 set<pair<const CWalletTx*, uint32_t> > setPresetCoins;
56fe75cb 5880 CCurrencyValueMap valueFromPresetInputs;
5881 CAmount nativeValueFromPresets = 0;
989b1de1
MT
5882
5883 std::vector<COutPoint> vPresetInputs;
5884 if (coinControl)
5885 coinControl->ListSelected(vPresetInputs);
5886 BOOST_FOREACH(const COutPoint& outpoint, vPresetInputs)
5887 {
5888 map<uint256, CWalletTx>::const_iterator it = mapWallet.find(outpoint.hash);
5889 if (it != mapWallet.end())
5890 {
5891 const CWalletTx* pcoin = &it->second;
5892 // Clearly invalid input, fail
5893 if (pcoin->vout.size() <= outpoint.n)
5894 return false;
56fe75cb 5895 valueFromPresetInputs += pcoin->vout[outpoint.n].ReserveOutValue();
5896 nativeValueFromPresets += pcoin->vout[outpoint.n].nValue;
989b1de1
MT
5897 setPresetCoins.insert(make_pair(pcoin, outpoint.n));
5898 } else
5899 return false; // TODO: Allow non-wallet inputs
5900 }
5901
5902 // remove preset inputs from vCoins
5903 for (vector<COutput>::iterator it = vCoins.begin(); it != vCoins.end() && coinControl && coinControl->HasSelected();)
5904 {
5905 if (setPresetCoins.count(make_pair(it->tx, it->i)))
5906 it = vCoins.erase(it);
5907 else
5908 ++it;
5909 }
56a7b665 5910
5911 bool retval = false;
2f416b17 5912 if ( targetNativeValue <= nativeRet &&
5913 targetReserveValues <= targetReserveValues.IntersectingValues(valueFromPresetInputs) && targetNativeValue <= nativeValueFromPresets )
989b1de1 5914 retval = true;
56fe75cb 5915 else if ( SelectReserveCoinsMinConf(targetReserveValues, targetNativeValue, 1, 6, vCoins, setCoinsRet, valueRet, nativeRet) != 0 )
989b1de1 5916 retval = true;
56fe75cb 5917 else if ( SelectReserveCoinsMinConf(targetReserveValues, targetNativeValue, 1, 1, vCoins, setCoinsRet, valueRet, nativeRet) != 0 )
989b1de1 5918 retval = true;
56fe75cb 5919 else if ( bSpendZeroConfChange && SelectReserveCoinsMinConf(targetReserveValues, targetNativeValue, 0, 1, vCoins, setCoinsRet, valueRet, nativeRet) != 0 )
989b1de1
MT
5920 retval = true;
5921 // because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset
5922 setCoinsRet.insert(setPresetCoins.begin(), setPresetCoins.end());
5923 // add preset inputs to the total value selected
56fe75cb 5924 valueRet += valueFromPresetInputs;
5925 nativeRet += nativeValueFromPresets;
989b1de1
MT
5926 return retval;
5927}
5928
aa30f655
MC
5929bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount &nFeeRet, int& nChangePosRet, std::string& strFailReason)
5930{
5931 vector<CRecipient> vecSend;
5932
5933 // Turn the txout set into a CRecipient vector
5934 BOOST_FOREACH(const CTxOut& txOut, tx.vout)
5935 {
5936 CRecipient recipient = {txOut.scriptPubKey, txOut.nValue, false};
5937 vecSend.push_back(recipient);
5938 }
5939
5940 CCoinControl coinControl;
5941 coinControl.fAllowOtherInputs = true;
5942 BOOST_FOREACH(const CTxIn& txin, tx.vin)
5943 coinControl.Select(txin.prevout);
5944
5945 CReserveKey reservekey(this);
5946 CWalletTx wtx;
efb7662d 5947
aa30f655
MC
5948 if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosRet, strFailReason, &coinControl, false))
5949 return false;
5950
5951 if (nChangePosRet != -1)
5952 tx.vout.insert(tx.vout.begin() + nChangePosRet, wtx.vout[nChangePosRet]);
5953
5954 // Add new txins (keeping original txin scriptSig/order)
5955 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
5956 {
5957 bool found = false;
5958 BOOST_FOREACH(const CTxIn& origTxIn, tx.vin)
5959 {
5960 if (txin.prevout.hash == origTxIn.prevout.hash && txin.prevout.n == origTxIn.prevout.n)
5961 {
5962 found = true;
5963 break;
5964 }
5965 }
5966 if (!found)
5967 tx.vin.push_back(txin);
5968 }
5969
5970 return true;
e8ef3da7
WL
5971}
5972
aa30f655
MC
5973bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet,
5974 int& nChangePosRet, std::string& strFailReason, const CCoinControl* coinControl, bool sign)
e8ef3da7 5975{
79383e0a 5976 uint64_t interest2 = 0; CAmount nValue = 0; unsigned int nSubtractFeeFromAmount = 0;
292623ad 5977 BOOST_FOREACH (const CRecipient& recipient, vecSend)
e8ef3da7 5978 {
292623ad 5979 if (nValue < 0 || recipient.nAmount < 0)
1f00f4e9
GA
5980 {
5981 strFailReason = _("Transaction amounts must be positive");
e8ef3da7 5982 return false;
1f00f4e9 5983 }
292623ad
CL
5984 nValue += recipient.nAmount;
5985
5986 if (recipient.fSubtractFeeFromAmount)
5987 nSubtractFeeFromAmount++;
e8ef3da7
WL
5988 }
5989 if (vecSend.empty() || nValue < 0)
1f00f4e9
GA
5990 {
5991 strFailReason = _("Transaction amounts must be positive");
e8ef3da7 5992 return false;
1f00f4e9 5993 }
e8ef3da7 5994
b33d1f5e 5995 wtxNew.fTimeReceivedIsTxTime = true;
4c6e2295 5996 wtxNew.BindWallet(this);
9bb37bf0 5997 int nextBlockHeight = chainActive.Height() + 1;
bb6c3482 5998
5999 CMutableTransaction txNew = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextBlockHeight);
6000 txNew.nLockTime = (uint32_t)chainActive.LastTip()->nTime + 1; // set to a time close to now
e8ef3da7 6001
9bb37bf0 6002 // Activates after Overwinter network upgrade
88d014d0 6003 if (Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_OVERWINTER)) {
fa70084c 6004 if (txNew.nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD){
9bb37bf0 6005 strFailReason = _("nExpiryHeight must be less than TX_EXPIRY_HEIGHT_THRESHOLD.");
7b92f27e 6006 return false;
9bb37bf0 6007 }
e19d8b3d 6008 }
15ec5525 6009
25fee350 6010 unsigned int max_tx_size = MAX_TX_SIZE_AFTER_SAPLING;
88d014d0 6011 if (!Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_SAPLING)) {
15ec5525
JG
6012 max_tx_size = MAX_TX_SIZE_BEFORE_SAPLING;
6013 }
efb7662d 6014
ba7fcc8d
PT
6015 // Discourage fee sniping.
6016 //
6017 // However because of a off-by-one-error in previous versions we need to
6018 // neuter it by setting nLockTime to at least one less than nBestHeight.
6019 // Secondly currently propagation of transactions created for block heights
6020 // corresponding to blocks that were just mined may be iffy - transactions
6021 // aren't re-accepted into the mempool - we additionally neuter the code by
6022 // going ten blocks back. Doesn't yet do anything for sniping, but does act
6023 // to shake out wallet bugs like not showing nLockTime'd transactions at
6024 // all.
6025 txNew.nLockTime = std::max(0, chainActive.Height() - 10);
6026
6027 // Secondly occasionally randomly pick a nLockTime even further back, so
6028 // that transactions that are delayed after signing for whatever reason,
6029 // e.g. high-latency mix networks and some CoinJoin implementations, have
6030 // better privacy.
6031 if (GetRandInt(10) == 0)
6032 txNew.nLockTime = std::max(0, (int)txNew.nLockTime - GetRandInt(100));
6033
6034 assert(txNew.nLockTime <= (unsigned int)chainActive.Height());
6035 assert(txNew.nLockTime < LOCKTIME_THRESHOLD);
6036
e8ef3da7 6037 {
f8dcd5ca 6038 LOCK2(cs_main, cs_wallet);
e8ef3da7 6039 {
c1c9d5b4 6040 nFeeRet = 0;
050d2e95 6041 while (true)
e8ef3da7 6042 {
f19ffc34 6043 //interest = 0;
4949004d
PW
6044 txNew.vin.clear();
6045 txNew.vout.clear();
e8ef3da7 6046 wtxNew.fFromMe = true;
292623ad
CL
6047 nChangePosRet = -1;
6048 bool fFirst = true;
e8ef3da7 6049
292623ad
CL
6050 CAmount nTotalValue = nValue;
6051 if (nSubtractFeeFromAmount == 0)
6052 nTotalValue += nFeeRet;
e8ef3da7
WL
6053 double dPriority = 0;
6054 // vouts to the payees
292623ad 6055 BOOST_FOREACH (const CRecipient& recipient, vecSend)
8de9bb53 6056 {
292623ad
CL
6057 CTxOut txout(recipient.nAmount, recipient.scriptPubKey);
6058
6059 if (recipient.fSubtractFeeFromAmount)
6060 {
6061 txout.nValue -= nFeeRet / nSubtractFeeFromAmount; // Subtract fee equally from each selected recipient
6062
6063 if (fFirst) // first receiver pays the remainder not divisible by output count
6064 {
6065 fFirst = false;
6066 txout.nValue -= nFeeRet % nSubtractFeeFromAmount;
6067 }
6068 }
6069
2f537fa1 6070 COptCCParams p;
6071
6072 if (txout.IsDust(::minRelayTxFee) && !(txout.nValue == 0 && txout.scriptPubKey.IsPayToCryptoCondition(p) && p.IsValid() && p.evalCode != EVAL_NONE))
1f00f4e9 6073 {
292623ad
CL
6074 if (recipient.fSubtractFeeFromAmount && nFeeRet > 0)
6075 {
6076 if (txout.nValue < 0)
6077 strFailReason = _("The transaction amount is too small to pay the fee");
6078 else
6079 strFailReason = _("The transaction amount is too small to send after the fee has been deducted");
6080 }
6081 else
6082 strFailReason = _("Transaction amount too small");
8de9bb53 6083 return false;
1f00f4e9 6084 }
4949004d 6085 txNew.vout.push_back(txout);
8de9bb53 6086 }
e8ef3da7
WL
6087
6088 // Choose coins to use
6089 set<pair<const CWalletTx*,unsigned int> > setCoins;
a372168e 6090 CAmount nValueIn = 0;
1e435b54 6091 bool fOnlyProtectedCoinbaseCoins = false;
6092 bool fNeedProtectedCoinbaseCoins = false;
9152feb5 6093 interest2 = 0;
1e435b54 6094 if (!SelectCoins(nTotalValue, setCoins, nValueIn, fOnlyProtectedCoinbaseCoins, fNeedProtectedCoinbaseCoins, coinControl))
1f00f4e9 6095 {
1e435b54 6096 if (fOnlyProtectedCoinbaseCoins) {
6097 strFailReason = _("Coinbase funds earned while shielding protection is active can only be sent to a zaddr");
6098 } else if (fNeedProtectedCoinbaseCoins) {
6099 strFailReason = _("Insufficient funds, protected coinbase funds can only be spent after they have been sent to a zaddr");
2b1cda3b
S
6100 } else {
6101 strFailReason = _("Insufficient funds");
6102 }
e8ef3da7 6103 return false;
1f00f4e9 6104 }
e8ef3da7
WL
6105 BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
6106 {
a372168e 6107 CAmount nCredit = pcoin.first->vout[pcoin.second].nValue;
2d9b0b7f 6108 //The coin age after the next block (depth+1) is used instead of the current,
d7836552
GM
6109 //reflecting an assumption the user would accept a bit more delay for
6110 //a chance at a free transaction.
2d9b0b7f 6111 //But mempool inputs might still be in the mempool, so their age stays 0
38dfbe15 6112 //fprintf(stderr,"nCredit %.8f interest %.8f\n",(double)nCredit/COIN,(double)pcoin.first->vout[pcoin.second].interest/COIN);
d1f29a9d 6113 if ( KOMODO_EXCHANGEWALLET == 0 && ASSETCHAINS_SYMBOL[0] == 0 )
608252ed 6114 {
6ad13d7c 6115 interest2 += pcoin.first->vout[pcoin.second].interest;
d1f29a9d 6116 //fprintf(stderr,"%.8f ",(double)pcoin.first->vout[pcoin.second].interest/COIN);
85cb030e 6117 }
2d9b0b7f
AM
6118 int age = pcoin.first->GetDepthInMainChain();
6119 if (age != 0)
6120 age += 1;
6121 dPriority += (double)nCredit * age;
e8ef3da7 6122 }
79383e0a 6123 //if ( KOMODO_EXCHANGEWALLET != 0 )
6124 //{
2626c7e3 6125 //fprintf(stderr,"KOMODO_EXCHANGEWALLET disable interest sum %.8f, interest2 %.8f\n",(double)interest/COIN,(double)interest2/COIN);
79383e0a 6126 //interest = 0; // interest2 also
6127 //}
1bc74c28 6128 if ( ASSETCHAINS_SYMBOL[0] == 0 && DONATION_PUBKEY.size() == 66 && interest2 > 5000 )
6129 {
817ad14d 6130 CScript scriptDonation = CScript() << ParseHex(DONATION_PUBKEY) << OP_CHECKSIG;
6131 CTxOut newTxOut(interest2,scriptDonation);
719aa8b1 6132 int32_t nDonationPosRet = txNew.vout.size() - 1; // dont change first or last
6133 vector<CTxOut>::iterator position = txNew.vout.begin()+nDonationPosRet;
817ad14d 6134 txNew.vout.insert(position, newTxOut);
1bc74c28 6135 interest2 = 0;
6136 }
608252ed 6137 CAmount nChange = (nValueIn - nValue + interest2);
b7c685b8 6138 //fprintf(stderr,"wallet change %.8f (%.8f - %.8f) interest2 %.8f total %.8f\n",(double)nChange/COIN,(double)nValueIn/COIN,(double)nValue/COIN,(double)interest2/COIN,(double)nTotalValue/COIN);
292623ad
CL
6139 if (nSubtractFeeFromAmount == 0)
6140 nChange -= nFeeRet;
a7dd11c6
PW
6141
6142 if (nChange > 0)
e8ef3da7 6143 {
bf798734
GA
6144 // Fill a vout to ourself
6145 // TODO: pass in scriptChange instead of reservekey so
6146 // change transaction isn't always pay-to-bitcoin-address
e8ef3da7 6147 CScript scriptChange;
6a86c24d
CL
6148
6149 // coin control: send change to custom address
6150 if (coinControl && !boost::get<CNoDestination>(&coinControl->destChange))
0be990ba 6151 scriptChange = GetScriptForDestination(coinControl->destChange);
6a86c24d
CL
6152
6153 // no coin control: send change to newly generated address
6154 else
6155 {
6156 // Note: We use a new key here to keep it from being obvious which side is the change.
6157 // The drawback is that by not reusing a previous key, the change may be lost if a
6158 // backup is restored, if the backup doesn't have the new private key for the change.
6159 // If we reused the old key, it would be possible to add code to look for and
6160 // rediscover unknown transactions that were written with keys of ours to recover
6161 // post-backup change.
6162
6163 // Reserve a new key pair from key pool
6164 CPubKey vchPubKey;
3ec03ada 6165 extern int32_t USE_EXTERNAL_PUBKEY; extern std::string NOTARY_PUBKEY;
6166 if ( USE_EXTERNAL_PUBKEY == 0 )
6167 {
3ec03ada 6168 bool ret;
6169 ret = reservekey.GetReservedKey(vchPubKey);
6170 assert(ret); // should never fail, as we just unlocked
6171 scriptChange = GetScriptForDestination(vchPubKey.GetID());
6172 }
6173 else
6174 {
18c6cfce 6175 //fprintf(stderr,"use notary pubkey\n");
3ec03ada 6176 scriptChange = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG;
6177 }
6a86c24d 6178 }
e8ef3da7 6179
8de9bb53
GA
6180 CTxOut newTxOut(nChange, scriptChange);
6181
292623ad
CL
6182 // We do not move dust-change to fees, because the sender would end up paying more than requested.
6183 // This would be against the purpose of the all-inclusive feature.
6184 // So instead we raise the change and deduct from the recipient.
6185 if (nSubtractFeeFromAmount > 0 && newTxOut.IsDust(::minRelayTxFee))
6186 {
6187 CAmount nDust = newTxOut.GetDustThreshold(::minRelayTxFee) - newTxOut.nValue;
6188 newTxOut.nValue += nDust; // raise change until no more dust
6189 for (unsigned int i = 0; i < vecSend.size(); i++) // subtract from first recipient
6190 {
6191 if (vecSend[i].fSubtractFeeFromAmount)
6192 {
6193 txNew.vout[i].nValue -= nDust;
6194 if (txNew.vout[i].IsDust(::minRelayTxFee))
6195 {
6196 strFailReason = _("The transaction amount is too small to send after the fee has been deducted");
6197 return false;
6198 }
6199 break;
6200 }
6201 }
6202 }
6203
8de9bb53 6204 // Never create dust outputs; if we would, just
2f537fa1 6205 // add the dust to the fee. Valid cryptoconditions with a valid eval function are allowed to create outputs of 0
13fc83c7 6206 if (newTxOut.IsDust(::minRelayTxFee))
8de9bb53
GA
6207 {
6208 nFeeRet += nChange;
6209 reservekey.ReturnKey();
6210 }
6211 else
6212 {
429dabb5 6213 nChangePosRet = txNew.vout.size() - 1; // dont change first or last
292623ad 6214 vector<CTxOut>::iterator position = txNew.vout.begin()+nChangePosRet;
4949004d 6215 txNew.vout.insert(position, newTxOut);
8de9bb53 6216 }
f38345e9 6217 } else reservekey.ReturnKey();
e8ef3da7
WL
6218
6219 // Fill vin
ba7fcc8d
PT
6220 //
6221 // Note how the sequence number is set to max()-1 so that the
6222 // nLockTime set above actually works.
e8ef3da7 6223 BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
805344dc 6224 txNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second,CScript(),
ba7fcc8d 6225 std::numeric_limits<unsigned int>::max()-1));
989b1de1
MT
6226
6227 // Check mempooltxinputlimit to avoid creating a transaction which the local mempool rejects
6228 size_t limit = (size_t)GetArg("-mempooltxinputlimit", 0);
6229 {
6230 LOCK(cs_main);
88d014d0 6231 if (Params().GetConsensus().NetworkUpgradeActive(chainActive.Height() + 1, Consensus::UPGRADE_OVERWINTER)) {
989b1de1
MT
6232 limit = 0;
6233 }
6234 }
6235 if (limit > 0) {
6236 size_t n = txNew.vin.size();
6237 if (n > limit) {
6238 strFailReason = _(strprintf("Too many transparent inputs %zu > limit %zu", n, limit).c_str());
6239 return false;
6240 }
6241 }
6242
6243 // Grab the current consensus branch ID
6244 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
6245
6246 // Sign
6247 int nIn = 0;
6248 CTransaction txNewConst(txNew);
6249 BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
6250 {
6251 bool signSuccess;
6252 const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey;
6253 SignatureData sigdata;
6254 if (sign)
a4f9bc97 6255 signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, coin.first->vout[coin.second].nValue, scriptPubKey), scriptPubKey, sigdata, consensusBranchId);
989b1de1
MT
6256 else
6257 signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata, consensusBranchId);
6258
6259 if (!signSuccess)
6260 {
6261 strFailReason = _("Signing transaction failed");
6262 return false;
6263 } else {
6264 UpdateTransaction(txNew, nIn, sigdata);
6265 }
6266
6267 nIn++;
6268 }
6269
6270 unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION);
6271
6272 // Remove scriptSigs if we used dummy signatures for fee calculation
6273 if (!sign) {
6274 BOOST_FOREACH (CTxIn& vin, txNew.vin)
6275 vin.scriptSig = CScript();
6276 }
6277
6278 // Embed the constructed transaction data in wtxNew.
6279 *static_cast<CTransaction*>(&wtxNew) = CTransaction(txNew);
6280
6281 // Limit size
6282 if (nBytes >= max_tx_size)
6283 {
6284 strFailReason = _("Transaction too large");
6285 return false;
6286 }
6287
6288 dPriority = wtxNew.ComputePriority(dPriority, nBytes);
6289
6290 // Can we complete this as a free transaction?
6291 if (fSendFreeTransactions && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE)
6292 {
6293 // Not enough fee: enough priority?
6294 double dPriorityNeeded = mempool.estimatePriority(nTxConfirmTarget);
6295 // Not enough mempool history to estimate: use hard-coded AllowFree.
6296 if (dPriorityNeeded <= 0 && AllowFree(dPriority))
6297 break;
6298
6299 // Small enough, and priority high enough, to send for free
6300 if (dPriorityNeeded > 0 && dPriority >= dPriorityNeeded)
6301 break;
6302 }
6303
6304 CAmount nFeeNeeded = GetMinimumFee(nBytes, nTxConfirmTarget, mempool);
6305 if ( nFeeNeeded < 5000 )
6306 nFeeNeeded = 5000;
6307
6308 // If we made it here and we aren't even able to meet the relay fee on the next pass, give up
6309 // because we must be at the maximum allowed fee.
6310 if (nFeeNeeded < ::minRelayTxFee.GetFee(nBytes))
6311 {
6312 strFailReason = _("Transaction too large for fee policy");
6313 return false;
6314 }
6315
6316 if (nFeeRet >= nFeeNeeded)
6317 break; // Done, enough fee included.
6318
6319 // Include more fee and try again.
6320 nFeeRet = nFeeNeeded;
6321 continue;
6322 }
6323 }
6324 }
6325
6326 return true;
6327}
6328
56fe75cb 6329// almost the same as CreateTransaction with the difference being that input and output are assumed to be
6330// tokens/reserve currencies, not the native currency of this chain, represented as reserve outputs for both input and output.
6331// That means that all outputs must be reserve consuming outputs. Fee is added or converted from reserves if this is a
6332// fractional reserve chain. Fees are calculated based on the current reserve conversion price.
0f957664 6333int CWallet::CreateReserveTransaction(const vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet,
56fe75cb 6334 int& nChangePosRet, int &nChangeOutputs, std::string& strFailReason, const CCoinControl* coinControl,
6335 const CTxDestination *pOnlyFromDest, bool sign)
989b1de1 6336{
56fe75cb 6337 CCurrencyValueMap totalReserveOutput;
6338 CAmount totalNativeOutput = 0;
6339
6340 CCurrencyValueMap reserveCurrencies;
989b1de1
MT
6341 unsigned int nSubtractFeeFromAmount = 0;
6342
56fe75cb 6343 // fees can only be deducted from fractional reserve outputs on fractional currency blockchains, otherwise,
6344 // Verus/Verustest must be used to cover fees.
6345 bool isVerusActive = IsVerusActive();
2f416b17 6346 if (!isVerusActive)
56fe75cb 6347 {
6348 if (ConnectedChains.ReserveCurrencies().size())
6349 {
6350 for (auto &oneCur : ConnectedChains.ReserveCurrencies())
6351 {
6352 reserveCurrencies.valueMap[oneCur.first] = 1; // we're only testing for intersection, not value
6353 }
6354 }
6355 }
6356
6357 // make sure we have some outputs
6358 if (vecSend.empty())
6359 {
6360 strFailReason = _("Transaction must have outputs");
0f957664 6361 return RPC_INVALID_PARAMETER;
56fe75cb 6362 }
989b1de1 6363
2f416b17 6364 CCurrencyDefinition newCurrency;
6365
989b1de1
MT
6366 // make sure that there are recipients, all recipients expect reserve inputs, and amounts are all non-negative
6367 BOOST_FOREACH (const CRecipient& recipient, vecSend)
6368 {
2f416b17 6369 COptCCParams p;
6370 if (recipient.scriptPubKey.IsPayToCryptoCondition(p) && p.IsValid() && p.evalCode == EVAL_CURRENCY_DEFINITION && p.vData.size() >= 1)
6371 {
6372 if (newCurrency.IsValid())
6373 {
6374 strFailReason = _("A normal transaction cannot define define multiple currencies");
0f957664 6375 return RPC_INVALID_PARAMETER;
2f416b17 6376 }
6377 newCurrency = CCurrencyDefinition(p.vData[0]);
6378 }
56fe75cb 6379 CCurrencyValueMap values = recipient.scriptPubKey.ReserveOutValue();
6380 CCurrencyValueMap zeroes = values - values; // zero values of the same currencies
6381
6382 if (!values.IsValid())
989b1de1 6383 {
56fe75cb 6384 strFailReason = _("Output cannot have NULL currency type");
0f957664 6385 return RPC_INVALID_PARAMETER;
989b1de1 6386 }
56fe75cb 6387 if (values.HasNegative())
989b1de1 6388 {
56fe75cb 6389 strFailReason = _("Transaction output amounts must not be negative");
0f957664 6390 return RPC_INVALID_PARAMETER;
989b1de1 6391 }
2f416b17 6392
56fe75cb 6393 totalNativeOutput += recipient.nAmount;
f023c2d4 6394
56fe75cb 6395 totalReserveOutput += values;
f365e363 6396
56fe75cb 6397 // if we should take from this output, it must be able to pay the fee. fail if it does not
6398 if (recipient.fSubtractFeeFromAmount && (recipient.nAmount > 0 || reserveCurrencies.Intersects(values)))
6399 {
6400 nSubtractFeeFromAmount++;
6401 }
6402 else if (recipient.fSubtractFeeFromAmount)
989b1de1 6403 {
56fe75cb 6404 strFailReason = _("Cannot specify to subtract fee from amount on non-native, non-reserve currency outputs");
0f957664 6405 return RPC_INVALID_PARAMETER;
989b1de1 6406 }
f365e363 6407
56fe75cb 6408 // make sure we have no negative totals. we do not move this outside the loop, so we can check against overflow on every iteration
6409 if (totalReserveOutput.HasNegative())
989b1de1 6410 {
f365e363 6411 strFailReason = _("Transaction amounts must not be negative");
0f957664 6412 return RPC_INVALID_PARAMETER;
989b1de1 6413 }
989b1de1
MT
6414 }
6415
2f416b17 6416 if (newCurrency.IsValid())
6417 {
6418 totalReserveOutput.valueMap.erase(newCurrency.GetID());
6419 }
6420
f023c2d4 6421 //printf("totalReserveOutput: %s\n", totalReserveOutput.ToUniValue().write(1,2).c_str());
6422
989b1de1 6423 int nextBlockHeight = chainActive.Height() + 1;
401e75b1 6424
989b1de1 6425 CMutableTransaction txNew = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextBlockHeight);
401e75b1 6426
6427 std::vector<CTxIn> extraInputs = wtxNew.vin;
6428
6429 wtxNew.fTimeReceivedIsTxTime = true;
6430 wtxNew.BindWallet(this);
989b1de1
MT
6431 txNew.nLockTime = (uint32_t)chainActive.LastTip()->nTime + 1; // set to a time close to now
6432
9bb37bf0 6433 // Activates after Overwinter network upgrade
2c6c5526 6434 if (Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_OVERWINTER)) {
fa70084c 6435 if (txNew.nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD){
14556680 6436 strFailReason = "nExpiryHeight must be less than" + std::to_string((uint32_t)TX_EXPIRY_HEIGHT_THRESHOLD);
0f957664 6437 return RPC_INVALID_PARAMETER;
9bb37bf0 6438 }
989b1de1
MT
6439 }
6440
6441 unsigned int max_tx_size = MAX_TX_SIZE_AFTER_SAPLING;
2c6c5526 6442 if (!Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_SAPLING)) {
15ec5525
JG
6443 max_tx_size = MAX_TX_SIZE_BEFORE_SAPLING;
6444 }
989b1de1
MT
6445
6446 // Discourage fee sniping.
6447 //
6448 // However because of a off-by-one-error in previous versions we need to
6449 // neuter it by setting nLockTime to at least one less than nBestHeight.
6450 // Secondly currently propagation of transactions created for block heights
6451 // corresponding to blocks that were just mined may be iffy - transactions
6452 // aren't re-accepted into the mempool - we additionally neuter the code by
6453 // going ten blocks back. Doesn't yet do anything for sniping, but does act
6454 // to shake out wallet bugs like not showing nLockTime'd transactions at
6455 // all.
6456 txNew.nLockTime = std::max(0, chainActive.Height() - 10);
6457
6458 // Secondly occasionally randomly pick a nLockTime even further back, so
6459 // that transactions that are delayed after signing for whatever reason,
6460 // e.g. high-latency mix networks and some CoinJoin implementations, have
6461 // better privacy.
6462 if (GetRandInt(10) == 0)
6463 txNew.nLockTime = std::max(0, (int)txNew.nLockTime - GetRandInt(100));
6464
6465 assert(txNew.nLockTime <= (unsigned int)chainActive.Height());
6466 assert(txNew.nLockTime < LOCKTIME_THRESHOLD);
6467
56fe75cb 6468 CCurrencyValueMap exchangeRates;
989b1de1
MT
6469 {
6470 LOCK2(cs_main, cs_wallet);
56fe75cb 6471
1fb6db72 6472 auto currencyState = ConnectedChains.GetCurrencyState(nextBlockHeight - 1);
6473 for (int i = 0; i < currencyState.currencies.size(); i++)
6474 {
6475 exchangeRates.valueMap[currencyState.currencies[i]] = currencyState.PriceInReserve(i);
6476 }
56fe75cb 6477
1fb6db72 6478 nFeeRet = 5000;
6479 while (true)
6480 {
6481 //interest = 0;
6482 txNew.vin.clear();
6483 txNew.vout.clear();
6484 wtxNew.fFromMe = true;
6485 nChangePosRet = -1;
6486 nChangeOutputs = 0;
6487 bool fFirst = true;
6488
6489 // dust threshold of reserve may be different than native coin, if so, convert
6490 CAmount dustThreshold;
6491
6492 CAmount nTotalNativeValue = totalNativeOutput;
6493 CCurrencyValueMap totalReserveValue = totalReserveOutput;
6494
6495 if (nSubtractFeeFromAmount == 0)
6496 nTotalNativeValue += nFeeRet;
6497
6498 double dPriority = 0;
6499 // vouts to the payees
6500 BOOST_FOREACH (const CRecipient& recipient, vecSend)
6501 {
6502 // native output value for a reserve output is generally 0. fees are paid by converting from
6503 // reserve token and the difference between input and output in reserve is the fee
6504 // the actual reserve token output value is in the scriptPubKey
6505 CTxOut txout(recipient.nAmount, recipient.scriptPubKey);
6506 CAmount nativeEquivalent = txout.nValue;
6507
6508 // here, if we know that it isn't an opret, it will have an output that expects input
6509 if (!recipient.scriptPubKey.IsOpReturn())
989b1de1 6510 {
1fb6db72 6511 COptCCParams p;
6512 CCurrencyValueMap reserveOutput = recipient.scriptPubKey.ReserveOutValue(p);
6513 CCurrencyValueMap relevantReserves;
989b1de1 6514
1fb6db72 6515 if (recipient.fSubtractFeeFromAmount)
989b1de1 6516 {
1fb6db72 6517 CAmount subFee = nFeeRet / nSubtractFeeFromAmount; // Subtract fee equally from each selected recipient
989b1de1 6518
1fb6db72 6519 if (fFirst) // first receiver pays the remainder not divisible by output count
989b1de1 6520 {
1fb6db72 6521 fFirst = false;
6522 subFee += nFeeRet % nSubtractFeeFromAmount;
6523 }
989b1de1 6524
1fb6db72 6525 if (subFee <= txout.nValue)
6526 {
6527 txout.nValue -= subFee;
6528 }
6529 else if ((relevantReserves = reserveOutput.IntersectingValues(reserveCurrencies)).valueMap.size())
6530 {
6531 // if we will subtract from more than one currency, divide fee among them equally
6532 CAmount subSubFee = subFee / relevantReserves.valueMap.size();
6533 CAmount extraFee = subFee % relevantReserves.valueMap.size();
6534 // TODO: this does not support multi-currency, since the outputs do not. it will need
6535 // to be checked when we enable multi-currency outputs
6536 for (auto &oneCur : relevantReserves.valueMap)
56fe75cb 6537 {
1fb6db72 6538 auto it = exchangeRates.valueMap.find(oneCur.first);
6539 assert(it != exchangeRates.valueMap.end());
6540 reserveOutput.valueMap[it->first] -= currencyState.NativeToReserveRaw(subFee + (extraFee ? 1 : 0), it->second);
6541 if (extraFee)
989b1de1 6542 {
1fb6db72 6543 extraFee--;
989b1de1 6544 }
989b1de1 6545 }
1fb6db72 6546 txout.scriptPubKey.SetReserveOutValue(reserveOutput);
6547 }
6548 else
6549 {
6550 // asking to pay a fee on an output, but not being able to is not accepted, should
6551 // never get here, as it should have been checked above
6552 strFailReason = "Cannot subtract fee from amount on non-native, non-reserve currency outputs";
6553 return RPC_INVALID_PARAMETER;
989b1de1 6554 }
1fb6db72 6555 }
989b1de1 6556
1fb6db72 6557 dustThreshold = txout.GetDustThreshold(::minRelayTxFee);
989b1de1 6558
1fb6db72 6559 // only non-crypto condition, and normal reserve outputs are subject to dust limitations
6560 if (!p.IsValid() ||
6561 p.evalCode == EVAL_RESERVE_OUTPUT ||
6562 p.evalCode == EVAL_RESERVE_DEPOSIT ||
6563 p.evalCode == EVAL_RESERVE_EXCHANGE ||
6564 p.evalCode == EVAL_NONE)
6565 {
6566 // add all values to a native equivalent
6567 // reserve currencies have a native value as well
6568 if (exchangeRates.IntersectingValues(reserveOutput).valueMap.size())
989b1de1 6569 {
1fb6db72 6570 nativeEquivalent += currencyState.ReserveToNativeRaw(relevantReserves, exchangeRates.AsCurrencyVector(currencyState.currencies));
6571 }
6572 else
6573 {
6574 nativeEquivalent += reserveOutput.valueMap.size() ? reserveOutput.valueMap.begin()->second : 0;
6575 }
6576
6577 if (nativeEquivalent < dustThreshold)
6578 {
6579 if (recipient.fSubtractFeeFromAmount && nFeeRet > 0)
989b1de1 6580 {
1fb6db72 6581 if (nativeEquivalent < 0)
6582 strFailReason = _("The transaction amount is too small to pay the fee");
989b1de1 6583 else
1fb6db72 6584 strFailReason = _("The transaction amount is too small to send after the fee has been deducted");
989b1de1 6585 }
1fb6db72 6586 else
6587 strFailReason = _("Transaction amount too small");
6588 return RPC_INVALID_PARAMETER;
989b1de1
MT
6589 }
6590 }
989b1de1 6591 }
1fb6db72 6592 txNew.vout.push_back(txout);
6593 }
989b1de1 6594
1fb6db72 6595 // Choose coins to use
6596 set<pair<const CWalletTx*,unsigned int> > setCoins;
6597 CCurrencyValueMap totalValueIn;
6598 CAmount totalNativeValueIn = 0;
6599 bool fOnlyCoinbaseCoins = false;
6600 bool fNeedCoinbaseCoins = false;
6601
6602 if (!SelectReserveCoins(totalReserveValue,
6603 nTotalNativeValue,
6604 setCoins,
6605 totalValueIn,
6606 totalNativeValueIn,
6607 fOnlyCoinbaseCoins,
6608 fNeedCoinbaseCoins,
6609 coinControl,
6610 pOnlyFromDest))
6611 {
6612 strFailReason = _("Insufficient funds");
6613 return RPC_WALLET_INSUFFICIENT_FUNDS;
6614 }
56fe75cb 6615
1fb6db72 6616 /*
6617 if (totalValueIn.valueMap.count(ASSETCHAINS_CHAINID))
6618 {
6619 for (auto oneOut : setCoins)
7beb1c0b 6620 {
1fb6db72 6621 UniValue oneTxObj(UniValue::VOBJ);
6622 TxToUniv(*oneOut.first, uint256(), oneTxObj);
6623 printf("TRANSACTION\n%s\n", oneTxObj.write(1,2).c_str());
7beb1c0b 6624 }
1fb6db72 6625 printf("totalValueIn: %s\ntotalReserveValue: %s\n", totalValueIn.ToUniValue().write().c_str(), totalReserveValue.ToUniValue().write().c_str());
6626 }
6627 */
56a7b665 6628
1fb6db72 6629 std::vector<std::pair<std::pair<const CWalletTx*, unsigned int>, CAmount>> coinsWithEquivalentNative;
6630 if (reserveCurrencies.valueMap.size())
6631 {
6632 BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
989b1de1 6633 {
1fb6db72 6634 CAmount nCredit = pcoin.first->vout[pcoin.second].nValue +
6635 currencyState.ReserveToNativeRaw(reserveCurrencies.IntersectingValues(pcoin.first->vout[pcoin.second].ReserveOutValue()),
6636 exchangeRates.AsCurrencyVector(currencyState.currencies));
6637 coinsWithEquivalentNative.push_back(make_pair(pcoin, nCredit));
989b1de1 6638 }
1fb6db72 6639 }
989b1de1 6640
1fb6db72 6641 CCurrencyValueMap reserveChange = totalValueIn - totalReserveValue;
f023c2d4 6642
1fb6db72 6643 //printf("reservechange: %s\ntotalvaluein: %s\n", reserveChange.ToUniValue().write(1,2).c_str(), totalValueIn.ToUniValue().write(1,2).c_str());
f023c2d4 6644
1fb6db72 6645 CCurrencyValueMap convertibleChange = reserveCurrencies.IntersectingValues(reserveChange);
6646 CAmount nChange = totalNativeValueIn - nTotalNativeValue;
6647 CAmount nConvertedReserveChange = 0;
989b1de1 6648
1fb6db72 6649 // /printf("tokenChange: %s\nnativeChange: %s\n", reserveChange.ToUniValue().write().c_str(), ValueFromAmount(nChange).write().c_str());
56a7b665 6650
1fb6db72 6651 // if we will try to take the fee from change
6652 if (nSubtractFeeFromAmount == 0)
6653 {
6654 if (nChange < nFeeRet && convertibleChange.valueMap.size())
56fe75cb 6655 {
1fb6db72 6656 nConvertedReserveChange = currencyState.ReserveToNativeRaw(convertibleChange,
6657 exchangeRates.AsCurrencyVector(currencyState.currencies));
56fe75cb 6658 }
1fb6db72 6659 nChange -= nFeeRet;
6660 }
989b1de1 6661
1fb6db72 6662 if ((nChange + nConvertedReserveChange > 0) || (reserveChange > CCurrencyValueMap()))
6663 {
6664 // if we can and need to convert reserves, adjust reserve change output amounts as needed
6665 if (nChange < 0 && convertibleChange.valueMap.size())
989b1de1 6666 {
1fb6db72 6667 // no native change output, so, convert what's needed and make reserve output(s)
6668 // attempt to convert equally across currencies, and if we fail, take the rest as
6669 // first come, first served
6670 CAmount nChangePerCur = -nChange / convertibleChange.valueMap.size();
6671 CAmount nChangeMod = -nChange % convertibleChange.valueMap.size();
6672 CAmount remainder = 0;
6673 nChange = 0;
6674 for (int i = 0; i < currencyState.currencies.size(); i++)
6675 {
6676 auto it = reserveChange.valueMap.find(currencyState.currencies[i]);
6677 if (it != reserveChange.valueMap.end())
6678 {
6679 CAmount feeAsReserve = currencyState.NativeToReserve(nChangePerCur + (nChangeMod ? 1 : 0), i);
6680 if (it->second - feeAsReserve <= 0)
6681 {
6682 // if we don't have enough reserve in this currency for its part of the fee, we will
6683 // take it all, and then take more from the other currencies as needed
6684 remainder += currencyState.ReserveToNative(feeAsReserve - it->second, i);
6685 reserveChange.valueMap.erase(it);
6686 }
6687 else
6688 {
6689 it->second -= feeAsReserve;
6690 }
6691 }
6692 }
6693 // if we have any fee left to convert because we were short on some currency, take it
6694 // from the remaining reserves in change
6695 if (remainder)
56fe75cb 6696 {
56fe75cb 6697 for (int i = 0; i < currencyState.currencies.size(); i++)
6698 {
6699 auto it = reserveChange.valueMap.find(currencyState.currencies[i]);
6700 if (it != reserveChange.valueMap.end())
6701 {
1fb6db72 6702 CAmount feeAsReserve = currencyState.NativeToReserve(remainder, i);
56fe75cb 6703 if (it->second - feeAsReserve <= 0)
6704 {
6705 // if we don't have enough reserve in this currency for its part of the fee, we will
6706 // take it all, and then take more from the other currencies as needed
56fe75cb 6707 reserveChange.valueMap.erase(it);
1fb6db72 6708 remainder -= currencyState.ReserveToNative(it->second, i);
56fe75cb 6709 }
6710 else
6711 {
6712 it->second -= feeAsReserve;
1fb6db72 6713 break;
56fe75cb 6714 }
6715 }
6716 }
6717 }
1fb6db72 6718 }
989b1de1 6719
1fb6db72 6720 // coin control: send change to custom address
989b1de1 6721
1fb6db72 6722 // reserve tokens can currently only be sent to public keys or addresses that are in the current wallet
6723 // since reserve token outputs are CCs by definition
6724 CTxDestination changeDest;
6725 if (coinControl && coinControl->destChange.which() != COptCCParams::ADDRTYPE_INVALID)
6726 {
6727 changeDest = coinControl->destChange;
6728 }
6729 else
6730 {
6731 // no coin control: send change to newly generated address
6732
6733 // Note: We use a new key here to keep it from being obvious which side is the change.
6734 // The drawback is that by not reusing a previous key, the change may be lost if a
6735 // backup is restored, if the backup doesn't have the new private key for the change.
6736 // If we reused the old key, it would be possible to add code to look for and
6737 // rediscover unknown transactions that were written with keys of ours to recover
6738 // post-backup change.
6739
6740 // Reserve a new key pair from key pool
6741 extern int32_t USE_EXTERNAL_PUBKEY; extern std::string NOTARY_PUBKEY;
6742 CPubKey pubKey;
44ac8ad4 6743 if ( USE_EXTERNAL_PUBKEY != 0 )
989b1de1 6744 {
44ac8ad4 6745 //fprintf(stderr,"use notary pubkey\n");
6746 pubKey = CPubKey(ParseHex(NOTARY_PUBKEY));
0fa1bca8 6747 changeDest = CTxDestination(pubKey);
6748 }
6749 else if (pOnlyFromDest && pOnlyFromDest->which() == COptCCParams::ADDRTYPE_ID)
6750 {
6751 changeDest = *pOnlyFromDest;
989b1de1
MT
6752 }
6753 else
6754 {
44ac8ad4 6755 bool ret;
6756 ret = reservekey.GetReservedKey(pubKey);
6757 assert(ret); // should never fail, as we just unlocked
0fa1bca8 6758 changeDest = CTxDestination(pubKey);
989b1de1 6759 }
1fb6db72 6760 }
989b1de1 6761
1fb6db72 6762 // generate all necessary change outputs for all currencies
6763 // first determine if any outputs left are dust. if so, just add them to the fee
6764 if (nChange < dustThreshold)
6765 {
6766 nFeeRet += nChange;
6767 nChange = 0;
6768 }
6769 else
6770 {
6771 nChangePosRet = txNew.vout.size() - 1; // dont change first or last
6772 nChangeOutputs++;
6773 vector<CTxOut>::iterator position = txNew.vout.begin() + nChangePosRet;
6774 txNew.vout.insert(position, CTxOut(nChange, GetScriptForDestination(changeDest)));
6775 }
6776
6777 // now, loop through the remaining reserve currencies and make a change output for each
6778 // if dust, just remove
6779 auto reserveIndexMap = currencyState.GetReserveMap();
6780 for (auto &curChangeOut : reserveChange.valueMap)
6781 {
6782 CAmount outVal;
6783 assert(curChangeOut.first != ASSETCHAINS_CHAINID);
6784 auto curIt = reserveIndexMap.find(curChangeOut.first);
6785 if (curIt != reserveIndexMap.end())
989b1de1 6786 {
1fb6db72 6787 outVal = currencyState.ReserveToNative(curChangeOut.second, curIt->second);
56fe75cb 6788 }
6789 else
6790 {
1fb6db72 6791 outVal = curChangeOut.second;
56fe75cb 6792 }
1fb6db72 6793
6794 if (outVal >= dustThreshold)
56fe75cb 6795 {
1fb6db72 6796 vector<CTxOut>::iterator position = txNew.vout.begin() + (nChangePosRet + nChangeOutputs++);
6797 CTokenOutput to = CTokenOutput(curChangeOut.first, curChangeOut.second);
6798 txNew.vout.insert(position, CTxOut(0, MakeMofNCCScript(CConditionObj<CTokenOutput>(EVAL_RESERVE_OUTPUT, {changeDest}, 1, &to))));
989b1de1 6799 }
1fb6db72 6800 // if it is dust and we cannot convert to native, drop it. it may be taken by the miner
6801 else if (curIt != reserveIndexMap.end())
989b1de1 6802 {
1fb6db72 6803 nFeeRet += outVal;
989b1de1 6804 }
1fb6db72 6805 }
989b1de1 6806
1fb6db72 6807 // if we made no change outputs, return the key
6808 if (!nChangeOutputs)
401e75b1 6809 {
1fb6db72 6810 reservekey.ReturnKey();
401e75b1 6811 }
1fb6db72 6812 } else reservekey.ReturnKey();
e8ef3da7 6813
1fb6db72 6814 // Fill vin
6815 //
6816 // Note how the sequence number is set to max()-1 so that the
6817 // nLockTime set above actually works.
6818 for (auto &oneIn : extraInputs)
6819 {
6820 auto wit = mapWallet.find(oneIn.prevout.hash);
6821 if (wit != mapWallet.end() &&
6822 wit->second.vout.size() > oneIn.prevout.n &&
6823 !wit->second.vout[oneIn.prevout.n].nValue &&
6824 wit->second.vout[oneIn.prevout.n].ReserveOutValue() == CCurrencyValueMap())
31afbcc5 6825 {
1fb6db72 6826 setCoins.insert(std::make_pair(&(wit->second), oneIn.prevout.n));
31afbcc5 6827 }
1fb6db72 6828 else
aa30f655 6829 {
1fb6db72 6830 setCoins.clear();
6831 break;
aa30f655 6832 }
1fb6db72 6833 }
6834 BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
6835 txNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second,CScript(),
6836 std::numeric_limits<unsigned int>::max()-1));
aa30f655 6837
1fb6db72 6838 // Check mempooltxinputlimit to avoid creating a transaction which the local mempool rejects
6839 size_t limit = (size_t)GetArg("-mempooltxinputlimit", 0);
6840 {
6841 LOCK(cs_main);
6842 if (Params().GetConsensus().NetworkUpgradeActive(chainActive.Height() + 1, Consensus::UPGRADE_OVERWINTER)) {
6843 limit = 0;
6844 }
6845 }
6846 if (limit > 0) {
6847 size_t n = txNew.vin.size();
6848 if (n > limit) {
6849 strFailReason = _(strprintf("Too many transparent inputs %zu > limit %zu", n, limit).c_str());
6850 return RPC_INVALID_PARAMETER;
aa30f655 6851 }
1fb6db72 6852 }
e8ef3da7 6853
1fb6db72 6854 // Grab the current consensus branch ID
6855 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
4949004d 6856
1fb6db72 6857 // Sign
6858 int nIn = 0;
6859 CTransaction txNewConst(txNew);
6860 BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
6861 {
6862 bool signSuccess;
6863 const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey;
6864 SignatureData sigdata;
6865 if (sign)
6866 signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, coin.first->vout[coin.second].nValue, scriptPubKey), scriptPubKey, sigdata, consensusBranchId);
6867 else
6868 signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata, consensusBranchId);
6869
6870 if (!signSuccess)
1f00f4e9 6871 {
1fb6db72 6872 strFailReason = _("Signing transaction failed");
0f957664 6873 return RPC_TRANSACTION_ERROR;
1fb6db72 6874 } else {
6875 UpdateTransaction(txNew, nIn, sigdata);
1f00f4e9 6876 }
aa30f655 6877
1fb6db72 6878 nIn++;
6879 }
e8ef3da7 6880
1fb6db72 6881 unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION);
aa279d61 6882
1fb6db72 6883 // Remove scriptSigs if we used dummy signatures for fee calculation
6884 if (!sign) {
6885 BOOST_FOREACH (CTxIn& vin, txNew.vin)
6886 vin.scriptSig = CScript();
6887 }
b33d1f5e 6888
1fb6db72 6889 // Embed the constructed transaction data in wtxNew.
6890 *static_cast<CTransaction*>(&wtxNew) = CTransaction(txNew);
b33d1f5e 6891
1fb6db72 6892 // Limit size
6893 if (nBytes >= max_tx_size)
6894 {
6895 strFailReason = _("Transaction too large");
6896 return RPC_TRANSACTION_ERROR;
6897 }
e8ef3da7 6898
1fb6db72 6899 dPriority = wtxNew.ComputePriority(dPriority, nBytes);
b33d1f5e 6900
1fb6db72 6901 // Can we complete this as a free transaction?
6902 if (fSendFreeTransactions && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE)
6903 {
6904 // Not enough fee: enough priority?
6905 double dPriorityNeeded = mempool.estimatePriority(nTxConfirmTarget);
6906 // Not enough mempool history to estimate: use hard-coded AllowFree.
6907 if (dPriorityNeeded <= 0 && AllowFree(dPriority))
6908 break;
6909
6910 // Small enough, and priority high enough, to send for free
6911 if (dPriorityNeeded > 0 && dPriority >= dPriorityNeeded)
6912 break;
6913 }
6914
6915 CAmount nFeeNeeded = GetMinimumFee(nBytes, nTxConfirmTarget, mempool);
6916 if ( nFeeNeeded < 5000 )
6917 nFeeNeeded = 5000;
6918
6919 // If we made it here and we aren't even able to meet the relay fee on the next pass, give up
6920 // because we must be at the maximum allowed fee.
6921 if (nFeeNeeded < ::minRelayTxFee.GetFee(nBytes))
6922 {
6923 strFailReason = _("Transaction too large for fee policy");
6924 return RPC_TRANSACTION_ERROR;
e8ef3da7 6925 }
1fb6db72 6926
6927 if (nFeeRet >= nFeeNeeded)
6928 break; // Done, enough fee included.
6929
6930 // Include more fee and try again.
6931 nFeeRet = nFeeNeeded;
6932 continue;
e8ef3da7
WL
6933 }
6934 }
79e34907 6935 return RPC_OK;
e8ef3da7
WL
6936}
6937
5b40d886
MF
6938/**
6939 * Call after CreateTransaction unless you want to abort
6940 */
3220d993 6941bool CWallet::CommitTransaction(CWalletTx& wtxNew, boost::optional<CReserveKey&> reservekey)
e8ef3da7 6942{
e8ef3da7 6943 {
f8dcd5ca 6944 LOCK2(cs_main, cs_wallet);
7d9d134b 6945 LogPrintf("CommitTransaction:\n%s", wtxNew.ToString());
e8ef3da7
WL
6946 {
6947 // This is only to keep the database open to defeat the auto-flush for the
6948 // duration of this scope. This is the only place where this optimization
6949 // maybe makes sense; please don't do it anywhere else.
44bc988e 6950 CWalletDB* pwalletdb = fFileBacked ? new CWalletDB(strWalletFile,"r+") : NULL;
e8ef3da7 6951
3220d993
E
6952 if (reservekey) {
6953 // Take key pair from key pool so it won't be used again
6954 reservekey.get().KeepKey();
6955 }
e8ef3da7
WL
6956
6957 // Add tx to wallet, because if it has change it's also ours,
6958 // otherwise just for transaction history.
44bc988e 6959 AddToWallet(wtxNew, false, pwalletdb);
e8ef3da7 6960
93a18a36 6961 // Notify that old coins are spent
e8ef3da7
WL
6962 set<CWalletTx*> setCoins;
6963 BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
6964 {
6965 CWalletTx &coin = mapWallet[txin.prevout.hash];
4c6e2295 6966 coin.BindWallet(this);
805344dc 6967 NotifyTransactionChanged(this, coin.GetHash(), CT_UPDATED);
e8ef3da7
WL
6968 }
6969
6970 if (fFileBacked)
6971 delete pwalletdb;
6972 }
6973
6974 // Track how many getdata requests our transaction gets
805344dc 6975 mapRequestCount[wtxNew.GetHash()] = 0;
e8ef3da7 6976
6f252627 6977 if (fBroadcastTransactions)
e8ef3da7 6978 {
6f252627
WL
6979 // Broadcast
6980 if (!wtxNew.AcceptToMemoryPool(false))
6981 {
68c266b2 6982 fprintf(stderr,"commit failed\n");
83a426bc 6983 // This must not fail. The transaction has already been signed and recorded.
7ff9d122 6984 LogPrintf("CommitTransaction(): Error: Transaction not valid\n");
6f252627
WL
6985 return false;
6986 }
6987 wtxNew.RelayWalletTransaction();
e8ef3da7 6988 }
e8ef3da7 6989 }
e8ef3da7
WL
6990 return true;
6991}
6992
a372168e 6993CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool)
b33d1f5e
GA
6994{
6995 // payTxFee is user-set "I want to pay this much"
a372168e 6996 CAmount nFeeNeeded = payTxFee.GetFee(nTxBytes);
c1c9d5b4
CL
6997 // user selected total at least (default=true)
6998 if (fPayAtLeastCustomFee && nFeeNeeded > 0 && nFeeNeeded < payTxFee.GetFeePerK())
6999 nFeeNeeded = payTxFee.GetFeePerK();
b33d1f5e
GA
7000 // User didn't set: use -txconfirmtarget to estimate...
7001 if (nFeeNeeded == 0)
7002 nFeeNeeded = pool.estimateFee(nConfirmTarget).GetFee(nTxBytes);
7003 // ... unless we don't have enough mempool data, in which case fall
7004 // back to a hard-coded fee
7005 if (nFeeNeeded == 0)
13fc83c7 7006 nFeeNeeded = minTxFee.GetFee(nTxBytes);
aa279d61
GM
7007 // prevent user from paying a non-sense fee (like 1 satoshi): 0 < fee < minRelayFee
7008 if (nFeeNeeded < ::minRelayTxFee.GetFee(nTxBytes))
7009 nFeeNeeded = ::minRelayTxFee.GetFee(nTxBytes);
7010 // But always obey the maximum
7011 if (nFeeNeeded > maxTxFee)
7012 nFeeNeeded = maxTxFee;
b33d1f5e
GA
7013 return nFeeNeeded;
7014}
7015
e8ef3da7 7016
cf53fd7c 7017void komodo_prefetch(FILE *fp);
e8ef3da7 7018
eed1785f 7019DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
e8ef3da7
WL
7020{
7021 if (!fFileBacked)
4f76be1d 7022 return DB_LOAD_OK;
e8ef3da7 7023 fFirstRunRet = false;
e86c03cf 7024 if ( 0 ) // doesnt help
cf53fd7c 7025 {
e86c03cf 7026 fprintf(stderr,"loading wallet %s %u\n",strWalletFile.c_str(),(uint32_t)time(NULL));
cf53fd7c 7027 FILE *fp;
7028 if ( (fp= fopen(strWalletFile.c_str(),"rb")) != 0 )
7029 {
7030 komodo_prefetch(fp);
7031 fclose(fp);
7032 }
7033 }
e86c03cf 7034 //fprintf(stderr,"prefetched wallet %s %u\n",strWalletFile.c_str(),(uint32_t)time(NULL));
eed1785f 7035 DBErrors nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this);
e86c03cf 7036 //fprintf(stderr,"loaded wallet %s %u\n",strWalletFile.c_str(),(uint32_t)time(NULL));
d764d916 7037 if (nLoadWalletRet == DB_NEED_REWRITE)
9e9869d0 7038 {
d764d916
GA
7039 if (CDB::Rewrite(strWalletFile, "\x04pool"))
7040 {
012ca1c9 7041 LOCK(cs_wallet);
d764d916
GA
7042 setKeyPool.clear();
7043 // Note: can't top-up keypool here, because wallet is locked.
7044 // User will be prompted to unlock wallet the next operation
c6de7c35 7045 // that requires a new key.
d764d916 7046 }
9e9869d0
PW
7047 }
7048
7ec55267
MC
7049 if (nLoadWalletRet != DB_LOAD_OK)
7050 return nLoadWalletRet;
fd61d6f5 7051 fFirstRunRet = !vchDefaultKey.IsValid();
e8ef3da7 7052
39278369
CL
7053 uiInterface.LoadWallet(this);
7054
116df55e 7055 return DB_LOAD_OK;
e8ef3da7
WL
7056}
7057
ae3d0aba 7058
77cbd462 7059DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
518f3bda
JG
7060{
7061 if (!fFileBacked)
7062 return DB_LOAD_OK;
77cbd462 7063 DBErrors nZapWalletTxRet = CWalletDB(strWalletFile,"cr+").ZapWalletTx(this, vWtx);
518f3bda
JG
7064 if (nZapWalletTxRet == DB_NEED_REWRITE)
7065 {
7066 if (CDB::Rewrite(strWalletFile, "\x04pool"))
7067 {
7068 LOCK(cs_wallet);
7069 setKeyPool.clear();
7070 // Note: can't top-up keypool here, because wallet is locked.
7071 // User will be prompted to unlock wallet the next operation
5b40d886 7072 // that requires a new key.
518f3bda
JG
7073 }
7074 }
7075
7076 if (nZapWalletTxRet != DB_LOAD_OK)
7077 return nZapWalletTxRet;
7078
7079 return DB_LOAD_OK;
7080}
7081
7082
a41d5fe0 7083bool CWallet::SetAddressBook(const CTxDestination& address, const string& strName, const string& strPurpose)
ae3d0aba 7084{
ca4cf5cf
GA
7085 bool fUpdated = false;
7086 {
7087 LOCK(cs_wallet); // mapAddressBook
7088 std::map<CTxDestination, CAddressBookData>::iterator mi = mapAddressBook.find(address);
7089 fUpdated = mi != mapAddressBook.end();
7090 mapAddressBook[address].name = strName;
7091 if (!strPurpose.empty()) /* update purpose only if requested */
7092 mapAddressBook[address].purpose = strPurpose;
7093 }
8d657a65 7094 NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address) != ISMINE_NO,
ca4cf5cf 7095 strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) );
ae3d0aba
WL
7096 if (!fFileBacked)
7097 return false;
07444da1 7098 if (!strPurpose.empty() && !CWalletDB(strWalletFile).WritePurpose(EncodeDestination(address), strPurpose))
a41d5fe0 7099 return false;
07444da1 7100 return CWalletDB(strWalletFile).WriteName(EncodeDestination(address), strName);
ae3d0aba
WL
7101}
7102
a41d5fe0 7103bool CWallet::DelAddressBook(const CTxDestination& address)
ae3d0aba 7104{
b10e1470 7105 {
ca4cf5cf
GA
7106 LOCK(cs_wallet); // mapAddressBook
7107
7108 if(fFileBacked)
b10e1470 7109 {
ca4cf5cf 7110 // Delete destdata tuples associated with address
07444da1 7111 std::string strAddress = EncodeDestination(address);
ca4cf5cf
GA
7112 BOOST_FOREACH(const PAIRTYPE(string, string) &item, mapAddressBook[address].destdata)
7113 {
7114 CWalletDB(strWalletFile).EraseDestData(strAddress, item.first);
7115 }
b10e1470 7116 }
ca4cf5cf 7117 mapAddressBook.erase(address);
b10e1470
WL
7118 }
7119
8d657a65 7120 NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address) != ISMINE_NO, "", CT_DELETED);
ca4cf5cf 7121
ae3d0aba
WL
7122 if (!fFileBacked)
7123 return false;
07444da1
PW
7124 CWalletDB(strWalletFile).ErasePurpose(EncodeDestination(address));
7125 return CWalletDB(strWalletFile).EraseName(EncodeDestination(address));
ae3d0aba
WL
7126}
7127
fd61d6f5 7128bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
ae3d0aba
WL
7129{
7130 if (fFileBacked)
7131 {
7132 if (!CWalletDB(strWalletFile).WriteDefaultKey(vchPubKey))
7133 return false;
7134 }
7135 vchDefaultKey = vchPubKey;
7136 return true;
7137}
7138
5b40d886
MF
7139/**
7140 * Mark old keypool keys as used,
efb7662d 7141 * and generate all new keys
5b40d886 7142 */
37971fcc
GA
7143bool CWallet::NewKeyPool()
7144{
37971fcc 7145 {
f8dcd5ca 7146 LOCK(cs_wallet);
37971fcc 7147 CWalletDB walletdb(strWalletFile);
51ed9ec9 7148 BOOST_FOREACH(int64_t nIndex, setKeyPool)
37971fcc
GA
7149 walletdb.ErasePool(nIndex);
7150 setKeyPool.clear();
7151
7152 if (IsLocked())
7153 return false;
7154
51ed9ec9 7155 int64_t nKeys = max(GetArg("-keypool", 100), (int64_t)0);
37971fcc
GA
7156 for (int i = 0; i < nKeys; i++)
7157 {
51ed9ec9 7158 int64_t nIndex = i+1;
37971fcc
GA
7159 walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey()));
7160 setKeyPool.insert(nIndex);
7161 }
f48742c2 7162 LogPrintf("CWallet::NewKeyPool wrote %d new keys\n", nKeys);
37971fcc
GA
7163 }
7164 return true;
7165}
7166
13dd2d09 7167bool CWallet::TopUpKeyPool(unsigned int kpSize)
e8ef3da7 7168{
e8ef3da7 7169 {
f8dcd5ca
PW
7170 LOCK(cs_wallet);
7171
4e87d341
MC
7172 if (IsLocked())
7173 return false;
7174
e8ef3da7
WL
7175 CWalletDB walletdb(strWalletFile);
7176
7177 // Top up key pool
13dd2d09
JG
7178 unsigned int nTargetSize;
7179 if (kpSize > 0)
7180 nTargetSize = kpSize;
7181 else
51ed9ec9 7182 nTargetSize = max(GetArg("-keypool", 100), (int64_t) 0);
13dd2d09 7183
faf705a4 7184 while (setKeyPool.size() < (nTargetSize + 1))
e8ef3da7 7185 {
51ed9ec9 7186 int64_t nEnd = 1;
e8ef3da7
WL
7187 if (!setKeyPool.empty())
7188 nEnd = *(--setKeyPool.end()) + 1;
7189 if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
5262fde0 7190 throw runtime_error("TopUpKeyPool(): writing generated key failed");
e8ef3da7 7191 setKeyPool.insert(nEnd);
783b182c 7192 LogPrintf("keypool added key %d, size=%u\n", nEnd, setKeyPool.size());
e8ef3da7 7193 }
4e87d341
MC
7194 }
7195 return true;
7196}
7197
51ed9ec9 7198void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool)
4e87d341
MC
7199{
7200 nIndex = -1;
fd61d6f5 7201 keypool.vchPubKey = CPubKey();
4e87d341 7202 {
f8dcd5ca
PW
7203 LOCK(cs_wallet);
7204
4e87d341
MC
7205 if (!IsLocked())
7206 TopUpKeyPool();
e8ef3da7
WL
7207
7208 // Get the oldest key
4e87d341
MC
7209 if(setKeyPool.empty())
7210 return;
7211
7212 CWalletDB walletdb(strWalletFile);
7213
e8ef3da7
WL
7214 nIndex = *(setKeyPool.begin());
7215 setKeyPool.erase(setKeyPool.begin());
7216 if (!walletdb.ReadPool(nIndex, keypool))
5262fde0 7217 throw runtime_error("ReserveKeyFromKeyPool(): read failed");
fd61d6f5 7218 if (!HaveKey(keypool.vchPubKey.GetID()))
5262fde0 7219 throw runtime_error("ReserveKeyFromKeyPool(): unknown key in key pool");
fd61d6f5 7220 assert(keypool.vchPubKey.IsValid());
36a65612 7221 //LogPrintf("keypool reserve %d\n", nIndex);
e8ef3da7
WL
7222 }
7223}
7224
51ed9ec9 7225void CWallet::KeepKey(int64_t nIndex)
e8ef3da7
WL
7226{
7227 // Remove from key pool
7228 if (fFileBacked)
7229 {
7230 CWalletDB walletdb(strWalletFile);
6cc4a62c 7231 walletdb.ErasePool(nIndex);
e8ef3da7 7232 }
f48742c2 7233 LogPrintf("keypool keep %d\n", nIndex);
e8ef3da7
WL
7234}
7235
51ed9ec9 7236void CWallet::ReturnKey(int64_t nIndex)
e8ef3da7
WL
7237{
7238 // Return to key pool
f8dcd5ca
PW
7239 {
7240 LOCK(cs_wallet);
e8ef3da7 7241 setKeyPool.insert(nIndex);
f8dcd5ca 7242 }
36a65612 7243 //LogPrintf("keypool return %d\n", nIndex);
e8ef3da7
WL
7244}
7245
71ac5052 7246bool CWallet::GetKeyFromPool(CPubKey& result)
e8ef3da7 7247{
51ed9ec9 7248 int64_t nIndex = 0;
e8ef3da7 7249 CKeyPool keypool;
7db3b75b 7250 {
f8dcd5ca 7251 LOCK(cs_wallet);
ed02c95d
GA
7252 ReserveKeyFromKeyPool(nIndex, keypool);
7253 if (nIndex == -1)
7db3b75b 7254 {
ed02c95d
GA
7255 if (IsLocked()) return false;
7256 result = GenerateNewKey();
7db3b75b
GA
7257 return true;
7258 }
ed02c95d
GA
7259 KeepKey(nIndex);
7260 result = keypool.vchPubKey;
7db3b75b 7261 }
7db3b75b 7262 return true;
e8ef3da7
WL
7263}
7264
51ed9ec9 7265int64_t CWallet::GetOldestKeyPoolTime()
e8ef3da7 7266{
51ed9ec9 7267 int64_t nIndex = 0;
e8ef3da7
WL
7268 CKeyPool keypool;
7269 ReserveKeyFromKeyPool(nIndex, keypool);
4e87d341
MC
7270 if (nIndex == -1)
7271 return GetTime();
e8ef3da7
WL
7272 ReturnKey(nIndex);
7273 return keypool.nTime;
7274}
7275
a372168e 7276std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
22dfd735 7277{
a372168e 7278 map<CTxDestination, CAmount> balances;
22dfd735 7279
7280 {
7281 LOCK(cs_wallet);
7282 BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet)
7283 {
7284 CWalletTx *pcoin = &walletEntry.second;
7285
75a4d512 7286 if (!CheckFinalTx(*pcoin) || !pcoin->IsTrusted())
22dfd735 7287 continue;
7288
7289 if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
7290 continue;
7291
7292 int nDepth = pcoin->GetDepthInMainChain();
a3e192a3 7293 if (nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? 0 : 1))
22dfd735 7294 continue;
7295
b1093efa 7296 for (unsigned int i = 0; i < pcoin->vout.size(); i++)
22dfd735 7297 {
b1093efa 7298 CTxDestination addr;
22dfd735 7299 if (!IsMine(pcoin->vout[i]))
7300 continue;
b1093efa
GM
7301 if(!ExtractDestination(pcoin->vout[i].scriptPubKey, addr))
7302 continue;
22dfd735 7303
a372168e 7304 CAmount n = IsSpent(walletEntry.first, i) ? 0 : pcoin->vout[i].nValue;
22dfd735 7305
22dfd735 7306 if (!balances.count(addr))
7307 balances[addr] = 0;
7308 balances[addr] += n;
7309 }
7310 }
7311 }
7312
7313 return balances;
7314}
7315
b1093efa 7316set< set<CTxDestination> > CWallet::GetAddressGroupings()
22dfd735 7317{
95691680 7318 AssertLockHeld(cs_wallet); // mapWallet
b1093efa
GM
7319 set< set<CTxDestination> > groupings;
7320 set<CTxDestination> grouping;
22dfd735 7321
7322 BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet)
7323 {
7324 CWalletTx *pcoin = &walletEntry.second;
7325
a3fad211 7326 if (pcoin->vin.size() > 0)
22dfd735 7327 {
a3fad211 7328 bool any_mine = false;
22dfd735 7329 // group all input addresses with each other
7330 BOOST_FOREACH(CTxIn txin, pcoin->vin)
b1093efa
GM
7331 {
7332 CTxDestination address;
a3fad211
GM
7333 if(!IsMine(txin)) /* If this input isn't mine, ignore it */
7334 continue;
b1093efa
GM
7335 if(!ExtractDestination(mapWallet[txin.prevout.hash].vout[txin.prevout.n].scriptPubKey, address))
7336 continue;
7337 grouping.insert(address);
a3fad211 7338 any_mine = true;
b1093efa 7339 }
22dfd735 7340
7341 // group change with input addresses
a3fad211
GM
7342 if (any_mine)
7343 {
7344 BOOST_FOREACH(CTxOut txout, pcoin->vout)
7345 if (IsChange(txout))
7346 {
7347 CTxDestination txoutAddr;
7348 if(!ExtractDestination(txout.scriptPubKey, txoutAddr))
7349 continue;
7350 grouping.insert(txoutAddr);
7351 }
7352 }
7353 if (grouping.size() > 0)
7354 {
7355 groupings.insert(grouping);
7356 grouping.clear();
7357 }
22dfd735 7358 }
7359
7360 // group lone addrs by themselves
b1093efa 7361 for (unsigned int i = 0; i < pcoin->vout.size(); i++)
22dfd735 7362 if (IsMine(pcoin->vout[i]))
7363 {
b1093efa
GM
7364 CTxDestination address;
7365 if(!ExtractDestination(pcoin->vout[i].scriptPubKey, address))
7366 continue;
7367 grouping.insert(address);
22dfd735 7368 groupings.insert(grouping);
7369 grouping.clear();
7370 }
7371 }
7372
b1093efa
GM
7373 set< set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses
7374 map< CTxDestination, set<CTxDestination>* > setmap; // map addresses to the unique group containing it
7375 BOOST_FOREACH(set<CTxDestination> grouping, groupings)
22dfd735 7376 {
7377 // make a set of all the groups hit by this new group
b1093efa
GM
7378 set< set<CTxDestination>* > hits;
7379 map< CTxDestination, set<CTxDestination>* >::iterator it;
7380 BOOST_FOREACH(CTxDestination address, grouping)
22dfd735 7381 if ((it = setmap.find(address)) != setmap.end())
7382 hits.insert((*it).second);
7383
7384 // merge all hit groups into a new single group and delete old groups
b1093efa
GM
7385 set<CTxDestination>* merged = new set<CTxDestination>(grouping);
7386 BOOST_FOREACH(set<CTxDestination>* hit, hits)
22dfd735 7387 {
7388 merged->insert(hit->begin(), hit->end());
7389 uniqueGroupings.erase(hit);
7390 delete hit;
7391 }
7392 uniqueGroupings.insert(merged);
7393
7394 // update setmap
b1093efa 7395 BOOST_FOREACH(CTxDestination element, *merged)
22dfd735 7396 setmap[element] = merged;
7397 }
7398
b1093efa
GM
7399 set< set<CTxDestination> > ret;
7400 BOOST_FOREACH(set<CTxDestination>* uniqueGrouping, uniqueGroupings)
22dfd735 7401 {
7402 ret.insert(*uniqueGrouping);
7403 delete uniqueGrouping;
7404 }
7405
7406 return ret;
7407}
7408
db954a65 7409std::set<CTxDestination> CWallet::GetAccountAddresses(const std::string& strAccount) const
3624356e 7410{
43422a01 7411 LOCK(cs_wallet);
3624356e
GA
7412 set<CTxDestination> result;
7413 BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, mapAddressBook)
7414 {
7415 const CTxDestination& address = item.first;
7416 const string& strName = item.second.name;
7417 if (strName == strAccount)
7418 result.insert(address);
7419 }
7420 return result;
7421}
7422
360cfe14 7423bool CReserveKey::GetReservedKey(CPubKey& pubkey)
e8ef3da7
WL
7424{
7425 if (nIndex == -1)
7426 {
7427 CKeyPool keypool;
7428 pwallet->ReserveKeyFromKeyPool(nIndex, keypool);
0d7b28e5
MC
7429 if (nIndex != -1)
7430 vchPubKey = keypool.vchPubKey;
360cfe14 7431 else {
6c37f7fd 7432 return false;
cee69980 7433 }
e8ef3da7 7434 }
fd61d6f5 7435 assert(vchPubKey.IsValid());
360cfe14
PW
7436 pubkey = vchPubKey;
7437 return true;
e8ef3da7
WL
7438}
7439
7440void CReserveKey::KeepKey()
7441{
7442 if (nIndex != -1)
7443 pwallet->KeepKey(nIndex);
7444 nIndex = -1;
fd61d6f5 7445 vchPubKey = CPubKey();
e8ef3da7
WL
7446}
7447
7448void CReserveKey::ReturnKey()
7449{
7450 if (nIndex != -1)
7451 pwallet->ReturnKey(nIndex);
7452 nIndex = -1;
fd61d6f5 7453 vchPubKey = CPubKey();
e8ef3da7 7454}
ae3d0aba 7455
434e4273 7456void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) const
30ab2c9c
PW
7457{
7458 setAddress.clear();
7459
7460 CWalletDB walletdb(strWalletFile);
7461
f8dcd5ca 7462 LOCK2(cs_main, cs_wallet);
51ed9ec9 7463 BOOST_FOREACH(const int64_t& id, setKeyPool)
30ab2c9c
PW
7464 {
7465 CKeyPool keypool;
7466 if (!walletdb.ReadPool(id, keypool))
5262fde0 7467 throw runtime_error("GetAllReserveKeyHashes(): read failed");
fd61d6f5 7468 assert(keypool.vchPubKey.IsValid());
10254401
PW
7469 CKeyID keyID = keypool.vchPubKey.GetID();
7470 if (!HaveKey(keyID))
5262fde0 7471 throw runtime_error("GetAllReserveKeyHashes(): unknown key in key pool");
10254401 7472 setAddress.insert(keyID);
30ab2c9c
PW
7473 }
7474}
fe4a6550
WL
7475
7476void CWallet::UpdatedTransaction(const uint256 &hashTx)
7477{
7478 {
7479 LOCK(cs_wallet);
7480 // Only notify UI if this transaction is in this wallet
7481 map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(hashTx);
7482 if (mi != mapWallet.end())
7483 NotifyTransactionChanged(this, hashTx, CT_UPDATED);
7484 }
7485}
fdbb537d 7486
489fe227 7487class MiningAddressScript : public CReserveScript
7488{
7489 // CReserveScript requires implementing this function, so that if an
7490 // internal (not-visible) wallet address is used, the wallet can mark it as
7491 // important when a block is mined (so it then appears to the user).
7492 // If -mineraddress is set, the user already knows about and is managing the
7493 // address, so we don't need to do anything here.
7494 void KeepScript() {}
7495};
7496
7497void GetScriptForMiningAddress(boost::shared_ptr<CReserveScript> &script)
7498{
7499 CTxDestination addr = DecodeDestination(GetArg("-mineraddress", ""));
7500 if (!IsValidDestination(addr)) {
7501 return;
7502 }
7503
7504 boost::shared_ptr<MiningAddressScript> mAddr(new MiningAddressScript());
7505 script = mAddr;
7506 script->reserveScript = GetScriptForDestination(addr);
7507}
7508
f4055fe1 7509void CWallet::GetScriptForMining(boost::shared_ptr<CReserveScript> &script)
b2993bc5 7510{
489fe227 7511 if (!GetArg("-mineraddress", "").empty())
7512 {
7513 GetScriptForMiningAddress(script);
b2993bc5
JS
7514 return;
7515 }
7516
f4055fe1 7517 boost::shared_ptr<CReserveKey> rKey(new CReserveKey(this));
b2993bc5 7518 CPubKey pubkey;
f4055fe1 7519 if (!rKey->GetReservedKey(pubkey))
b2993bc5 7520 return;
f4055fe1
JS
7521
7522 script = rKey;
7523 script->reserveScript = CScript() << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
b2993bc5
JS
7524}
7525
fdbb537d
JG
7526void CWallet::LockCoin(COutPoint& output)
7527{
95691680 7528 AssertLockHeld(cs_wallet); // setLockedCoins
fdbb537d
JG
7529 setLockedCoins.insert(output);
7530}
7531
7532void CWallet::UnlockCoin(COutPoint& output)
7533{
95691680 7534 AssertLockHeld(cs_wallet); // setLockedCoins
fdbb537d
JG
7535 setLockedCoins.erase(output);
7536}
7537
7538void CWallet::UnlockAllCoins()
7539{
95691680 7540 AssertLockHeld(cs_wallet); // setLockedCoins
fdbb537d
JG
7541 setLockedCoins.clear();
7542}
7543
7544bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const
7545{
95691680 7546 AssertLockHeld(cs_wallet); // setLockedCoins
fdbb537d
JG
7547 COutPoint outpt(hash, n);
7548
7549 return (setLockedCoins.count(outpt) > 0);
7550}
7551
7552void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts)
7553{
95691680 7554 AssertLockHeld(cs_wallet); // setLockedCoins
fdbb537d
JG
7555 for (std::set<COutPoint>::iterator it = setLockedCoins.begin();
7556 it != setLockedCoins.end(); it++) {
7557 COutPoint outpt = (*it);
7558 vOutpts.push_back(outpt);
7559 }
7560}
7561
98a4f6a6
BM
7562
7563// Note Locking Operations
7564
e935beb8 7565void CWallet::LockNote(const JSOutPoint& output)
98a4f6a6 7566{
d358d145
S
7567 AssertLockHeld(cs_wallet); // setLockedSproutNotes
7568 setLockedSproutNotes.insert(output);
98a4f6a6
BM
7569}
7570
e935beb8 7571void CWallet::UnlockNote(const JSOutPoint& output)
98a4f6a6 7572{
d358d145
S
7573 AssertLockHeld(cs_wallet); // setLockedSproutNotes
7574 setLockedSproutNotes.erase(output);
98a4f6a6
BM
7575}
7576
9ae73247 7577void CWallet::UnlockAllSproutNotes()
98a4f6a6 7578{
d358d145
S
7579 AssertLockHeld(cs_wallet); // setLockedSproutNotes
7580 setLockedSproutNotes.clear();
98a4f6a6
BM
7581}
7582
e935beb8 7583bool CWallet::IsLockedNote(const JSOutPoint& outpt) const
98a4f6a6 7584{
d358d145 7585 AssertLockHeld(cs_wallet); // setLockedSproutNotes
98a4f6a6 7586
d358d145 7587 return (setLockedSproutNotes.count(outpt) > 0);
98a4f6a6
BM
7588}
7589
0f62cacf 7590std::vector<JSOutPoint> CWallet::ListLockedSproutNotes()
98a4f6a6 7591{
d358d145
S
7592 AssertLockHeld(cs_wallet); // setLockedSproutNotes
7593 std::vector<JSOutPoint> vOutpts(setLockedSproutNotes.begin(), setLockedSproutNotes.end());
98a4f6a6
BM
7594 return vOutpts;
7595}
7596
b1c693e5
S
7597void CWallet::LockNote(const SaplingOutPoint& output)
7598{
7599 AssertLockHeld(cs_wallet);
7600 setLockedSaplingNotes.insert(output);
7601}
7602
7603void CWallet::UnlockNote(const SaplingOutPoint& output)
7604{
7605 AssertLockHeld(cs_wallet);
7606 setLockedSaplingNotes.erase(output);
7607}
7608
7609void CWallet::UnlockAllSaplingNotes()
7610{
7611 AssertLockHeld(cs_wallet);
7612 setLockedSaplingNotes.clear();
7613}
7614
7615bool CWallet::IsLockedNote(const SaplingOutPoint& output) const
7616{
7617 AssertLockHeld(cs_wallet);
7618 return (setLockedSaplingNotes.count(output) > 0);
7619}
7620
7621std::vector<SaplingOutPoint> CWallet::ListLockedSaplingNotes()
7622{
7623 AssertLockHeld(cs_wallet);
7624 std::vector<SaplingOutPoint> vOutputs(setLockedSaplingNotes.begin(), setLockedSaplingNotes.end());
7625 return vOutputs;
7626}
7627
5b40d886 7628/** @} */ // end of Actions
8b59a3d3 7629
7630class CAffectedKeysVisitor : public boost::static_visitor<void> {
7631private:
7632 const CKeyStore &keystore;
7633 std::vector<CKeyID> &vKeys;
7634
7635public:
7636 CAffectedKeysVisitor(const CKeyStore &keystoreIn, std::vector<CKeyID> &vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {}
7637
7638 void Process(const CScript &script) {
7639 txnouttype type;
7640 std::vector<CTxDestination> vDest;
7641 int nRequired;
7642 if (ExtractDestinations(script, type, vDest, nRequired)) {
7643 BOOST_FOREACH(const CTxDestination &dest, vDest)
7644 boost::apply_visitor(*this, dest);
7645 }
7646 }
7647
7648 void operator()(const CKeyID &keyId) {
7649 if (keystore.HaveKey(keyId))
7650 vKeys.push_back(keyId);
7651 }
7652
b8deecdc 7653 void operator()(const CPubKey &key) {
7654 CKeyID keyId = key.GetID();
7655 if (keystore.HaveKey(keyId))
7656 vKeys.push_back(keyId);
7657 }
7658
56fe75cb 7659 // TODO: need to finish storage of quantum public key in wallet
7660 void operator()(const CQuantumID &keyId) {
7661 if (keystore.HaveKey(keyId))
7662 vKeys.push_back(keyId);
7663 }
7664
2d8b9129 7665 void operator()(const CIndexID &keyId) {
7666 }
7667
8b59a3d3 7668 void operator()(const CScriptID &scriptId) {
7669 CScript script;
7670 if (keystore.GetCScript(scriptId, script))
7671 Process(script);
7672 }
7673
0d7fed99 7674 void operator()(const CIdentityID &idId) {
5bc89dab 7675 std::pair<CIdentityMapKey, CIdentityMapValue> identity;
7676 if (keystore.GetIdentity(idId, identity))
0d7fed99 7677 {
5bc89dab 7678 for (auto dest : identity.second.primaryAddresses)
0d7fed99 7679 {
7680 boost::apply_visitor(*this, dest);
7681 }
7682 }
7683 }
7684
8b59a3d3 7685 void operator()(const CNoDestination &none) {}
7686};
7687
51ed9ec9 7688void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const {
95691680 7689 AssertLockHeld(cs_wallet); // mapKeyMetadata
434e4273
PW
7690 mapKeyBirth.clear();
7691
7692 // get birth times for keys with metadata
7693 for (std::map<CKeyID, CKeyMetadata>::const_iterator it = mapKeyMetadata.begin(); it != mapKeyMetadata.end(); it++)
7694 if (it->second.nCreateTime)
7695 mapKeyBirth[it->first] = it->second.nCreateTime;
7696
7697 // map in which we'll infer heights of other keys
4c6d41b8 7698 CBlockIndex *pindexMax = chainActive[std::max(0, chainActive.Height() - 144)]; // the tip can be reorganised; use a 144-block safety margin
434e4273
PW
7699 std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock;
7700 std::set<CKeyID> setKeys;
7701 GetKeys(setKeys);
7702 BOOST_FOREACH(const CKeyID &keyid, setKeys) {
7703 if (mapKeyBirth.count(keyid) == 0)
7704 mapKeyFirstBlock[keyid] = pindexMax;
7705 }
7706 setKeys.clear();
7707
7708 // if there are no such keys, we're done
7709 if (mapKeyFirstBlock.empty())
7710 return;
7711
7712 // find first block that affects those keys, if there are any left
7713 std::vector<CKeyID> vAffected;
7714 for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++) {
7715 // iterate over all wallet transactions...
7716 const CWalletTx &wtx = (*it).second;
145d5be8 7717 BlockMap::const_iterator blit = mapBlockIndex.find(wtx.hashBlock);
4c6d41b8 7718 if (blit != mapBlockIndex.end() && chainActive.Contains(blit->second)) {
434e4273 7719 // ... which are already in a block
4b729ec5 7720 int nHeight = blit->second->GetHeight();
434e4273
PW
7721 BOOST_FOREACH(const CTxOut &txout, wtx.vout) {
7722 // iterate over all their outputs
8b59a3d3 7723 CAffectedKeysVisitor(*this, vAffected).Process(txout.scriptPubKey);
434e4273
PW
7724 BOOST_FOREACH(const CKeyID &keyid, vAffected) {
7725 // ... and all their affected keys
7726 std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid);
4b729ec5 7727 if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->GetHeight())
434e4273
PW
7728 rit->second = blit->second;
7729 }
7730 vAffected.clear();
7731 }
7732 }
7733 }
7734
7735 // Extract block timestamps for those keys
7736 for (std::map<CKeyID, CBlockIndex*>::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++)
209377a7 7737 mapKeyBirth[it->first] = it->second->GetBlockTime() - 7200; // block times can be 2h off
434e4273 7738}
b10e1470
WL
7739
7740bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
7741{
8476d5d4
CL
7742 if (boost::get<CNoDestination>(&dest))
7743 return false;
7744
b10e1470
WL
7745 mapAddressBook[dest].destdata.insert(std::make_pair(key, value));
7746 if (!fFileBacked)
7747 return true;
07444da1 7748 return CWalletDB(strWalletFile).WriteDestData(EncodeDestination(dest), key, value);
b10e1470
WL
7749}
7750
7751bool CWallet::EraseDestData(const CTxDestination &dest, const std::string &key)
7752{
7753 if (!mapAddressBook[dest].destdata.erase(key))
7754 return false;
7755 if (!fFileBacked)
7756 return true;
07444da1 7757 return CWalletDB(strWalletFile).EraseDestData(EncodeDestination(dest), key);
b10e1470
WL
7758}
7759
7760bool CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
7761{
7762 mapAddressBook[dest].destdata.insert(std::make_pair(key, value));
7763 return true;
7764}
7765
7766bool CWallet::GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const
7767{
7768 std::map<CTxDestination, CAddressBookData>::const_iterator i = mapAddressBook.find(dest);
7769 if(i != mapAddressBook.end())
7770 {
7771 CAddressBookData::StringMap::const_iterator j = i->second.destdata.find(key);
7772 if(j != i->second.destdata.end())
7773 {
7774 if(value)
7775 *value = j->second;
7776 return true;
7777 }
7778 }
7779 return false;
7780}
af8297c0
WL
7781
7782CKeyPool::CKeyPool()
7783{
7784 nTime = GetTime();
7785}
7786
7787CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn)
7788{
7789 nTime = GetTime();
7790 vchPubKey = vchPubKeyIn;
7791}
7792
7793CWalletKey::CWalletKey(int64_t nExpires)
7794{
7795 nTimeCreated = (nExpires ? GetTime() : 0);
7796 nTimeExpires = nExpires;
7797}
0101483f 7798
d917c115 7799void CMerkleTx::SetMerkleBranch(const CBlock& block)
0101483f 7800{
0101483f
WL
7801 CBlock blockTmp;
7802
4b0deb3b
DK
7803 // Update the tx's hashBlock
7804 hashBlock = block.GetHash();
0101483f 7805
4b0deb3b
DK
7806 // Locate the transaction
7807 for (nIndex = 0; nIndex < (int)block.vtx.size(); nIndex++)
7808 if (block.vtx[nIndex] == *(CTransaction*)this)
7809 break;
7810 if (nIndex == (int)block.vtx.size())
7811 {
7812 vMerkleBranch.clear();
7813 nIndex = -1;
f9150807 7814 LogPrintf("ERROR: %s: couldn't find tx (%s) in block (%s)\n", __func__, GetHash().GetHex().c_str(), hashBlock.GetHex().c_str());
0101483f
WL
7815 }
7816
4b0deb3b
DK
7817 // Fill in merkle branch
7818 vMerkleBranch = block.GetMerkleBranch(nIndex);
0101483f
WL
7819}
7820
a31e8bad 7821int CMerkleTx::GetDepthInMainChainINTERNAL(const CBlockIndex* &pindexRet) const
0101483f 7822{
4f152496 7823 if (hashBlock.IsNull() || nIndex == -1)
0101483f
WL
7824 return 0;
7825 AssertLockHeld(cs_main);
7826
7827 // Find the block it claims to be in
145d5be8 7828 BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
0101483f
WL
7829 if (mi == mapBlockIndex.end())
7830 return 0;
7831 CBlockIndex* pindex = (*mi).second;
7832 if (!pindex || !chainActive.Contains(pindex))
7833 return 0;
7834
7835 // Make sure the merkle branch connects to this block
7836 if (!fMerkleVerified)
7837 {
805344dc 7838 if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != pindex->hashMerkleRoot)
0101483f
WL
7839 return 0;
7840 fMerkleVerified = true;
7841 }
7842
7843 pindexRet = pindex;
4b729ec5 7844 return chainActive.Height() - pindex->GetHeight() + 1;
0101483f
WL
7845}
7846
a31e8bad 7847int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const
0101483f
WL
7848{
7849 AssertLockHeld(cs_main);
7850 int nResult = GetDepthInMainChainINTERNAL(pindexRet);
805344dc 7851 if (nResult == 0 && !mempool.exists(GetHash()))
0101483f
WL
7852 return -1; // Not in chain, not in mempool
7853
7854 return nResult;
7855}
7856
7857int CMerkleTx::GetBlocksToMaturity() const
7858{
7a90b9dd 7859 if ( ASSETCHAINS_SYMBOL[0] == 0 )
7860 COINBASE_MATURITY = _COINBASE_MATURITY;
0101483f
WL
7861 if (!IsCoinBase())
7862 return 0;
39267c35 7863 int32_t depth = GetDepthInMainChain();
204cf3fc 7864 int32_t ut = UnlockTime(0);
c2f6623f 7865 int32_t toMaturity = (ut - chainActive.Height()) < 0 ? 0 : ut - chainActive.Height();
7866 //printf("depth.%i, unlockTime.%i, toMaturity.%i\n", depth, ut, toMaturity);
7867 ut = (COINBASE_MATURITY - depth) < 0 ? 0 : COINBASE_MATURITY - depth;
204cf3fc 7868 return(ut < toMaturity ? toMaturity : ut);
0101483f
WL
7869}
7870
1371e6f5 7871bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee)
0101483f
WL
7872{
7873 CValidationState state;
1371e6f5 7874 return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectAbsurdFee);
0101483f
WL
7875}
7876
cb0d208f
S
7877/**
7878 * Find notes in the wallet filtered by payment address, min depth and ability to spend.
7879 * These notes are decrypted and added to the output parameter vector, outEntries.
7880 */
94e99acd 7881void CWallet::GetFilteredNotes(
a630f503 7882 std::vector<SproutNoteEntry>& sproutEntries,
94e99acd
JG
7883 std::vector<SaplingNoteEntry>& saplingEntries,
7884 std::string address,
7885 int minDepth,
7886 bool ignoreSpent,
ef27d7e4 7887 bool requireSpendingKey)
a5ac2e25 7888{
bdbe8e85
JG
7889 std::set<PaymentAddress> filterAddresses;
7890
a5ac2e25 7891 if (address.length() > 0) {
e5eab182 7892 filterAddresses.insert(DecodePaymentAddress(address));
a5ac2e25
S
7893 }
7894
ef27d7e4 7895 GetFilteredNotes(sproutEntries, saplingEntries, filterAddresses, minDepth, INT_MAX, ignoreSpent, requireSpendingKey);
bdbe8e85
JG
7896}
7897
7898/**
095eee4f
EOW
7899 * Find notes in the wallet filtered by payment addresses, min depth, max depth,
7900 * if the note is spent, if a spending key is required, and if the notes are locked.
bdbe8e85
JG
7901 * These notes are decrypted and added to the output parameter vector, outEntries.
7902 */
7903void CWallet::GetFilteredNotes(
a630f503 7904 std::vector<SproutNoteEntry>& sproutEntries,
94e99acd 7905 std::vector<SaplingNoteEntry>& saplingEntries,
bdbe8e85
JG
7906 std::set<PaymentAddress>& filterAddresses,
7907 int minDepth,
ef27d7e4 7908 int maxDepth,
bdbe8e85 7909 bool ignoreSpent,
ef27d7e4
EOW
7910 bool requireSpendingKey,
7911 bool ignoreLocked)
bdbe8e85 7912{
a5ac2e25
S
7913 LOCK2(cs_main, cs_wallet);
7914
7915 for (auto & p : mapWallet) {
7916 CWalletTx wtx = p.second;
7917
7918 // Filter the transactions before checking for notes
095eee4f
EOW
7919 if (!CheckFinalTx(wtx) ||
7920 wtx.GetBlocksToMaturity() > 0 ||
7921 wtx.GetDepthInMainChain() < minDepth ||
7922 wtx.GetDepthInMainChain() > maxDepth) {
a5ac2e25
S
7923 continue;
7924 }
7925
005f3ad1 7926 for (auto & pair : wtx.mapSproutNoteData) {
a5ac2e25 7927 JSOutPoint jsop = pair.first;
005f3ad1 7928 SproutNoteData nd = pair.second;
e5eab182 7929 SproutPaymentAddress pa = nd.address;
a5ac2e25
S
7930
7931 // skip notes which belong to a different payment address in the wallet
bdbe8e85 7932 if (!(filterAddresses.empty() || filterAddresses.count(pa))) {
a5ac2e25
S
7933 continue;
7934 }
7935
7936 // skip note which has been spent
3b6dd486 7937 if (ignoreSpent && nd.nullifier && IsSproutSpent(*nd.nullifier)) {
a5ac2e25
S
7938 continue;
7939 }
7940
9a2b8ae5 7941 // skip notes which cannot be spent
ef27d7e4 7942 if (requireSpendingKey && !HaveSproutSpendingKey(pa)) {
9a2b8ae5
JG
7943 continue;
7944 }
efb7662d 7945
4e6400bc 7946 // skip locked notes
ef27d7e4 7947 if (ignoreLocked && IsLockedNote(jsop)) {
4e6400bc
BM
7948 continue;
7949 }
9a2b8ae5 7950
f57f76d7 7951 int i = jsop.js; // Index into CTransaction.vJoinSplit
a5ac2e25
S
7952 int j = jsop.n; // Index into JSDescription.ciphertexts
7953
7954 // Get cached decryptor
7955 ZCNoteDecryption decryptor;
7956 if (!GetNoteDecryptor(pa, decryptor)) {
7957 // Note decryptors are created when the wallet is loaded, so it should always exist
80ed13d5 7958 throw std::runtime_error(strprintf("Could not find note decryptor for payment address %s", EncodePaymentAddress(pa)));
a5ac2e25
S
7959 }
7960
7961 // determine amount of funds in the note
f57f76d7 7962 auto hSig = wtx.vJoinSplit[i].h_sig(*pzcashParams, wtx.joinSplitPubKey);
a5ac2e25 7963 try {
5020a936 7964 SproutNotePlaintext plaintext = SproutNotePlaintext::decrypt(
a5ac2e25 7965 decryptor,
f57f76d7
DA
7966 wtx.vJoinSplit[i].ciphertexts[j],
7967 wtx.vJoinSplit[i].ephemeralKey,
a5ac2e25
S
7968 hSig,
7969 (unsigned char) j);
7970
a630f503
E
7971 sproutEntries.push_back(SproutNoteEntry {
7972 jsop, pa, plaintext.note(pa), plaintext.memo(), wtx.GetDepthInMainChain() });
a5ac2e25 7973
51fde9ea 7974 } catch (const note_decryption_failed &err) {
a5ac2e25 7975 // Couldn't decrypt with this spending key
80ed13d5 7976 throw std::runtime_error(strprintf("Could not decrypt note for payment address %s", EncodePaymentAddress(pa)));
51fde9ea
JG
7977 } catch (const std::exception &exc) {
7978 // Unexpected failure
80ed13d5 7979 throw std::runtime_error(strprintf("Error while decrypting note for payment address %s: %s", EncodePaymentAddress(pa), exc.what()));
a5ac2e25
S
7980 }
7981 }
94e99acd
JG
7982
7983 for (auto & pair : wtx.mapSaplingNoteData) {
7984 SaplingOutPoint op = pair.first;
7985 SaplingNoteData nd = pair.second;
7986
7987 auto maybe_pt = SaplingNotePlaintext::decrypt(
7988 wtx.vShieldedOutput[op.n].encCiphertext,
7989 nd.ivk,
7990 wtx.vShieldedOutput[op.n].ephemeralKey,
7991 wtx.vShieldedOutput[op.n].cm);
7992 assert(static_cast<bool>(maybe_pt));
7993 auto notePt = maybe_pt.get();
7994
7995 auto maybe_pa = nd.ivk.address(notePt.d);
7996 assert(static_cast<bool>(maybe_pa));
7997 auto pa = maybe_pa.get();
7998
7999 // skip notes which belong to a different payment address in the wallet
8000 if (!(filterAddresses.empty() || filterAddresses.count(pa))) {
8001 continue;
8002 }
8003
8004 if (ignoreSpent && nd.nullifier && IsSaplingSpent(*nd.nullifier)) {
8005 continue;
8006 }
8007
8008 // skip notes which cannot be spent
ef27d7e4 8009 if (requireSpendingKey) {
94e99acd
JG
8010 libzcash::SaplingIncomingViewingKey ivk;
8011 libzcash::SaplingFullViewingKey fvk;
8012 if (!(GetSaplingIncomingViewingKey(pa, ivk) &&
8013 GetSaplingFullViewingKey(ivk, fvk) &&
8014 HaveSaplingSpendingKey(fvk))) {
8015 continue;
8016 }
8017 }
8018
8019 // skip locked notes
0adb77d3
EOW
8020 if (ignoreLocked && IsLockedNote(op)) {
8021 continue;
8022 }
94e99acd
JG
8023
8024 auto note = notePt.note(nd.ivk).get();
8025 saplingEntries.push_back(SaplingNoteEntry {
94e99acd
JG
8026 op, pa, note, notePt.memo(), wtx.GetDepthInMainChain() });
8027 }
d72c19a6
S
8028 }
8029}
8030
d72c19a6 8031
053cb349
JG
8032//
8033// Shielded key and address generalizations
8034//
8035
8036bool PaymentAddressBelongsToWallet::operator()(const libzcash::SproutPaymentAddress &zaddr) const
8037{
8038 return m_wallet->HaveSproutSpendingKey(zaddr) || m_wallet->HaveSproutViewingKey(zaddr);
8039}
8040
8041bool PaymentAddressBelongsToWallet::operator()(const libzcash::SaplingPaymentAddress &zaddr) const
8042{
8043 libzcash::SaplingIncomingViewingKey ivk;
8044
70b4ad2d
JG
8045 // If we have a SaplingExtendedSpendingKey in the wallet, then we will
8046 // also have the corresponding SaplingFullViewingKey.
053cb349
JG
8047 return m_wallet->GetSaplingIncomingViewingKey(zaddr, ivk) &&
8048 m_wallet->HaveSaplingFullViewingKey(ivk);
8049}
8050
8051bool PaymentAddressBelongsToWallet::operator()(const libzcash::InvalidEncoding& no) const
8052{
8053 return false;
8054}
e22c115e 8055
81e0fd2e
JG
8056bool HaveSpendingKeyForPaymentAddress::operator()(const libzcash::SproutPaymentAddress &zaddr) const
8057{
8058 return m_wallet->HaveSproutSpendingKey(zaddr);
8059}
8060
8061bool HaveSpendingKeyForPaymentAddress::operator()(const libzcash::SaplingPaymentAddress &zaddr) const
8062{
8063 libzcash::SaplingIncomingViewingKey ivk;
8064 libzcash::SaplingFullViewingKey fvk;
8065
8066 return m_wallet->GetSaplingIncomingViewingKey(zaddr, ivk) &&
8067 m_wallet->GetSaplingFullViewingKey(ivk, fvk) &&
8068 m_wallet->HaveSaplingSpendingKey(fvk);
8069}
8070
8071bool HaveSpendingKeyForPaymentAddress::operator()(const libzcash::InvalidEncoding& no) const
8072{
8073 return false;
8074}
8075
e22c115e
JG
8076boost::optional<libzcash::SpendingKey> GetSpendingKeyForPaymentAddress::operator()(
8077 const libzcash::SproutPaymentAddress &zaddr) const
8078{
8079 libzcash::SproutSpendingKey k;
8080 if (m_wallet->GetSproutSpendingKey(zaddr, k)) {
8081 return libzcash::SpendingKey(k);
8082 } else {
8083 return boost::none;
a5ac2e25
S
8084 }
8085}
e22c115e
JG
8086
8087boost::optional<libzcash::SpendingKey> GetSpendingKeyForPaymentAddress::operator()(
8088 const libzcash::SaplingPaymentAddress &zaddr) const
8089{
5e360fb2
EOW
8090 libzcash::SaplingExtendedSpendingKey extsk;
8091 if (m_wallet->GetSaplingExtendedSpendingKey(zaddr, extsk)) {
8092 return libzcash::SpendingKey(extsk);
e22c115e
JG
8093 } else {
8094 return boost::none;
8095 }
8096}
8097
8098boost::optional<libzcash::SpendingKey> GetSpendingKeyForPaymentAddress::operator()(
8099 const libzcash::InvalidEncoding& no) const
8100{
8101 // Defaults to InvalidEncoding
8102 return libzcash::SpendingKey();
8103}
fcab001b 8104
0f03de55 8105SpendingKeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SproutSpendingKey &sk) const {
2fe39561 8106 auto addr = sk.address();
9bcf90e2
EOW
8107 if (log){
8108 LogPrint("zrpc", "Importing zaddr %s...\n", EncodePaymentAddress(addr));
8109 }
fcab001b 8110 if (m_wallet->HaveSproutSpendingKey(addr)) {
0f03de55
EOW
8111 return KeyAlreadyExists;
8112 } else if (m_wallet-> AddSproutZKey(sk)) {
9bcf90e2 8113 m_wallet->mapSproutZKeyMetadata[addr].nCreateTime = nTime;
0f03de55
EOW
8114 return KeyAdded;
8115 } else {
8116 return KeyNotAdded;
fcab001b
EOW
8117 }
8118}
8119
0f03de55 8120SpendingKeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SaplingExtendedSpendingKey &sk) const {
fcab001b
EOW
8121 auto fvk = sk.expsk.full_viewing_key();
8122 auto ivk = fvk.in_viewing_key();
8123 auto addr = sk.DefaultAddress();
8124 {
9bcf90e2
EOW
8125 if (log){
8126 LogPrint("zrpc", "Importing zaddr %s...\n", EncodePaymentAddress(addr));
8127 }
fcab001b
EOW
8128 // Don't throw error in case a key is already there
8129 if (m_wallet->HaveSaplingSpendingKey(fvk)) {
0f03de55 8130 return KeyAlreadyExists;
fcab001b 8131 } else {
fcab001b 8132 if (!m_wallet-> AddSaplingZKey(sk, addr)) {
0f03de55 8133 return KeyNotAdded;
fcab001b
EOW
8134 }
8135
8136 // Sapling addresses can't have been used in transactions prior to activation.
8137 if (params.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight == Consensus::NetworkUpgrade::ALWAYS_ACTIVE) {
9bcf90e2 8138 m_wallet->mapSaplingZKeyMetadata[ivk].nCreateTime = nTime;
fcab001b 8139 } else {
9bcf90e2
EOW
8140 // 154051200 seconds from epoch is Friday, 26 October 2018 00:00:00 GMT - definitely before Sapling activates
8141 m_wallet->mapSaplingZKeyMetadata[ivk].nCreateTime = std::max((int64_t) 154051200, nTime);
fcab001b 8142 }
2fe39561
EOW
8143 if (hdKeypath) {
8144 m_wallet->mapSaplingZKeyMetadata[ivk].hdKeypath = hdKeypath.get();
8145 }
8146 if (seedFpStr) {
8147 uint256 seedFp;
8148 seedFp.SetHex(seedFpStr.get());
8149 m_wallet->mapSaplingZKeyMetadata[ivk].seedFp = seedFp;
8150 }
0f03de55 8151 return KeyAdded;
fcab001b
EOW
8152 }
8153 }
8154}
8155
0f03de55 8156SpendingKeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::InvalidEncoding& no) const {
fcab001b
EOW
8157 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
8158}
This page took 2.124482 seconds and 4 git commands to generate.