]> Git Repo - VerusCoin.git/blame - src/wallet/wallet.cpp
ID staking fix
[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
6e7fb01d 1714 int proveBlockHeight = posHeight > secondBlockHeight ? posHeight : secondBlockHeight;
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
06f41160 1890int32_t CWallet::VerusStakeTransaction(CBlock *pBlock, CMutableTransaction &txNew, uint32_t &bnTarget, arith_uint256 &hashResult, uint8_t *utxosig, CPubKey pk) 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 saplingStake = stakeHeight >= Params().GetConsensus().vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight;
1901 bool extendedStake = CConstVerusSolutionVector::GetVersionByHeight(stakeHeight) >= CActivationHeight::ACTIVATE_EXTENDEDSTAKE;
8a727a26 1902
56fe75cb 1903 if (!saplingStake)
06f41160 1904 pk = CPubKey();
1905
1f722359 1906 bnTarget = lwmaGetNextPOSRequired(tipindex, Params().GetConsensus());
1f722359 1907
ec1c84a0 1908 if (!VerusSelectStakeOutput(pBlock, hashResult, stakeSource, voutNum, stakeHeight, bnTarget) ||
1fae37f6 1909 !Solver(stakeSource.vout[voutNum].scriptPubKey, whichType, vSolutions))
1f722359 1910 {
0cc87e8f 1911 //LogPrintf("Searched for eligible staking transactions, no winners found\n");
1f722359
MT
1912 return 0;
1913 }
1914
1f722359
MT
1915 bool signSuccess;
1916 SignatureData sigdata;
86e31e3d 1917 uint64_t txfee;
86e31e3d 1918 auto consensusBranchId = CurrentEpochBranchId(stakeHeight, Params().GetConsensus());
1f722359
MT
1919
1920 const CKeyStore& keystore = *pwalletMain;
1921 txNew.vin.resize(1);
1922 txNew.vout.resize(1);
88d014d0 1923 txfee = 0;
1f722359
MT
1924 txNew.vin[0].prevout.hash = stakeSource.GetHash();
1925 txNew.vin[0].prevout.n = voutNum;
1926
1fae37f6
MT
1927 if (whichType == TX_PUBKEY)
1928 {
1929 txNew.vout[0].scriptPubKey << ToByteVector(vSolutions[0]) << OP_CHECKSIG;
06f41160 1930 if (!pk.IsValid())
1931 pk = CPubKey(vSolutions[0]);
1fae37f6
MT
1932 }
1933 else if (whichType == TX_PUBKEYHASH)
1934 {
1935 txNew.vout[0].scriptPubKey << OP_DUP << OP_HASH160 << ToByteVector(vSolutions[0]) << OP_EQUALVERIFY << OP_CHECKSIG;
56fe75cb 1936 if (saplingStake && !pk.IsValid())
8a727a26 1937 {
1938 // we need a pubkey, so try to get one from the key ID, if not there, fail
1939 if (!keystore.GetPubKey(CKeyID(uint160(vSolutions[0])), pk))
1940 return 0;
1941 }
1fae37f6 1942 }
e54e3c24 1943 else if (whichType == TX_CRYPTOCONDITION)
1944 {
1945 // same output as stake
1946 txNew.vout[0].scriptPubKey = stakeSource.vout[voutNum].scriptPubKey;
1947 }
1fae37f6 1948 else
e54e3c24 1949 {
1fae37f6 1950 return 0;
e54e3c24 1951 }
1f722359 1952
8a727a26 1953 // if we are staking with the extended format, add the opreturn data required
56fe75cb 1954 if (saplingStake)
8a727a26 1955 {
7a993143 1956 // set expiry to time out after 100 blocks, so we can remove the transaction if it orphans
1957 txNew.nExpiryHeight = stakeHeight + 100;
1958
8a727a26 1959 uint256 srcBlock = uint256();
1960 CBlockIndex *pSrcIndex;
1961
1962 txNew.vout.push_back(CTxOut());
1963 CTxOut &txOut1 = txNew.vout[1];
1964 txOut1.nValue = 0;
1965 if (!GetTransaction(stakeSource.GetHash(), stakeSource, srcBlock))
1966 return 0;
1967
d565e7b7 1968 BlockMap::const_iterator it = mapBlockIndex.find(srcBlock);
1969 if (it == mapBlockIndex.end() || (pSrcIndex = it->second) == 0)
8a727a26 1970 return 0;
1971
ec8a120b 1972 // !! DISABLE THIS FOR RELEASE: THIS MAKES A CHEAT TRANSACTION FOR EVERY STAKE FOR TESTING
9befb850 1973 //CMutableTransaction cheat;
1974 //cheat = CMutableTransaction(txNew);
1975 //printf("TESTING ONLY: THIS SHOULD NOT BE ENABLED FOR RELEASE - MAKING CHEAT TRANSACTION FOR TESTING\n");
1976 //cheat.vout[1].scriptPubKey << OP_RETURN
1977 // << CStakeParams(pSrcIndex->GetHeight(), tipindex->GetHeight() + 1, pSrcIndex->GetBlockHash(), pk).AsVector();
ec8a120b 1978 // !! DOWN TO HERE
43260416 1979
56fe75cb 1980 if (extendedStake)
1981 {
1982 CTxDestination dest;
1983 if (VERUS_DEFAULTID.IsNull())
1984 {
1985 ExtractDestination(txNew.vout[0].scriptPubKey, dest, true);
1986 }
1987 else
1988 {
1989 dest = VERUS_DEFAULTID;
1990 }
1991 if (dest.which() == COptCCParams::ADDRTYPE_INVALID)
1992 {
1993 return 0;
1994 }
1995
1996 txOut1.scriptPubKey << OP_RETURN
1997 << CStakeParams(pSrcIndex->GetHeight(), tipindex->GetHeight() + 1, tipindex->GetBlockHash(), dest).AsVector();
31609f35 1998
1999 auto vchVec = CStakeParams(pSrcIndex->GetHeight(), tipindex->GetHeight() + 1, tipindex->GetBlockHash(), dest).AsVector();
56fe75cb 2000 }
2001 else
2002 {
2003 txOut1.scriptPubKey << OP_RETURN
2004 << CStakeParams(pSrcIndex->GetHeight(), tipindex->GetHeight() + 1, tipindex->GetBlockHash(), pk).AsVector();
2005 }
8a727a26 2006
41e9e058 2007 // !! DISABLE THIS FOR RELEASE: REMOVE THIS TOO
9befb850 2008 //nValue = cheat.vout[0].nValue = stakeSource.vout[voutNum].nValue - txfee;
2009 //cheat.nLockTime = 0;
2010 //CTransaction cheatConst(cheat);
2011 //SignatureData cheatSig;
2012 //if (!ProduceSignature(TransactionSignatureCreator(&keystore, &cheatConst, 0, nValue, SIGHASH_ALL), stakeSource.vout[voutNum].scriptPubKey, cheatSig, consensusBranchId))
2013 // fprintf(stderr,"failed to create cheat test signature\n");
2014 //else
2015 //{
2016 // uint8_t *ptr;
2017 // UpdateTransaction(cheat,0,cheatSig);
2018 // cheatList.Add(CTxHolder(CTransaction(cheat), tipindex->GetHeight() + 1));
2019 //}
41e9e058 2020 // !! DOWN TO HERE
2021 }
43260416 2022
31bbe234 2023 nValue = txNew.vout[0].nValue = stakeSource.vout[voutNum].nValue - txfee;
3bfa5e22 2024
1f722359
MT
2025 txNew.nLockTime = 0;
2026 CTransaction txNewConst(txNew);
a4f9bc97 2027 signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, nValue, stakeSource.vout[voutNum].scriptPubKey), stakeSource.vout[voutNum].scriptPubKey, sigdata, consensusBranchId);
1f722359
MT
2028 if (!signSuccess)
2029 fprintf(stderr,"failed to create signature\n");
2030 else
2031 {
2032 uint8_t *ptr;
2033 UpdateTransaction(txNew,0,sigdata);
9feb4b9e 2034 ptr = (uint8_t *)&sigdata.scriptSig[0];
1f722359
MT
2035 siglen = sigdata.scriptSig.size();
2036 for (int i=0; i<siglen; i++)
2037 utxosig[i] = ptr[i];//, fprintf(stderr,"%02x",ptr[i]);
2038 }
2039 return(siglen);
2040}
2041
95d888a6
PW
2042void CWallet::MarkDirty()
2043{
95d888a6 2044 {
f8dcd5ca 2045 LOCK(cs_wallet);
95d888a6
PW
2046 BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
2047 item.second.MarkDirty();
2048 }
2049}
2050
1a62587e 2051/**
9a2b8ae5
JG
2052 * Ensure that every note in the wallet (for which we possess a spending key)
2053 * has a cached nullifier.
1a62587e
JG
2054 */
2055bool CWallet::UpdateNullifierNoteMap()
2056{
2057 {
2058 LOCK(cs_wallet);
2059
2060 if (IsLocked())
2061 return false;
2062
2063 ZCNoteDecryption dec;
2064 for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
005f3ad1 2065 for (mapSproutNoteData_t::value_type& item : wtxItem.second.mapSproutNoteData) {
1a62587e 2066 if (!item.second.nullifier) {
9a2b8ae5
JG
2067 if (GetNoteDecryptor(item.second.address, dec)) {
2068 auto i = item.first.js;
f57f76d7 2069 auto hSig = wtxItem.second.vJoinSplit[i].h_sig(
9a2b8ae5 2070 *pzcashParams, wtxItem.second.joinSplitPubKey);
618206c7 2071 item.second.nullifier = GetSproutNoteNullifier(
f57f76d7 2072 wtxItem.second.vJoinSplit[i],
9a2b8ae5
JG
2073 item.second.address,
2074 dec,
2075 hSig,
2076 item.first.n);
2077 }
1a62587e
JG
2078 }
2079 }
ad1e90dd
S
2080
2081 // TODO: Sapling. This method is only called from RPC walletpassphrase, which is currently unsupported
2082 // as RPC encryptwallet is hidden behind two flags: -developerencryptwallet -experimentalfeatures
2083
6e263a5f 2084 UpdateNullifierNoteMapWithTx(wtxItem.second);
1a62587e
JG
2085 }
2086 }
2087 return true;
2088}
2089
6e263a5f 2090/**
ad1e90dd
S
2091 * Update mapSproutNullifiersToNotes and mapSaplingNullifiersToNotes
2092 * with the cached nullifiers in this tx.
6e263a5f
JG
2093 */
2094void CWallet::UpdateNullifierNoteMapWithTx(const CWalletTx& wtx)
8db7e25c
JG
2095{
2096 {
2097 LOCK(cs_wallet);
005f3ad1 2098 for (const mapSproutNoteData_t::value_type& item : wtx.mapSproutNoteData) {
1a62587e 2099 if (item.second.nullifier) {
f41bf503 2100 mapSproutNullifiersToNotes[*item.second.nullifier] = item.first;
1a62587e 2101 }
8db7e25c 2102 }
ad1e90dd
S
2103
2104 for (const mapSaplingNoteData_t::value_type& item : wtx.mapSaplingNoteData) {
1a62587e 2105 if (item.second.nullifier) {
ad1e90dd 2106 mapSaplingNullifiersToNotes[*item.second.nullifier] = item.first;
1a62587e 2107 }
8db7e25c
JG
2108 }
2109 }
2110}
2111
ad1e90dd
S
2112/**
2113 * Update mapSaplingNullifiersToNotes, computing the nullifier from a cached witness if necessary.
2114 */
2115void CWallet::UpdateSaplingNullifierNoteMapWithTx(CWalletTx& wtx) {
2116 LOCK(cs_wallet);
2117
2118 for (mapSaplingNoteData_t::value_type &item : wtx.mapSaplingNoteData) {
2119 SaplingOutPoint op = item.first;
2120 SaplingNoteData nd = item.second;
2121
c343e2db 2122 if (nd.witnesses.empty()) {
ad1e90dd
S
2123 // If there are no witnesses, erase the nullifier and associated mapping.
2124 if (item.second.nullifier) {
2125 mapSaplingNullifiersToNotes.erase(item.second.nullifier.get());
2126 }
2127 item.second.nullifier = boost::none;
2128 }
c343e2db 2129 else {
ad1e90dd
S
2130 uint64_t position = nd.witnesses.front().position();
2131 SaplingFullViewingKey fvk = mapSaplingFullViewingKeys.at(nd.ivk);
2132 OutputDescription output = wtx.vShieldedOutput[op.n];
2133 auto optPlaintext = SaplingNotePlaintext::decrypt(output.encCiphertext, nd.ivk, output.ephemeralKey, output.cm);
2134 if (!optPlaintext) {
2135 // An item in mapSaplingNoteData must have already been successfully decrypted,
2136 // otherwise the item would not exist in the first place.
2137 assert(false);
2138 }
2139 auto optNote = optPlaintext.get().note(nd.ivk);
2140 if (!optNote) {
2141 assert(false);
2142 }
2143 auto optNullifier = optNote.get().nullifier(fvk, position);
2144 if (!optNullifier) {
2145 // This should not happen. If it does, maybe the position has been corrupted or miscalculated?
2146 assert(false);
2147 }
2148 uint256 nullifier = optNullifier.get();
2149 mapSaplingNullifiersToNotes[nullifier] = op;
2150 item.second.nullifier = nullifier;
2151 }
2152 }
2153}
2154
2155/**
2156 * Iterate over transactions in a block and update the cached Sapling nullifiers
2157 * for transactions which belong to the wallet.
2158 */
2159void CWallet::UpdateSaplingNullifierNoteMapForBlock(const CBlock *pblock) {
2160 LOCK(cs_wallet);
2161
2162 for (const CTransaction& tx : pblock->vtx) {
2163 auto hash = tx.GetHash();
2164 bool txIsOurs = mapWallet.count(hash);
2165 if (txIsOurs) {
2166 UpdateSaplingNullifierNoteMapWithTx(mapWallet[hash]);
2167 }
8db7e25c
JG
2168 }
2169}
2170
44bc988e 2171bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb)
e8ef3da7 2172{
805344dc 2173 uint256 hash = wtxIn.GetHash();
731b89b8
GA
2174
2175 if (fFromLoadWallet)
2176 {
2177 mapWallet[hash] = wtxIn;
09ec3af1 2178 mapWallet[hash].BindWallet(this);
6e263a5f 2179 UpdateNullifierNoteMapWithTx(mapWallet[hash]);
93a18a36 2180 AddToSpends(hash);
731b89b8
GA
2181 }
2182 else
e8ef3da7 2183 {
f8dcd5ca 2184 LOCK(cs_wallet);
e8ef3da7
WL
2185 // Inserts only if not already there, returns tx inserted or tx found
2186 pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
2187 CWalletTx& wtx = (*ret.first).second;
4c6e2295 2188 wtx.BindWallet(this);
6e263a5f 2189 UpdateNullifierNoteMapWithTx(wtx);
e8ef3da7
WL
2190 bool fInsertedNew = ret.second;
2191 if (fInsertedNew)
9c7722b7 2192 {
e8ef3da7 2193 wtx.nTimeReceived = GetAdjustedTime();
44bc988e 2194 wtx.nOrderPos = IncOrderPosNext(pwalletdb);
c3f95ef1
LD
2195
2196 wtx.nTimeSmart = wtx.nTimeReceived;
4f152496 2197 if (!wtxIn.hashBlock.IsNull())
c3f95ef1
LD
2198 {
2199 if (mapBlockIndex.count(wtxIn.hashBlock))
2200 {
209377a7 2201 int64_t latestNow = wtx.nTimeReceived;
2202 int64_t latestEntry = 0;
c3f95ef1
LD
2203 {
2204 // Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future
51ed9ec9 2205 int64_t latestTolerated = latestNow + 300;
ddb709e9
LD
2206 std::list<CAccountingEntry> acentries;
2207 TxItems txOrdered = OrderedTxItems(acentries);
c3f95ef1
LD
2208 for (TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
2209 {
2210 CWalletTx *const pwtx = (*it).second.first;
2211 if (pwtx == &wtx)
2212 continue;
2213 CAccountingEntry *const pacentry = (*it).second.second;
51ed9ec9 2214 int64_t nSmartTime;
c3f95ef1
LD
2215 if (pwtx)
2216 {
2217 nSmartTime = pwtx->nTimeSmart;
2218 if (!nSmartTime)
2219 nSmartTime = pwtx->nTimeReceived;
2220 }
2221 else
2222 nSmartTime = pacentry->nTime;
2223 if (nSmartTime <= latestTolerated)
2224 {
2225 latestEntry = nSmartTime;
2226 if (nSmartTime > latestNow)
2227 latestNow = nSmartTime;
2228 break;
2229 }
2230 }
2231 }
2232
209377a7 2233 int64_t blocktime = mapBlockIndex[wtxIn.hashBlock]->GetBlockTime();
c3f95ef1
LD
2234 wtx.nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
2235 }
2236 else
5262fde0 2237 LogPrintf("AddToWallet(): found %s in block %s not in index\n",
805344dc 2238 wtxIn.GetHash().ToString(),
7d9d134b 2239 wtxIn.hashBlock.ToString());
c3f95ef1 2240 }
93a18a36 2241 AddToSpends(hash);
9c7722b7 2242 }
e8ef3da7
WL
2243
2244 bool fUpdated = false;
2245 if (!fInsertedNew)
2246 {
2247 // Merge
4f152496 2248 if (!wtxIn.hashBlock.IsNull() && wtxIn.hashBlock != wtx.hashBlock)
e8ef3da7
WL
2249 {
2250 wtx.hashBlock = wtxIn.hashBlock;
2251 fUpdated = true;
2252 }
2253 if (wtxIn.nIndex != -1 && (wtxIn.vMerkleBranch != wtx.vMerkleBranch || wtxIn.nIndex != wtx.nIndex))
2254 {
2255 wtx.vMerkleBranch = wtxIn.vMerkleBranch;
2256 wtx.nIndex = wtxIn.nIndex;
2257 fUpdated = true;
2258 }
ac1c9435 2259 if (UpdatedNoteData(wtxIn, wtx)) {
c3a7307a
JG
2260 fUpdated = true;
2261 }
e8ef3da7
WL
2262 if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
2263 {
2264 wtx.fFromMe = wtxIn.fFromMe;
2265 fUpdated = true;
2266 }
e8ef3da7
WL
2267 }
2268
0cc87e8f 2269 //// debug log out
2270 if (fDebug)
2271 {
2272 LogPrintf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
2273 }
e8ef3da7
WL
2274
2275 // Write to disk
2276 if (fInsertedNew || fUpdated)
44bc988e 2277 if (!wtx.WriteToDisk(pwalletdb))
e8ef3da7 2278 return false;
ee4b170c 2279
93a18a36
GA
2280 // Break debit/credit balance caches:
2281 wtx.MarkDirty();
e8ef3da7 2282
fe4a6550
WL
2283 // Notify UI of new or updated transaction
2284 NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
cae686d3 2285
2286 // notify an external script when a wallet transaction comes in or is updated
2287 std::string strCmd = GetArg("-walletnotify", "");
2288
2289 if ( !strCmd.empty())
2290 {
805344dc 2291 boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
cae686d3 2292 boost::thread t(runCommand, strCmd); // thread runs free
2293 }
2294
fe4a6550 2295 }
e8ef3da7
WL
2296 return true;
2297}
2298
ac1c9435
JG
2299bool CWallet::UpdatedNoteData(const CWalletTx& wtxIn, CWalletTx& wtx)
2300{
3a83e7c9
S
2301 bool unchangedSproutFlag = (wtxIn.mapSproutNoteData.empty() || wtxIn.mapSproutNoteData == wtx.mapSproutNoteData);
2302 if (!unchangedSproutFlag) {
2303 auto tmp = wtxIn.mapSproutNoteData;
2304 // Ensure we keep any cached witnesses we may already have
2305 for (const std::pair <JSOutPoint, SproutNoteData> nd : wtx.mapSproutNoteData) {
2306 if (tmp.count(nd.first) && nd.second.witnesses.size() > 0) {
2307 tmp.at(nd.first).witnesses.assign(
2308 nd.second.witnesses.cbegin(), nd.second.witnesses.cend());
2309 }
2310 tmp.at(nd.first).witnessHeight = nd.second.witnessHeight;
2311 }
2312 // Now copy over the updated note data
2313 wtx.mapSproutNoteData = tmp;
ac1c9435 2314 }
3a83e7c9
S
2315
2316 bool unchangedSaplingFlag = (wtxIn.mapSaplingNoteData.empty() || wtxIn.mapSaplingNoteData == wtx.mapSaplingNoteData);
2317 if (!unchangedSaplingFlag) {
2318 auto tmp = wtxIn.mapSaplingNoteData;
2319 // Ensure we keep any cached witnesses we may already have
2320
2321 for (const std::pair <SaplingOutPoint, SaplingNoteData> nd : wtx.mapSaplingNoteData) {
2322 if (tmp.count(nd.first) && nd.second.witnesses.size() > 0) {
2323 tmp.at(nd.first).witnesses.assign(
2324 nd.second.witnesses.cbegin(), nd.second.witnesses.cend());
2325 }
2326 tmp.at(nd.first).witnessHeight = nd.second.witnessHeight;
ac1c9435 2327 }
3a83e7c9
S
2328
2329 // Now copy over the updated note data
2330 wtx.mapSaplingNoteData = tmp;
ac1c9435 2331 }
3a83e7c9
S
2332
2333 return !unchangedSproutFlag || !unchangedSaplingFlag;
ac1c9435
JG
2334}
2335
b27ae18a 2336std::pair<bool, bool> CWallet::CheckAuthority(const CIdentity &identity)
5bc89dab 2337{
14f010d8 2338 std::pair<bool, bool> canSignCanSpend({false, false});
b27ae18a 2339 if (!identity.IsValidUnrevoked())
2340 {
2341 return canSignCanSpend;
2342 }
5bc89dab 2343 std::set<CIdentityID> keySet;
2344
2345 // determine our status of cansign or canspend for this new ID
b27ae18a 2346 for (auto key : identity.primaryAddresses)
5bc89dab 2347 {
2348 CKeyID keyID = CKeyID(GetDestinationID(key));
2349 if (HaveKey(keyID))
2350 {
2351 keySet.insert(keyID);
2352 }
2353 }
2354
2355 // if we have enough keys to fully authorize, it is ours
b27ae18a 2356 if (keySet.size() >= identity.minSigs)
5bc89dab 2357 {
2358 canSignCanSpend.first = true;
2359 canSignCanSpend.second = true;
2360 }
2361 else if (keySet.size())
2362 {
2363 canSignCanSpend.first = true;
5bc89dab 2364 }
2365 return canSignCanSpend;
2366}
2367
2368bool CWallet::MarkIdentityDirty(const CIdentityID &idID)
2369{
2370 bool found = false;
2371 // if we already had signing authority, but not spending, enumerate wallet transactions sent to this ID and mark them dirty
2372 // for proper balance calculation
2373 for (auto &txidAndWtx : mapWallet)
2374 {
2375 bool dirty = false;
2376 txnouttype txType;
2377 std::vector<CTxDestination> addresses;
2378 int minSigs;
2379 for (auto txout : txidAndWtx.second.vout)
2380 {
2381 if (txout.scriptPubKey.IsPayToCryptoCondition() && ExtractDestinations(txout.scriptPubKey, txType, addresses, minSigs))
2382 {
2383 for (auto dest : addresses)
2384 {
2385 if (GetDestinationID(dest) == idID)
2386 {
2387 dirty = true;
2388 found = true;
2389 break;
2390 }
2391 }
2392 }
2393 }
2394 if (dirty)
2395 {
2396 txidAndWtx.second.MarkDirty();
2397 }
2398 }
2399 return found;
2400}
2401
5b40d886
MF
2402/**
2403 * Add a transaction to the wallet, or update it.
2404 * pblock is optional, but should be provided if the transaction is known to be in a block.
2405 * If fUpdate is true, existing transactions will be updated.
3ff68c50
JG
2406 *
2407 * If pblock is null, this transaction has either recently entered the mempool from the
2408 * network, is re-entering the mempool after a block was disconnected, or is exiting the
2409 * mempool because it conflicts with another transaction. In all these cases, if there is
2410 * an existing wallet transaction, the wallet transaction's Merkle branch data is _not_
2411 * updated; instead, the transaction being in the mempool or conflicted is determined on
2412 * the fly in CMerkleTx::GetDepthInMainChain().
5b40d886 2413 */
d38da59b 2414bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate)
e8ef3da7 2415{
e8ef3da7 2416 {
53d56881 2417 AssertLockHeld(cs_wallet);
a20f2622 2418 uint256 txHash = tx.GetHash();
d00f15b4 2419 bool fExisted = mapWallet.count(txHash) != 0;
6cc4a62c 2420 if (fExisted && !fUpdate) return false;
78584ef7 2421 auto sproutNoteData = FindMySproutNotes(tx);
a4ecd0fa
EOW
2422 auto saplingNoteDataAndAddressesToAdd = FindMySaplingNotes(tx);
2423 auto saplingNoteData = saplingNoteDataAndAddressesToAdd.first;
2424 auto addressesToAdd = saplingNoteDataAndAddressesToAdd.second;
2425 for (const auto &addressToAdd : addressesToAdd) {
2426 if (!AddSaplingIncomingViewingKey(addressToAdd.second, addressToAdd.first)) {
2427 return false;
2428 }
2429 }
b3ea772e 2430
b3ea772e 2431 bool canSign = false;
2f537fa1 2432 bool isMine = false;
b3ea772e 2433
2434 for (auto output : tx.vout)
2435 {
2436 bool canSpend = false;
2437 COptCCParams p;
2438
2f537fa1 2439 if (output.scriptPubKey.IsPayToCryptoCondition(p) && p.IsValid() && p.version >= p.VERSION_V3)
b3ea772e 2440 {
e14c324c 2441 // assert and fix if we find any spot where this wouldn't be held, rather than
2442 // creating a deadlock by attempting to take the cs out of order
2443 AssertLockHeld(cs_main);
2444
2445 uint32_t nHeight = 0;
2446 if (pblock)
2447 {
2448 auto blkIndexIt = mapBlockIndex.find(pblock->GetHash());
2449 if (blkIndexIt != mapBlockIndex.end())
2450 {
2451 nHeight = blkIndexIt->second->GetHeight();
2452 }
2453 else
2454 {
5bc89dab 2455 // doesn't seem like this should ever happen
e14c324c 2456 assert(false);
2457 }
2458 }
2459
5bc89dab 2460 CIdentityMapValue identity;
e14c324c 2461
5bc89dab 2462 if (p.evalCode == EVAL_IDENTITY_PRIMARY && p.vData.size() && (*(CIdentity *)&identity = CIdentity(p.vData[0])).IsValid())
b3ea772e 2463 {
5bc89dab 2464 identity.txid = tx.GetHash();
22adf258 2465 CIdentityMapKey idMapKey = CIdentityMapKey(identity.GetID(),
5ae5090d 2466 nHeight,
2467 1,
2468 CIdentityMapKey::VALID);
5bc89dab 2469
b3ea772e 2470 std::set<CKeyID> keySet;
22adf258 2471 CIdentityID idID(identity.GetID());
5ae5090d 2472 int blockOrder = 1;
5bc89dab 2473 bool doneWithID = false;
2474
2475 std::pair<CIdentityMapKey, CIdentityMapValue> idHistory;
2476
2477 // if we are deleting, current identity is what it was, idHistory is what it will be, if adding, current is what it will be, idHistory is what it was
2478 std::pair<bool, bool> wasCanSignCanSpend({false, false});
e54e3c24 2479 std::pair<bool, bool> canSignCanSpend(CheckAuthority(identity));
b3ea772e 2480
d26748d5 2481 // if it is revoked, consider the recovery authority in the can sign/can spend decision
2482 if (identity.IsRevoked())
2483 {
2484 // if it's revoked, default will be no authority, and we will only have authority if
2485 // we have recovery identity in this wallet
2486 std::pair<CIdentityMapKey, CIdentityMapValue> recoveryAuthority;
2487 if (GetIdentity(identity.recoveryAuthority, recoveryAuthority, nHeight ? nHeight : INT_MAX))
2488 {
2489 canSignCanSpend = CheckAuthority(recoveryAuthority.second);
2490 }
2491 }
2492
e54e3c24 2493 // does identity already exist in this wallet?
5bc89dab 2494 if (GetIdentity(idID, idHistory, nHeight ? nHeight : INT_MAX))
b3ea772e 2495 {
e54e3c24 2496 wasCanSignCanSpend = CheckAuthority(idHistory.second);
2497
2498 // if this is the initial registration, delete all other instances of the ID
d00f15b4 2499 if (CNameReservation(tx).IsValid())
2500 {
2501 while (GetIdentity(idID, idHistory))
2502 {
2503 RemoveIdentity(idHistory.first, idHistory.second.txid);
e54e3c24 2504 // set wasCanSignCanSpend to true, true to delete any dependent transactions
2505 wasCanSignCanSpend = {true, true};
d00f15b4 2506 }
2507 idHistory = std::pair<CIdentityMapKey, CIdentityMapValue>();
d00f15b4 2508 }
2509 else if (nHeight && idHistory.first.blockHeight == nHeight && idHistory.second.txid != identity.txid)
e14c324c 2510 {
e54e3c24 2511 // this is one of more than one identity records in the same block
22adf258 2512 std::vector<std::pair<CIdentityMapKey, CIdentityMapValue>> thisHeightIdentities;
2513 CIdentityMapKey heightKey(idID, nHeight);
2514 GetIdentity(heightKey, heightKey, thisHeightIdentities);
2515
93459a00 2516 std::map<uint256, std::pair<CIdentityMapKey, CIdentityMapValue>> firstIDMap;
22adf258 2517 for (auto &foundID : thisHeightIdentities)
2518 {
2519 firstIDMap[foundID.second.txid] = foundID;
2520 }
2521
93459a00 2522 if (firstIDMap.count(identity.txid))
2523 {
e54e3c24 2524 doneWithID = true;
93459a00 2525 }
2526 else
2527 {
2528 blockOrder = thisHeightIdentities.size() + 1;
2529 firstIDMap.insert(make_pair(identity.txid,
2530 make_pair(CIdentityMapKey(idID,
2531 nHeight,
2532 blockOrder,
d26748d5 2533 (canSignCanSpend.first ? CIdentityMapKey::CAN_SIGN : 0) + canSignCanSpend.second ? CIdentityMapKey::CAN_SPEND : 0),
93459a00 2534 identity)));
93459a00 2535
e54e3c24 2536 // now we have all the entries of the specified height, including those from before and the new one in the firstIDMap
2537 // 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
2538 // to sort, we make a new map, indexed by the one that it spends, then follow the chain
2539 std::map<uint256, std::pair<CIdentityMapKey, CIdentityMapValue>> indexedByPrior;
2540 std::pair<CIdentityMapKey, CIdentityMapValue> firstInBlock;
22adf258 2541
e54e3c24 2542 for (auto &idEntry : firstIDMap)
22adf258 2543 {
e54e3c24 2544 uint256 spendsTxId;
2545 CTransaction entryTx;
2546 uint256 blkHash;
2547 if (!myGetTransaction(idEntry.first, entryTx, blkHash))
22adf258 2548 {
e54e3c24 2549 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 2550 }
e54e3c24 2551 else
22adf258 2552 {
e54e3c24 2553 bool isFirst = true;
2554 for (auto &input : entryTx.vin)
22adf258 2555 {
e54e3c24 2556 auto idMapIt = firstIDMap.find(input.prevout.hash);
2557 if (idMapIt != firstIDMap.end())
2558 {
2559 indexedByPrior[input.prevout.hash] = idEntry.second;
2560 isFirst = false;
2561 }
2562 }
2563 if (isFirst)
2564 {
2565 // this should first be added solo, so #1 should always be set
2566 if (idEntry.second.first.blockOrder != 1)
2567 {
2568 LogPrint("%s - error: unexpected block order in %s\n", __func__, idEntry.first.GetHex().c_str());
2569 }
2570 firstInBlock = idEntry.second;
22adf258 2571 }
22adf258 2572 }
2573 }
22adf258 2574
e54e3c24 2575 if (!firstInBlock.first.IsValid())
22adf258 2576 {
e54e3c24 2577 LogPrint("%s - error: missing first in block\n", __func__);
2578 }
2579 else
2580 {
2581 // now validate that from 1st to last, we have order correct
2582 std::pair<CIdentityMapKey, CIdentityMapValue> *pCurID;
2583 int i = 1;
2584 for (pCurID = &firstInBlock; pCurID; i++)
22adf258 2585 {
e54e3c24 2586 if (pCurID->first.blockOrder != i)
2587 {
2588 LogPrint("%s - error: incorrect block order in entry %s\n", __func__, pCurID->second.txid.GetHex().c_str());
2589 printf("%s - error: incorrect block order in entry %s\n", __func__, pCurID->second.txid.GetHex().c_str());
2590 }
22adf258 2591 }
2592 }
2593 }
e14c324c 2594 }
d00f15b4 2595 else if (nHeight && idHistory.first.blockHeight == nHeight)
b3ea772e 2596 {
e54e3c24 2597 // nHeight means this is an add, it has the same txid as an ID already present in the wallet, so we can ignore
2598 doneWithID = true;
5bc89dab 2599 }
e54e3c24 2600 else
5bc89dab 2601 {
2602 if (idHistory.first.flags & idHistory.first.CAN_SPEND)
2603 {
2604 wasCanSignCanSpend.first = true;
2605 wasCanSignCanSpend.second = true;
2606 }
2607 else if ((idHistory.first.flags & idHistory.first.CAN_SIGN))
2608 {
2609 wasCanSignCanSpend.first = true;
2610 }
e54e3c24 2611 // if we are supposed to remove the last entry, do so
2612 if (!pblock && txHash == idHistory.second.txid)
2613 {
2614 RemoveIdentity(idHistory.first, idHistory.second.txid);
2615 }
5bc89dab 2616 }
b3ea772e 2617 }
5bc89dab 2618 else if (!pblock)
b3ea772e 2619 {
5bc89dab 2620 // not present, nothing to delete
2621 doneWithID = true;
b3ea772e 2622 }
e14c324c 2623
5bc89dab 2624 if (!doneWithID)
b3ea772e 2625 {
5bc89dab 2626 if (pblock)
e14c324c 2627 {
956ab931 2628 // 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
2629 if ((wasCanSignCanSpend.first || canSignCanSpend.first || (idHistory.first.flags & idHistory.first.MANUAL_HOLD)) && !(idHistory.first.flags & idHistory.first.BLACKLIST))
e14c324c 2630 {
956ab931 2631 idMapKey = CIdentityMapKey(identity.GetID(),
2632 nHeight,
2633 blockOrder,
2634 idHistory.first.VALID |
2635 ((idHistory.second.IsValid() ? idHistory.first.flags : 0) & idHistory.first.MANUAL_HOLD) |
2636 (canSignCanSpend.first ? idHistory.first.CAN_SIGN : 0) |
2637 (canSignCanSpend.second ? idHistory.first.CAN_SPEND : 0));
c0724caf 2638 AddUpdateIdentity(idMapKey, identity);
e14c324c 2639 }
2640 }
5bc89dab 2641 else
e14c324c 2642 {
e54e3c24 2643 std::pair<bool, bool> swapBools = canSignCanSpend;
2644 canSignCanSpend = wasCanSignCanSpend;
2645 wasCanSignCanSpend = swapBools;
e14c324c 2646 }
5bc89dab 2647
996f6c33 2648 // store transitions as needed in the wallet
a20f2622 2649 if (canSignCanSpend.first != wasCanSignCanSpend.first || canSignCanSpend.second != wasCanSignCanSpend.second)
e14c324c 2650 {
dcc9eba2 2651 // mark all transactions dirty to recalculate numbers
2652 for (auto &txidAndWtx : mapWallet)
2653 {
2654 // mark the whole wallet dirty. if this is an issue, we can optimize.
2655 txidAndWtx.second.MarkDirty();
2656 }
2657
5bc89dab 2658 if (canSignCanSpend.first != wasCanSignCanSpend.first)
2659 {
2f537fa1 2660 if (canSignCanSpend.first)
2661 {
a20f2622 2662 // add all UTXOs that are sent to this address to this wallet
2663 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue>> unspentOutputs;
22adf258 2664 if (GetAddressUnspent(idID, CScript::P2ID, unspentOutputs))
a20f2622 2665 {
a20f2622 2666 auto consensus = Params().GetConsensus();
2667 for (auto &newOut : unspentOutputs)
2668 {
e54e3c24 2669 // Do not flush the wallet here for performance reasons
2670 // this is safe, as in case of a crash, we rescan the necessary blocks on startup through our SetBestChain-mechanism
2671 CWalletDB walletdb(strWalletFile, "r+", false);
2672
996f6c33 2673 // must not be the current tx, not already present, and be a CC output to be correctly sent to an identity
e54e3c24 2674 if (txHash != newOut.first.txhash && GetWalletTx(newOut.first.txhash) == nullptr && newOut.second.script.IsPayToCryptoCondition())
a20f2622 2675 {
2676 txnouttype newTypeRet;
2677 std::vector<CTxDestination> newAddressRet;
2678 int newNRequired;
2679 bool newCanSign, newCanSpend;
996f6c33 2680 if (!(ExtractDestinations(newOut.second.script, newTypeRet, newAddressRet, newNRequired, this, &newCanSign, &newCanSpend) && newCanSign))
a20f2622 2681 {
2682 continue;
2683 }
2684 uint256 blkHash;
2685 CTransaction newTx;
2686 if (myGetTransaction(newOut.first.txhash, newTx, blkHash))
2687 {
2688 auto sprNoteData = FindMySproutNotes(newTx);
2689 auto sapNoteDataAndAddressesToAdd = FindMySaplingNotes(newTx);
2690 auto sapNoteData = sapNoteDataAndAddressesToAdd.first;
2691 auto addrsToAdd = sapNoteDataAndAddressesToAdd.second;
2692 for (const auto &addressToAdd : addrsToAdd)
2693 {
2694 AddSaplingIncomingViewingKey(addressToAdd.second, addressToAdd.first);
2695 }
2696
2697 CWalletTx wtx(this, newTx);
2698
2699 if (sprNoteData.size() > 0) {
2700 wtx.SetSproutNoteData(sprNoteData);
2701 }
2702
2703 if (sapNoteData.size() > 0) {
2704 wtx.SetSaplingNoteData(sapNoteData);
2705 }
2706
2707 // Get merkle branch if transaction was found in a block
2708 CBlock block;
2709 auto blkIndexIt = mapBlockIndex.find(blkHash);
2710 if (!blkHash.IsNull() && blkIndexIt != mapBlockIndex.end() && chainActive.Contains(blkIndexIt->second))
2711 {
2712 // if it's supposed to be in a block, but can't be loaded, don't add without merkle
2713 if (!ReadBlockFromDisk(block, blkIndexIt->second, consensus))
2714 {
2715 continue;
2716 }
2717 wtx.SetMerkleBranch(block);
2718 }
2719
a20f2622 2720 AddToWallet(wtx, false, &walletdb);
2721 }
2722 }
2723 }
2724 }
2f537fa1 2725 }
2726 else
5bc89dab 2727 {
2728 // 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
2729 // 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
2730 // 2. if deletion, remove all transactions since the last idHistory that are in the wallet due to this ID
2731 // 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
2732
2733 std::set<CIdentityID> idsToCheck = std::set<CIdentityID>({idID});
2734
2735 // first and last blocks to consider when deleting spent transactions from the wallet
956ab931 2736 uint32_t deleteSpentFrom;
5bc89dab 2737
2738 if (!pblock)
2739 {
956ab931 2740 deleteSpentFrom = idHistory.first.blockHeight + 1;
5bc89dab 2741 }
2742 else
2743 {
956ab931 2744 deleteSpentFrom = idMapKey.blockHeight + 1;
5bc89dab 2745 }
2746
c6782713 2747 std::vector<uint256> txesToErase;
2748
5bc89dab 2749 for (auto &txidAndWtx : mapWallet)
2750 {
956ab931 2751 const CBlockIndex *pIndex;
996f6c33 2752 if (txidAndWtx.second.GetDepthInMainChain(pIndex) > 0 && pIndex->GetHeight() <= deleteSpentFrom)
5bc89dab 2753 {
956ab931 2754 continue;
5bc89dab 2755 }
2756
2757 // if the tx is from this wallet, we will not erase it
2758 if (IsFromMe(txidAndWtx.second))
2759 {
2760 continue;
2761 }
2762
2763 txnouttype txType;
2764 std::vector<CTxDestination> addresses;
2765 int minSigs;
2766 bool eraseTx = true;
2767 std::vector<CIdentityID> oneTxIDs;
2768 int i = 0;
2769 uint256 hashTx = txidAndWtx.second.GetHash();
2770
2771 // look for a reason not to delete this tx
2772 for (auto txout : txidAndWtx.second.vout)
2773 {
2774 // we only want to remove UTXOs that are sent to this ID, used to be ours, and are no longer cansign
2775 if (!txout.scriptPubKey.IsPayToCryptoCondition() || IsSpent(hashTx, i))
2776 {
c0724caf 2777 // if this is ours, we will not erase the tx, mark dirty
5bc89dab 2778 if (IsMine(txout))
2779 {
2780 eraseTx = false;
2781 break;
2782 }
2783 continue;
2784 }
2785 bool canSignOut = false;
2786 bool canSpendOut = false;
2787
956ab931 2788 if (ExtractDestinations(txout.scriptPubKey, txType, addresses, minSigs, this, &canSignOut, &canSpendOut))
5bc89dab 2789 {
2790 if (canSignOut || canSpendOut)
2791 {
2792 // we should keep this transaction anyhow, check next
2793 eraseTx = false;
2794 break;
2795 }
2796
2797 for (auto &dest : addresses)
2798 {
2799 if (dest.which() == COptCCParams::ADDRTYPE_ID)
2800 {
2801 oneTxIDs.push_back(GetDestinationID(dest));
2802 }
2803 }
2804 }
2805
2806 i++;
2807 }
2808 if (eraseTx)
2809 {
c6782713 2810 txesToErase.push_back(txidAndWtx.first);
5bc89dab 2811
2812 for (auto &checkID : oneTxIDs)
2813 {
2814 idsToCheck.insert(checkID);
2815 }
2816 }
2817 }
c6782713 2818
2819 for (auto hash : txesToErase)
2820 {
2821 EraseFromWallet(hash);
2822 }
5bc89dab 2823
996f6c33 2824 if (pblock && idsToCheck.count(idID))
2825 {
2826 // do not remove the current identity that was just added to take away our authority
2827 // that is an important record to keep
2828 idsToCheck.erase(idID);
2829 }
2830
2831 // 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 2832 // loop through all transactions and remove all IDs found in the remaining transactions from our idsToCheck set after we
2833 // have gone through all wallet transactions, we can delete all IDs remaining in the idsToCheck set
2834 // that are not on manual hold
2835 for (auto &txidAndWtx : mapWallet)
2836 {
2837 for (auto txout : txidAndWtx.second.vout)
2838 {
2839 if (!txout.scriptPubKey.IsPayToCryptoCondition())
2840 {
2841 continue;
2842 }
2843 bool canSignOut = false;
2844 bool canSpendOut = false;
2845 txnouttype txType;
2846 std::vector<CTxDestination> addresses;
2847 int minSigs;
2848 if (ExtractDestinations(txout.scriptPubKey, txType, addresses, minSigs, this, &canSignOut, &canSpendOut))
2849 {
2850 if (canSignOut || canSpendOut)
2851 {
2852 for (auto &dest : addresses)
2853 {
2854 if (dest.which() == COptCCParams::ADDRTYPE_ID)
2855 {
2856 idsToCheck.erase(GetDestinationID(dest));
2857 if (!idsToCheck.size())
2858 {
2859 break;
2860 }
2861 }
2862 }
e54e3c24 2863 }
5bc89dab 2864 }
2865 if (!idsToCheck.size())
2866 {
2867 break;
2868 }
2869 }
2870 if (!idsToCheck.size())
2871 {
2872 break;
2873 }
2874 }
996f6c33 2875
5bc89dab 2876 // delete all remaining IDs that are not held for manual hold
2877 for (auto &idToRemove : idsToCheck)
2878 {
2879 std::pair<CIdentityMapKey, CIdentityMapValue> identityToRemove;
2880
2881 // if not cansign or canspend, no transactions we care about relating to it and no manual hold, delete the ID from the wallet
956ab931 2882 // also keep the first transition after one we will keep
5bc89dab 2883 if (GetIdentity(idToRemove, identityToRemove) &&
2884 !((identityToRemove.first.flags & (identityToRemove.first.CAN_SIGN + identityToRemove.first.CAN_SPEND)) || identityToRemove.first.flags & identityToRemove.first.MANUAL_HOLD))
2885 {
d26748d5 2886 std::pair<CIdentityMapKey, CIdentityMapValue> priorIdentity;
2887
996f6c33 2888 if (!GetPriorIdentity(identityToRemove.first, priorIdentity) ||
2889 !((priorIdentity.first.flags & (priorIdentity.first.CAN_SIGN + priorIdentity.first.CAN_SPEND)) || identityToRemove.first.flags & identityToRemove.first.MANUAL_HOLD))
956ab931 2890 {
d26748d5 2891 // if we don't have recovery on a revoked ID in our wallet, then remove it
2892 std::pair<CIdentityMapKey, CIdentityMapValue> recoveryIdentity;
2893 if (!identityToRemove.second.IsRevoked() || !GetIdentity(identityToRemove.second.recoveryAuthority, recoveryIdentity) || !(recoveryIdentity.first.flags & recoveryIdentity.first.CAN_SIGN))
2894 {
2895 RemoveIdentity(CIdentityMapKey(idToRemove));
2896 }
956ab931 2897 }
5bc89dab 2898 }
2899 }
2900 }
2901 }
e14c324c 2902 }
b3ea772e 2903 }
2904 }
b3ea772e 2905 }
2906 }
2907
2f537fa1 2908 isMine = IsMine(tx);
b3ea772e 2909
b7c685b8 2910 if (fExisted || isMine || IsFromMe(tx) || sproutNoteData.size() > 0 || saplingNoteData.size() > 0)
6cc4a62c 2911 {
2f537fa1 2912 CWalletTx wtx(this, tx);
44bc988e 2913
78584ef7
S
2914 if (sproutNoteData.size() > 0) {
2915 wtx.SetSproutNoteData(sproutNoteData);
2916 }
2917
2918 if (saplingNoteData.size() > 0) {
2919 wtx.SetSaplingNoteData(saplingNoteData);
be74c80d 2920 }
c3a7307a 2921
6cc4a62c
GA
2922 // Get merkle branch if transaction was found in a block
2923 if (pblock)
4b0deb3b 2924 wtx.SetMerkleBranch(*pblock);
44bc988e
CL
2925
2926 // Do not flush the wallet here for performance reasons
2927 // this is safe, as in case of a crash, we rescan the necessary blocks on startup through our SetBestChain-mechanism
2928 CWalletDB walletdb(strWalletFile, "r+", false);
2929
2930 return AddToWallet(wtx, false, &walletdb);
6cc4a62c 2931 }
e8ef3da7 2932 }
e8ef3da7
WL
2933 return false;
2934}
2935
d38da59b 2936void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock)
93a18a36 2937{
7c8111f3 2938 LOCK(cs_wallet);
d38da59b 2939 if (!AddToWalletIfInvolvingMe(tx, pblock, true))
93a18a36
GA
2940 return; // Not one of ours
2941
ac1c9435
JG
2942 MarkAffectedTransactionsDirty(tx);
2943}
2944
2945void CWallet::MarkAffectedTransactionsDirty(const CTransaction& tx)
2946{
93a18a36
GA
2947 // If a transaction changes 'conflicted' state, that changes the balance
2948 // available of the outputs it spends. So force those to be
2949 // recomputed, also:
2950 BOOST_FOREACH(const CTxIn& txin, tx.vin)
2951 {
2952 if (mapWallet.count(txin.prevout.hash))
2953 mapWallet[txin.prevout.hash].MarkDirty();
2954 }
f57f76d7 2955 for (const JSDescription& jsdesc : tx.vJoinSplit) {
8db7e25c 2956 for (const uint256& nullifier : jsdesc.nullifiers) {
f41bf503 2957 if (mapSproutNullifiersToNotes.count(nullifier) &&
dae1c420 2958 mapWallet.count(mapSproutNullifiersToNotes[nullifier].hash)) {
f41bf503 2959 mapWallet[mapSproutNullifiersToNotes[nullifier].hash].MarkDirty();
8db7e25c
JG
2960 }
2961 }
2962 }
dae1c420
S
2963
2964 for (const SpendDescription &spend : tx.vShieldedSpend) {
2965 uint256 nullifier = spend.nullifier;
2966 if (mapSaplingNullifiersToNotes.count(nullifier) &&
2967 mapWallet.count(mapSaplingNullifiersToNotes[nullifier].hash)) {
2968 mapWallet[mapSaplingNullifiersToNotes[nullifier].hash].MarkDirty();
2969 }
2970 }
00588c3f
PW
2971}
2972
2973void CWallet::EraseFromWallet(const uint256 &hash)
e8ef3da7
WL
2974{
2975 if (!fFileBacked)
00588c3f 2976 return;
e8ef3da7 2977 {
f8dcd5ca 2978 LOCK(cs_wallet);
e8ef3da7
WL
2979 if (mapWallet.erase(hash))
2980 CWalletDB(strWalletFile).EraseTx(hash);
2981 }
00588c3f 2982 return;
e8ef3da7
WL
2983}
2984
47ab0926 2985void CWallet::RescanWallet()
2986{
2987 if (needsRescan)
2988 {
2989 CBlockIndex *start = chainActive.Height() > 0 ? chainActive[1] : NULL;
2990 if (start)
2991 ScanForWalletTransactions(start, true);
2992 needsRescan = false;
2993 }
2994}
2995
e8ef3da7 2996
1a62587e
JG
2997/**
2998 * Returns a nullifier if the SpendingKey is available
2999 * Throws std::runtime_error if the decryptor doesn't match this note
3000 */
618206c7
S
3001boost::optional<uint256> CWallet::GetSproutNoteNullifier(const JSDescription &jsdesc,
3002 const libzcash::SproutPaymentAddress &address,
3003 const ZCNoteDecryption &dec,
3004 const uint256 &hSig,
3005 uint8_t n) const
1a62587e
JG
3006{
3007 boost::optional<uint256> ret;
5020a936 3008 auto note_pt = libzcash::SproutNotePlaintext::decrypt(
1a62587e
JG
3009 dec,
3010 jsdesc.ciphertexts[n],
3011 jsdesc.ephemeralKey,
3012 hSig,
3013 (unsigned char) n);
3014 auto note = note_pt.note(address);
c1009374
SB
3015
3016 // Check note plaintext against note commitment
3017 if (note.cm() != jsdesc.commitments[n]) {
3018 throw libzcash::note_decryption_failed();
3019 }
3020
9a2b8ae5
JG
3021 // SpendingKeys are only available if:
3022 // - We have them (this isn't a viewing key)
3023 // - The wallet is unlocked
e5eab182 3024 libzcash::SproutSpendingKey key;
25d5e80c 3025 if (GetSproutSpendingKey(address, key)) {
1a62587e
JG
3026 ret = note.nullifier(key);
3027 }
3028 return ret;
3029}
3030
e492d986
JG
3031/**
3032 * Finds all output notes in the given transaction that have been sent to
3033 * PaymentAddresses in this wallet.
3034 *
3035 * It should never be necessary to call this method with a CWalletTx, because
57faf44e 3036 * the result of FindMySproutNotes (for the addresses available at the time) will
005f3ad1 3037 * already have been cached in CWalletTx.mapSproutNoteData.
e492d986 3038 */
57faf44e 3039mapSproutNoteData_t CWallet::FindMySproutNotes(const CTransaction &tx) const
02e67455 3040{
3fac1020 3041 LOCK(cs_SpendingKeyStore);
fa511e10 3042 uint256 hash = tx.GetHash();
02e67455 3043
005f3ad1 3044 mapSproutNoteData_t noteData;
f57f76d7
DA
3045 for (size_t i = 0; i < tx.vJoinSplit.size(); i++) {
3046 auto hSig = tx.vJoinSplit[i].h_sig(*pzcashParams, tx.joinSplitPubKey);
3047 for (uint8_t j = 0; j < tx.vJoinSplit[i].ciphertexts.size(); j++) {
3fac1020 3048 for (const NoteDecryptorMap::value_type& item : mapNoteDecryptors) {
02e67455 3049 try {
02e67455 3050 auto address = item.first;
02e67455 3051 JSOutPoint jsoutpt {hash, i, j};
618206c7 3052 auto nullifier = GetSproutNoteNullifier(
f57f76d7 3053 tx.vJoinSplit[i],
1a62587e
JG
3054 address,
3055 item.second,
3056 hSig, j);
3057 if (nullifier) {
005f3ad1 3058 SproutNoteData nd {address, *nullifier};
1a62587e
JG
3059 noteData.insert(std::make_pair(jsoutpt, nd));
3060 } else {
005f3ad1 3061 SproutNoteData nd {address};
1a62587e
JG
3062 noteData.insert(std::make_pair(jsoutpt, nd));
3063 }
02e67455 3064 break;
51fde9ea 3065 } catch (const note_decryption_failed &err) {
1a62587e 3066 // Couldn't decrypt with this decryptor
32a103aa
JG
3067 } catch (const std::exception &exc) {
3068 // Unexpected failure
57faf44e 3069 LogPrintf("FindMySproutNotes(): Unexpected error while testing decrypt:\n");
32a103aa 3070 LogPrintf("%s\n", exc.what());
02e67455
JG
3071 }
3072 }
3073 }
3074 }
3075 return noteData;
3076}
3077
78584ef7
S
3078
3079/**
3080 * Finds all output notes in the given transaction that have been sent to
3081 * SaplingPaymentAddresses in this wallet.
3082 *
3083 * It should never be necessary to call this method with a CWalletTx, because
3084 * the result of FindMySaplingNotes (for the addresses available at the time) will
3085 * already have been cached in CWalletTx.mapSaplingNoteData.
3086 */
a4ecd0fa 3087std::pair<mapSaplingNoteData_t, SaplingIncomingViewingKeyMap> CWallet::FindMySaplingNotes(const CTransaction &tx) const
78584ef7
S
3088{
3089 LOCK(cs_SpendingKeyStore);
3090 uint256 hash = tx.GetHash();
3091
3092 mapSaplingNoteData_t noteData;
a4ecd0fa 3093 SaplingIncomingViewingKeyMap viewingKeysToAdd;
78584ef7
S
3094
3095 // Protocol Spec: 4.19 Block Chain Scanning (Sapling)
3096 for (uint32_t i = 0; i < tx.vShieldedOutput.size(); ++i) {
3097 const OutputDescription output = tx.vShieldedOutput[i];
ec064abb
S
3098 for (auto it = mapSaplingFullViewingKeys.begin(); it != mapSaplingFullViewingKeys.end(); ++it) {
3099 SaplingIncomingViewingKey ivk = it->first;
78584ef7
S
3100 auto result = SaplingNotePlaintext::decrypt(output.encCiphertext, ivk, output.ephemeralKey, output.cm);
3101 if (!result) {
3102 continue;
3103 }
a4ecd0fa
EOW
3104 auto address = ivk.address(result.get().d);
3105 if (address && mapSaplingIncomingViewingKeys.count(address.get()) == 0) {
3106 viewingKeysToAdd[address.get()] = ivk;
3107 }
78584ef7
S
3108 // We don't cache the nullifier here as computing it requires knowledge of the note position
3109 // in the commitment tree, which can only be determined when the transaction has been mined.
3110 SaplingOutPoint op {hash, i};
3111 SaplingNoteData nd;
3112 nd.ivk = ivk;
3113 noteData.insert(std::make_pair(op, nd));
3114 break;
3115 }
3116 }
3117
a4ecd0fa 3118 return std::make_pair(noteData, viewingKeysToAdd);
78584ef7
S
3119}
3120
037cacf2 3121bool CWallet::IsSproutNullifierFromMe(const uint256& nullifier) const
1551db87
JG
3122{
3123 {
3124 LOCK(cs_wallet);
f41bf503
S
3125 if (mapSproutNullifiersToNotes.count(nullifier) &&
3126 mapWallet.count(mapSproutNullifiersToNotes.at(nullifier).hash)) {
1551db87
JG
3127 return true;
3128 }
3129 }
3130 return false;
3131}
3132
d7cf640b 3133bool CWallet::IsSaplingNullifierFromMe(const uint256& nullifier) const
be74c80d
JG
3134{
3135 {
3136 LOCK(cs_wallet);
d7cf640b
S
3137 if (mapSaplingNullifiersToNotes.count(nullifier) &&
3138 mapWallet.count(mapSaplingNullifiersToNotes.at(nullifier).hash)) {
3139 return true;
3140 }
3141 }
3142 return false;
3143}
3144
8e8279e7 3145void CWallet::GetSproutNoteWitnesses(std::vector<JSOutPoint> notes,
8ea8ef98 3146 std::vector<boost::optional<SproutWitness>>& witnesses,
8e8279e7 3147 uint256 &final_anchor)
be74c80d 3148{
29523dc7
EOW
3149 LOCK(cs_wallet);
3150 witnesses.resize(notes.size());
3151 boost::optional<uint256> rt;
3152 int i = 0;
3153 for (JSOutPoint note : notes) {
3154 if (mapWallet.count(note.hash) &&
3155 mapWallet[note.hash].mapSproutNoteData.count(note) &&
3156 mapWallet[note.hash].mapSproutNoteData[note].witnesses.size() > 0) {
3157 witnesses[i] = mapWallet[note.hash].mapSproutNoteData[note].witnesses.front();
3158 if (!rt) {
3159 rt = witnesses[i]->root();
3160 } else {
3161 assert(*rt == witnesses[i]->root());
be74c80d 3162 }
be74c80d 3163 }
29523dc7
EOW
3164 i++;
3165 }
3166 // All returned witnesses have the same anchor
3167 if (rt) {
3168 final_anchor = *rt;
be74c80d
JG
3169 }
3170}
3171
e6b0a8b9 3172void CWallet::GetSaplingNoteWitnesses(std::vector<SaplingOutPoint> notes,
8ea8ef98 3173 std::vector<boost::optional<SaplingWitness>>& witnesses,
e6b0a8b9
EOW
3174 uint256 &final_anchor)
3175{
3176 LOCK(cs_wallet);
3177 witnesses.resize(notes.size());
3178 boost::optional<uint256> rt;
3179 int i = 0;
3180 for (SaplingOutPoint note : notes) {
3181 if (mapWallet.count(note.hash) &&
3182 mapWallet[note.hash].mapSaplingNoteData.count(note) &&
3183 mapWallet[note.hash].mapSaplingNoteData[note].witnesses.size() > 0) {
3184 witnesses[i] = mapWallet[note.hash].mapSaplingNoteData[note].witnesses.front();
3185 if (!rt) {
3186 rt = witnesses[i]->root();
3187 } else {
3188 assert(*rt == witnesses[i]->root());
3189 }
be74c80d 3190 }
e6b0a8b9
EOW
3191 i++;
3192 }
3193 // All returned witnesses have the same anchor
3194 if (rt) {
3195 final_anchor = *rt;
be74c80d
JG
3196 }
3197}
3198
c8988460 3199isminetype CWallet::IsMine(const CTxIn &txin) const
e8ef3da7 3200{
e8ef3da7 3201 {
f8dcd5ca 3202 LOCK(cs_wallet);
e8ef3da7
WL
3203 map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
3204 if (mi != mapWallet.end())
3205 {
3206 const CWalletTx& prev = (*mi).second;
3207 if (txin.prevout.n < prev.vout.size())
ea340a14 3208 return (::IsMine(*this, prev.vout[txin.prevout.n].scriptPubKey));
e8ef3da7
WL
3209 }
3210 }
a3e192a3 3211 return ISMINE_NO;
e8ef3da7
WL
3212}
3213
a372168e 3214CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const
e8ef3da7 3215{
e8ef3da7 3216 {
f8dcd5ca 3217 LOCK(cs_wallet);
e8ef3da7
WL
3218 map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
3219 if (mi != mapWallet.end())
3220 {
3221 const CWalletTx& prev = (*mi).second;
3222 if (txin.prevout.n < prev.vout.size())
ea340a14 3223 if (::IsMine(*this, prev.vout[txin.prevout.n].scriptPubKey) & filter)
47658758 3224 return prev.vout[txin.prevout.n].nValue; // komodo_interest?
e8ef3da7
WL
3225 }
3226 }
3227 return 0;
3228}
3229
56fe75cb 3230CCurrencyValueMap CWallet::GetReserveDebit(const CTxIn &txin, const isminefilter& filter) const
3231{
3232 {
3233 LOCK(cs_wallet);
3234 map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
3235 if (mi != mapWallet.end())
3236 {
3237 const CWalletTx& prev = (*mi).second;
3238 if (txin.prevout.n < prev.vout.size())
3239 if (::IsMine(*this, prev.vout[txin.prevout.n].scriptPubKey) & filter)
3240 return prev.vout[txin.prevout.n].ReserveOutValue();
3241 }
3242 }
3243 return CCurrencyValueMap();
3244}
3245
eca0b1ea
JT
3246isminetype CWallet::IsMine(const CTxOut& txout) const
3247{
3248 return ::IsMine(*this, txout.scriptPubKey);
3249}
3250
3251CAmount CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter) const
3252{
3253 if (!MoneyRange(txout.nValue))
3254 throw std::runtime_error("CWallet::GetCredit(): value out of range");
3255 return ((IsMine(txout) & filter) ? txout.nValue : 0);
3256}
3257
e679ec96
GA
3258bool CWallet::IsChange(const CTxOut& txout) const
3259{
2a45a494 3260 // TODO: fix handling of 'change' outputs. The assumption is that any
d5087d1b 3261 // payment to a script that is ours, but is not in the address book
2a45a494
GA
3262 // is change. That assumption is likely to break when we implement multisignature
3263 // wallets that return change back into a multi-signature-protected address;
3264 // a better way of identifying which outputs are 'the send' and which are
3265 // 'the change' will need to be implemented (maybe extend CWalletTx to remember
3266 // which output, if any, was change).
d5087d1b 3267 if (::IsMine(*this, txout.scriptPubKey))
f8dcd5ca 3268 {
d5087d1b
PW
3269 CTxDestination address;
3270 if (!ExtractDestination(txout.scriptPubKey, address))
3271 return true;
3272
f8dcd5ca
PW
3273 LOCK(cs_wallet);
3274 if (!mapAddressBook.count(address))
3275 return true;
3276 }
e679ec96
GA
3277 return false;
3278}
3279
eca0b1ea
JT
3280CAmount CWallet::GetChange(const CTxOut& txout) const
3281{
3282 if (!MoneyRange(txout.nValue))
3283 throw std::runtime_error("CWallet::GetChange(): value out of range");
3284 return (IsChange(txout) ? txout.nValue : 0);
3285}
3286
ea340a14 3287typedef vector<unsigned char> valtype;
3288unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore);
3289
90e75021 3290bool CWallet::IsMine(const CTransaction& tx)
eca0b1ea 3291{
90e75021 3292 for (int i = 0; i < tx.vout.size(); i++)
3293 {
1a0fc308 3294 if (IsMine(tx, i))
eca0b1ea 3295 return true;
90e75021 3296 }
3297 return false;
3298}
3299
29bd53a1
MT
3300// special case handling for non-standard/Verus OP_RETURN script outputs, which need the transaction
3301// to determine ownership
ea340a14 3302isminetype CWallet::IsMine(const CTransaction& tx, uint32_t voutNum)
29bd53a1
MT
3303{
3304 vector<valtype> vSolutions;
3305 txnouttype whichType;
0d7fed99 3306 CScript scriptPubKey = tx.vout[voutNum].scriptPubKey;
29bd53a1 3307
0d7fed99 3308 if (scriptPubKey.IsCheckLockTimeVerify())
b7c685b8 3309 {
0d7fed99 3310 uint8_t pushOp = scriptPubKey[0];
3311 uint32_t scriptStart = pushOp + 3;
b7c685b8 3312
0d7fed99 3313 // continue with post CLTV script
3314 scriptPubKey = CScript(scriptPubKey.size() > scriptStart ? scriptPubKey.begin() + scriptStart : scriptPubKey.end(), scriptPubKey.end());
3315 }
3316
3317 COptCCParams p;
3318 if (scriptPubKey.IsPayToCryptoCondition(p) && p.IsValid())
3319 {
3320 std::vector<CTxDestination> dests;
3321 int minSigs;
3322 bool canSign = false;
3323 bool canSpend = false;
b7c685b8 3324
0d7fed99 3325 if (ExtractDestinations(scriptPubKey, whichType, dests, minSigs, this, &canSign, &canSpend))
3326 {
3327 if (canSpend)
b7c685b8 3328 {
3329 return ISMINE_SPENDABLE;
3330 }
0d7fed99 3331 else if (canSign)
b7c685b8 3332 {
3333 return ISMINE_WATCH_ONLY;
3334 }
2f537fa1 3335 else
3336 {
3337 return ISMINE_NO;
3338 }
b7c685b8 3339 }
3340 else
3341 {
0d7fed99 3342 return ISMINE_NO;
b7c685b8 3343 }
3344 }
3345 else if (!Solver(scriptPubKey, whichType, vSolutions))
3346 {
29bd53a1
MT
3347 if (this->HaveWatchOnly(scriptPubKey))
3348 return ISMINE_WATCH_ONLY;
3349 return ISMINE_NO;
3350 }
3351
3352 CKeyID keyID;
90e75021 3353 CScriptID scriptID;
29bd53a1
MT
3354 CScriptExt subscript;
3355 int voutNext = voutNum + 1;
3356
3357 switch (whichType)
3358 {
3359 case TX_NONSTANDARD:
3360 case TX_NULL_DATA:
3361 break;
3362
68b9a352 3363 case TX_CRYPTOCONDITION:
ac53126c 3364 // for now, default is that the first value returned will be the target address, subsequent values will be
3365 // pubkeys. if we have the first in our wallet, we consider it spendable for now
3366 if (vSolutions[0].size() == 33)
68b9a352 3367 {
ac53126c 3368 keyID = CPubKey(vSolutions[0]).GetID();
3369 }
3370 else if (vSolutions[0].size() == 20)
3371 {
3372 keyID = CKeyID(uint160(vSolutions[0]));
3373 }
3374 if (!keyID.IsNull() && HaveKey(keyID))
3375 {
3376 return ISMINE_SPENDABLE;
68b9a352 3377 }
3378 break;
3379
29bd53a1
MT
3380 case TX_PUBKEY:
3381 keyID = CPubKey(vSolutions[0]).GetID();
3382 if (this->HaveKey(keyID))
3383 return ISMINE_SPENDABLE;
3384 break;
3385
3386 case TX_PUBKEYHASH:
3387 keyID = CKeyID(uint160(vSolutions[0]));
3388 if (this->HaveKey(keyID))
3389 return ISMINE_SPENDABLE;
3390 break;
3391
3392 case TX_SCRIPTHASH:
90e75021 3393 scriptID = CScriptID(uint160(vSolutions[0]));
29bd53a1
MT
3394 if (this->GetCScript(scriptID, subscript))
3395 {
3396 // if this is a CLTV, handle it differently
ef70c5b2 3397 if (subscript.IsCheckLockTimeVerify())
29bd53a1 3398 {
ea340a14 3399 return (::IsMine(*this, subscript));
29bd53a1
MT
3400 }
3401 else
3402 {
3403 isminetype ret = ::IsMine(*this, subscript);
3404 if (ret == ISMINE_SPENDABLE)
3405 return ret;
3406 }
3407 }
ebee7b5b
MT
3408 else if (tx.vout.size() > (voutNum + 1) &&
3409 tx.vout.back().scriptPubKey.size() > 7 &&
3410 tx.vout.back().scriptPubKey[0] == OP_RETURN)
29bd53a1
MT
3411 {
3412 // get the opret script from next vout, verify that the front is CLTV and hash matches
3413 // if so, remove it and use the solver
3414 opcodetype op;
3415 std::vector<uint8_t> opretData;
ebee7b5b
MT
3416 CScript::const_iterator it = tx.vout.back().scriptPubKey.begin() + 1;
3417 if (tx.vout.back().scriptPubKey.GetOp2(it, op, &opretData))
29bd53a1 3418 {
9feb4b9e 3419 if (opretData.size() > 0 && opretData[0] == OPRETTYPE_TIMELOCK)
29bd53a1 3420 {
9feb4b9e 3421 CScript opretScript = CScript(opretData.begin() + 1, opretData.end());
29bd53a1
MT
3422
3423 if (CScriptID(opretScript) == scriptID &&
ef70c5b2 3424 opretScript.IsCheckLockTimeVerify())
29bd53a1 3425 {
ea340a14 3426 // if we find that this is ours, we need to add this script to the wallet,
3427 // and we can then recognize this transaction
3428 isminetype t = ::IsMine(*this, opretScript);
3429 if (t != ISMINE_NO)
3430 {
3431 this->AddCScript(opretScript);
3432 }
3433 return t;
29bd53a1
MT
3434 }
3435 }
3436 }
3437 }
3438 break;
3439
3440 case TX_MULTISIG:
3441 // Only consider transactions "mine" if we own ALL the
3442 // keys involved. Multi-signature transactions that are
3443 // partially owned (somebody else has a key that can spend
3444 // them) enable spend-out-from-under-you attacks, especially
3445 // in shared-wallet situations.
3446 vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
3447 if (HaveKeys(keys, *this) == keys.size())
3448 return ISMINE_SPENDABLE;
3449 break;
3450 }
3451
3452 if (this->HaveWatchOnly(scriptPubKey))
3453 return ISMINE_WATCH_ONLY;
3454
3455 return ISMINE_NO;
3456}
3457
eca0b1ea
JT
3458bool CWallet::IsFromMe(const CTransaction& tx) const
3459{
1551db87
JG
3460 if (GetDebit(tx, ISMINE_ALL) > 0) {
3461 return true;
3462 }
f57f76d7 3463 for (const JSDescription& jsdesc : tx.vJoinSplit) {
1551db87 3464 for (const uint256& nullifier : jsdesc.nullifiers) {
037cacf2 3465 if (IsSproutNullifierFromMe(nullifier)) {
1551db87
JG
3466 return true;
3467 }
3468 }
3469 }
d7cf640b
S
3470 for (const SpendDescription &spend : tx.vShieldedSpend) {
3471 if (IsSaplingNullifierFromMe(spend.nullifier)) {
3472 return true;
3473 }
3474 }
1551db87 3475 return false;
eca0b1ea
JT
3476}
3477
3478CAmount CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter) const
3479{
3480 CAmount nDebit = 0;
3481 BOOST_FOREACH(const CTxIn& txin, tx.vin)
3482 {
3483 nDebit += GetDebit(txin, filter);
3484 if (!MoneyRange(nDebit))
3485 throw std::runtime_error("CWallet::GetDebit(): value out of range");
3486 }
3487 return nDebit;
3488}
3489
56fe75cb 3490CCurrencyValueMap CWallet::GetReserveDebit(const CTransaction& tx, const isminefilter& filter) const
3491{
3492 CCurrencyValueMap retVal;
3493 BOOST_FOREACH(const CTxIn& txin, tx.vin)
3494 {
3495 retVal += GetReserveDebit(txin, filter);
3496 }
3497 return retVal;
3498}
3499
fab1429d 3500CAmount CWallet::GetCredit(const CTransaction& tx, int32_t voutNum, const isminefilter& filter) const
3501{
3502 if (voutNum >= tx.vout.size() || !MoneyRange(tx.vout[voutNum].nValue))
3503 throw std::runtime_error("CWallet::GetCredit(): value out of range");
ea340a14 3504 return ((IsMine(tx.vout[voutNum]) & filter) ? tx.vout[voutNum].nValue : 0);
fab1429d 3505}
3506
56fe75cb 3507CCurrencyValueMap CWallet::GetReserveCredit(const CTransaction& tx, int32_t voutNum, const isminefilter& filter) const
3a27113e 3508{
56fe75cb 3509 return ((IsMine(tx.vout[voutNum]) & filter) ? tx.vout[voutNum].ReserveOutValue() : CCurrencyValueMap());
3a27113e 3510}
3511
56fe75cb 3512CCurrencyValueMap CWallet::GetReserveCredit(const CTransaction& tx, const isminefilter& filter) const
3a27113e 3513{
56fe75cb 3514 CCurrencyValueMap nCredit;
3a27113e 3515 for (int i = 0; i < tx.vout.size(); i++)
3516 {
3517 nCredit += GetReserveCredit(tx, i, filter);
3518 }
3519 return nCredit;
3520}
3521
eca0b1ea
JT
3522CAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) const
3523{
3524 CAmount nCredit = 0;
fab1429d 3525 for (int i = 0; i < tx.vout.size(); i++)
eca0b1ea 3526 {
fab1429d 3527 nCredit += GetCredit(tx, i, filter);
eca0b1ea
JT
3528 }
3529 return nCredit;
3530}
3531
3532CAmount CWallet::GetChange(const CTransaction& tx) const
3533{
3534 CAmount nChange = 0;
3535 BOOST_FOREACH(const CTxOut& txout, tx.vout)
3536 {
3537 nChange += GetChange(txout);
3538 if (!MoneyRange(nChange))
3539 throw std::runtime_error("CWallet::GetChange(): value out of range");
3540 }
3541 return nChange;
3542}
3543
e2416930
JG
3544bool CWallet::IsHDFullyEnabled() const
3545{
3546 // Only Sapling addresses are HD for now
3547 return false;
3548}
3549
3550void CWallet::GenerateNewSeed()
3551{
3552 LOCK(cs_wallet);
3553
3554 auto seed = HDSeed::Random(HD_WALLET_SEED_LENGTH);
3555
3556 int64_t nCreationTime = GetTime();
3557
3558 // If the wallet is encrypted and locked, this will fail.
3559 if (!SetHDSeed(seed))
3560 throw std::runtime_error(std::string(__func__) + ": SetHDSeed failed");
3561
3562 // store the key creation time together with
3563 // the child index counter in the database
3564 // as a hdchain object
3565 CHDChain newHdChain;
3566 newHdChain.nVersion = CHDChain::VERSION_HD_BASE;
3567 newHdChain.seedFp = seed.Fingerprint();
3568 newHdChain.nCreateTime = nCreationTime;
3569 SetHDChain(newHdChain, false);
3570}
3571
3572bool CWallet::SetHDSeed(const HDSeed& seed)
c3a7307a 3573{
e2416930
JG
3574 if (!CCryptoKeyStore::SetHDSeed(seed)) {
3575 return false;
3576 }
3577
3578 if (!fFileBacked) {
3579 return true;
3580 }
3581
3582 {
3583 LOCK(cs_wallet);
3584 if (!IsCrypted()) {
3585 return CWalletDB(strWalletFile).WriteHDSeed(seed);
3586 }
3587 }
3588 return true;
3589}
3590
3591bool CWallet::SetCryptedHDSeed(const uint256& seedFp, const std::vector<unsigned char> &vchCryptedSecret)
3592{
3593 if (!CCryptoKeyStore::SetCryptedHDSeed(seedFp, vchCryptedSecret)) {
3594 return false;
3595 }
3596
3597 if (!fFileBacked) {
3598 return true;
3599 }
3600
3601 {
3602 LOCK(cs_wallet);
3603 if (pwalletdbEncryption)
3604 return pwalletdbEncryption->WriteCryptedHDSeed(seedFp, vchCryptedSecret);
3605 else
3606 return CWalletDB(strWalletFile).WriteCryptedHDSeed(seedFp, vchCryptedSecret);
3607 }
3608 return false;
3609}
3610
52cfa9c1
E
3611HDSeed CWallet::GetHDSeedForRPC() const {
3612 HDSeed seed;
3613 if (!pwalletMain->GetHDSeed(seed)) {
3614 throw JSONRPCError(RPC_WALLET_ERROR, "HD seed not found");
3615 }
3616 return seed;
3617}
3618
e2416930
JG
3619void CWallet::SetHDChain(const CHDChain& chain, bool memonly)
3620{
3621 LOCK(cs_wallet);
3622 if (!memonly && fFileBacked && !CWalletDB(strWalletFile).WriteHDChain(chain))
3623 throw std::runtime_error(std::string(__func__) + ": writing chain failed");
3624
3625 hdChain = chain;
3626}
3627
3628bool CWallet::LoadHDSeed(const HDSeed& seed)
3629{
3630 return CBasicKeyStore::SetHDSeed(seed);
3631}
3632
3633bool CWallet::LoadCryptedHDSeed(const uint256& seedFp, const std::vector<unsigned char>& seed)
3634{
3635 return CCryptoKeyStore::SetCryptedHDSeed(seedFp, seed);
3636}
3637
8e8279e7 3638void CWalletTx::SetSproutNoteData(mapSproutNoteData_t &noteData)
c3a7307a 3639{
005f3ad1
EOW
3640 mapSproutNoteData.clear();
3641 for (const std::pair<JSOutPoint, SproutNoteData> nd : noteData) {
f57f76d7
DA
3642 if (nd.first.js < vJoinSplit.size() &&
3643 nd.first.n < vJoinSplit[nd.first.js].ciphertexts.size()) {
c3a7307a 3644 // Store the address and nullifier for the Note
005f3ad1 3645 mapSproutNoteData[nd.first] = nd.second;
c3a7307a 3646 } else {
57faf44e 3647 // If FindMySproutNotes() was used to obtain noteData,
c3a7307a 3648 // this should never happen
8e8279e7 3649 throw std::logic_error("CWalletTx::SetSproutNoteData(): Invalid note");
c3a7307a
JG
3650 }
3651 }
3652}
3653
e6b0a8b9
EOW
3654void CWalletTx::SetSaplingNoteData(mapSaplingNoteData_t &noteData)
3655{
3656 mapSaplingNoteData.clear();
3657 for (const std::pair<SaplingOutPoint, SaplingNoteData> nd : noteData) {
3658 if (nd.first.n < vShieldedOutput.size()) {
3659 mapSaplingNoteData[nd.first] = nd.second;
3660 } else {
3661 throw std::logic_error("CWalletTx::SetSaplingNoteData(): Invalid note");
c3a7307a
JG
3662 }
3663 }
3664}
3665
79cd5c96 3666std::pair<SproutNotePlaintext, SproutPaymentAddress> CWalletTx::DecryptSproutNote(
3667 JSOutPoint jsop) const
3668{
3669 LOCK(pwallet->cs_wallet);
3670
3671 auto nd = this->mapSproutNoteData.at(jsop);
3672 SproutPaymentAddress pa = nd.address;
3673
3674 // Get cached decryptor
3675 ZCNoteDecryption decryptor;
3676 if (!pwallet->GetNoteDecryptor(pa, decryptor)) {
3677 // Note decryptors are created when the wallet is loaded, so it should always exist
3678 throw std::runtime_error(strprintf(
3679 "Could not find note decryptor for payment address %s",
3680 EncodePaymentAddress(pa)));
3681 }
3682
3683 auto hSig = this->vJoinSplit[jsop.js].h_sig(*pzcashParams, this->joinSplitPubKey);
3684 try {
3685 SproutNotePlaintext plaintext = SproutNotePlaintext::decrypt(
3686 decryptor,
3687 this->vJoinSplit[jsop.js].ciphertexts[jsop.n],
3688 this->vJoinSplit[jsop.js].ephemeralKey,
3689 hSig,
3690 (unsigned char) jsop.n);
3691
3692 return std::make_pair(plaintext, pa);
3693 } catch (const note_decryption_failed &err) {
3694 // Couldn't decrypt with this spending key
3695 throw std::runtime_error(strprintf(
3696 "Could not decrypt note for payment address %s",
3697 EncodePaymentAddress(pa)));
3698 } catch (const std::exception &exc) {
3699 // Unexpected failure
3700 throw std::runtime_error(strprintf(
3701 "Error while decrypting note for payment address %s: %s",
3702 EncodePaymentAddress(pa), exc.what()));
3703 }
3704}
3705
3706boost::optional<std::pair<
3707 SaplingNotePlaintext,
3708 SaplingPaymentAddress>> CWalletTx::DecryptSaplingNote(SaplingOutPoint op) const
3709{
3710 // Check whether we can decrypt this SaplingOutPoint
3711 if (this->mapSaplingNoteData.count(op) == 0) {
3712 return boost::none;
3713 }
3714
3715 auto output = this->vShieldedOutput[op.n];
3716 auto nd = this->mapSaplingNoteData.at(op);
3717
3718 auto maybe_pt = SaplingNotePlaintext::decrypt(
3719 output.encCiphertext,
3720 nd.ivk,
3721 output.ephemeralKey,
3722 output.cm);
3723 assert(static_cast<bool>(maybe_pt));
3724 auto notePt = maybe_pt.get();
3725
3726 auto maybe_pa = nd.ivk.address(notePt.d);
3727 assert(static_cast<bool>(maybe_pa));
3728 auto pa = maybe_pa.get();
3729
3730 return std::make_pair(notePt, pa);
3731}
3732
3733boost::optional<std::pair<
3734 SaplingNotePlaintext,
3735 SaplingPaymentAddress>> CWalletTx::RecoverSaplingNote(
3736 SaplingOutPoint op, std::set<uint256>& ovks) const
3737{
3738 auto output = this->vShieldedOutput[op.n];
3739
3740 for (auto ovk : ovks) {
3741 auto outPt = SaplingOutgoingPlaintext::decrypt(
3742 output.outCiphertext,
3743 ovk,
3744 output.cv,
3745 output.cm,
3746 output.ephemeralKey);
3747 if (!outPt) {
3748 continue;
3749 }
3750
3751 auto maybe_pt = SaplingNotePlaintext::decrypt(
3752 output.encCiphertext,
3753 output.ephemeralKey,
3754 outPt->esk,
3755 outPt->pk_d,
3756 output.cm);
3757 assert(static_cast<bool>(maybe_pt));
3758 auto notePt = maybe_pt.get();
3759
3760 return std::make_pair(notePt, SaplingPaymentAddress(notePt.d, outPt->pk_d));
3761 }
3762
3763 // Couldn't recover with any of the provided OutgoingViewingKeys
3764 return boost::none;
3765}
3766
51ed9ec9 3767int64_t CWalletTx::GetTxTime() const
e8ef3da7 3768{
51ed9ec9 3769 int64_t n = nTimeSmart;
c3f95ef1 3770 return n ? n : nTimeReceived;
e8ef3da7
WL
3771}
3772
3773int CWalletTx::GetRequestCount() const
3774{
3775 // Returns -1 if it wasn't being tracked
3776 int nRequests = -1;
e8ef3da7 3777 {
f8dcd5ca 3778 LOCK(pwallet->cs_wallet);
e8ef3da7
WL
3779 if (IsCoinBase())
3780 {
3781 // Generated block
4f152496 3782 if (!hashBlock.IsNull())
e8ef3da7
WL
3783 {
3784 map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
3785 if (mi != pwallet->mapRequestCount.end())
3786 nRequests = (*mi).second;
3787 }
3788 }
3789 else
3790 {
3791 // Did anyone request this transaction?
805344dc 3792 map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash());
e8ef3da7
WL
3793 if (mi != pwallet->mapRequestCount.end())
3794 {
3795 nRequests = (*mi).second;
3796
3797 // How about the block it's in?
4f152496 3798 if (nRequests == 0 && !hashBlock.IsNull())
e8ef3da7
WL
3799 {
3800 map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
3801 if (mi != pwallet->mapRequestCount.end())
3802 nRequests = (*mi).second;
3803 else
3804 nRequests = 1; // If it's in someone else's block it must have got out
3805 }
3806 }
3807 }
3808 }
3809 return nRequests;
3810}
3811
86cf60b5 3812// GetAmounts will determine the transparent debits and credits for a given wallet tx.
1b4568cb 3813void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
a372168e 3814 list<COutputEntry>& listSent, CAmount& nFee, string& strSentAccount, const isminefilter& filter) const
e8ef3da7 3815{
e07c8e91 3816 nFee = 0;
e8ef3da7
WL
3817 listReceived.clear();
3818 listSent.clear();
3819 strSentAccount = strFromAccount;
3820
86cf60b5 3821 // Is this tx sent/signed by me?
a372168e 3822 CAmount nDebit = GetDebit(filter);
86cf60b5
S
3823 bool isFromMyTaddr = nDebit > 0; // debit>0 means we signed/sent this transaction
3824
86cf60b5
S
3825 // Compute fee if we sent this transaction.
3826 if (isFromMyTaddr) {
f6863889
S
3827 CAmount nValueOut = GetValueOut(); // transparent outputs plus all Sprout vpub_old and negative Sapling valueBalance
3828 CAmount nValueIn = GetShieldedValueIn();
86cf60b5
S
3829 nFee = nDebit - nValueOut + nValueIn;
3830 }
3831
3832 // Create output entry for vpub_old/new, if we sent utxos from this transaction
3833 if (isFromMyTaddr) {
3834 CAmount myVpubOld = 0;
3835 CAmount myVpubNew = 0;
f57f76d7 3836 for (const JSDescription& js : vJoinSplit) {
86cf60b5
S
3837 bool fMyJSDesc = false;
3838
3839 // Check input side
3840 for (const uint256& nullifier : js.nullifiers) {
037cacf2 3841 if (pwallet->IsSproutNullifierFromMe(nullifier)) {
86cf60b5
S
3842 fMyJSDesc = true;
3843 break;
3844 }
3845 }
3846
3847 // Check output side
3848 if (!fMyJSDesc) {
005f3ad1 3849 for (const std::pair<JSOutPoint, SproutNoteData> nd : this->mapSproutNoteData) {
f57f76d7 3850 if (nd.first.js < vJoinSplit.size() && nd.first.n < vJoinSplit[nd.first.js].ciphertexts.size()) {
86cf60b5
S
3851 fMyJSDesc = true;
3852 break;
3853 }
3854 }
3855 }
3856
3857 if (fMyJSDesc) {
3858 myVpubOld += js.vpub_old;
3859 myVpubNew += js.vpub_new;
3860 }
3861
3862 if (!MoneyRange(js.vpub_old) || !MoneyRange(js.vpub_new) || !MoneyRange(myVpubOld) || !MoneyRange(myVpubNew)) {
3863 throw std::runtime_error("CWalletTx::GetAmounts: value out of range");
3864 }
3865 }
3866
3867 // Create an output for the value taken from or added to the transparent value pool by JoinSplits
3868 if (myVpubOld > myVpubNew) {
3869 COutputEntry output = {CNoDestination(), myVpubOld - myVpubNew, (int)vout.size()};
3870 listSent.push_back(output);
3871 } else if (myVpubNew > myVpubOld) {
3872 COutputEntry output = {CNoDestination(), myVpubNew - myVpubOld, (int)vout.size()};
3873 listReceived.push_back(output);
3874 }
e8ef3da7
WL
3875 }
3876
f9816408
S
3877 // If we sent utxos from this transaction, create output for value taken from (negative valueBalance)
3878 // or added (positive valueBalance) to the transparent value pool by Sapling shielding and unshielding.
3879 if (isFromMyTaddr) {
3880 if (valueBalance < 0) {
3881 COutputEntry output = {CNoDestination(), -valueBalance, (int) vout.size()};
3882 listSent.push_back(output);
3883 } else if (valueBalance > 0) {
3884 COutputEntry output = {CNoDestination(), valueBalance, (int) vout.size()};
3885 listReceived.push_back(output);
3886 }
3887 }
3888
e679ec96 3889 // Sent/received.
5bb76550 3890 for (unsigned int i = 0; i < vout.size(); ++i)
e8ef3da7 3891 {
1b4568cb 3892 const CTxOut& txout = vout[i];
a5c6c5d6 3893 isminetype fIsMine = pwallet->IsMine(txout);
96ed6821
LD
3894 // Only need to handle txouts if AT LEAST one of these is true:
3895 // 1) they debit from us (sent)
3896 // 2) the output is to us (received)
3897 if (nDebit > 0)
3898 {
3899 // Don't report 'change' txouts
73b4d696 3900 if (!(filter & ISMINE_CHANGE) && pwallet->IsChange(txout))
96ed6821 3901 continue;
96ed6821 3902 }
a5c6c5d6 3903 else if (!(fIsMine & filter))
96ed6821
LD
3904 continue;
3905
3906 // In either case, we need to get the destination address
10254401 3907 CTxDestination address;
10254401 3908 if (!ExtractDestination(txout.scriptPubKey, address))
e8ef3da7 3909 {
7d306d64 3910 //LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",this->GetHash().ToString()); complains on the opreturns
96ed6821 3911 address = CNoDestination();
e8ef3da7
WL
3912 }
3913
5bb76550 3914 COutputEntry output = {address, txout.nValue, (int)i};
1b4568cb 3915
96ed6821 3916 // If we are debited by the transaction, add the output as a "sent" entry
e8ef3da7 3917 if (nDebit > 0)
1b4568cb 3918 listSent.push_back(output);
e8ef3da7 3919
96ed6821 3920 // If we are receiving the output, add it as a "received" entry
d512534c 3921 if (fIsMine & filter)
1b4568cb 3922 listReceived.push_back(output);
e8ef3da7
WL
3923 }
3924
3925}
3926
a372168e
MF
3927void CWalletTx::GetAccountAmounts(const string& strAccount, CAmount& nReceived,
3928 CAmount& nSent, CAmount& nFee, const isminefilter& filter) const
e8ef3da7 3929{
e07c8e91 3930 nReceived = nSent = nFee = 0;
e8ef3da7 3931
a372168e 3932 CAmount allFee;
e8ef3da7 3933 string strSentAccount;
1b4568cb
CL
3934 list<COutputEntry> listReceived;
3935 list<COutputEntry> listSent;
d4640d7d 3936 GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
e8ef3da7 3937
e8ef3da7
WL
3938 if (strAccount == strSentAccount)
3939 {
1b4568cb
CL
3940 BOOST_FOREACH(const COutputEntry& s, listSent)
3941 nSent += s.amount;
e8ef3da7
WL
3942 nFee = allFee;
3943 }
e8ef3da7 3944 {
f8dcd5ca 3945 LOCK(pwallet->cs_wallet);
1b4568cb 3946 BOOST_FOREACH(const COutputEntry& r, listReceived)
e8ef3da7 3947 {
1b4568cb 3948 if (pwallet->mapAddressBook.count(r.destination))
e8ef3da7 3949 {
1b4568cb 3950 map<CTxDestination, CAddressBookData>::const_iterator mi = pwallet->mapAddressBook.find(r.destination);
61885513 3951 if (mi != pwallet->mapAddressBook.end() && (*mi).second.name == strAccount)
1b4568cb 3952 nReceived += r.amount;
e8ef3da7
WL
3953 }
3954 else if (strAccount.empty())
3955 {
1b4568cb 3956 nReceived += r.amount;
e8ef3da7
WL
3957 }
3958 }
3959 }
3960}
3961
722fa283 3962
44bc988e 3963bool CWalletTx::WriteToDisk(CWalletDB *pwalletdb)
e8ef3da7 3964{
805344dc 3965 return pwalletdb->WriteTx(GetHash(), *this);
e8ef3da7
WL
3966}
3967
4bc00dc1 3968void CWallet::WitnessNoteCommitment(std::vector<uint256> commitments,
8ea8ef98 3969 std::vector<boost::optional<SproutWitness>>& witnesses,
4bc00dc1 3970 uint256 &final_anchor)
a8ac403d 3971{
2dc35992 3972 witnesses.resize(commitments.size());
a8ac403d 3973 CBlockIndex* pindex = chainActive.Genesis();
4fc309f0 3974 SproutMerkleTree tree;
a8ac403d
SB
3975
3976 while (pindex) {
3977 CBlock block;
88d014d0 3978 ReadBlockFromDisk(block, pindex, Params().GetConsensus(), 1);
a8ac403d
SB
3979
3980 BOOST_FOREACH(const CTransaction& tx, block.vtx)
3981 {
f57f76d7 3982 BOOST_FOREACH(const JSDescription& jsdesc, tx.vJoinSplit)
a8ac403d 3983 {
22de1602 3984 BOOST_FOREACH(const uint256 &note_commitment, jsdesc.commitments)
a8ac403d 3985 {
4bc00dc1 3986 tree.append(note_commitment);
1760b3cd 3987
8ea8ef98 3988 BOOST_FOREACH(boost::optional<SproutWitness>& wit, witnesses) {
2dc35992 3989 if (wit) {
4bc00dc1 3990 wit->append(note_commitment);
2dc35992
SB
3991 }
3992 }
3993
3994 size_t i = 0;
3995 BOOST_FOREACH(uint256& commitment, commitments) {
4bc00dc1 3996 if (note_commitment == commitment) {
2dc35992 3997 witnesses.at(i) = tree.witness();
1760b3cd 3998 }
2dc35992 3999 i++;
a8ac403d
SB
4000 }
4001 }
4002 }
4003 }
4004
ccb439c5 4005 uint256 current_anchor = tree.root();
a8ac403d
SB
4006
4007 // Consistency check: we should be able to find the current tree
4008 // in our CCoins view.
4fc309f0 4009 SproutMerkleTree dummy_tree;
008f4ee8 4010 assert(pcoinsTip->GetSproutAnchorAt(current_anchor, dummy_tree));
a8ac403d
SB
4011
4012 pindex = chainActive.Next(pindex);
4013 }
4014
ccb439c5
SB
4015 // TODO: #93; Select a root via some heuristic.
4016 final_anchor = tree.root();
a8ac403d 4017
8ea8ef98 4018 BOOST_FOREACH(boost::optional<SproutWitness>& wit, witnesses) {
2dc35992
SB
4019 if (wit) {
4020 assert(final_anchor == wit->root());
4021 }
1760b3cd 4022 }
a8ac403d
SB
4023}
4024
5b40d886
MF
4025/**
4026 * Scan the block chain (starting in pindexStart) for transactions
4027 * from or to us. If fUpdate is true, found transactions that already
4028 * exist in the wallet will be updated.
4029 */
e8ef3da7
WL
4030int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
4031{
4032 int ret = 0;
75b8953a 4033 int64_t nNow = GetTime();
11982d36 4034 const CChainParams& chainParams = Params();
e8ef3da7
WL
4035
4036 CBlockIndex* pindex = pindexStart;
cd10562c
S
4037
4038 std::vector<uint256> myTxHashes;
4039
e8ef3da7 4040 {
55a1db4f 4041 LOCK2(cs_main, cs_wallet);
39278369
CL
4042
4043 // no need to read and scan block, if block was created before
4044 // our wallet birthday (as adjusted for block time variability)
209377a7 4045 while (pindex && nTimeFirstKey && (pindex->GetBlockTime() < (nTimeFirstKey - 7200)))
39278369
CL
4046 pindex = chainActive.Next(pindex);
4047
4048 ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
11982d36 4049 double dProgressStart = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex, false);
86131275 4050 double dProgressTip = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.LastTip(), false);
e8ef3da7
WL
4051 while (pindex)
4052 {
4b729ec5 4053 if (pindex->GetHeight() % 100 == 0 && dProgressTip - dProgressStart > 0.0)
11982d36 4054 ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex, false) - dProgressStart) / (dProgressTip - dProgressStart) * 100))));
8da9dd07 4055
e8ef3da7 4056 CBlock block;
71cf6ba9 4057 ReadBlockFromDisk(block, pindex, Params().GetConsensus());
e8ef3da7
WL
4058 BOOST_FOREACH(CTransaction& tx, block.vtx)
4059 {
cd10562c
S
4060 if (AddToWalletIfInvolvingMe(tx, &block, fUpdate)) {
4061 myTxHashes.push_back(tx.GetHash());
e8ef3da7 4062 ret++;
cd10562c 4063 }
e8ef3da7 4064 }
b6961fc1 4065
4fc309f0
EOW
4066 SproutMerkleTree sproutTree;
4067 SaplingMerkleTree saplingTree;
b6961fc1
JG
4068 // This should never fail: we should always be able to get the tree
4069 // state on the path to the tip of our chain
f86ee1c2
EOW
4070 assert(pcoinsTip->GetSproutAnchorAt(pindex->hashSproutAnchor, sproutTree));
4071 if (pindex->pprev) {
88d014d0 4072 if (Params().GetConsensus().NetworkUpgradeActive(pindex->pprev->GetHeight(), Consensus::UPGRADE_SAPLING)) {
d9fe33b8
S
4073 assert(pcoinsTip->GetSaplingAnchorAt(pindex->pprev->hashFinalSaplingRoot, saplingTree));
4074 }
f86ee1c2 4075 }
b6961fc1 4076 // Increment note witness caches
162bfc3a 4077 ChainTipAdded(pindex, &block, sproutTree, saplingTree);
b6961fc1 4078
4c6d41b8 4079 pindex = chainActive.Next(pindex);
75b8953a
B
4080 if (GetTime() >= nNow + 60) {
4081 nNow = GetTime();
4b729ec5 4082 LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->GetHeight(), Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex));
75b8953a 4083 }
e8ef3da7 4084 }
cd10562c
S
4085
4086 // After rescanning, persist Sapling note data that might have changed, e.g. nullifiers.
4087 // Do not flush the wallet here for performance reasons.
4088 CWalletDB walletdb(strWalletFile, "r+", false);
4089 for (auto hash : myTxHashes) {
4090 CWalletTx wtx = mapWallet[hash];
4091 if (!wtx.mapSaplingNoteData.empty()) {
4092 if (!wtx.WriteToDisk(&walletdb)) {
4093 LogPrintf("Rescanning... WriteToDisk failed to update Sapling note data for: %s\n", hash.ToString());
4094 }
4095 }
4096 }
4097
39278369 4098 ShowProgress(_("Rescanning..."), 100); // hide progress dialog in GUI
e8ef3da7
WL
4099 }
4100 return ret;
4101}
4102
4103void CWallet::ReacceptWalletTransactions()
4104{
7e6d23b1 4105 // If transactions aren't being broadcasted, don't let them into local mempool either
6f252627
WL
4106 if (!fBroadcastTransactions)
4107 return;
55a1db4f 4108 LOCK2(cs_main, cs_wallet);
e9c3215b 4109 std::map<int64_t, CWalletTx*> mapSorted;
4110
4111 // Sort pending wallet transactions based on their initial wallet insertion order
93a18a36 4112 BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
e8ef3da7 4113 {
93a18a36
GA
4114 const uint256& wtxid = item.first;
4115 CWalletTx& wtx = item.second;
805344dc 4116 assert(wtx.GetHash() == wtxid);
e8ef3da7 4117
93a18a36
GA
4118 int nDepth = wtx.GetDepthInMainChain();
4119
e9c3215b 4120 if (!wtx.IsCoinBase() && nDepth < 0) {
4121 mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx));
e8ef3da7
WL
4122 }
4123 }
e9c3215b 4124
43260416 4125 std::vector<uint256> vwtxh;
4126
e9c3215b 4127 // Try to add wallet transactions to memory pool
4128 BOOST_FOREACH(PAIRTYPE(const int64_t, CWalletTx*)& item, mapSorted)
4129 {
4130 CWalletTx& wtx = *(item.second);
4131
4132 LOCK(mempool.cs);
271326fa 4133 CValidationState state;
4134 // attempt to add them, but don't set any DOS level
085c3640 4135 if (!::AcceptToMemoryPool(mempool, state, wtx, false, NULL, true, 0))
4136 {
4137 int nDoS;
4138 bool invalid = state.IsInvalid(nDoS);
4139
4140 // log rejection and deletion
4141 // printf("ERROR reaccepting wallet transaction %s to mempool, reason: %s, DoS: %d\n", wtx.GetHash().ToString().c_str(), state.GetRejectReason().c_str(), nDoS);
4142
4143 if (!wtx.IsCoinBase() && invalid && nDoS > 0)
4144 {
d738023b 4145 LogPrintf("erasing transaction %s\n", wtx.GetHash().GetHex().c_str());
43260416 4146 vwtxh.push_back(wtx.GetHash());
085c3640 4147 }
4148 }
e9c3215b 4149 }
43260416 4150 for (auto hash : vwtxh)
4151 {
4152 EraseFromWallet(hash);
4153 }
e8ef3da7
WL
4154}
4155
0f5954c4 4156bool CWalletTx::RelayWalletTransaction()
e8ef3da7 4157{
7000ef1a 4158 if ( pwallet == 0 )
4159 {
4160 fprintf(stderr,"unexpected null pwallet in RelayWalletTransaction\n");
4161 return(false);
4162 }
6f252627 4163 assert(pwallet->GetBroadcastTransactions());
e8ef3da7
WL
4164 if (!IsCoinBase())
4165 {
bd070d8b 4166 if (GetDepthInMainChain() == 0)
4167 {
4168 // if tx is expired, dont relay
805344dc 4169 LogPrintf("Relaying wtx %s\n", GetHash().ToString());
d38da59b 4170 RelayTransaction((CTransaction)*this);
0f5954c4 4171 return true;
e8ef3da7
WL
4172 }
4173 }
0f5954c4 4174 return false;
e8ef3da7
WL
4175}
4176
3015e0bc 4177set<uint256> CWalletTx::GetConflicts() const
731b89b8
GA
4178{
4179 set<uint256> result;
4180 if (pwallet != NULL)
4181 {
805344dc 4182 uint256 myHash = GetHash();
3015e0bc 4183 result = pwallet->GetConflicts(myHash);
731b89b8
GA
4184 result.erase(myHash);
4185 }
4186 return result;
4187}
4188
bbacd882
CF
4189CAmount CWalletTx::GetDebit(const isminefilter& filter) const
4190{
4191 if (vin.empty())
4192 return 0;
4193
4194 CAmount debit = 0;
4195 if(filter & ISMINE_SPENDABLE)
4196 {
4197 if (fDebitCached)
4198 debit += nDebitCached;
4199 else
4200 {
4201 nDebitCached = pwallet->GetDebit(*this, ISMINE_SPENDABLE);
4202 fDebitCached = true;
4203 debit += nDebitCached;
4204 }
4205 }
4206 if(filter & ISMINE_WATCH_ONLY)
4207 {
4208 if(fWatchDebitCached)
4209 debit += nWatchDebitCached;
4210 else
4211 {
4212 nWatchDebitCached = pwallet->GetDebit(*this, ISMINE_WATCH_ONLY);
4213 fWatchDebitCached = true;
4214 debit += nWatchDebitCached;
4215 }
4216 }
4217 return debit;
4218}
4219
56fe75cb 4220CCurrencyValueMap CWalletTx::GetReserveDebit(const isminefilter& filter) const
3a27113e 4221{
4222 if (vin.empty())
56fe75cb 4223 return CCurrencyValueMap();
3a27113e 4224
56fe75cb 4225 return pwallet->GetReserveDebit(*this, filter);
3a27113e 4226}
4227
bbacd882
CF
4228CAmount CWalletTx::GetCredit(const isminefilter& filter) const
4229{
4230 // Must wait until coinbase is safely deep enough in the chain before valuing it
4231 if (IsCoinBase() && GetBlocksToMaturity() > 0)
4232 return 0;
4233
4234 int64_t credit = 0;
4235 if (filter & ISMINE_SPENDABLE)
4236 {
4237 // GetBalance can assume transactions in mapWallet won't change
4238 if (fCreditCached)
4239 credit += nCreditCached;
4240 else
4241 {
4242 nCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE);
4243 fCreditCached = true;
4244 credit += nCreditCached;
4245 }
4246 }
4247 if (filter & ISMINE_WATCH_ONLY)
4248 {
4249 if (fWatchCreditCached)
4250 credit += nWatchCreditCached;
4251 else
4252 {
4253 nWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY);
4254 fWatchCreditCached = true;
4255 credit += nWatchCreditCached;
4256 }
4257 }
4258 return credit;
4259}
4260
a78c55ad 4261bool CWalletTx::HasMatureCoins() const
4262{
4263 // Must wait until coinbase is safely deep enough in the chain before valuing it
4264 if (!(IsCoinBase() && GetBlocksToMaturity() > 0))
4265 {
4266 return true;
4267 }
4268 else
4269 {
4270 for (auto oneout : vout)
4271 {
4272 if (oneout.scriptPubKey.IsInstantSpend())
4273 {
4274 return true;
4275 }
4276 }
4277 return false;
4278 }
4279}
4280
56fe75cb 4281CCurrencyValueMap CWalletTx::GetReserveCredit(const isminefilter& filter) const
3a27113e 4282{
4283 // Must wait until coinbase is safely deep enough in the chain before valuing it
4284 if (IsCoinBase() && GetBlocksToMaturity() > 0)
56fe75cb 4285 return CCurrencyValueMap();
3a27113e 4286
56fe75cb 4287 return pwallet->GetReserveCredit(*this, filter);
3a27113e 4288}
4289
bbacd882
CF
4290CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const
4291{
4292 if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
4293 {
4294 if (fUseCache && fImmatureCreditCached)
4295 return nImmatureCreditCached;
4296 nImmatureCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE);
4297 fImmatureCreditCached = true;
4298 return nImmatureCreditCached;
4299 }
4300
4301 return 0;
4302}
4303
56fe75cb 4304CCurrencyValueMap CWalletTx::GetImmatureReserveCredit(bool fUseCache) const
3a27113e 4305{
4306 if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
4307 {
56fe75cb 4308 pwallet->GetReserveCredit(*this, ISMINE_SPENDABLE);
3a27113e 4309 }
4310
56fe75cb 4311 return CCurrencyValueMap();
3a27113e 4312}
4313
bbacd882
CF
4314CAmount CWalletTx::GetAvailableCredit(bool fUseCache) const
4315{
4316 if (pwallet == 0)
4317 return 0;
4318
4319 // Must wait until coinbase is safely deep enough in the chain before valuing it
4320 if (IsCoinBase() && GetBlocksToMaturity() > 0)
4321 return 0;
4322
4323 if (fUseCache && fAvailableCreditCached)
4324 return nAvailableCreditCached;
4325
4326 CAmount nCredit = 0;
805344dc 4327 uint256 hashTx = GetHash();
bbacd882
CF
4328 for (unsigned int i = 0; i < vout.size(); i++)
4329 {
4330 if (!pwallet->IsSpent(hashTx, i))
4331 {
fab1429d 4332 nCredit += pwallet->GetCredit(*this, i, ISMINE_SPENDABLE);
bbacd882
CF
4333 }
4334 }
4335
4336 nAvailableCreditCached = nCredit;
4337 fAvailableCreditCached = true;
4338 return nCredit;
4339}
4340
56fe75cb 4341CCurrencyValueMap CWalletTx::GetAvailableReserveCredit(bool fUseCache) const
3a27113e 4342{
56fe75cb 4343 CCurrencyValueMap retVal;
3a27113e 4344 if (pwallet == 0)
56fe75cb 4345 return retVal;
3a27113e 4346
4347 // Must wait until coinbase is safely deep enough in the chain before valuing it
4348 if (IsCoinBase() && GetBlocksToMaturity() > 0)
56fe75cb 4349 return retVal;
3a27113e 4350
3a27113e 4351 uint256 hashTx = GetHash();
4352 for (unsigned int i = 0; i < vout.size(); i++)
4353 {
4354 if (!pwallet->IsSpent(hashTx, i))
4355 {
56fe75cb 4356 retVal += pwallet->GetReserveCredit(*this, i, ISMINE_SPENDABLE);
3a27113e 4357 }
4358 }
56fe75cb 4359 return retVal;
3a27113e 4360}
4361
bbacd882
CF
4362CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool& fUseCache) const
4363{
4364 if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
4365 {
4366 if (fUseCache && fImmatureWatchCreditCached)
4367 return nImmatureWatchCreditCached;
4368 nImmatureWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY);
4369 fImmatureWatchCreditCached = true;
4370 return nImmatureWatchCreditCached;
4371 }
4372
4373 return 0;
4374}
4375
56fe75cb 4376CCurrencyValueMap CWalletTx::GetImmatureWatchOnlyReserveCredit(const bool& fUseCache) const
3a27113e 4377{
4378 if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
4379 {
56fe75cb 4380 return pwallet->GetReserveCredit(*this, ISMINE_WATCH_ONLY);
3a27113e 4381 }
4382
56fe75cb 4383 return CCurrencyValueMap();
3a27113e 4384}
4385
bbacd882
CF
4386CAmount CWalletTx::GetAvailableWatchOnlyCredit(const bool& fUseCache) const
4387{
4388 if (pwallet == 0)
4389 return 0;
4390
4391 // Must wait until coinbase is safely deep enough in the chain before valuing it
4392 if (IsCoinBase() && GetBlocksToMaturity() > 0)
4393 return 0;
4394
4395 if (fUseCache && fAvailableWatchCreditCached)
4396 return nAvailableWatchCreditCached;
4397
4398 CAmount nCredit = 0;
4399 for (unsigned int i = 0; i < vout.size(); i++)
4400 {
805344dc 4401 if (!pwallet->IsSpent(GetHash(), i))
bbacd882 4402 {
fab1429d 4403 nCredit += pwallet->GetCredit(*this, i, ISMINE_WATCH_ONLY);
bbacd882
CF
4404 if (!MoneyRange(nCredit))
4405 throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
4406 }
4407 }
4408
4409 nAvailableWatchCreditCached = nCredit;
4410 fAvailableWatchCreditCached = true;
4411 return nCredit;
4412}
4413
56fe75cb 4414CCurrencyValueMap CWalletTx::GetAvailableWatchOnlyReserveCredit(const bool& fUseCache) const
3a27113e 4415{
56fe75cb 4416 CCurrencyValueMap retVal;
3a27113e 4417 if (pwallet == 0)
56fe75cb 4418 return retVal;
3a27113e 4419
4420 // Must wait until coinbase is safely deep enough in the chain before valuing it
4421 if (IsCoinBase() && GetBlocksToMaturity() > 0)
56fe75cb 4422 return retVal;
3a27113e 4423
3a27113e 4424 for (unsigned int i = 0; i < vout.size(); i++)
4425 {
4426 if (!pwallet->IsSpent(GetHash(), i))
4427 {
56fe75cb 4428 retVal += pwallet->GetReserveCredit(*this, i, ISMINE_WATCH_ONLY);
3a27113e 4429 }
4430 }
4431
56fe75cb 4432 return retVal;
3a27113e 4433}
4434
bbacd882
CF
4435CAmount CWalletTx::GetChange() const
4436{
4437 if (fChangeCached)
4438 return nChangeCached;
4439 nChangeCached = pwallet->GetChange(*this);
4440 fChangeCached = true;
4441 return nChangeCached;
4442}
4443
4444bool CWalletTx::IsTrusted() const
4445{
4446 // Quick answer in most cases
75a4d512 4447 if (!CheckFinalTx(*this))
bbacd882
CF
4448 return false;
4449 int nDepth = GetDepthInMainChain();
4450 if (nDepth >= 1)
4451 return true;
4452 if (nDepth < 0)
4453 return false;
4454 if (!bSpendZeroConfChange || !IsFromMe(ISMINE_ALL)) // using wtx's cached debit
4455 return false;
4456
4457 // Trusted if all inputs are from us and are in the mempool:
4458 BOOST_FOREACH(const CTxIn& txin, vin)
4459 {
4460 // Transactions not sent by us: not trusted
4461 const CWalletTx* parent = pwallet->GetWalletTx(txin.prevout.hash);
4462 if (parent == NULL)
4463 return false;
4464 const CTxOut& parentOut = parent->vout[txin.prevout.n];
4465 if (pwallet->IsMine(parentOut) != ISMINE_SPENDABLE)
4466 return false;
4467 }
4468 return true;
4469}
4470
0f5954c4
GA
4471std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
4472{
4473 std::vector<uint256> result;
4474
4475 LOCK(cs_wallet);
4476 // Sort them in chronological order
4477 multimap<unsigned int, CWalletTx*> mapSorted;
bd070d8b 4478 uint32_t now = (uint32_t)time(NULL);
47ab0926 4479 std::vector<uint256> vwtxh;
0f5954c4
GA
4480 BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
4481 {
4482 CWalletTx& wtx = item.second;
4483 // Don't rebroadcast if newer than nTime:
4484 if (wtx.nTimeReceived > nTime)
4485 continue;
3abeed2c 4486 if ( (wtx.nLockTime >= LOCKTIME_THRESHOLD && wtx.nLockTime < now-KOMODO_MAXMEMPOOLTIME) || wtx.hashBlock.IsNull() )
bd070d8b 4487 {
1aa576ad 4488 //LogPrintf("skip Relaying wtx %s nLockTime %u vs now.%u\n", wtx.GetHash().ToString(),(uint32_t)wtx.nLockTime,now);
d738023b 4489 //vwtxh.push_back(wtx.GetHash());
3abeed2c 4490 continue;
bd070d8b 4491 }
0f5954c4
GA
4492 mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
4493 }
4494 BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
4495 {
7000ef1a 4496 if ( item.second != 0 )
4497 {
3872e9cb 4498 CWalletTx &wtx = *item.second;
7000ef1a 4499 if (wtx.RelayWalletTransaction())
4500 result.push_back(wtx.GetHash());
4501 }
0f5954c4 4502 }
47ab0926 4503 for (auto hash : vwtxh)
4504 {
d738023b 4505 EraseFromWallets(hash);
47ab0926 4506 }
0f5954c4
GA
4507 return result;
4508}
4509
4510void CWallet::ResendWalletTransactions(int64_t nBestBlockTime)
e8ef3da7
WL
4511{
4512 // Do this infrequently and randomly to avoid giving away
4513 // that these are our transactions.
6f252627 4514 if (GetTime() < nNextResend || !fBroadcastTransactions)
e8ef3da7 4515 return;
203d1ae6
LD
4516 bool fFirst = (nNextResend == 0);
4517 nNextResend = GetTime() + GetRand(30 * 60);
e8ef3da7
WL
4518 if (fFirst)
4519 return;
4520
4521 // Only do it if there's been a new block since last time
0f5954c4 4522 if (nBestBlockTime < nLastResend)
e8ef3da7 4523 return;
203d1ae6 4524 nLastResend = GetTime();
e8ef3da7 4525
0f5954c4
GA
4526 // Rebroadcast unconfirmed txes older than 5 minutes before the last
4527 // block was found:
4528 std::vector<uint256> relayed = ResendWalletTransactionsBefore(nBestBlockTime-5*60);
4529 if (!relayed.empty())
4530 LogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, relayed.size());
e8ef3da7
WL
4531}
4532
5b40d886 4533/** @} */ // end of mapWallet
e8ef3da7
WL
4534
4535
4536
4537
5b40d886
MF
4538/** @defgroup Actions
4539 *
4540 * @{
4541 */
e8ef3da7
WL
4542
4543
a372168e 4544CAmount CWallet::GetBalance() const
e8ef3da7 4545{
a372168e 4546 CAmount nTotal = 0;
e8ef3da7 4547 {
55a1db4f 4548 LOCK2(cs_main, cs_wallet);
e8ef3da7
WL
4549 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4550 {
4551 const CWalletTx* pcoin = &(*it).second;
0542619d 4552 if (pcoin->IsTrusted())
8fdb7e10 4553 nTotal += pcoin->GetAvailableCredit();
e8ef3da7
WL
4554 }
4555 }
4556
e8ef3da7
WL
4557 return nTotal;
4558}
4559
56fe75cb 4560CCurrencyValueMap CWallet::GetReserveBalance() const
3a27113e 4561{
56fe75cb 4562 CCurrencyValueMap retVal;
3a27113e 4563 {
4564 LOCK2(cs_main, cs_wallet);
4565 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4566 {
4567 const CWalletTx* pcoin = &(*it).second;
4568 if (pcoin->IsTrusted())
56fe75cb 4569 retVal += pcoin->GetAvailableReserveCredit();
3a27113e 4570 }
4571 }
4572
56fe75cb 4573 return retVal;
3a27113e 4574}
4575
a372168e 4576CAmount CWallet::GetUnconfirmedBalance() const
df5ccbd2 4577{
a372168e 4578 CAmount nTotal = 0;
df5ccbd2 4579 {
55a1db4f 4580 LOCK2(cs_main, cs_wallet);
df5ccbd2
WL
4581 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4582 {
4583 const CWalletTx* pcoin = &(*it).second;
75a4d512 4584 if (!CheckFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
8fdb7e10 4585 nTotal += pcoin->GetAvailableCredit();
4586 }
4587 }
4588 return nTotal;
4589}
4590
56fe75cb 4591CCurrencyValueMap CWallet::GetUnconfirmedReserveBalance() const
3a27113e 4592{
56fe75cb 4593 CCurrencyValueMap retVal;
3a27113e 4594 {
4595 LOCK2(cs_main, cs_wallet);
4596 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4597 {
4598 const CWalletTx* pcoin = &(*it).second;
4599 if (!CheckFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
56fe75cb 4600 retVal += pcoin->GetAvailableReserveCredit();
3a27113e 4601 }
4602 }
56fe75cb 4603 return retVal;
3a27113e 4604}
4605
a372168e 4606CAmount CWallet::GetImmatureBalance() const
8fdb7e10 4607{
a372168e 4608 CAmount nTotal = 0;
8fdb7e10 4609 {
55a1db4f 4610 LOCK2(cs_main, cs_wallet);
8fdb7e10 4611 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4612 {
966a0e8c
PK
4613 const CWalletTx* pcoin = &(*it).second;
4614 nTotal += pcoin->GetImmatureCredit();
df5ccbd2
WL
4615 }
4616 }
4617 return nTotal;
4618}
e8ef3da7 4619
56fe75cb 4620CCurrencyValueMap CWallet::GetImmatureReserveBalance() const
3a27113e 4621{
56fe75cb 4622 CCurrencyValueMap retVal;
3a27113e 4623 {
4624 LOCK2(cs_main, cs_wallet);
4625 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4626 {
4627 const CWalletTx* pcoin = &(*it).second;
56fe75cb 4628 retVal += pcoin->GetImmatureReserveCredit();
3a27113e 4629 }
4630 }
56fe75cb 4631 return retVal;
3a27113e 4632}
4633
a372168e 4634CAmount CWallet::GetWatchOnlyBalance() const
ffd40da3 4635{
a372168e 4636 CAmount nTotal = 0;
ffd40da3 4637 {
39cc4922 4638 LOCK2(cs_main, cs_wallet);
ffd40da3
J
4639 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4640 {
4641 const CWalletTx* pcoin = &(*it).second;
4642 if (pcoin->IsTrusted())
4643 nTotal += pcoin->GetAvailableWatchOnlyCredit();
4644 }
4645 }
870da77d 4646
ffd40da3
J
4647 return nTotal;
4648}
4649
56fe75cb 4650CCurrencyValueMap CWallet::GetWatchOnlyReserveBalance() const
3a27113e 4651{
56fe75cb 4652 CCurrencyValueMap retVal;
3a27113e 4653 {
4654 LOCK2(cs_main, cs_wallet);
4655 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4656 {
4657 const CWalletTx* pcoin = &(*it).second;
4658 if (pcoin->IsTrusted())
56fe75cb 4659 retVal += pcoin->GetAvailableWatchOnlyReserveCredit();
3a27113e 4660 }
4661 }
4662
56fe75cb 4663 return retVal;
3a27113e 4664}
4665
a372168e 4666CAmount CWallet::GetUnconfirmedWatchOnlyBalance() const
ffd40da3 4667{
a372168e 4668 CAmount nTotal = 0;
ffd40da3 4669 {
39cc4922 4670 LOCK2(cs_main, cs_wallet);
ffd40da3
J
4671 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4672 {
4673 const CWalletTx* pcoin = &(*it).second;
75a4d512 4674 if (!CheckFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
ffd40da3
J
4675 nTotal += pcoin->GetAvailableWatchOnlyCredit();
4676 }
4677 }
4678 return nTotal;
4679}
4680
56fe75cb 4681CCurrencyValueMap CWallet::GetUnconfirmedWatchOnlyReserveBalance() const
3a27113e 4682{
56fe75cb 4683 CCurrencyValueMap retVal;
3a27113e 4684 {
4685 LOCK2(cs_main, cs_wallet);
4686 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4687 {
4688 const CWalletTx* pcoin = &(*it).second;
4689 if (!CheckFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
56fe75cb 4690 retVal += pcoin->GetAvailableWatchOnlyReserveCredit();
3a27113e 4691 }
4692 }
56fe75cb 4693 return retVal;
3a27113e 4694}
4695
a372168e 4696CAmount CWallet::GetImmatureWatchOnlyBalance() const
ffd40da3 4697{
a372168e 4698 CAmount nTotal = 0;
ffd40da3 4699 {
39cc4922 4700 LOCK2(cs_main, cs_wallet);
ffd40da3
J
4701 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4702 {
4703 const CWalletTx* pcoin = &(*it).second;
4704 nTotal += pcoin->GetImmatureWatchOnlyCredit();
4705 }
4706 }
4707 return nTotal;
4708}
4709
56fe75cb 4710CCurrencyValueMap CWallet::GetImmatureWatchOnlyReserveBalance() const
3a27113e 4711{
56fe75cb 4712 CCurrencyValueMap retVal;
3a27113e 4713 {
4714 LOCK2(cs_main, cs_wallet);
4715 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4716 {
4717 const CWalletTx* pcoin = &(*it).second;
56fe75cb 4718 retVal += pcoin->GetImmatureWatchOnlyReserveCredit();
3a27113e 4719 }
4720 }
56fe75cb 4721 return retVal;
3a27113e 4722}
4723
5b40d886
MF
4724/**
4725 * populate vCoins with vector of available COutputs.
4726 */
79383e0a 4727uint64_t komodo_interestnew(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
c60397dd 4728uint64_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 4729
20bcd9ba 4730void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeZeroValue, bool fIncludeCoinBase, bool fIncludeProtectedCoinbase, bool fIncludeImmatureCoins) const
9b0369c7 4731{
5c439232 4732 uint64_t interest,*ptr;
9b0369c7
CM
4733 vCoins.clear();
4734
4735 {
ea3acaf3 4736 LOCK2(cs_main, cs_wallet);
1e435b54 4737 uint32_t nHeight = chainActive.Height() + 1;
9b0369c7
CM
4738 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4739 {
93a18a36 4740 const uint256& wtxid = it->first;
9b0369c7
CM
4741 const CWalletTx* pcoin = &(*it).second;
4742
75a4d512 4743 if (!CheckFinalTx(*pcoin))
a2709fad
GA
4744 continue;
4745
0542619d 4746 if (fOnlyConfirmed && !pcoin->IsTrusted())
9b0369c7
CM
4747 continue;
4748
1e435b54 4749 bool isCoinbase = pcoin->IsCoinBase();
29c07a8f 4750 if (!fIncludeCoinBase && isCoinbase)
2b1cda3b 4751 continue;
1e435b54 4752
29c07a8f 4753 if (!fIncludeImmatureCoins && isCoinbase && pcoin->GetBlocksToMaturity() > 0)
9b0369c7
CM
4754 continue;
4755
2b72d46f
GA
4756 int nDepth = pcoin->GetDepthInMainChain();
4757 if (nDepth < 0)
4758 continue;
53dce971 4759
1e435b54 4760 uint32_t coinHeight = nHeight - nDepth;
4761 // even if we should include coinbases, we may opt to exclude protected coinbases, which must only be included when shielding
af521e42 4762 if (isCoinbase &&
4763 !fIncludeProtectedCoinbase &&
4764 Params().GetConsensus().fCoinbaseMustBeProtected &&
4765 CConstVerusSolutionVector::GetVersionByHeight(coinHeight) < CActivationHeight::SOLUTION_VERUSV4 &&
4766 CConstVerusSolutionVector::GetVersionByHeight(nHeight) < CActivationHeight::SOLUTION_VERUSV5)
1e435b54 4767 continue;
4768
fab1429d 4769 for (int i = 0; i < pcoin->vout.size(); i++)
0ad6a463 4770 {
ea340a14 4771 isminetype mine = IsMine(pcoin->vout[i]);
a3e192a3 4772 if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO &&
219953ce 4773 !IsLockedCoin((*it).first, i) && (pcoin->vout[i].nValue > 0 || fIncludeZeroValue) &&
6a86c24d 4774 (!coinControl || !coinControl->HasSelected() || coinControl->IsSelected((*it).first, i)))
0ad6a463 4775 {
6ad13d7c 4776 if ( KOMODO_EXCHANGEWALLET == 0 )
0ad6a463 4777 {
6ad13d7c 4778 uint32_t locktime; int32_t txheight; CBlockIndex *tipindex;
4b729ec5 4779 if ( ASSETCHAINS_SYMBOL[0] == 0 && chainActive.LastTip() != 0 && chainActive.LastTip()->GetHeight() >= 60000 )
0ad6a463 4780 {
6ad13d7c 4781 if ( pcoin->vout[i].nValue >= 10*COIN )
9d92c93d 4782 {
86131275 4783 if ( (tipindex= chainActive.LastTip()) != 0 )
6ad13d7c 4784 {
4b729ec5 4785 komodo_accrued_interest(&txheight,&locktime,wtxid,i,0,pcoin->vout[i].nValue,(int32_t)tipindex->GetHeight());
79383e0a 4786 interest = komodo_interestnew(txheight,pcoin->vout[i].nValue,locktime,tipindex->nTime);
6ad13d7c 4787 } else interest = 0;
4b729ec5 4788 //interest = komodo_interestnew(chainActive.LastTip()->GetHeight()+1,pcoin->vout[i].nValue,pcoin->nLockTime,chainActive.LastTip()->nTime);
6ad13d7c 4789 if ( interest != 0 )
4790 {
4791 //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 4792 //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 4793 //ptr = (uint64_t *)&pcoin->vout[i].nValue;
4794 //(*ptr) += interest;
4795 ptr = (uint64_t *)&pcoin->vout[i].interest;
4796 (*ptr) = interest;
4797 //pcoin->vout[i].nValue += interest;
4798 }
4799 else
4800 {
4801 ptr = (uint64_t *)&pcoin->vout[i].interest;
4802 (*ptr) = 0;
4803 }
e9e8044e 4804 }
258748f5 4805 else
4806 {
4807 ptr = (uint64_t *)&pcoin->vout[i].interest;
4808 (*ptr) = 0;
4809 }
0ad6a463 4810 }
258748f5 4811 else
4812 {
4813 ptr = (uint64_t *)&pcoin->vout[i].interest;
4814 (*ptr) = 0;
4815 }
4816 }
0ad6a463 4817 vCoins.push_back(COutput(pcoin, i, nDepth, (mine & ISMINE_SPENDABLE) != ISMINE_NO));
4818 }
fdbb537d 4819 }
9b0369c7
CM
4820 }
4821 }
4822}
4823
56fe75cb 4824void CWallet::AvailableReserveCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeCoinBase, bool fIncludeNative, const CTxDestination *pOnlyFromDest, const CCurrencyValueMap *pOnlyTheseCurrencies) const
989b1de1
MT
4825{
4826 vCoins.clear();
4827
4828 {
4829 LOCK2(cs_main, cs_wallet);
4830 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
4831 {
4832 const uint256& wtxid = it->first;
4833 const CWalletTx* pcoin = &(*it).second;
4834
4835 if (!CheckFinalTx(*pcoin))
4836 continue;
4837
4838 if (fOnlyConfirmed && !pcoin->IsTrusted())
4839 continue;
4840
4841 if (pcoin->IsCoinBase() && !fIncludeCoinBase)
4842 continue;
4843
4844 if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
4845 continue;
4846
4847 int nDepth = pcoin->GetDepthInMainChain();
4848 if (nDepth < 0)
4849 continue;
4850
4851 for (int i = 0; i < pcoin->vout.size(); i++)
4852 {
989b1de1 4853 isminetype mine = IsMine(pcoin->vout[i]);
2f416b17 4854 if (!(IsSpent(wtxid, i)) &&
4855 mine != ISMINE_NO &&
56fe75cb 4856 !IsLockedCoin((*it).first, i) &&
989b1de1
MT
4857 (!coinControl || !coinControl->HasSelected() || coinControl->IsSelected((*it).first, i)))
4858 {
4859 COptCCParams p;
15197dca 4860 CCurrencyValueMap rOut = pcoin->vout[i].scriptPubKey.ReserveOutValue(p, true);
4861 if (p.IsValid() && !pcoin->vout[i].scriptPubKey.IsSpendableOutputType(p))
4862 {
4863 continue;
4864 }
56fe75cb 4865 if (pOnlyFromDest)
989b1de1 4866 {
56fe75cb 4867 if (p.IsValid())
4868 {
4869 bool found = false;
4870 for (auto &oneDest : p.vKeys)
4871 {
4872 if (GetDestinationID(oneDest) == GetDestinationID(*pOnlyFromDest))
4873 {
4874 found = true;
4875 break;
4876 }
4877 }
4878 if (!found)
4879 {
4880 continue;
4881 }
4882 }
4883 else
4884 {
4885 // support P2PK or P2PKH
4886 CTxDestination dest;
4887 if (!ExtractDestination(pcoin->vout[i].scriptPubKey, dest) || GetDestinationID(dest) != GetDestinationID(*pOnlyFromDest))
4888 {
4889 continue;
4890 }
4891 }
4892 }
4893 // don't return zero valued outputs
15197dca 4894 if (rOut.CanonicalMap().valueMap.size() || pcoin->vout[i].nValue)
56fe75cb 4895 {
2f416b17 4896 if ((rOut.valueMap.size() && (!pOnlyTheseCurrencies || (pOnlyTheseCurrencies && pOnlyTheseCurrencies->Intersects(rOut)))) ||
4897 (fIncludeNative && pcoin->vout[i].nValue))
56fe75cb 4898 {
4899 vCoins.push_back(COutput(pcoin, i, nDepth, (mine & ISMINE_SPENDABLE) != ISMINE_NO));
4900 }
989b1de1
MT
4901 }
4902 }
4903 }
4904 }
4905 }
4906}
4907
0ad6a463 4908static 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
4909{
4910 vector<char> vfIncluded;
4911
4912 vfBest.assign(vValue.size(), true);
4913 nBest = nTotalLower;
4914
907a2aa4
GM
4915 seed_insecure_rand();
4916
831f59ce
CM
4917 for (int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++)
4918 {
4919 vfIncluded.assign(vValue.size(), false);
a372168e 4920 CAmount nTotal = 0;
831f59ce
CM
4921 bool fReachedTarget = false;
4922 for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
4923 {
4924 for (unsigned int i = 0; i < vValue.size(); i++)
4925 {
907a2aa4
GM
4926 //The solver here uses a randomized algorithm,
4927 //the randomness serves no real security purpose but is just
4928 //needed to prevent degenerate behavior and it is important
5b40d886 4929 //that the rng is fast. We do not use a constant random sequence,
907a2aa4
GM
4930 //because there may be some privacy improvement by making
4931 //the selection random.
4932 if (nPass == 0 ? insecure_rand()&1 : !vfIncluded[i])
831f59ce
CM
4933 {
4934 nTotal += vValue[i].first;
4935 vfIncluded[i] = true;
4936 if (nTotal >= nTargetValue)
4937 {
4938 fReachedTarget = true;
4939 if (nTotal < nBest)
4940 {
4941 nBest = nTotal;
4942 vfBest = vfIncluded;
4943 }
4944 nTotal -= vValue[i].first;
4945 vfIncluded[i] = false;
4946 }
4947 }
4948 }
4949 }
4950 }
4951}
4952
2ec1b02c 4953// returns true if the selection contributes to getting any closer to the target. for example,
4954// if a candidate value map contains more of currencies already present and none of those that are needed
4955// but not present, it will return false. if it contains currencies that are needed, it will return
4956// true.
4957bool CloserToTarget(const CCurrencyValueMap &target, const CCurrencyValueMap &current, const CCurrencyValueMap &candidate)
4958{
4959 CCurrencyValueMap workingTarget = target.SubtractToZero(current); // whatever is left is what we still need
4960 //printf("with candidate: \n%s\nprior target: %s\n", workingTarget.SubtractToZero(candidate).ToUniValue().write(1,2).c_str(),
4961 // workingTarget.ToUniValue().write(1,2).c_str());
4962 return workingTarget.SubtractToZero(candidate) < workingTarget;
4963}
4964
56fe75cb 4965static void ApproximateBestReserveSubset(vector<pair<CCurrencyValueMap, pair<const CWalletTx*,unsigned int> > >vValue,
2ec1b02c 4966 const CCurrencyValueMap &totalLower,
4967 const CCurrencyValueMap &targetValues,
56fe75cb 4968 vector<char>& vfBest,
4969 CCurrencyValueMap& bestTotals,
4970 int iterations = 1000)
4971{
4972 vector<char> vfIncluded;
4973
4974 vfBest.assign(vValue.size(), true);
4975 bestTotals = totalLower;
4976
4977 seed_insecure_rand();
4978
4979 for (int nRep = 0; nRep < iterations && bestTotals != targetValues; nRep++)
4980 {
4981 vfIncluded.assign(vValue.size(), false);
4982 CCurrencyValueMap totals;
4983 bool fReachedTarget = false;
4984 for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
4985 {
4986 for (unsigned int i = 0; i < vValue.size(); i++)
4987 {
4988 //The solver here uses a randomized algorithm,
4989 //the randomness serves no real security purpose but is just
4990 //needed to prevent degenerate behavior and it is important
4991 //that the rng is fast. We do not use a constant random sequence,
4992 //because there may be some privacy improvement by making
4993 //the selection random.
2ec1b02c 4994 /*
4995 printf("targetValues\n%s\ntotals\n%s\nvValue[i].first\n%s\n", targetValues.ToUniValue().write(1,2).c_str(),
4996 totals.ToUniValue().write(1,2).c_str(),
4997 vValue[i].first.ToUniValue().write(1,2).c_str());
4998 printf("iscloser: %d\n", CloserToTarget(targetValues, totals, vValue[i].first));
4999 */
5000 if ((nPass == 0 ? insecure_rand()&1 : !vfIncluded[i]) && CloserToTarget(targetValues, totals, vValue[i].first))
56fe75cb 5001 {
5002 totals += vValue[i].first;
5003 vfIncluded[i] = true;
56a7b665 5004 // we reached the target if we fulfill all currencies
5005 CCurrencyValueMap curLeft = totals - targetValues;
5006 if (!curLeft.HasNegative())
56fe75cb 5007 {
5008 fReachedTarget = true;
2ec1b02c 5009 if (CompareValueMap()(totals, bestTotals))
56fe75cb 5010 {
5011 bestTotals = totals;
5012 vfBest = vfIncluded;
5013 }
5014 totals -= vValue[i].first;
5015 vfIncluded[i] = false;
5016 }
5017 }
5018 }
5019 }
5020 }
5021}
5022
79383e0a 5023bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, vector<COutput> vCoins,set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const
e8ef3da7 5024{
79383e0a 5025 int32_t count = 0; //uint64_t lowest_interest = 0;
e8ef3da7 5026 setCoinsRet.clear();
79383e0a 5027 //memset(interests,0,sizeof(interests));
e8ef3da7 5028 nValueRet = 0;
e8ef3da7 5029 // List of values less than target
a372168e
MF
5030 pair<CAmount, pair<const CWalletTx*,unsigned int> > coinLowestLarger;
5031 coinLowestLarger.first = std::numeric_limits<CAmount>::max();
e8ef3da7 5032 coinLowestLarger.second.first = NULL;
a372168e
MF
5033 vector<pair<CAmount, pair<const CWalletTx*,unsigned int> > > vValue;
5034 CAmount nTotalLower = 0;
e8ef3da7 5035
e333ab56
CM
5036 random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
5037
c8988460 5038 BOOST_FOREACH(const COutput &output, vCoins)
e8ef3da7 5039 {
c8988460
PW
5040 if (!output.fSpendable)
5041 continue;
5042
b80aa0c7 5043 if (output.tx->vout[output.i].nValue == 0)
5044 {
5045 continue;
5046 }
5047
9b0369c7 5048 const CWalletTx *pcoin = output.tx;
e8ef3da7 5049
a3e192a3 5050 if (output.nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? nConfMine : nConfTheirs))
9b0369c7 5051 continue;
e8ef3da7 5052
9b0369c7 5053 int i = output.i;
a372168e 5054 CAmount n = pcoin->vout[i].nValue;
e8ef3da7 5055
a372168e 5056 pair<CAmount,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin, i));
e8ef3da7 5057
9b0369c7
CM
5058 if (n == nTargetValue)
5059 {
5060 setCoinsRet.insert(coin.second);
5061 nValueRet += coin.first;
79383e0a 5062 //if ( KOMODO_EXCHANGEWALLET == 0 )
5063 // *interestp += pcoin->vout[i].interest;
9b0369c7
CM
5064 return true;
5065 }
5066 else if (n < nTargetValue + CENT)
5067 {
5068 vValue.push_back(coin);
5069 nTotalLower += n;
79383e0a 5070 //if ( KOMODO_EXCHANGEWALLET == 0 && count < sizeof(interests)/sizeof(*interests) )
5071 //{
9067057a 5072 //fprintf(stderr,"count.%d %.8f\n",count,(double)pcoin->vout[i].interest/COIN);
79383e0a 5073 //interests[count++] = pcoin->vout[i].interest;
5074 //}
5075 if ( nTotalLower > 4*nTargetValue + CENT )
92c2aa6b 5076 {
eaba9a27 5077 //fprintf(stderr,"why bother with all the utxo if we have double what is needed?\n");
92c2aa6b 5078 break;
5079 }
9b0369c7
CM
5080 }
5081 else if (n < coinLowestLarger.first)
5082 {
5083 coinLowestLarger = coin;
79383e0a 5084 //if ( KOMODO_EXCHANGEWALLET == 0 )
5085 // lowest_interest = pcoin->vout[i].interest;
e8ef3da7
WL
5086 }
5087 }
5088
831f59ce 5089 if (nTotalLower == nTargetValue)
e8ef3da7 5090 {
c376ac35 5091 for (unsigned int i = 0; i < vValue.size(); ++i)
e8ef3da7
WL
5092 {
5093 setCoinsRet.insert(vValue[i].second);
5094 nValueRet += vValue[i].first;
79383e0a 5095 //if ( KOMODO_EXCHANGEWALLET == 0 && i < count )
5096 // *interestp += interests[i];
e8ef3da7
WL
5097 }
5098 return true;
5099 }
5100
831f59ce 5101 if (nTotalLower < nTargetValue)
e8ef3da7
WL
5102 {
5103 if (coinLowestLarger.second.first == NULL)
5104 return false;
5105 setCoinsRet.insert(coinLowestLarger.second);
5106 nValueRet += coinLowestLarger.first;
79383e0a 5107 //if ( KOMODO_EXCHANGEWALLET == 0 )
5108 // *interestp += lowest_interest;
e8ef3da7
WL
5109 return true;
5110 }
5111
e8ef3da7 5112 // Solve subset sum by stochastic approximation
d650f96d 5113 sort(vValue.rbegin(), vValue.rend(), CompareValueOnly());
831f59ce 5114 vector<char> vfBest;
a372168e 5115 CAmount nBest;
e8ef3da7 5116
831f59ce
CM
5117 ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest, 1000);
5118 if (nBest != nTargetValue && nTotalLower >= nTargetValue + CENT)
5119 ApproximateBestSubset(vValue, nTotalLower, nTargetValue + CENT, vfBest, nBest, 1000);
e8ef3da7 5120
831f59ce
CM
5121 // If we have a bigger coin and (either the stochastic approximation didn't find a good solution,
5122 // or the next bigger coin is closer), return the bigger coin
5123 if (coinLowestLarger.second.first &&
5124 ((nBest != nTargetValue && nBest < nTargetValue + CENT) || coinLowestLarger.first <= nBest))
e8ef3da7
WL
5125 {
5126 setCoinsRet.insert(coinLowestLarger.second);
5127 nValueRet += coinLowestLarger.first;
79383e0a 5128 //if ( KOMODO_EXCHANGEWALLET == 0 )
5129 // *interestp += lowest_interest;
e8ef3da7
WL
5130 }
5131 else {
c376ac35 5132 for (unsigned int i = 0; i < vValue.size(); i++)
e8ef3da7
WL
5133 if (vfBest[i])
5134 {
5135 setCoinsRet.insert(vValue[i].second);
5136 nValueRet += vValue[i].first;
79383e0a 5137 //if ( KOMODO_EXCHANGEWALLET == 0 && i < count )
5138 // *interestp += interests[i];
e8ef3da7
WL
5139 }
5140
faaeae1e 5141 LogPrint("selectcoins", "SelectCoins() best subset: ");
c376ac35 5142 for (unsigned int i = 0; i < vValue.size(); i++)
e8ef3da7 5143 if (vfBest[i])
4f0f864d 5144 LogPrint("selectcoins", "%s", FormatMoney(vValue[i].first));
7d9d134b 5145 LogPrint("selectcoins", "total %s\n", FormatMoney(nBest));
e8ef3da7
WL
5146 }
5147
5148 return true;
5149}
5150
1e435b54 5151bool CWallet::SelectCoins(const CAmount& nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, bool& fOnlyProtectedCoinbaseCoinsRet, bool& fNeedProtectedCoinbaseCoinsRet, const CCoinControl* coinControl) const
e8ef3da7 5152{
1e435b54 5153 // Output parameter fOnlyProtectedCoinbaseCoinsRet is set to true when the only available coins are coinbase utxos.
79383e0a 5154 uint64_t tmp; int32_t retval;
5155 //if ( interestp == 0 )
5156 //{
5157 // interestp = &tmp;
5158 // *interestp = 0;
5159 //}
2b1cda3b 5160 vector<COutput> vCoinsNoCoinbase, vCoinsWithCoinbase;
1e435b54 5161 AvailableCoins(vCoinsNoCoinbase, true, coinControl, false, true, false);
5162 AvailableCoins(vCoinsWithCoinbase, true, coinControl, false, true, true);
5163 fOnlyProtectedCoinbaseCoinsRet = vCoinsNoCoinbase.size() == 0 && vCoinsWithCoinbase.size() > 0;
2b1cda3b
S
5164
5165 // If coinbase utxos can only be sent to zaddrs, exclude any coinbase utxos from coin selection.
5166 bool fProtectCoinbase = Params().GetConsensus().fCoinbaseMustBeProtected;
5167 vector<COutput> vCoins = (fProtectCoinbase) ? vCoinsNoCoinbase : vCoinsWithCoinbase;
5168
1e435b54 5169 // Output parameter fNeedProtectedCoinbaseCoinsRet is set to true if coinbase utxos that must be shielded need to be spent to meet target amount
2b1cda3b
S
5170 if (fProtectCoinbase && vCoinsWithCoinbase.size() > vCoinsNoCoinbase.size()) {
5171 CAmount value = 0;
5172 for (const COutput& out : vCoinsNoCoinbase) {
5173 if (!out.fSpendable) {
5174 continue;
5175 }
5176 value += out.tx->vout[out.i].nValue;
f87150f4 5177 if ( KOMODO_EXCHANGEWALLET == 0 )
5178 value += out.tx->vout[out.i].interest;
2b1cda3b
S
5179 }
5180 if (value <= nTargetValue) {
5181 CAmount valueWithCoinbase = 0;
5182 for (const COutput& out : vCoinsWithCoinbase) {
5183 if (!out.fSpendable) {
5184 continue;
5185 }
5186 valueWithCoinbase += out.tx->vout[out.i].nValue;
f87150f4 5187 if ( KOMODO_EXCHANGEWALLET == 0 )
5188 valueWithCoinbase += out.tx->vout[out.i].interest;
2b1cda3b 5189 }
1e435b54 5190 fNeedProtectedCoinbaseCoinsRet = (valueWithCoinbase >= nTargetValue);
2b1cda3b
S
5191 }
5192 }
6a86c24d 5193 // coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
aa30f655 5194 if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs)
6a86c24d
CL
5195 {
5196 BOOST_FOREACH(const COutput& out, vCoins)
5197 {
aa30f655
MC
5198 if (!out.fSpendable)
5199 continue;
6a86c24d 5200 nValueRet += out.tx->vout[out.i].nValue;
79383e0a 5201 //if ( KOMODO_EXCHANGEWALLET == 0 )
5202 // *interestp += out.tx->vout[out.i].interest;
6a86c24d
CL
5203 setCoinsRet.insert(make_pair(out.tx, out.i));
5204 }
5205 return (nValueRet >= nTargetValue);
5206 }
aa30f655
MC
5207 // calculate value from preset inputs and store them
5208 set<pair<const CWalletTx*, uint32_t> > setPresetCoins;
5209 CAmount nValueFromPresetInputs = 0;
5210
5211 std::vector<COutPoint> vPresetInputs;
5212 if (coinControl)
5213 coinControl->ListSelected(vPresetInputs);
5214 BOOST_FOREACH(const COutPoint& outpoint, vPresetInputs)
5215 {
5216 map<uint256, CWalletTx>::const_iterator it = mapWallet.find(outpoint.hash);
5217 if (it != mapWallet.end())
5218 {
5219 const CWalletTx* pcoin = &it->second;
5220 // Clearly invalid input, fail
5221 if (pcoin->vout.size() <= outpoint.n)
5222 return false;
5223 nValueFromPresetInputs += pcoin->vout[outpoint.n].nValue;
945f015d 5224 if ( KOMODO_EXCHANGEWALLET == 0 )
5225 nValueFromPresetInputs += pcoin->vout[outpoint.n].interest;
aa30f655
MC
5226 setPresetCoins.insert(make_pair(pcoin, outpoint.n));
5227 } else
5228 return false; // TODO: Allow non-wallet inputs
5229 }
5230
5231 // remove preset inputs from vCoins
5232 for (vector<COutput>::iterator it = vCoins.begin(); it != vCoins.end() && coinControl && coinControl->HasSelected();)
5233 {
5234 if (setPresetCoins.count(make_pair(it->tx, it->i)))
5235 it = vCoins.erase(it);
5236 else
5237 ++it;
5238 }
945f015d 5239 retval = false;
5240 if ( nTargetValue <= nValueFromPresetInputs )
5241 retval = true;
79383e0a 5242 else if ( SelectCoinsMinConf(nTargetValue, 1, 6, vCoins, setCoinsRet, nValueRet) != 0 )
945f015d 5243 retval = true;
79383e0a 5244 else if ( SelectCoinsMinConf(nTargetValue, 1, 1, vCoins, setCoinsRet, nValueRet) != 0 )
945f015d 5245 retval = true;
79383e0a 5246 else if ( bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue, 0, 1, vCoins, setCoinsRet, nValueRet) != 0 )
945f015d 5247 retval = true;
aa30f655
MC
5248 // because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset
5249 setCoinsRet.insert(setPresetCoins.begin(), setPresetCoins.end());
aa30f655
MC
5250 // add preset inputs to the total value selected
5251 nValueRet += nValueFromPresetInputs;
945f015d 5252 return retval;
e8ef3da7
WL
5253}
5254
56fe75cb 5255bool CWallet::SelectReserveCoinsMinConf(const CCurrencyValueMap& targetValues,
5256 CAmount targetNativeValue,
5257 int nConfMine,
5258 int nConfTheirs,
5259 std::vector<COutput> vCoins,
5260 std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet,
5261 CCurrencyValueMap& valueRet,
5262 CAmount &nativeValueRet) const
989b1de1
MT
5263{
5264 int32_t count = 0; //uint64_t lowest_interest = 0;
5265 setCoinsRet.clear();
7beb1c0b 5266 valueRet.valueMap.clear();
5267 nativeValueRet = 0;
989b1de1 5268 //memset(interests,0,sizeof(interests));
56fe75cb 5269
989b1de1 5270 // List of values less than target
56a7b665 5271 std::vector<std::pair<CCurrencyValueMap, std::pair<const CWalletTx*, unsigned int>>> coinLowestLarger;
5272 std::vector<std::pair<CCurrencyValueMap, std::pair<const CWalletTx*, unsigned int>>> vValue;
56fe75cb 5273 CCurrencyValueMap totalLower;
56a7b665 5274 CAmount totalNativeLower = 0;
989b1de1
MT
5275
5276 random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
5277
56a7b665 5278 CCurrencyValueMap nTotalTarget = targetValues + CCurrencyValueMap(std::vector<uint160>({ASSETCHAINS_CHAINID}), std::vector<CAmount>({targetNativeValue}));
a1a85fd6 5279 //printf("totaltarget: %s\n", nTotalTarget.ToUniValue().write().c_str());
56a7b665 5280
989b1de1
MT
5281 BOOST_FOREACH(const COutput &output, vCoins)
5282 {
5283 if (!output.fSpendable)
5284 continue;
5285
5286 const CWalletTx *pcoin = output.tx;
5287
5288 if (output.nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? nConfMine : nConfTheirs))
5289 continue;
5290
5291 int i = output.i;
56a7b665 5292 CCurrencyValueMap nAll(pcoin->vout[i].scriptPubKey.ReserveOutValue());
56fe75cb 5293 CCurrencyValueMap n = targetValues.IntersectingValues(nAll);
56a7b665 5294 CCurrencyValueMap nTotal = n;
56fe75cb 5295 CAmount nativeN = pcoin->vout[i].nValue;
56a7b665 5296 if (nativeN)
5297 {
5298 nAll.valueMap[ASSETCHAINS_CHAINID] = nativeN;
5299 if (targetNativeValue)
5300 {
5301 nTotal.valueMap[ASSETCHAINS_CHAINID] = nativeN;
5302 }
5303 }
989b1de1 5304
a1a85fd6 5305 //printf("available: %s\nall currencies: %s\n", nAll.ToUniValue().write().c_str(), nTotal.ToUniValue().write().c_str());
2ec1b02c 5306
56a7b665 5307 // if it has no output types we care about, next
2ec1b02c 5308 if (!nTotal.CanonicalMap().valueMap.size())
56fe75cb 5309 {
5310 continue;
5311 }
56a7b665 5312 std::pair<CCurrencyValueMap, pair<const CWalletTx*, unsigned int>> coin = make_pair(nAll, make_pair(pcoin, i));
989b1de1 5313
56fe75cb 5314 // if the values are equivalent to targets, we're done
56a7b665 5315 if (nAll == nTotalTarget)
989b1de1
MT
5316 {
5317 setCoinsRet.insert(coin.second);
7beb1c0b 5318 valueRet = pcoin->vout[i].scriptPubKey.ReserveOutValue();
5319 nativeValueRet = nativeN;
989b1de1
MT
5320 return true;
5321 }
56a7b665 5322
5323 if (nTotal < nTotalTarget)
989b1de1
MT
5324 {
5325 vValue.push_back(coin);
56fe75cb 5326 totalLower += n;
5327 totalNativeLower += nativeN;
989b1de1 5328
56a7b665 5329 if ( totalLower > ((targetValues * 4) + CENT) && totalNativeLower > ((targetNativeValue * 4) + CENT))
989b1de1 5330 {
56fe75cb 5331 //fprintf(stderr,"why bother with other utxos if we have much more than what is needed?\n");
989b1de1
MT
5332 break;
5333 }
5334 }
56a7b665 5335 // if this one output can satisfy requirements, check if it is the smallest that can
5336 else if (!coinLowestLarger.size() ||
2ec1b02c 5337 !(coinLowestLarger[0].first.IntersectingValues(targetValues) < nTotal))
989b1de1 5338 {
56a7b665 5339 if (coinLowestLarger.size())
5340 {
5341 coinLowestLarger[0] = coin;
5342 }
5343 else
5344 {
5345 coinLowestLarger.push_back(coin);
5346 }
989b1de1
MT
5347 }
5348 }
5349
a1a85fd6 5350 //printf("totalLower: %s\ntotalNativeLower: %s\n", totalLower.ToUniValue().write().c_str(), ValueFromAmount(totalNativeLower).write().c_str());
2ec1b02c 5351
56fe75cb 5352 if (totalLower == targetValues && totalNativeLower == targetNativeValue)
989b1de1
MT
5353 {
5354 for (unsigned int i = 0; i < vValue.size(); ++i)
5355 {
5356 setCoinsRet.insert(vValue[i].second);
56fe75cb 5357 valueRet += vValue[i].second.first->vout[vValue[i].second.second].ReserveOutValue();
5358 nativeValueRet += vValue[i].second.first->vout[vValue[i].second.second].nValue;
989b1de1
MT
5359 }
5360 return true;
5361 }
5362
56fe75cb 5363 if (totalLower < targetValues || totalNativeLower < targetNativeValue)
989b1de1 5364 {
56a7b665 5365 // if we don't have a larger one, we can't satisfy it
5366 if (!coinLowestLarger.size())
989b1de1 5367 return false;
56a7b665 5368
5369 setCoinsRet.insert(coinLowestLarger[0].second);
7beb1c0b 5370 valueRet = coinLowestLarger[0].second.first->vout[coinLowestLarger[0].second.second].ReserveOutValue();
5371 nativeValueRet = coinLowestLarger[0].second.first->vout[coinLowestLarger[0].second.second].nValue;
989b1de1
MT
5372 return true;
5373 }
5374
56fe75cb 5375 // Solve subset sum by stochastic approximation, add native currency to maps to
5376 // simplify solution
56fe75cb 5377 totalLower.valueMap[ConnectedChains.ThisChain().GetID()] = totalNativeLower;
5378
a1a85fd6 5379 //printf("totalLower:%s\ntargetValuesWithNative:%s\n", totalLower.ToUniValue().write().c_str(), nTotalTarget.ToUniValue().write().c_str());
2ec1b02c 5380 CCurrencyValueMap totPrint;
5381 for (auto &one : vValue)
5382 {
5383 totPrint += one.first;
5384 }
a1a85fd6 5385 //printf("num outputs: %lu, totalmap: %s\n", vValue.size(), totPrint.ToUniValue().write(1,2).c_str());
2ec1b02c 5386
5387 std::sort(vValue.rbegin(), vValue.rend(), CompareValueMap());
56a7b665 5388
989b1de1 5389 vector<char> vfBest;
56fe75cb 5390 CCurrencyValueMap bestTotals;
989b1de1 5391
56a7b665 5392 ApproximateBestReserveSubset(vValue, totalLower, nTotalTarget, vfBest, bestTotals, 1000);
56fe75cb 5393 if (bestTotals != targetValues && totalLower >= targetValues + CENT)
56a7b665 5394 ApproximateBestReserveSubset(vValue, totalLower, nTotalTarget + CENT, vfBest, bestTotals, 1000);
989b1de1 5395
56a7b665 5396 for (unsigned int i = 0; i < vValue.size(); i++)
989b1de1 5397 {
56a7b665 5398 if (vfBest[i])
5399 {
5400 setCoinsRet.insert(vValue[i].second);
5401 valueRet += vValue[i].second.first->vout[vValue[i].second.second].ReserveOutValue();
5402 nativeValueRet += vValue[i].second.first->vout[vValue[i].second.second].nValue;
5403 }
989b1de1 5404 }
989b1de1 5405
56a7b665 5406 LogPrint("selectcoins", "SelectCoins() best subset: ");
5407 for (unsigned int i = 0; i < vValue.size(); i++)
5408 {
5409 if (vfBest[i])
5410 {
5411 LogPrint("selectcoins", "%s", FormatMoney(vValue[i].first.valueMap[targetValues.valueMap.begin()->first]));
5412 }
989b1de1 5413 }
56a7b665 5414 LogPrint("selectcoins", "total %s\n", FormatMoney(bestTotals.valueMap[targetValues.valueMap.begin()->first]));
989b1de1
MT
5415
5416 return true;
5417}
5418
56fe75cb 5419bool CWallet::SelectReserveCoins(const CCurrencyValueMap& targetReserveValues,
5420 CAmount targetNativeValue,
5421 set<pair<const CWalletTx*,unsigned int> >& setCoinsRet,
5422 CCurrencyValueMap &valueRet,
5423 CAmount &nativeRet,
5424 bool& fOnlyCoinbaseCoinsRet,
5425 bool& fNeedCoinbaseCoinsRet,
5426 const CCoinControl* coinControl,
5427 const CTxDestination *pOnlyFromDest) const
989b1de1
MT
5428{
5429 // Output parameter fOnlyCoinbaseCoinsRet is set to true when the only available coins are coinbase utxos.
56a7b665 5430
989b1de1 5431 vector<COutput> vCoinsNoCoinbase, vCoinsWithCoinbase;
56a7b665 5432 AvailableReserveCoins(vCoinsNoCoinbase, true, coinControl, false, true, pOnlyFromDest, &targetReserveValues);
5433 AvailableReserveCoins(vCoinsWithCoinbase, true, coinControl, true, true, pOnlyFromDest, &targetReserveValues);
989b1de1
MT
5434 fOnlyCoinbaseCoinsRet = vCoinsNoCoinbase.size() == 0 && vCoinsWithCoinbase.size() > 0;
5435
56a7b665 5436 // If coinbase utxos can only be sent to zaddrs, exclude any coinbase utxos from coin selection
5437 // TODO (after identity update, don't protect coinbases when making these outputs)
989b1de1 5438 bool fProtectCoinbase = Params().GetConsensus().fCoinbaseMustBeProtected;
989b1de1 5439
56a7b665 5440 vector<COutput> vCoins = (fProtectCoinbase) ? vCoinsNoCoinbase : vCoinsWithCoinbase;
c83e4936 5441
989b1de1
MT
5442 // Output parameter fNeedCoinbaseCoinsRet is set to true if coinbase utxos need to be spent to meet target amount
5443 if (fProtectCoinbase && vCoinsWithCoinbase.size() > vCoinsNoCoinbase.size()) {
c83e4936 5444 CCurrencyValueMap reserveValues;
56fe75cb 5445 CAmount nativeValue = 0;
989b1de1
MT
5446 for (const COutput& out : vCoinsNoCoinbase) {
5447 if (!out.fSpendable) {
5448 continue;
5449 }
56fe75cb 5450 nativeValue += out.tx->vout[out.i].nValue;
c83e4936 5451 reserveValues += out.tx->vout[out.i].ReserveOutValue();
989b1de1 5452 }
c83e4936 5453 if (reserveValues < targetReserveValues || nativeValue < targetNativeValue) {
5454 CCurrencyValueMap reserveValuesWithCoinbase;
56fe75cb 5455 CAmount nativeValueWithCoinbase = 0;
989b1de1
MT
5456 for (const COutput& out : vCoinsWithCoinbase) {
5457 if (!out.fSpendable) {
5458 continue;
5459 }
c83e4936 5460 reserveValuesWithCoinbase += out.tx->vout[out.i].ReserveOutValue();
56fe75cb 5461 nativeValueWithCoinbase += out.tx->vout[out.i].nValue;
989b1de1 5462 }
c83e4936 5463 fNeedCoinbaseCoinsRet = (reserveValuesWithCoinbase >= targetReserveValues) && (nativeValueWithCoinbase >= targetNativeValue);
989b1de1
MT
5464 }
5465 }
56fe75cb 5466
989b1de1
MT
5467 // coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
5468 if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs)
5469 {
5470 BOOST_FOREACH(const COutput& out, vCoins)
5471 {
5472 if (!out.fSpendable)
5473 continue;
56fe75cb 5474 valueRet += out.tx->vout[out.i].ReserveOutValue();
5475 nativeRet += out.tx->vout[out.i].nValue;
989b1de1
MT
5476 setCoinsRet.insert(make_pair(out.tx, out.i));
5477 }
56fe75cb 5478 return (valueRet >= targetReserveValues) && (nativeRet >= targetNativeValue);
989b1de1 5479 }
56fe75cb 5480
989b1de1
MT
5481 // calculate value from preset inputs and store them
5482 set<pair<const CWalletTx*, uint32_t> > setPresetCoins;
56fe75cb 5483 CCurrencyValueMap valueFromPresetInputs;
5484 CAmount nativeValueFromPresets = 0;
989b1de1
MT
5485
5486 std::vector<COutPoint> vPresetInputs;
5487 if (coinControl)
5488 coinControl->ListSelected(vPresetInputs);
5489 BOOST_FOREACH(const COutPoint& outpoint, vPresetInputs)
5490 {
5491 map<uint256, CWalletTx>::const_iterator it = mapWallet.find(outpoint.hash);
5492 if (it != mapWallet.end())
5493 {
5494 const CWalletTx* pcoin = &it->second;
5495 // Clearly invalid input, fail
5496 if (pcoin->vout.size() <= outpoint.n)
5497 return false;
56fe75cb 5498 valueFromPresetInputs += pcoin->vout[outpoint.n].ReserveOutValue();
5499 nativeValueFromPresets += pcoin->vout[outpoint.n].nValue;
989b1de1
MT
5500 setPresetCoins.insert(make_pair(pcoin, outpoint.n));
5501 } else
5502 return false; // TODO: Allow non-wallet inputs
5503 }
5504
5505 // remove preset inputs from vCoins
5506 for (vector<COutput>::iterator it = vCoins.begin(); it != vCoins.end() && coinControl && coinControl->HasSelected();)
5507 {
5508 if (setPresetCoins.count(make_pair(it->tx, it->i)))
5509 it = vCoins.erase(it);
5510 else
5511 ++it;
5512 }
56a7b665 5513
5514 bool retval = false;
2f416b17 5515 if ( targetNativeValue <= nativeRet &&
5516 targetReserveValues <= targetReserveValues.IntersectingValues(valueFromPresetInputs) && targetNativeValue <= nativeValueFromPresets )
989b1de1 5517 retval = true;
56fe75cb 5518 else if ( SelectReserveCoinsMinConf(targetReserveValues, targetNativeValue, 1, 6, vCoins, setCoinsRet, valueRet, nativeRet) != 0 )
989b1de1 5519 retval = true;
56fe75cb 5520 else if ( SelectReserveCoinsMinConf(targetReserveValues, targetNativeValue, 1, 1, vCoins, setCoinsRet, valueRet, nativeRet) != 0 )
989b1de1 5521 retval = true;
56fe75cb 5522 else if ( bSpendZeroConfChange && SelectReserveCoinsMinConf(targetReserveValues, targetNativeValue, 0, 1, vCoins, setCoinsRet, valueRet, nativeRet) != 0 )
989b1de1
MT
5523 retval = true;
5524 // because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset
5525 setCoinsRet.insert(setPresetCoins.begin(), setPresetCoins.end());
5526 // add preset inputs to the total value selected
56fe75cb 5527 valueRet += valueFromPresetInputs;
5528 nativeRet += nativeValueFromPresets;
989b1de1
MT
5529 return retval;
5530}
5531
aa30f655
MC
5532bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount &nFeeRet, int& nChangePosRet, std::string& strFailReason)
5533{
5534 vector<CRecipient> vecSend;
5535
5536 // Turn the txout set into a CRecipient vector
5537 BOOST_FOREACH(const CTxOut& txOut, tx.vout)
5538 {
5539 CRecipient recipient = {txOut.scriptPubKey, txOut.nValue, false};
5540 vecSend.push_back(recipient);
5541 }
5542
5543 CCoinControl coinControl;
5544 coinControl.fAllowOtherInputs = true;
5545 BOOST_FOREACH(const CTxIn& txin, tx.vin)
5546 coinControl.Select(txin.prevout);
5547
5548 CReserveKey reservekey(this);
5549 CWalletTx wtx;
efb7662d 5550
aa30f655
MC
5551 if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosRet, strFailReason, &coinControl, false))
5552 return false;
5553
5554 if (nChangePosRet != -1)
5555 tx.vout.insert(tx.vout.begin() + nChangePosRet, wtx.vout[nChangePosRet]);
5556
5557 // Add new txins (keeping original txin scriptSig/order)
5558 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
5559 {
5560 bool found = false;
5561 BOOST_FOREACH(const CTxIn& origTxIn, tx.vin)
5562 {
5563 if (txin.prevout.hash == origTxIn.prevout.hash && txin.prevout.n == origTxIn.prevout.n)
5564 {
5565 found = true;
5566 break;
5567 }
5568 }
5569 if (!found)
5570 tx.vin.push_back(txin);
5571 }
5572
5573 return true;
e8ef3da7
WL
5574}
5575
aa30f655
MC
5576bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet,
5577 int& nChangePosRet, std::string& strFailReason, const CCoinControl* coinControl, bool sign)
e8ef3da7 5578{
79383e0a 5579 uint64_t interest2 = 0; CAmount nValue = 0; unsigned int nSubtractFeeFromAmount = 0;
292623ad 5580 BOOST_FOREACH (const CRecipient& recipient, vecSend)
e8ef3da7 5581 {
292623ad 5582 if (nValue < 0 || recipient.nAmount < 0)
1f00f4e9
GA
5583 {
5584 strFailReason = _("Transaction amounts must be positive");
e8ef3da7 5585 return false;
1f00f4e9 5586 }
292623ad
CL
5587 nValue += recipient.nAmount;
5588
5589 if (recipient.fSubtractFeeFromAmount)
5590 nSubtractFeeFromAmount++;
e8ef3da7
WL
5591 }
5592 if (vecSend.empty() || nValue < 0)
1f00f4e9
GA
5593 {
5594 strFailReason = _("Transaction amounts must be positive");
e8ef3da7 5595 return false;
1f00f4e9 5596 }
e8ef3da7 5597
b33d1f5e 5598 wtxNew.fTimeReceivedIsTxTime = true;
4c6e2295 5599 wtxNew.BindWallet(this);
9bb37bf0 5600 int nextBlockHeight = chainActive.Height() + 1;
bb6c3482 5601
5602 CMutableTransaction txNew = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextBlockHeight);
5603 txNew.nLockTime = (uint32_t)chainActive.LastTip()->nTime + 1; // set to a time close to now
e8ef3da7 5604
9bb37bf0 5605 // Activates after Overwinter network upgrade
88d014d0 5606 if (Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_OVERWINTER)) {
fa70084c 5607 if (txNew.nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD){
9bb37bf0 5608 strFailReason = _("nExpiryHeight must be less than TX_EXPIRY_HEIGHT_THRESHOLD.");
7b92f27e 5609 return false;
9bb37bf0 5610 }
e19d8b3d 5611 }
15ec5525 5612
25fee350 5613 unsigned int max_tx_size = MAX_TX_SIZE_AFTER_SAPLING;
88d014d0 5614 if (!Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_SAPLING)) {
15ec5525
JG
5615 max_tx_size = MAX_TX_SIZE_BEFORE_SAPLING;
5616 }
efb7662d 5617
ba7fcc8d
PT
5618 // Discourage fee sniping.
5619 //
5620 // However because of a off-by-one-error in previous versions we need to
5621 // neuter it by setting nLockTime to at least one less than nBestHeight.
5622 // Secondly currently propagation of transactions created for block heights
5623 // corresponding to blocks that were just mined may be iffy - transactions
5624 // aren't re-accepted into the mempool - we additionally neuter the code by
5625 // going ten blocks back. Doesn't yet do anything for sniping, but does act
5626 // to shake out wallet bugs like not showing nLockTime'd transactions at
5627 // all.
5628 txNew.nLockTime = std::max(0, chainActive.Height() - 10);
5629
5630 // Secondly occasionally randomly pick a nLockTime even further back, so
5631 // that transactions that are delayed after signing for whatever reason,
5632 // e.g. high-latency mix networks and some CoinJoin implementations, have
5633 // better privacy.
5634 if (GetRandInt(10) == 0)
5635 txNew.nLockTime = std::max(0, (int)txNew.nLockTime - GetRandInt(100));
5636
5637 assert(txNew.nLockTime <= (unsigned int)chainActive.Height());
5638 assert(txNew.nLockTime < LOCKTIME_THRESHOLD);
5639
e8ef3da7 5640 {
f8dcd5ca 5641 LOCK2(cs_main, cs_wallet);
e8ef3da7 5642 {
c1c9d5b4 5643 nFeeRet = 0;
050d2e95 5644 while (true)
e8ef3da7 5645 {
f19ffc34 5646 //interest = 0;
4949004d
PW
5647 txNew.vin.clear();
5648 txNew.vout.clear();
e8ef3da7 5649 wtxNew.fFromMe = true;
292623ad
CL
5650 nChangePosRet = -1;
5651 bool fFirst = true;
e8ef3da7 5652
292623ad
CL
5653 CAmount nTotalValue = nValue;
5654 if (nSubtractFeeFromAmount == 0)
5655 nTotalValue += nFeeRet;
e8ef3da7
WL
5656 double dPriority = 0;
5657 // vouts to the payees
292623ad 5658 BOOST_FOREACH (const CRecipient& recipient, vecSend)
8de9bb53 5659 {
292623ad
CL
5660 CTxOut txout(recipient.nAmount, recipient.scriptPubKey);
5661
5662 if (recipient.fSubtractFeeFromAmount)
5663 {
5664 txout.nValue -= nFeeRet / nSubtractFeeFromAmount; // Subtract fee equally from each selected recipient
5665
5666 if (fFirst) // first receiver pays the remainder not divisible by output count
5667 {
5668 fFirst = false;
5669 txout.nValue -= nFeeRet % nSubtractFeeFromAmount;
5670 }
5671 }
5672
2f537fa1 5673 COptCCParams p;
5674
5675 if (txout.IsDust(::minRelayTxFee) && !(txout.nValue == 0 && txout.scriptPubKey.IsPayToCryptoCondition(p) && p.IsValid() && p.evalCode != EVAL_NONE))
1f00f4e9 5676 {
292623ad
CL
5677 if (recipient.fSubtractFeeFromAmount && nFeeRet > 0)
5678 {
5679 if (txout.nValue < 0)
5680 strFailReason = _("The transaction amount is too small to pay the fee");
5681 else
5682 strFailReason = _("The transaction amount is too small to send after the fee has been deducted");
5683 }
5684 else
5685 strFailReason = _("Transaction amount too small");
8de9bb53 5686 return false;
1f00f4e9 5687 }
4949004d 5688 txNew.vout.push_back(txout);
8de9bb53 5689 }
e8ef3da7
WL
5690
5691 // Choose coins to use
5692 set<pair<const CWalletTx*,unsigned int> > setCoins;
a372168e 5693 CAmount nValueIn = 0;
1e435b54 5694 bool fOnlyProtectedCoinbaseCoins = false;
5695 bool fNeedProtectedCoinbaseCoins = false;
9152feb5 5696 interest2 = 0;
1e435b54 5697 if (!SelectCoins(nTotalValue, setCoins, nValueIn, fOnlyProtectedCoinbaseCoins, fNeedProtectedCoinbaseCoins, coinControl))
1f00f4e9 5698 {
1e435b54 5699 if (fOnlyProtectedCoinbaseCoins) {
5700 strFailReason = _("Coinbase funds earned while shielding protection is active can only be sent to a zaddr");
5701 } else if (fNeedProtectedCoinbaseCoins) {
5702 strFailReason = _("Insufficient funds, protected coinbase funds can only be spent after they have been sent to a zaddr");
2b1cda3b
S
5703 } else {
5704 strFailReason = _("Insufficient funds");
5705 }
e8ef3da7 5706 return false;
1f00f4e9 5707 }
e8ef3da7
WL
5708 BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
5709 {
a372168e 5710 CAmount nCredit = pcoin.first->vout[pcoin.second].nValue;
2d9b0b7f 5711 //The coin age after the next block (depth+1) is used instead of the current,
d7836552
GM
5712 //reflecting an assumption the user would accept a bit more delay for
5713 //a chance at a free transaction.
2d9b0b7f 5714 //But mempool inputs might still be in the mempool, so their age stays 0
38dfbe15 5715 //fprintf(stderr,"nCredit %.8f interest %.8f\n",(double)nCredit/COIN,(double)pcoin.first->vout[pcoin.second].interest/COIN);
d1f29a9d 5716 if ( KOMODO_EXCHANGEWALLET == 0 && ASSETCHAINS_SYMBOL[0] == 0 )
608252ed 5717 {
6ad13d7c 5718 interest2 += pcoin.first->vout[pcoin.second].interest;
d1f29a9d 5719 //fprintf(stderr,"%.8f ",(double)pcoin.first->vout[pcoin.second].interest/COIN);
85cb030e 5720 }
2d9b0b7f
AM
5721 int age = pcoin.first->GetDepthInMainChain();
5722 if (age != 0)
5723 age += 1;
5724 dPriority += (double)nCredit * age;
e8ef3da7 5725 }
79383e0a 5726 //if ( KOMODO_EXCHANGEWALLET != 0 )
5727 //{
2626c7e3 5728 //fprintf(stderr,"KOMODO_EXCHANGEWALLET disable interest sum %.8f, interest2 %.8f\n",(double)interest/COIN,(double)interest2/COIN);
79383e0a 5729 //interest = 0; // interest2 also
5730 //}
1bc74c28 5731 if ( ASSETCHAINS_SYMBOL[0] == 0 && DONATION_PUBKEY.size() == 66 && interest2 > 5000 )
5732 {
817ad14d 5733 CScript scriptDonation = CScript() << ParseHex(DONATION_PUBKEY) << OP_CHECKSIG;
5734 CTxOut newTxOut(interest2,scriptDonation);
719aa8b1 5735 int32_t nDonationPosRet = txNew.vout.size() - 1; // dont change first or last
5736 vector<CTxOut>::iterator position = txNew.vout.begin()+nDonationPosRet;
817ad14d 5737 txNew.vout.insert(position, newTxOut);
1bc74c28 5738 interest2 = 0;
5739 }
608252ed 5740 CAmount nChange = (nValueIn - nValue + interest2);
b7c685b8 5741 //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
5742 if (nSubtractFeeFromAmount == 0)
5743 nChange -= nFeeRet;
a7dd11c6
PW
5744
5745 if (nChange > 0)
e8ef3da7 5746 {
bf798734
GA
5747 // Fill a vout to ourself
5748 // TODO: pass in scriptChange instead of reservekey so
5749 // change transaction isn't always pay-to-bitcoin-address
e8ef3da7 5750 CScript scriptChange;
6a86c24d
CL
5751
5752 // coin control: send change to custom address
5753 if (coinControl && !boost::get<CNoDestination>(&coinControl->destChange))
0be990ba 5754 scriptChange = GetScriptForDestination(coinControl->destChange);
6a86c24d
CL
5755
5756 // no coin control: send change to newly generated address
5757 else
5758 {
5759 // Note: We use a new key here to keep it from being obvious which side is the change.
5760 // The drawback is that by not reusing a previous key, the change may be lost if a
5761 // backup is restored, if the backup doesn't have the new private key for the change.
5762 // If we reused the old key, it would be possible to add code to look for and
5763 // rediscover unknown transactions that were written with keys of ours to recover
5764 // post-backup change.
5765
5766 // Reserve a new key pair from key pool
5767 CPubKey vchPubKey;
3ec03ada 5768 extern int32_t USE_EXTERNAL_PUBKEY; extern std::string NOTARY_PUBKEY;
5769 if ( USE_EXTERNAL_PUBKEY == 0 )
5770 {
3ec03ada 5771 bool ret;
5772 ret = reservekey.GetReservedKey(vchPubKey);
5773 assert(ret); // should never fail, as we just unlocked
5774 scriptChange = GetScriptForDestination(vchPubKey.GetID());
5775 }
5776 else
5777 {
18c6cfce 5778 //fprintf(stderr,"use notary pubkey\n");
3ec03ada 5779 scriptChange = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG;
5780 }
6a86c24d 5781 }
e8ef3da7 5782
8de9bb53
GA
5783 CTxOut newTxOut(nChange, scriptChange);
5784
292623ad
CL
5785 // We do not move dust-change to fees, because the sender would end up paying more than requested.
5786 // This would be against the purpose of the all-inclusive feature.
5787 // So instead we raise the change and deduct from the recipient.
5788 if (nSubtractFeeFromAmount > 0 && newTxOut.IsDust(::minRelayTxFee))
5789 {
5790 CAmount nDust = newTxOut.GetDustThreshold(::minRelayTxFee) - newTxOut.nValue;
5791 newTxOut.nValue += nDust; // raise change until no more dust
5792 for (unsigned int i = 0; i < vecSend.size(); i++) // subtract from first recipient
5793 {
5794 if (vecSend[i].fSubtractFeeFromAmount)
5795 {
5796 txNew.vout[i].nValue -= nDust;
5797 if (txNew.vout[i].IsDust(::minRelayTxFee))
5798 {
5799 strFailReason = _("The transaction amount is too small to send after the fee has been deducted");
5800 return false;
5801 }
5802 break;
5803 }
5804 }
5805 }
5806
8de9bb53 5807 // Never create dust outputs; if we would, just
2f537fa1 5808 // add the dust to the fee. Valid cryptoconditions with a valid eval function are allowed to create outputs of 0
13fc83c7 5809 if (newTxOut.IsDust(::minRelayTxFee))
8de9bb53
GA
5810 {
5811 nFeeRet += nChange;
5812 reservekey.ReturnKey();
5813 }
5814 else
5815 {
429dabb5 5816 nChangePosRet = txNew.vout.size() - 1; // dont change first or last
292623ad 5817 vector<CTxOut>::iterator position = txNew.vout.begin()+nChangePosRet;
4949004d 5818 txNew.vout.insert(position, newTxOut);
8de9bb53 5819 }
f38345e9 5820 } else reservekey.ReturnKey();
e8ef3da7
WL
5821
5822 // Fill vin
ba7fcc8d
PT
5823 //
5824 // Note how the sequence number is set to max()-1 so that the
5825 // nLockTime set above actually works.
e8ef3da7 5826 BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
805344dc 5827 txNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second,CScript(),
ba7fcc8d 5828 std::numeric_limits<unsigned int>::max()-1));
989b1de1
MT
5829
5830 // Check mempooltxinputlimit to avoid creating a transaction which the local mempool rejects
5831 size_t limit = (size_t)GetArg("-mempooltxinputlimit", 0);
5832 {
5833 LOCK(cs_main);
88d014d0 5834 if (Params().GetConsensus().NetworkUpgradeActive(chainActive.Height() + 1, Consensus::UPGRADE_OVERWINTER)) {
989b1de1
MT
5835 limit = 0;
5836 }
5837 }
5838 if (limit > 0) {
5839 size_t n = txNew.vin.size();
5840 if (n > limit) {
5841 strFailReason = _(strprintf("Too many transparent inputs %zu > limit %zu", n, limit).c_str());
5842 return false;
5843 }
5844 }
5845
5846 // Grab the current consensus branch ID
5847 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
5848
5849 // Sign
5850 int nIn = 0;
5851 CTransaction txNewConst(txNew);
5852 BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
5853 {
5854 bool signSuccess;
5855 const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey;
5856 SignatureData sigdata;
5857 if (sign)
a4f9bc97 5858 signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, coin.first->vout[coin.second].nValue, scriptPubKey), scriptPubKey, sigdata, consensusBranchId);
989b1de1
MT
5859 else
5860 signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata, consensusBranchId);
5861
5862 if (!signSuccess)
5863 {
5864 strFailReason = _("Signing transaction failed");
5865 return false;
5866 } else {
5867 UpdateTransaction(txNew, nIn, sigdata);
5868 }
5869
5870 nIn++;
5871 }
5872
5873 unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION);
5874
5875 // Remove scriptSigs if we used dummy signatures for fee calculation
5876 if (!sign) {
5877 BOOST_FOREACH (CTxIn& vin, txNew.vin)
5878 vin.scriptSig = CScript();
5879 }
5880
5881 // Embed the constructed transaction data in wtxNew.
5882 *static_cast<CTransaction*>(&wtxNew) = CTransaction(txNew);
5883
5884 // Limit size
5885 if (nBytes >= max_tx_size)
5886 {
5887 strFailReason = _("Transaction too large");
5888 return false;
5889 }
5890
5891 dPriority = wtxNew.ComputePriority(dPriority, nBytes);
5892
5893 // Can we complete this as a free transaction?
5894 if (fSendFreeTransactions && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE)
5895 {
5896 // Not enough fee: enough priority?
5897 double dPriorityNeeded = mempool.estimatePriority(nTxConfirmTarget);
5898 // Not enough mempool history to estimate: use hard-coded AllowFree.
5899 if (dPriorityNeeded <= 0 && AllowFree(dPriority))
5900 break;
5901
5902 // Small enough, and priority high enough, to send for free
5903 if (dPriorityNeeded > 0 && dPriority >= dPriorityNeeded)
5904 break;
5905 }
5906
5907 CAmount nFeeNeeded = GetMinimumFee(nBytes, nTxConfirmTarget, mempool);
5908 if ( nFeeNeeded < 5000 )
5909 nFeeNeeded = 5000;
5910
5911 // If we made it here and we aren't even able to meet the relay fee on the next pass, give up
5912 // because we must be at the maximum allowed fee.
5913 if (nFeeNeeded < ::minRelayTxFee.GetFee(nBytes))
5914 {
5915 strFailReason = _("Transaction too large for fee policy");
5916 return false;
5917 }
5918
5919 if (nFeeRet >= nFeeNeeded)
5920 break; // Done, enough fee included.
5921
5922 // Include more fee and try again.
5923 nFeeRet = nFeeNeeded;
5924 continue;
5925 }
5926 }
5927 }
5928
5929 return true;
5930}
5931
56fe75cb 5932// almost the same as CreateTransaction with the difference being that input and output are assumed to be
5933// tokens/reserve currencies, not the native currency of this chain, represented as reserve outputs for both input and output.
5934// That means that all outputs must be reserve consuming outputs. Fee is added or converted from reserves if this is a
5935// fractional reserve chain. Fees are calculated based on the current reserve conversion price.
989b1de1 5936bool CWallet::CreateReserveTransaction(const vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet,
56fe75cb 5937 int& nChangePosRet, int &nChangeOutputs, std::string& strFailReason, const CCoinControl* coinControl,
5938 const CTxDestination *pOnlyFromDest, bool sign)
989b1de1 5939{
56fe75cb 5940 CCurrencyValueMap totalReserveOutput;
5941 CAmount totalNativeOutput = 0;
5942
5943 CCurrencyValueMap reserveCurrencies;
989b1de1
MT
5944 unsigned int nSubtractFeeFromAmount = 0;
5945
56fe75cb 5946 // fees can only be deducted from fractional reserve outputs on fractional currency blockchains, otherwise,
5947 // Verus/Verustest must be used to cover fees.
5948 bool isVerusActive = IsVerusActive();
2f416b17 5949 if (!isVerusActive)
56fe75cb 5950 {
5951 if (ConnectedChains.ReserveCurrencies().size())
5952 {
5953 for (auto &oneCur : ConnectedChains.ReserveCurrencies())
5954 {
5955 reserveCurrencies.valueMap[oneCur.first] = 1; // we're only testing for intersection, not value
5956 }
5957 }
5958 }
5959
5960 // make sure we have some outputs
5961 if (vecSend.empty())
5962 {
5963 strFailReason = _("Transaction must have outputs");
5964 return false;
5965 }
989b1de1 5966
2f416b17 5967 CCurrencyDefinition newCurrency;
5968
989b1de1
MT
5969 // make sure that there are recipients, all recipients expect reserve inputs, and amounts are all non-negative
5970 BOOST_FOREACH (const CRecipient& recipient, vecSend)
5971 {
2f416b17 5972 COptCCParams p;
5973 if (recipient.scriptPubKey.IsPayToCryptoCondition(p) && p.IsValid() && p.evalCode == EVAL_CURRENCY_DEFINITION && p.vData.size() >= 1)
5974 {
5975 if (newCurrency.IsValid())
5976 {
5977 strFailReason = _("A normal transaction cannot define define multiple currencies");
5978 return false;
5979 }
5980 newCurrency = CCurrencyDefinition(p.vData[0]);
5981 }
56fe75cb 5982 CCurrencyValueMap values = recipient.scriptPubKey.ReserveOutValue();
5983 CCurrencyValueMap zeroes = values - values; // zero values of the same currencies
5984
5985 if (!values.IsValid())
989b1de1 5986 {
56fe75cb 5987 strFailReason = _("Output cannot have NULL currency type");
5988 return false;
989b1de1 5989 }
56fe75cb 5990 if (values.HasNegative())
989b1de1 5991 {
56fe75cb 5992 strFailReason = _("Transaction output amounts must not be negative");
989b1de1
MT
5993 return false;
5994 }
2f416b17 5995
56fe75cb 5996 totalNativeOutput += recipient.nAmount;
f023c2d4 5997
56fe75cb 5998 totalReserveOutput += values;
f365e363 5999
56fe75cb 6000 // if we should take from this output, it must be able to pay the fee. fail if it does not
6001 if (recipient.fSubtractFeeFromAmount && (recipient.nAmount > 0 || reserveCurrencies.Intersects(values)))
6002 {
6003 nSubtractFeeFromAmount++;
6004 }
6005 else if (recipient.fSubtractFeeFromAmount)
989b1de1 6006 {
56fe75cb 6007 strFailReason = _("Cannot specify to subtract fee from amount on non-native, non-reserve currency outputs");
6008 return false;
989b1de1 6009 }
f365e363 6010
56fe75cb 6011 // make sure we have no negative totals. we do not move this outside the loop, so we can check against overflow on every iteration
6012 if (totalReserveOutput.HasNegative())
989b1de1 6013 {
f365e363 6014 strFailReason = _("Transaction amounts must not be negative");
989b1de1
MT
6015 return false;
6016 }
989b1de1
MT
6017 }
6018
2f416b17 6019 if (newCurrency.IsValid())
6020 {
6021 totalReserveOutput.valueMap.erase(newCurrency.GetID());
6022 }
6023
f023c2d4 6024 //printf("totalReserveOutput: %s\n", totalReserveOutput.ToUniValue().write(1,2).c_str());
6025
989b1de1 6026 int nextBlockHeight = chainActive.Height() + 1;
401e75b1 6027
989b1de1 6028 CMutableTransaction txNew = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextBlockHeight);
401e75b1 6029
6030 std::vector<CTxIn> extraInputs = wtxNew.vin;
6031
6032 wtxNew.fTimeReceivedIsTxTime = true;
6033 wtxNew.BindWallet(this);
989b1de1
MT
6034 txNew.nLockTime = (uint32_t)chainActive.LastTip()->nTime + 1; // set to a time close to now
6035
9bb37bf0 6036 // Activates after Overwinter network upgrade
2c6c5526 6037 if (Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_OVERWINTER)) {
fa70084c 6038 if (txNew.nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD){
9bb37bf0 6039 strFailReason = _("nExpiryHeight must be less than TX_EXPIRY_HEIGHT_THRESHOLD.");
7b92f27e 6040 return false;
9bb37bf0 6041 }
989b1de1
MT
6042 }
6043
6044 unsigned int max_tx_size = MAX_TX_SIZE_AFTER_SAPLING;
2c6c5526 6045 if (!Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_SAPLING)) {
15ec5525
JG
6046 max_tx_size = MAX_TX_SIZE_BEFORE_SAPLING;
6047 }
989b1de1
MT
6048
6049 // Discourage fee sniping.
6050 //
6051 // However because of a off-by-one-error in previous versions we need to
6052 // neuter it by setting nLockTime to at least one less than nBestHeight.
6053 // Secondly currently propagation of transactions created for block heights
6054 // corresponding to blocks that were just mined may be iffy - transactions
6055 // aren't re-accepted into the mempool - we additionally neuter the code by
6056 // going ten blocks back. Doesn't yet do anything for sniping, but does act
6057 // to shake out wallet bugs like not showing nLockTime'd transactions at
6058 // all.
6059 txNew.nLockTime = std::max(0, chainActive.Height() - 10);
6060
6061 // Secondly occasionally randomly pick a nLockTime even further back, so
6062 // that transactions that are delayed after signing for whatever reason,
6063 // e.g. high-latency mix networks and some CoinJoin implementations, have
6064 // better privacy.
6065 if (GetRandInt(10) == 0)
6066 txNew.nLockTime = std::max(0, (int)txNew.nLockTime - GetRandInt(100));
6067
6068 assert(txNew.nLockTime <= (unsigned int)chainActive.Height());
6069 assert(txNew.nLockTime < LOCKTIME_THRESHOLD);
6070
56fe75cb 6071 CCurrencyValueMap exchangeRates;
6072 auto currencyState = ConnectedChains.GetCurrencyState(nextBlockHeight - 1);
6073 for (int i = 0; i < currencyState.currencies.size(); i++)
6074 {
6075 exchangeRates.valueMap[currencyState.currencies[i]] = currencyState.PriceInReserve(i);
6076 }
6077
989b1de1
MT
6078 {
6079 LOCK2(cs_main, cs_wallet);
6080 {
56a7b665 6081 nFeeRet = 5000;
989b1de1
MT
6082 while (true)
6083 {
6084 //interest = 0;
6085 txNew.vin.clear();
6086 txNew.vout.clear();
6087 wtxNew.fFromMe = true;
6088 nChangePosRet = -1;
56fe75cb 6089 nChangeOutputs = 0;
989b1de1
MT
6090 bool fFirst = true;
6091
56a7b665 6092 // dust threshold of reserve may be different than native coin, if so, convert
989b1de1
MT
6093 CAmount dustThreshold;
6094
56fe75cb 6095 CAmount nTotalNativeValue = totalNativeOutput;
6096 CCurrencyValueMap totalReserveValue = totalReserveOutput;
6097
989b1de1 6098 if (nSubtractFeeFromAmount == 0)
56fe75cb 6099 nTotalNativeValue += nFeeRet;
6100
989b1de1
MT
6101 double dPriority = 0;
6102 // vouts to the payees
6103 BOOST_FOREACH (const CRecipient& recipient, vecSend)
6104 {
f365e363 6105 // native output value for a reserve output is generally 0. fees are paid by converting from
989b1de1 6106 // reserve token and the difference between input and output in reserve is the fee
56fe75cb 6107 // the actual reserve token output value is in the scriptPubKey
6108 CTxOut txout(recipient.nAmount, recipient.scriptPubKey);
6109 CAmount nativeEquivalent = txout.nValue;
989b1de1 6110
56fe75cb 6111 // here, if we know that it isn't an opret, it will have an output that expects input
989b1de1
MT
6112 if (!recipient.scriptPubKey.IsOpReturn())
6113 {
6114 COptCCParams p;
56fe75cb 6115 CCurrencyValueMap reserveOutput = recipient.scriptPubKey.ReserveOutValue(p);
6116 CCurrencyValueMap relevantReserves;
989b1de1
MT
6117
6118 if (recipient.fSubtractFeeFromAmount)
6119 {
6120 CAmount subFee = nFeeRet / nSubtractFeeFromAmount; // Subtract fee equally from each selected recipient
6121
6122 if (fFirst) // first receiver pays the remainder not divisible by output count
6123 {
6124 fFirst = false;
6125 subFee += nFeeRet % nSubtractFeeFromAmount;
6126 }
6127
56fe75cb 6128 if (subFee <= txout.nValue)
989b1de1 6129 {
56fe75cb 6130 txout.nValue -= subFee;
6131 }
6132 else if ((relevantReserves = reserveOutput.IntersectingValues(reserveCurrencies)).valueMap.size())
6133 {
6134 // if we will subtract from more than one currency, divide fee among them equally
6135 CAmount subSubFee = subFee / relevantReserves.valueMap.size();
6136 CAmount extraFee = subFee % relevantReserves.valueMap.size();
6137 // TODO: this does not support multi-currency, since the outputs do not. it will need
6138 // to be checked when we enable multi-currency outputs
6139 for (auto &oneCur : relevantReserves.valueMap)
989b1de1 6140 {
56fe75cb 6141 auto it = exchangeRates.valueMap.find(oneCur.first);
6142 assert(it != exchangeRates.valueMap.end());
6143 reserveOutput.valueMap[it->first] -= currencyState.NativeToReserveRaw(subFee + (extraFee ? 1 : 0), it->second);
6144 if (extraFee)
6145 {
6146 extraFee--;
6147 }
989b1de1 6148 }
56fe75cb 6149 txout.scriptPubKey.SetReserveOutValue(reserveOutput);
6150 }
6151 else
6152 {
6153 // asking to pay a fee on an output, but not being able to is not accepted, should
6154 // never get here, as it should have been checked above
6155 strFailReason = _("UNEXPECTED ERROR: Cannot subtract fee from amount on non-native, non-reserve currency outputs");
6156 return false;
989b1de1 6157 }
989b1de1
MT
6158 }
6159
6160 dustThreshold = txout.GetDustThreshold(::minRelayTxFee);
6161
56fe75cb 6162 // only non-crypto condition, and normal reserve outputs are subject to dust limitations
6163 if (!p.IsValid() ||
6164 p.evalCode == EVAL_RESERVE_OUTPUT ||
6165 p.evalCode == EVAL_RESERVE_DEPOSIT ||
6166 p.evalCode == EVAL_RESERVE_EXCHANGE ||
56fe75cb 6167 p.evalCode == EVAL_NONE)
989b1de1 6168 {
56fe75cb 6169 // add all values to a native equivalent
6170 // reserve currencies have a native value as well
6dd9cd36 6171 if (exchangeRates.IntersectingValues(reserveOutput).valueMap.size())
6172 {
6173 nativeEquivalent += currencyState.ReserveToNativeRaw(relevantReserves, exchangeRates.AsCurrencyVector(currencyState.currencies));
6174 }
6175 else
6176 {
6177 nativeEquivalent += reserveOutput.valueMap.size() ? reserveOutput.valueMap.begin()->second : 0;
6178 }
6179
56fe75cb 6180 if (nativeEquivalent < dustThreshold)
989b1de1 6181 {
56fe75cb 6182 if (recipient.fSubtractFeeFromAmount && nFeeRet > 0)
6183 {
6184 if (nativeEquivalent < 0)
6185 strFailReason = _("The transaction amount is too small to pay the fee");
6186 else
6187 strFailReason = _("The transaction amount is too small to send after the fee has been deducted");
6188 }
989b1de1 6189 else
56fe75cb 6190 strFailReason = _("Transaction amount too small");
6191 return false;
989b1de1 6192 }
989b1de1
MT
6193 }
6194 }
989b1de1
MT
6195 txNew.vout.push_back(txout);
6196 }
6197
6198 // Choose coins to use
6199 set<pair<const CWalletTx*,unsigned int> > setCoins;
56fe75cb 6200 CCurrencyValueMap totalValueIn;
6201 CAmount totalNativeValueIn = 0;
989b1de1
MT
6202 bool fOnlyCoinbaseCoins = false;
6203 bool fNeedCoinbaseCoins = false;
6204
56fe75cb 6205 if (!SelectReserveCoins(totalReserveValue,
6206 nTotalNativeValue,
6207 setCoins,
6208 totalValueIn,
6209 totalNativeValueIn,
6210 fOnlyCoinbaseCoins,
6211 fNeedCoinbaseCoins,
6212 coinControl,
6213 pOnlyFromDest))
989b1de1
MT
6214 {
6215 if (fOnlyCoinbaseCoins && Params().GetConsensus().fCoinbaseMustBeProtected) {
6216 strFailReason = _("Coinbase funds can only be sent to a zaddr");
6217 } else if (fNeedCoinbaseCoins) {
6218 strFailReason = _("Insufficient funds, coinbase funds can only be spent after they have been sent to a zaddr");
6219 } else {
6220 strFailReason = _("Insufficient funds");
6221 }
6222 return false;
6223 }
56fe75cb 6224
2ec1b02c 6225 /*
7beb1c0b 6226 if (totalValueIn.valueMap.count(ASSETCHAINS_CHAINID))
6227 {
6228 for (auto oneOut : setCoins)
6229 {
6230 UniValue oneTxObj(UniValue::VOBJ);
6231 TxToUniv(*oneOut.first, uint256(), oneTxObj);
6232 printf("TRANSACTION\n%s\n", oneTxObj.write(1,2).c_str());
6233 }
6234 printf("totalValueIn: %s\ntotalReserveValue: %s\n", totalValueIn.ToUniValue().write().c_str(), totalReserveValue.ToUniValue().write().c_str());
6235 }
2ec1b02c 6236 */
56a7b665 6237
56fe75cb 6238 std::vector<std::pair<std::pair<const CWalletTx*, unsigned int>, CAmount>> coinsWithEquivalentNative;
56a7b665 6239 if (reserveCurrencies.valueMap.size())
989b1de1 6240 {
56a7b665 6241 BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
6242 {
6243 CAmount nCredit = pcoin.first->vout[pcoin.second].nValue +
6244 currencyState.ReserveToNativeRaw(reserveCurrencies.IntersectingValues(pcoin.first->vout[pcoin.second].ReserveOutValue()),
6245 exchangeRates.AsCurrencyVector(currencyState.currencies));
6246 coinsWithEquivalentNative.push_back(make_pair(pcoin, nCredit));
6247 }
989b1de1
MT
6248 }
6249
56fe75cb 6250 CCurrencyValueMap reserveChange = totalValueIn - totalReserveValue;
f023c2d4 6251
6252 //printf("reservechange: %s\ntotalvaluein: %s\n", reserveChange.ToUniValue().write(1,2).c_str(), totalValueIn.ToUniValue().write(1,2).c_str());
6253
56fe75cb 6254 CCurrencyValueMap convertibleChange = reserveCurrencies.IntersectingValues(reserveChange);
6255 CAmount nChange = totalNativeValueIn - nTotalNativeValue;
6256 CAmount nConvertedReserveChange = 0;
989b1de1 6257
7beb1c0b 6258 // /printf("tokenChange: %s\nnativeChange: %s\n", reserveChange.ToUniValue().write().c_str(), ValueFromAmount(nChange).write().c_str());
56a7b665 6259
56fe75cb 6260 // if we will try to take the fee from change
989b1de1 6261 if (nSubtractFeeFromAmount == 0)
56fe75cb 6262 {
56a7b665 6263 if (nChange < nFeeRet && convertibleChange.valueMap.size())
56fe75cb 6264 {
6265 nConvertedReserveChange = currencyState.ReserveToNativeRaw(convertibleChange,
6266 exchangeRates.AsCurrencyVector(currencyState.currencies));
6267 }
989b1de1 6268 nChange -= nFeeRet;
56fe75cb 6269 }
989b1de1 6270
56a7b665 6271 if ((nChange + nConvertedReserveChange > 0) || (reserveChange > CCurrencyValueMap()))
989b1de1 6272 {
56a7b665 6273 // if we can and need to convert reserves, adjust reserve change output amounts as needed
6274 if (nChange < 0 && convertibleChange.valueMap.size())
56fe75cb 6275 {
6276 // no native change output, so, convert what's needed and make reserve output(s)
6277 // attempt to convert equally across currencies, and if we fail, take the rest as
6278 // first come, first served
6279 CAmount nChangePerCur = -nChange / convertibleChange.valueMap.size();
6280 CAmount nChangeMod = -nChange % convertibleChange.valueMap.size();
6281 CAmount remainder = 0;
6282 nChange = 0;
6283 for (int i = 0; i < currencyState.currencies.size(); i++)
6284 {
6285 auto it = reserveChange.valueMap.find(currencyState.currencies[i]);
6286 if (it != reserveChange.valueMap.end())
6287 {
6288 CAmount feeAsReserve = currencyState.NativeToReserve(nChangePerCur + (nChangeMod ? 1 : 0), i);
6289 if (it->second - feeAsReserve <= 0)
6290 {
6291 // if we don't have enough reserve in this currency for its part of the fee, we will
6292 // take it all, and then take more from the other currencies as needed
6293 remainder += currencyState.ReserveToNative(feeAsReserve - it->second, i);
6294 reserveChange.valueMap.erase(it);
6295 }
6296 else
6297 {
6298 it->second -= feeAsReserve;
6299 }
6300 }
6301 }
6302 // if we have any fee left to convert because we were short on some currency, take it
6303 // from the remaining reserves in change
6304 if (remainder)
6305 {
6306 for (int i = 0; i < currencyState.currencies.size(); i++)
6307 {
6308 auto it = reserveChange.valueMap.find(currencyState.currencies[i]);
6309 if (it != reserveChange.valueMap.end())
6310 {
6311 CAmount feeAsReserve = currencyState.NativeToReserve(remainder, i);
6312 if (it->second - feeAsReserve <= 0)
6313 {
6314 // if we don't have enough reserve in this currency for its part of the fee, we will
6315 // take it all, and then take more from the other currencies as needed
6316 reserveChange.valueMap.erase(it);
6317 remainder -= currencyState.ReserveToNative(it->second, i);
6318 }
6319 else
6320 {
6321 it->second -= feeAsReserve;
6322 break;
6323 }
6324 }
6325 }
6326 }
6327 }
989b1de1
MT
6328
6329 // coin control: send change to custom address
6330
6331 // reserve tokens can currently only be sent to public keys or addresses that are in the current wallet
6332 // since reserve token outputs are CCs by definition
56fe75cb 6333 CTxDestination changeDest;
6334 if (coinControl && coinControl->destChange.which() != COptCCParams::ADDRTYPE_INVALID)
989b1de1 6335 {
56fe75cb 6336 changeDest = coinControl->destChange;
989b1de1
MT
6337 }
6338 else
6339 {
6340 // no coin control: send change to newly generated address
6341
6342 // Note: We use a new key here to keep it from being obvious which side is the change.
6343 // The drawback is that by not reusing a previous key, the change may be lost if a
6344 // backup is restored, if the backup doesn't have the new private key for the change.
6345 // If we reused the old key, it would be possible to add code to look for and
6346 // rediscover unknown transactions that were written with keys of ours to recover
6347 // post-backup change.
6348
6349 // Reserve a new key pair from key pool
6350 extern int32_t USE_EXTERNAL_PUBKEY; extern std::string NOTARY_PUBKEY;
56fe75cb 6351 CPubKey pubKey;
989b1de1
MT
6352 if ( USE_EXTERNAL_PUBKEY == 0 )
6353 {
6354 bool ret;
56fe75cb 6355 ret = reservekey.GetReservedKey(pubKey);
989b1de1
MT
6356 assert(ret); // should never fail, as we just unlocked
6357 }
6358 else
6359 {
6360 //fprintf(stderr,"use notary pubkey\n");
56fe75cb 6361 pubKey = CPubKey(ParseHex(NOTARY_PUBKEY));
989b1de1 6362 }
56fe75cb 6363 changeDest = CTxDestination(pubKey);
989b1de1
MT
6364 }
6365
56fe75cb 6366 // generate all necessary change outputs for all currencies
6367 // first determine if any outputs left are dust. if so, just add them to the fee
6368 if (nChange < dustThreshold)
989b1de1 6369 {
56fe75cb 6370 nFeeRet += nChange;
6371 nChange = 0;
6372 }
6373 else
6374 {
6375 nChangePosRet = txNew.vout.size() - 1; // dont change first or last
6376 nChangeOutputs++;
6377 vector<CTxOut>::iterator position = txNew.vout.begin() + nChangePosRet;
6378 txNew.vout.insert(position, CTxOut(nChange, GetScriptForDestination(changeDest)));
6379 }
989b1de1 6380
56fe75cb 6381 // now, loop through the remaining reserve currencies and make a change output for each
56a7b665 6382 // if dust, just remove
6383 auto reserveIndexMap = currencyState.GetReserveMap();
6384 for (auto &curChangeOut : reserveChange.valueMap)
56fe75cb 6385 {
56a7b665 6386 CAmount outVal;
6387 assert(curChangeOut.first != ASSETCHAINS_CHAINID);
6388 auto curIt = reserveIndexMap.find(curChangeOut.first);
6389 if (curIt != reserveIndexMap.end())
989b1de1 6390 {
56a7b665 6391 outVal = currencyState.ReserveToNative(curChangeOut.second, curIt->second);
6392 }
6393 else
6394 {
6395 outVal = curChangeOut.second;
6396 }
6397
6398 if (outVal >= dustThreshold)
6399 {
6400 vector<CTxOut>::iterator position = txNew.vout.begin() + (nChangePosRet + nChangeOutputs++);
6401 CTokenOutput to = CTokenOutput(curChangeOut.first, curChangeOut.second);
6402 txNew.vout.insert(position, CTxOut(0, MakeMofNCCScript(CConditionObj<CTokenOutput>(EVAL_RESERVE_OUTPUT, {changeDest}, 1, &to))));
6403 }
6404 // if it is dust and we cannot convert to native, drop it. it may be taken by the miner
6405 else if (curIt != reserveIndexMap.end())
6406 {
6407 nFeeRet += outVal;
989b1de1
MT
6408 }
6409 }
6410
56fe75cb 6411 // if we made no change outputs, return the key
6412 if (!nChangeOutputs)
989b1de1 6413 {
989b1de1
MT
6414 reservekey.ReturnKey();
6415 }
989b1de1
MT
6416 } else reservekey.ReturnKey();
6417
6418 // Fill vin
6419 //
6420 // Note how the sequence number is set to max()-1 so that the
6421 // nLockTime set above actually works.
401e75b1 6422 for (auto &oneIn : extraInputs)
6423 {
6424 auto wit = mapWallet.find(oneIn.prevout.hash);
6425 if (wit != mapWallet.end() &&
6426 wit->second.vout.size() > oneIn.prevout.n &&
6427 !wit->second.vout[oneIn.prevout.n].nValue &&
6428 wit->second.vout[oneIn.prevout.n].ReserveOutValue() == CCurrencyValueMap())
6429 {
6430 setCoins.insert(std::make_pair(&(wit->second), oneIn.prevout.n));
6431 }
6432 else
6433 {
6434 setCoins.clear();
6435 break;
6436 }
6437 }
989b1de1
MT
6438 BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
6439 txNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second,CScript(),
6440 std::numeric_limits<unsigned int>::max()-1));
e8ef3da7 6441
9e84b5aa
S
6442 // Check mempooltxinputlimit to avoid creating a transaction which the local mempool rejects
6443 size_t limit = (size_t)GetArg("-mempooltxinputlimit", 0);
31afbcc5
JG
6444 {
6445 LOCK(cs_main);
2c6c5526 6446 if (Params().GetConsensus().NetworkUpgradeActive(chainActive.Height() + 1, Consensus::UPGRADE_OVERWINTER)) {
31afbcc5
JG
6447 limit = 0;
6448 }
6449 }
9e84b5aa
S
6450 if (limit > 0) {
6451 size_t n = txNew.vin.size();
6452 if (n > limit) {
6453 strFailReason = _(strprintf("Too many transparent inputs %zu > limit %zu", n, limit).c_str());
6454 return false;
6455 }
6456 }
6457
be126699
JG
6458 // Grab the current consensus branch ID
6459 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
6460
e8ef3da7
WL
6461 // Sign
6462 int nIn = 0;
aa30f655 6463 CTransaction txNewConst(txNew);
e8ef3da7 6464 BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
aa30f655
MC
6465 {
6466 bool signSuccess;
6467 const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey;
157a5d0d 6468 SignatureData sigdata;
aa30f655 6469 if (sign)
a4f9bc97 6470 signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, coin.first->vout[coin.second].nValue, scriptPubKey), scriptPubKey, sigdata, consensusBranchId);
aa30f655 6471 else
be126699 6472 signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata, consensusBranchId);
aa30f655
MC
6473
6474 if (!signSuccess)
1f00f4e9
GA
6475 {
6476 strFailReason = _("Signing transaction failed");
e8ef3da7 6477 return false;
157a5d0d
PW
6478 } else {
6479 UpdateTransaction(txNew, nIn, sigdata);
1f00f4e9 6480 }
157a5d0d 6481
aa30f655
MC
6482 nIn++;
6483 }
6484
6485 unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION);
6486
6487 // Remove scriptSigs if we used dummy signatures for fee calculation
6488 if (!sign) {
6489 BOOST_FOREACH (CTxIn& vin, txNew.vin)
6490 vin.scriptSig = CScript();
6491 }
e8ef3da7 6492
4949004d
PW
6493 // Embed the constructed transaction data in wtxNew.
6494 *static_cast<CTransaction*>(&wtxNew) = CTransaction(txNew);
6495
e8ef3da7 6496 // Limit size
15ec5525 6497 if (nBytes >= max_tx_size)
1f00f4e9
GA
6498 {
6499 strFailReason = _("Transaction too large");
e8ef3da7 6500 return false;
1f00f4e9 6501 }
aa30f655 6502
4d707d51 6503 dPriority = wtxNew.ComputePriority(dPriority, nBytes);
e8ef3da7 6504
aa279d61
GM
6505 // Can we complete this as a free transaction?
6506 if (fSendFreeTransactions && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE)
6507 {
6508 // Not enough fee: enough priority?
6509 double dPriorityNeeded = mempool.estimatePriority(nTxConfirmTarget);
6510 // Not enough mempool history to estimate: use hard-coded AllowFree.
6511 if (dPriorityNeeded <= 0 && AllowFree(dPriority))
6512 break;
6513
6514 // Small enough, and priority high enough, to send for free
6515 if (dPriorityNeeded > 0 && dPriority >= dPriorityNeeded)
6516 break;
6517 }
b33d1f5e 6518
1e3fdfaa 6519 CAmount nFeeNeeded = GetMinimumFee(nBytes, nTxConfirmTarget, mempool);
6520 if ( nFeeNeeded < 5000 )
6521 nFeeNeeded = 5000;
b33d1f5e 6522
aa279d61
GM
6523 // If we made it here and we aren't even able to meet the relay fee on the next pass, give up
6524 // because we must be at the maximum allowed fee.
6525 if (nFeeNeeded < ::minRelayTxFee.GetFee(nBytes))
e8ef3da7 6526 {
aa279d61
GM
6527 strFailReason = _("Transaction too large for fee policy");
6528 return false;
e8ef3da7
WL
6529 }
6530
aa279d61
GM
6531 if (nFeeRet >= nFeeNeeded)
6532 break; // Done, enough fee included.
b33d1f5e
GA
6533
6534 // Include more fee and try again.
6535 nFeeRet = nFeeNeeded;
6536 continue;
e8ef3da7
WL
6537 }
6538 }
6539 }
292623ad 6540 return true;
e8ef3da7
WL
6541}
6542
5b40d886
MF
6543/**
6544 * Call after CreateTransaction unless you want to abort
6545 */
3220d993 6546bool CWallet::CommitTransaction(CWalletTx& wtxNew, boost::optional<CReserveKey&> reservekey)
e8ef3da7 6547{
e8ef3da7 6548 {
f8dcd5ca 6549 LOCK2(cs_main, cs_wallet);
7d9d134b 6550 LogPrintf("CommitTransaction:\n%s", wtxNew.ToString());
e8ef3da7
WL
6551 {
6552 // This is only to keep the database open to defeat the auto-flush for the
6553 // duration of this scope. This is the only place where this optimization
6554 // maybe makes sense; please don't do it anywhere else.
44bc988e 6555 CWalletDB* pwalletdb = fFileBacked ? new CWalletDB(strWalletFile,"r+") : NULL;
e8ef3da7 6556
3220d993
E
6557 if (reservekey) {
6558 // Take key pair from key pool so it won't be used again
6559 reservekey.get().KeepKey();
6560 }
e8ef3da7
WL
6561
6562 // Add tx to wallet, because if it has change it's also ours,
6563 // otherwise just for transaction history.
44bc988e 6564 AddToWallet(wtxNew, false, pwalletdb);
e8ef3da7 6565
93a18a36 6566 // Notify that old coins are spent
e8ef3da7
WL
6567 set<CWalletTx*> setCoins;
6568 BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
6569 {
6570 CWalletTx &coin = mapWallet[txin.prevout.hash];
4c6e2295 6571 coin.BindWallet(this);
805344dc 6572 NotifyTransactionChanged(this, coin.GetHash(), CT_UPDATED);
e8ef3da7
WL
6573 }
6574
6575 if (fFileBacked)
6576 delete pwalletdb;
6577 }
6578
6579 // Track how many getdata requests our transaction gets
805344dc 6580 mapRequestCount[wtxNew.GetHash()] = 0;
e8ef3da7 6581
6f252627 6582 if (fBroadcastTransactions)
e8ef3da7 6583 {
6f252627
WL
6584 // Broadcast
6585 if (!wtxNew.AcceptToMemoryPool(false))
6586 {
68c266b2 6587 fprintf(stderr,"commit failed\n");
83a426bc 6588 // This must not fail. The transaction has already been signed and recorded.
7ff9d122 6589 LogPrintf("CommitTransaction(): Error: Transaction not valid\n");
6f252627
WL
6590 return false;
6591 }
6592 wtxNew.RelayWalletTransaction();
e8ef3da7 6593 }
e8ef3da7 6594 }
e8ef3da7
WL
6595 return true;
6596}
6597
a372168e 6598CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool)
b33d1f5e
GA
6599{
6600 // payTxFee is user-set "I want to pay this much"
a372168e 6601 CAmount nFeeNeeded = payTxFee.GetFee(nTxBytes);
c1c9d5b4
CL
6602 // user selected total at least (default=true)
6603 if (fPayAtLeastCustomFee && nFeeNeeded > 0 && nFeeNeeded < payTxFee.GetFeePerK())
6604 nFeeNeeded = payTxFee.GetFeePerK();
b33d1f5e
GA
6605 // User didn't set: use -txconfirmtarget to estimate...
6606 if (nFeeNeeded == 0)
6607 nFeeNeeded = pool.estimateFee(nConfirmTarget).GetFee(nTxBytes);
6608 // ... unless we don't have enough mempool data, in which case fall
6609 // back to a hard-coded fee
6610 if (nFeeNeeded == 0)
13fc83c7 6611 nFeeNeeded = minTxFee.GetFee(nTxBytes);
aa279d61
GM
6612 // prevent user from paying a non-sense fee (like 1 satoshi): 0 < fee < minRelayFee
6613 if (nFeeNeeded < ::minRelayTxFee.GetFee(nTxBytes))
6614 nFeeNeeded = ::minRelayTxFee.GetFee(nTxBytes);
6615 // But always obey the maximum
6616 if (nFeeNeeded > maxTxFee)
6617 nFeeNeeded = maxTxFee;
b33d1f5e
GA
6618 return nFeeNeeded;
6619}
6620
e8ef3da7 6621
cf53fd7c 6622void komodo_prefetch(FILE *fp);
e8ef3da7 6623
eed1785f 6624DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
e8ef3da7
WL
6625{
6626 if (!fFileBacked)
4f76be1d 6627 return DB_LOAD_OK;
e8ef3da7 6628 fFirstRunRet = false;
e86c03cf 6629 if ( 0 ) // doesnt help
cf53fd7c 6630 {
e86c03cf 6631 fprintf(stderr,"loading wallet %s %u\n",strWalletFile.c_str(),(uint32_t)time(NULL));
cf53fd7c 6632 FILE *fp;
6633 if ( (fp= fopen(strWalletFile.c_str(),"rb")) != 0 )
6634 {
6635 komodo_prefetch(fp);
6636 fclose(fp);
6637 }
6638 }
e86c03cf 6639 //fprintf(stderr,"prefetched wallet %s %u\n",strWalletFile.c_str(),(uint32_t)time(NULL));
eed1785f 6640 DBErrors nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this);
e86c03cf 6641 //fprintf(stderr,"loaded wallet %s %u\n",strWalletFile.c_str(),(uint32_t)time(NULL));
d764d916 6642 if (nLoadWalletRet == DB_NEED_REWRITE)
9e9869d0 6643 {
d764d916
GA
6644 if (CDB::Rewrite(strWalletFile, "\x04pool"))
6645 {
012ca1c9 6646 LOCK(cs_wallet);
d764d916
GA
6647 setKeyPool.clear();
6648 // Note: can't top-up keypool here, because wallet is locked.
6649 // User will be prompted to unlock wallet the next operation
c6de7c35 6650 // that requires a new key.
d764d916 6651 }
9e9869d0
PW
6652 }
6653
7ec55267
MC
6654 if (nLoadWalletRet != DB_LOAD_OK)
6655 return nLoadWalletRet;
fd61d6f5 6656 fFirstRunRet = !vchDefaultKey.IsValid();
e8ef3da7 6657
39278369
CL
6658 uiInterface.LoadWallet(this);
6659
116df55e 6660 return DB_LOAD_OK;
e8ef3da7
WL
6661}
6662
ae3d0aba 6663
77cbd462 6664DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
518f3bda
JG
6665{
6666 if (!fFileBacked)
6667 return DB_LOAD_OK;
77cbd462 6668 DBErrors nZapWalletTxRet = CWalletDB(strWalletFile,"cr+").ZapWalletTx(this, vWtx);
518f3bda
JG
6669 if (nZapWalletTxRet == DB_NEED_REWRITE)
6670 {
6671 if (CDB::Rewrite(strWalletFile, "\x04pool"))
6672 {
6673 LOCK(cs_wallet);
6674 setKeyPool.clear();
6675 // Note: can't top-up keypool here, because wallet is locked.
6676 // User will be prompted to unlock wallet the next operation
5b40d886 6677 // that requires a new key.
518f3bda
JG
6678 }
6679 }
6680
6681 if (nZapWalletTxRet != DB_LOAD_OK)
6682 return nZapWalletTxRet;
6683
6684 return DB_LOAD_OK;
6685}
6686
6687
a41d5fe0 6688bool CWallet::SetAddressBook(const CTxDestination& address, const string& strName, const string& strPurpose)
ae3d0aba 6689{
ca4cf5cf
GA
6690 bool fUpdated = false;
6691 {
6692 LOCK(cs_wallet); // mapAddressBook
6693 std::map<CTxDestination, CAddressBookData>::iterator mi = mapAddressBook.find(address);
6694 fUpdated = mi != mapAddressBook.end();
6695 mapAddressBook[address].name = strName;
6696 if (!strPurpose.empty()) /* update purpose only if requested */
6697 mapAddressBook[address].purpose = strPurpose;
6698 }
8d657a65 6699 NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address) != ISMINE_NO,
ca4cf5cf 6700 strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) );
ae3d0aba
WL
6701 if (!fFileBacked)
6702 return false;
07444da1 6703 if (!strPurpose.empty() && !CWalletDB(strWalletFile).WritePurpose(EncodeDestination(address), strPurpose))
a41d5fe0 6704 return false;
07444da1 6705 return CWalletDB(strWalletFile).WriteName(EncodeDestination(address), strName);
ae3d0aba
WL
6706}
6707
a41d5fe0 6708bool CWallet::DelAddressBook(const CTxDestination& address)
ae3d0aba 6709{
b10e1470 6710 {
ca4cf5cf
GA
6711 LOCK(cs_wallet); // mapAddressBook
6712
6713 if(fFileBacked)
b10e1470 6714 {
ca4cf5cf 6715 // Delete destdata tuples associated with address
07444da1 6716 std::string strAddress = EncodeDestination(address);
ca4cf5cf
GA
6717 BOOST_FOREACH(const PAIRTYPE(string, string) &item, mapAddressBook[address].destdata)
6718 {
6719 CWalletDB(strWalletFile).EraseDestData(strAddress, item.first);
6720 }
b10e1470 6721 }
ca4cf5cf 6722 mapAddressBook.erase(address);
b10e1470
WL
6723 }
6724
8d657a65 6725 NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address) != ISMINE_NO, "", CT_DELETED);
ca4cf5cf 6726
ae3d0aba
WL
6727 if (!fFileBacked)
6728 return false;
07444da1
PW
6729 CWalletDB(strWalletFile).ErasePurpose(EncodeDestination(address));
6730 return CWalletDB(strWalletFile).EraseName(EncodeDestination(address));
ae3d0aba
WL
6731}
6732
fd61d6f5 6733bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
ae3d0aba
WL
6734{
6735 if (fFileBacked)
6736 {
6737 if (!CWalletDB(strWalletFile).WriteDefaultKey(vchPubKey))
6738 return false;
6739 }
6740 vchDefaultKey = vchPubKey;
6741 return true;
6742}
6743
5b40d886
MF
6744/**
6745 * Mark old keypool keys as used,
efb7662d 6746 * and generate all new keys
5b40d886 6747 */
37971fcc
GA
6748bool CWallet::NewKeyPool()
6749{
37971fcc 6750 {
f8dcd5ca 6751 LOCK(cs_wallet);
37971fcc 6752 CWalletDB walletdb(strWalletFile);
51ed9ec9 6753 BOOST_FOREACH(int64_t nIndex, setKeyPool)
37971fcc
GA
6754 walletdb.ErasePool(nIndex);
6755 setKeyPool.clear();
6756
6757 if (IsLocked())
6758 return false;
6759
51ed9ec9 6760 int64_t nKeys = max(GetArg("-keypool", 100), (int64_t)0);
37971fcc
GA
6761 for (int i = 0; i < nKeys; i++)
6762 {
51ed9ec9 6763 int64_t nIndex = i+1;
37971fcc
GA
6764 walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey()));
6765 setKeyPool.insert(nIndex);
6766 }
f48742c2 6767 LogPrintf("CWallet::NewKeyPool wrote %d new keys\n", nKeys);
37971fcc
GA
6768 }
6769 return true;
6770}
6771
13dd2d09 6772bool CWallet::TopUpKeyPool(unsigned int kpSize)
e8ef3da7 6773{
e8ef3da7 6774 {
f8dcd5ca
PW
6775 LOCK(cs_wallet);
6776
4e87d341
MC
6777 if (IsLocked())
6778 return false;
6779
e8ef3da7
WL
6780 CWalletDB walletdb(strWalletFile);
6781
6782 // Top up key pool
13dd2d09
JG
6783 unsigned int nTargetSize;
6784 if (kpSize > 0)
6785 nTargetSize = kpSize;
6786 else
51ed9ec9 6787 nTargetSize = max(GetArg("-keypool", 100), (int64_t) 0);
13dd2d09 6788
faf705a4 6789 while (setKeyPool.size() < (nTargetSize + 1))
e8ef3da7 6790 {
51ed9ec9 6791 int64_t nEnd = 1;
e8ef3da7
WL
6792 if (!setKeyPool.empty())
6793 nEnd = *(--setKeyPool.end()) + 1;
6794 if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
5262fde0 6795 throw runtime_error("TopUpKeyPool(): writing generated key failed");
e8ef3da7 6796 setKeyPool.insert(nEnd);
783b182c 6797 LogPrintf("keypool added key %d, size=%u\n", nEnd, setKeyPool.size());
e8ef3da7 6798 }
4e87d341
MC
6799 }
6800 return true;
6801}
6802
51ed9ec9 6803void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool)
4e87d341
MC
6804{
6805 nIndex = -1;
fd61d6f5 6806 keypool.vchPubKey = CPubKey();
4e87d341 6807 {
f8dcd5ca
PW
6808 LOCK(cs_wallet);
6809
4e87d341
MC
6810 if (!IsLocked())
6811 TopUpKeyPool();
e8ef3da7
WL
6812
6813 // Get the oldest key
4e87d341
MC
6814 if(setKeyPool.empty())
6815 return;
6816
6817 CWalletDB walletdb(strWalletFile);
6818
e8ef3da7
WL
6819 nIndex = *(setKeyPool.begin());
6820 setKeyPool.erase(setKeyPool.begin());
6821 if (!walletdb.ReadPool(nIndex, keypool))
5262fde0 6822 throw runtime_error("ReserveKeyFromKeyPool(): read failed");
fd61d6f5 6823 if (!HaveKey(keypool.vchPubKey.GetID()))
5262fde0 6824 throw runtime_error("ReserveKeyFromKeyPool(): unknown key in key pool");
fd61d6f5 6825 assert(keypool.vchPubKey.IsValid());
36a65612 6826 //LogPrintf("keypool reserve %d\n", nIndex);
e8ef3da7
WL
6827 }
6828}
6829
51ed9ec9 6830void CWallet::KeepKey(int64_t nIndex)
e8ef3da7
WL
6831{
6832 // Remove from key pool
6833 if (fFileBacked)
6834 {
6835 CWalletDB walletdb(strWalletFile);
6cc4a62c 6836 walletdb.ErasePool(nIndex);
e8ef3da7 6837 }
f48742c2 6838 LogPrintf("keypool keep %d\n", nIndex);
e8ef3da7
WL
6839}
6840
51ed9ec9 6841void CWallet::ReturnKey(int64_t nIndex)
e8ef3da7
WL
6842{
6843 // Return to key pool
f8dcd5ca
PW
6844 {
6845 LOCK(cs_wallet);
e8ef3da7 6846 setKeyPool.insert(nIndex);
f8dcd5ca 6847 }
36a65612 6848 //LogPrintf("keypool return %d\n", nIndex);
e8ef3da7
WL
6849}
6850
71ac5052 6851bool CWallet::GetKeyFromPool(CPubKey& result)
e8ef3da7 6852{
51ed9ec9 6853 int64_t nIndex = 0;
e8ef3da7 6854 CKeyPool keypool;
7db3b75b 6855 {
f8dcd5ca 6856 LOCK(cs_wallet);
ed02c95d
GA
6857 ReserveKeyFromKeyPool(nIndex, keypool);
6858 if (nIndex == -1)
7db3b75b 6859 {
ed02c95d
GA
6860 if (IsLocked()) return false;
6861 result = GenerateNewKey();
7db3b75b
GA
6862 return true;
6863 }
ed02c95d
GA
6864 KeepKey(nIndex);
6865 result = keypool.vchPubKey;
7db3b75b 6866 }
7db3b75b 6867 return true;
e8ef3da7
WL
6868}
6869
51ed9ec9 6870int64_t CWallet::GetOldestKeyPoolTime()
e8ef3da7 6871{
51ed9ec9 6872 int64_t nIndex = 0;
e8ef3da7
WL
6873 CKeyPool keypool;
6874 ReserveKeyFromKeyPool(nIndex, keypool);
4e87d341
MC
6875 if (nIndex == -1)
6876 return GetTime();
e8ef3da7
WL
6877 ReturnKey(nIndex);
6878 return keypool.nTime;
6879}
6880
a372168e 6881std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
22dfd735 6882{
a372168e 6883 map<CTxDestination, CAmount> balances;
22dfd735 6884
6885 {
6886 LOCK(cs_wallet);
6887 BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet)
6888 {
6889 CWalletTx *pcoin = &walletEntry.second;
6890
75a4d512 6891 if (!CheckFinalTx(*pcoin) || !pcoin->IsTrusted())
22dfd735 6892 continue;
6893
6894 if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
6895 continue;
6896
6897 int nDepth = pcoin->GetDepthInMainChain();
a3e192a3 6898 if (nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? 0 : 1))
22dfd735 6899 continue;
6900
b1093efa 6901 for (unsigned int i = 0; i < pcoin->vout.size(); i++)
22dfd735 6902 {
b1093efa 6903 CTxDestination addr;
22dfd735 6904 if (!IsMine(pcoin->vout[i]))
6905 continue;
b1093efa
GM
6906 if(!ExtractDestination(pcoin->vout[i].scriptPubKey, addr))
6907 continue;
22dfd735 6908
a372168e 6909 CAmount n = IsSpent(walletEntry.first, i) ? 0 : pcoin->vout[i].nValue;
22dfd735 6910
22dfd735 6911 if (!balances.count(addr))
6912 balances[addr] = 0;
6913 balances[addr] += n;
6914 }
6915 }
6916 }
6917
6918 return balances;
6919}
6920
b1093efa 6921set< set<CTxDestination> > CWallet::GetAddressGroupings()
22dfd735 6922{
95691680 6923 AssertLockHeld(cs_wallet); // mapWallet
b1093efa
GM
6924 set< set<CTxDestination> > groupings;
6925 set<CTxDestination> grouping;
22dfd735 6926
6927 BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet)
6928 {
6929 CWalletTx *pcoin = &walletEntry.second;
6930
a3fad211 6931 if (pcoin->vin.size() > 0)
22dfd735 6932 {
a3fad211 6933 bool any_mine = false;
22dfd735 6934 // group all input addresses with each other
6935 BOOST_FOREACH(CTxIn txin, pcoin->vin)
b1093efa
GM
6936 {
6937 CTxDestination address;
a3fad211
GM
6938 if(!IsMine(txin)) /* If this input isn't mine, ignore it */
6939 continue;
b1093efa
GM
6940 if(!ExtractDestination(mapWallet[txin.prevout.hash].vout[txin.prevout.n].scriptPubKey, address))
6941 continue;
6942 grouping.insert(address);
a3fad211 6943 any_mine = true;
b1093efa 6944 }
22dfd735 6945
6946 // group change with input addresses
a3fad211
GM
6947 if (any_mine)
6948 {
6949 BOOST_FOREACH(CTxOut txout, pcoin->vout)
6950 if (IsChange(txout))
6951 {
6952 CTxDestination txoutAddr;
6953 if(!ExtractDestination(txout.scriptPubKey, txoutAddr))
6954 continue;
6955 grouping.insert(txoutAddr);
6956 }
6957 }
6958 if (grouping.size() > 0)
6959 {
6960 groupings.insert(grouping);
6961 grouping.clear();
6962 }
22dfd735 6963 }
6964
6965 // group lone addrs by themselves
b1093efa 6966 for (unsigned int i = 0; i < pcoin->vout.size(); i++)
22dfd735 6967 if (IsMine(pcoin->vout[i]))
6968 {
b1093efa
GM
6969 CTxDestination address;
6970 if(!ExtractDestination(pcoin->vout[i].scriptPubKey, address))
6971 continue;
6972 grouping.insert(address);
22dfd735 6973 groupings.insert(grouping);
6974 grouping.clear();
6975 }
6976 }
6977
b1093efa
GM
6978 set< set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses
6979 map< CTxDestination, set<CTxDestination>* > setmap; // map addresses to the unique group containing it
6980 BOOST_FOREACH(set<CTxDestination> grouping, groupings)
22dfd735 6981 {
6982 // make a set of all the groups hit by this new group
b1093efa
GM
6983 set< set<CTxDestination>* > hits;
6984 map< CTxDestination, set<CTxDestination>* >::iterator it;
6985 BOOST_FOREACH(CTxDestination address, grouping)
22dfd735 6986 if ((it = setmap.find(address)) != setmap.end())
6987 hits.insert((*it).second);
6988
6989 // merge all hit groups into a new single group and delete old groups
b1093efa
GM
6990 set<CTxDestination>* merged = new set<CTxDestination>(grouping);
6991 BOOST_FOREACH(set<CTxDestination>* hit, hits)
22dfd735 6992 {
6993 merged->insert(hit->begin(), hit->end());
6994 uniqueGroupings.erase(hit);
6995 delete hit;
6996 }
6997 uniqueGroupings.insert(merged);
6998
6999 // update setmap
b1093efa 7000 BOOST_FOREACH(CTxDestination element, *merged)
22dfd735 7001 setmap[element] = merged;
7002 }
7003
b1093efa
GM
7004 set< set<CTxDestination> > ret;
7005 BOOST_FOREACH(set<CTxDestination>* uniqueGrouping, uniqueGroupings)
22dfd735 7006 {
7007 ret.insert(*uniqueGrouping);
7008 delete uniqueGrouping;
7009 }
7010
7011 return ret;
7012}
7013
db954a65 7014std::set<CTxDestination> CWallet::GetAccountAddresses(const std::string& strAccount) const
3624356e 7015{
43422a01 7016 LOCK(cs_wallet);
3624356e
GA
7017 set<CTxDestination> result;
7018 BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, mapAddressBook)
7019 {
7020 const CTxDestination& address = item.first;
7021 const string& strName = item.second.name;
7022 if (strName == strAccount)
7023 result.insert(address);
7024 }
7025 return result;
7026}
7027
360cfe14 7028bool CReserveKey::GetReservedKey(CPubKey& pubkey)
e8ef3da7
WL
7029{
7030 if (nIndex == -1)
7031 {
7032 CKeyPool keypool;
7033 pwallet->ReserveKeyFromKeyPool(nIndex, keypool);
0d7b28e5
MC
7034 if (nIndex != -1)
7035 vchPubKey = keypool.vchPubKey;
360cfe14 7036 else {
6c37f7fd 7037 return false;
cee69980 7038 }
e8ef3da7 7039 }
fd61d6f5 7040 assert(vchPubKey.IsValid());
360cfe14
PW
7041 pubkey = vchPubKey;
7042 return true;
e8ef3da7
WL
7043}
7044
7045void CReserveKey::KeepKey()
7046{
7047 if (nIndex != -1)
7048 pwallet->KeepKey(nIndex);
7049 nIndex = -1;
fd61d6f5 7050 vchPubKey = CPubKey();
e8ef3da7
WL
7051}
7052
7053void CReserveKey::ReturnKey()
7054{
7055 if (nIndex != -1)
7056 pwallet->ReturnKey(nIndex);
7057 nIndex = -1;
fd61d6f5 7058 vchPubKey = CPubKey();
e8ef3da7 7059}
ae3d0aba 7060
434e4273 7061void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) const
30ab2c9c
PW
7062{
7063 setAddress.clear();
7064
7065 CWalletDB walletdb(strWalletFile);
7066
f8dcd5ca 7067 LOCK2(cs_main, cs_wallet);
51ed9ec9 7068 BOOST_FOREACH(const int64_t& id, setKeyPool)
30ab2c9c
PW
7069 {
7070 CKeyPool keypool;
7071 if (!walletdb.ReadPool(id, keypool))
5262fde0 7072 throw runtime_error("GetAllReserveKeyHashes(): read failed");
fd61d6f5 7073 assert(keypool.vchPubKey.IsValid());
10254401
PW
7074 CKeyID keyID = keypool.vchPubKey.GetID();
7075 if (!HaveKey(keyID))
5262fde0 7076 throw runtime_error("GetAllReserveKeyHashes(): unknown key in key pool");
10254401 7077 setAddress.insert(keyID);
30ab2c9c
PW
7078 }
7079}
fe4a6550
WL
7080
7081void CWallet::UpdatedTransaction(const uint256 &hashTx)
7082{
7083 {
7084 LOCK(cs_wallet);
7085 // Only notify UI if this transaction is in this wallet
7086 map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(hashTx);
7087 if (mi != mapWallet.end())
7088 NotifyTransactionChanged(this, hashTx, CT_UPDATED);
7089 }
7090}
fdbb537d 7091
f4055fe1 7092void CWallet::GetScriptForMining(boost::shared_ptr<CReserveScript> &script)
b2993bc5
JS
7093{
7094 if (!GetArg("-mineraddress", "").empty()) {
7095 return;
7096 }
7097
f4055fe1 7098 boost::shared_ptr<CReserveKey> rKey(new CReserveKey(this));
b2993bc5 7099 CPubKey pubkey;
f4055fe1 7100 if (!rKey->GetReservedKey(pubkey))
b2993bc5 7101 return;
f4055fe1
JS
7102
7103 script = rKey;
7104 script->reserveScript = CScript() << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
b2993bc5
JS
7105}
7106
fdbb537d
JG
7107void CWallet::LockCoin(COutPoint& output)
7108{
95691680 7109 AssertLockHeld(cs_wallet); // setLockedCoins
fdbb537d
JG
7110 setLockedCoins.insert(output);
7111}
7112
7113void CWallet::UnlockCoin(COutPoint& output)
7114{
95691680 7115 AssertLockHeld(cs_wallet); // setLockedCoins
fdbb537d
JG
7116 setLockedCoins.erase(output);
7117}
7118
7119void CWallet::UnlockAllCoins()
7120{
95691680 7121 AssertLockHeld(cs_wallet); // setLockedCoins
fdbb537d
JG
7122 setLockedCoins.clear();
7123}
7124
7125bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const
7126{
95691680 7127 AssertLockHeld(cs_wallet); // setLockedCoins
fdbb537d
JG
7128 COutPoint outpt(hash, n);
7129
7130 return (setLockedCoins.count(outpt) > 0);
7131}
7132
7133void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts)
7134{
95691680 7135 AssertLockHeld(cs_wallet); // setLockedCoins
fdbb537d
JG
7136 for (std::set<COutPoint>::iterator it = setLockedCoins.begin();
7137 it != setLockedCoins.end(); it++) {
7138 COutPoint outpt = (*it);
7139 vOutpts.push_back(outpt);
7140 }
7141}
7142
98a4f6a6
BM
7143
7144// Note Locking Operations
7145
e935beb8 7146void CWallet::LockNote(const JSOutPoint& output)
98a4f6a6 7147{
d358d145
S
7148 AssertLockHeld(cs_wallet); // setLockedSproutNotes
7149 setLockedSproutNotes.insert(output);
98a4f6a6
BM
7150}
7151
e935beb8 7152void CWallet::UnlockNote(const JSOutPoint& output)
98a4f6a6 7153{
d358d145
S
7154 AssertLockHeld(cs_wallet); // setLockedSproutNotes
7155 setLockedSproutNotes.erase(output);
98a4f6a6
BM
7156}
7157
9ae73247 7158void CWallet::UnlockAllSproutNotes()
98a4f6a6 7159{
d358d145
S
7160 AssertLockHeld(cs_wallet); // setLockedSproutNotes
7161 setLockedSproutNotes.clear();
98a4f6a6
BM
7162}
7163
e935beb8 7164bool CWallet::IsLockedNote(const JSOutPoint& outpt) const
98a4f6a6 7165{
d358d145 7166 AssertLockHeld(cs_wallet); // setLockedSproutNotes
98a4f6a6 7167
d358d145 7168 return (setLockedSproutNotes.count(outpt) > 0);
98a4f6a6
BM
7169}
7170
0f62cacf 7171std::vector<JSOutPoint> CWallet::ListLockedSproutNotes()
98a4f6a6 7172{
d358d145
S
7173 AssertLockHeld(cs_wallet); // setLockedSproutNotes
7174 std::vector<JSOutPoint> vOutpts(setLockedSproutNotes.begin(), setLockedSproutNotes.end());
98a4f6a6
BM
7175 return vOutpts;
7176}
7177
b1c693e5
S
7178void CWallet::LockNote(const SaplingOutPoint& output)
7179{
7180 AssertLockHeld(cs_wallet);
7181 setLockedSaplingNotes.insert(output);
7182}
7183
7184void CWallet::UnlockNote(const SaplingOutPoint& output)
7185{
7186 AssertLockHeld(cs_wallet);
7187 setLockedSaplingNotes.erase(output);
7188}
7189
7190void CWallet::UnlockAllSaplingNotes()
7191{
7192 AssertLockHeld(cs_wallet);
7193 setLockedSaplingNotes.clear();
7194}
7195
7196bool CWallet::IsLockedNote(const SaplingOutPoint& output) const
7197{
7198 AssertLockHeld(cs_wallet);
7199 return (setLockedSaplingNotes.count(output) > 0);
7200}
7201
7202std::vector<SaplingOutPoint> CWallet::ListLockedSaplingNotes()
7203{
7204 AssertLockHeld(cs_wallet);
7205 std::vector<SaplingOutPoint> vOutputs(setLockedSaplingNotes.begin(), setLockedSaplingNotes.end());
7206 return vOutputs;
7207}
7208
5b40d886 7209/** @} */ // end of Actions
8b59a3d3 7210
7211class CAffectedKeysVisitor : public boost::static_visitor<void> {
7212private:
7213 const CKeyStore &keystore;
7214 std::vector<CKeyID> &vKeys;
7215
7216public:
7217 CAffectedKeysVisitor(const CKeyStore &keystoreIn, std::vector<CKeyID> &vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {}
7218
7219 void Process(const CScript &script) {
7220 txnouttype type;
7221 std::vector<CTxDestination> vDest;
7222 int nRequired;
7223 if (ExtractDestinations(script, type, vDest, nRequired)) {
7224 BOOST_FOREACH(const CTxDestination &dest, vDest)
7225 boost::apply_visitor(*this, dest);
7226 }
7227 }
7228
7229 void operator()(const CKeyID &keyId) {
7230 if (keystore.HaveKey(keyId))
7231 vKeys.push_back(keyId);
7232 }
7233
b8deecdc 7234 void operator()(const CPubKey &key) {
7235 CKeyID keyId = key.GetID();
7236 if (keystore.HaveKey(keyId))
7237 vKeys.push_back(keyId);
7238 }
7239
56fe75cb 7240 // TODO: need to finish storage of quantum public key in wallet
7241 void operator()(const CQuantumID &keyId) {
7242 if (keystore.HaveKey(keyId))
7243 vKeys.push_back(keyId);
7244 }
7245
8b59a3d3 7246 void operator()(const CScriptID &scriptId) {
7247 CScript script;
7248 if (keystore.GetCScript(scriptId, script))
7249 Process(script);
7250 }
7251
0d7fed99 7252 void operator()(const CIdentityID &idId) {
5bc89dab 7253 std::pair<CIdentityMapKey, CIdentityMapValue> identity;
7254 if (keystore.GetIdentity(idId, identity))
0d7fed99 7255 {
5bc89dab 7256 for (auto dest : identity.second.primaryAddresses)
0d7fed99 7257 {
7258 boost::apply_visitor(*this, dest);
7259 }
7260 }
7261 }
7262
8b59a3d3 7263 void operator()(const CNoDestination &none) {}
7264};
7265
51ed9ec9 7266void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const {
95691680 7267 AssertLockHeld(cs_wallet); // mapKeyMetadata
434e4273
PW
7268 mapKeyBirth.clear();
7269
7270 // get birth times for keys with metadata
7271 for (std::map<CKeyID, CKeyMetadata>::const_iterator it = mapKeyMetadata.begin(); it != mapKeyMetadata.end(); it++)
7272 if (it->second.nCreateTime)
7273 mapKeyBirth[it->first] = it->second.nCreateTime;
7274
7275 // map in which we'll infer heights of other keys
4c6d41b8 7276 CBlockIndex *pindexMax = chainActive[std::max(0, chainActive.Height() - 144)]; // the tip can be reorganised; use a 144-block safety margin
434e4273
PW
7277 std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock;
7278 std::set<CKeyID> setKeys;
7279 GetKeys(setKeys);
7280 BOOST_FOREACH(const CKeyID &keyid, setKeys) {
7281 if (mapKeyBirth.count(keyid) == 0)
7282 mapKeyFirstBlock[keyid] = pindexMax;
7283 }
7284 setKeys.clear();
7285
7286 // if there are no such keys, we're done
7287 if (mapKeyFirstBlock.empty())
7288 return;
7289
7290 // find first block that affects those keys, if there are any left
7291 std::vector<CKeyID> vAffected;
7292 for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++) {
7293 // iterate over all wallet transactions...
7294 const CWalletTx &wtx = (*it).second;
145d5be8 7295 BlockMap::const_iterator blit = mapBlockIndex.find(wtx.hashBlock);
4c6d41b8 7296 if (blit != mapBlockIndex.end() && chainActive.Contains(blit->second)) {
434e4273 7297 // ... which are already in a block
4b729ec5 7298 int nHeight = blit->second->GetHeight();
434e4273
PW
7299 BOOST_FOREACH(const CTxOut &txout, wtx.vout) {
7300 // iterate over all their outputs
8b59a3d3 7301 CAffectedKeysVisitor(*this, vAffected).Process(txout.scriptPubKey);
434e4273
PW
7302 BOOST_FOREACH(const CKeyID &keyid, vAffected) {
7303 // ... and all their affected keys
7304 std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid);
4b729ec5 7305 if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->GetHeight())
434e4273
PW
7306 rit->second = blit->second;
7307 }
7308 vAffected.clear();
7309 }
7310 }
7311 }
7312
7313 // Extract block timestamps for those keys
7314 for (std::map<CKeyID, CBlockIndex*>::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++)
209377a7 7315 mapKeyBirth[it->first] = it->second->GetBlockTime() - 7200; // block times can be 2h off
434e4273 7316}
b10e1470
WL
7317
7318bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
7319{
8476d5d4
CL
7320 if (boost::get<CNoDestination>(&dest))
7321 return false;
7322
b10e1470
WL
7323 mapAddressBook[dest].destdata.insert(std::make_pair(key, value));
7324 if (!fFileBacked)
7325 return true;
07444da1 7326 return CWalletDB(strWalletFile).WriteDestData(EncodeDestination(dest), key, value);
b10e1470
WL
7327}
7328
7329bool CWallet::EraseDestData(const CTxDestination &dest, const std::string &key)
7330{
7331 if (!mapAddressBook[dest].destdata.erase(key))
7332 return false;
7333 if (!fFileBacked)
7334 return true;
07444da1 7335 return CWalletDB(strWalletFile).EraseDestData(EncodeDestination(dest), key);
b10e1470
WL
7336}
7337
7338bool CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
7339{
7340 mapAddressBook[dest].destdata.insert(std::make_pair(key, value));
7341 return true;
7342}
7343
7344bool CWallet::GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const
7345{
7346 std::map<CTxDestination, CAddressBookData>::const_iterator i = mapAddressBook.find(dest);
7347 if(i != mapAddressBook.end())
7348 {
7349 CAddressBookData::StringMap::const_iterator j = i->second.destdata.find(key);
7350 if(j != i->second.destdata.end())
7351 {
7352 if(value)
7353 *value = j->second;
7354 return true;
7355 }
7356 }
7357 return false;
7358}
af8297c0
WL
7359
7360CKeyPool::CKeyPool()
7361{
7362 nTime = GetTime();
7363}
7364
7365CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn)
7366{
7367 nTime = GetTime();
7368 vchPubKey = vchPubKeyIn;
7369}
7370
7371CWalletKey::CWalletKey(int64_t nExpires)
7372{
7373 nTimeCreated = (nExpires ? GetTime() : 0);
7374 nTimeExpires = nExpires;
7375}
0101483f 7376
d917c115 7377void CMerkleTx::SetMerkleBranch(const CBlock& block)
0101483f 7378{
0101483f
WL
7379 CBlock blockTmp;
7380
4b0deb3b
DK
7381 // Update the tx's hashBlock
7382 hashBlock = block.GetHash();
0101483f 7383
4b0deb3b
DK
7384 // Locate the transaction
7385 for (nIndex = 0; nIndex < (int)block.vtx.size(); nIndex++)
7386 if (block.vtx[nIndex] == *(CTransaction*)this)
7387 break;
7388 if (nIndex == (int)block.vtx.size())
7389 {
7390 vMerkleBranch.clear();
7391 nIndex = -1;
5262fde0 7392 LogPrintf("ERROR: SetMerkleBranch(): couldn't find tx in block\n");
0101483f
WL
7393 }
7394
4b0deb3b
DK
7395 // Fill in merkle branch
7396 vMerkleBranch = block.GetMerkleBranch(nIndex);
0101483f
WL
7397}
7398
a31e8bad 7399int CMerkleTx::GetDepthInMainChainINTERNAL(const CBlockIndex* &pindexRet) const
0101483f 7400{
4f152496 7401 if (hashBlock.IsNull() || nIndex == -1)
0101483f
WL
7402 return 0;
7403 AssertLockHeld(cs_main);
7404
7405 // Find the block it claims to be in
145d5be8 7406 BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
0101483f
WL
7407 if (mi == mapBlockIndex.end())
7408 return 0;
7409 CBlockIndex* pindex = (*mi).second;
7410 if (!pindex || !chainActive.Contains(pindex))
7411 return 0;
7412
7413 // Make sure the merkle branch connects to this block
7414 if (!fMerkleVerified)
7415 {
805344dc 7416 if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != pindex->hashMerkleRoot)
0101483f
WL
7417 return 0;
7418 fMerkleVerified = true;
7419 }
7420
7421 pindexRet = pindex;
4b729ec5 7422 return chainActive.Height() - pindex->GetHeight() + 1;
0101483f
WL
7423}
7424
a31e8bad 7425int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const
0101483f
WL
7426{
7427 AssertLockHeld(cs_main);
7428 int nResult = GetDepthInMainChainINTERNAL(pindexRet);
805344dc 7429 if (nResult == 0 && !mempool.exists(GetHash()))
0101483f
WL
7430 return -1; // Not in chain, not in mempool
7431
7432 return nResult;
7433}
7434
7435int CMerkleTx::GetBlocksToMaturity() const
7436{
7a90b9dd 7437 if ( ASSETCHAINS_SYMBOL[0] == 0 )
7438 COINBASE_MATURITY = _COINBASE_MATURITY;
0101483f
WL
7439 if (!IsCoinBase())
7440 return 0;
39267c35 7441 int32_t depth = GetDepthInMainChain();
204cf3fc 7442 int32_t ut = UnlockTime(0);
c2f6623f 7443 int32_t toMaturity = (ut - chainActive.Height()) < 0 ? 0 : ut - chainActive.Height();
7444 //printf("depth.%i, unlockTime.%i, toMaturity.%i\n", depth, ut, toMaturity);
7445 ut = (COINBASE_MATURITY - depth) < 0 ? 0 : COINBASE_MATURITY - depth;
204cf3fc 7446 return(ut < toMaturity ? toMaturity : ut);
0101483f
WL
7447}
7448
1371e6f5 7449bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee)
0101483f
WL
7450{
7451 CValidationState state;
1371e6f5 7452 return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectAbsurdFee);
0101483f
WL
7453}
7454
cb0d208f
S
7455/**
7456 * Find notes in the wallet filtered by payment address, min depth and ability to spend.
7457 * These notes are decrypted and added to the output parameter vector, outEntries.
7458 */
94e99acd 7459void CWallet::GetFilteredNotes(
a630f503 7460 std::vector<SproutNoteEntry>& sproutEntries,
94e99acd
JG
7461 std::vector<SaplingNoteEntry>& saplingEntries,
7462 std::string address,
7463 int minDepth,
7464 bool ignoreSpent,
ef27d7e4 7465 bool requireSpendingKey)
a5ac2e25 7466{
bdbe8e85
JG
7467 std::set<PaymentAddress> filterAddresses;
7468
a5ac2e25 7469 if (address.length() > 0) {
e5eab182 7470 filterAddresses.insert(DecodePaymentAddress(address));
a5ac2e25
S
7471 }
7472
ef27d7e4 7473 GetFilteredNotes(sproutEntries, saplingEntries, filterAddresses, minDepth, INT_MAX, ignoreSpent, requireSpendingKey);
bdbe8e85
JG
7474}
7475
7476/**
095eee4f
EOW
7477 * Find notes in the wallet filtered by payment addresses, min depth, max depth,
7478 * if the note is spent, if a spending key is required, and if the notes are locked.
bdbe8e85
JG
7479 * These notes are decrypted and added to the output parameter vector, outEntries.
7480 */
7481void CWallet::GetFilteredNotes(
a630f503 7482 std::vector<SproutNoteEntry>& sproutEntries,
94e99acd 7483 std::vector<SaplingNoteEntry>& saplingEntries,
bdbe8e85
JG
7484 std::set<PaymentAddress>& filterAddresses,
7485 int minDepth,
ef27d7e4 7486 int maxDepth,
bdbe8e85 7487 bool ignoreSpent,
ef27d7e4
EOW
7488 bool requireSpendingKey,
7489 bool ignoreLocked)
bdbe8e85 7490{
a5ac2e25
S
7491 LOCK2(cs_main, cs_wallet);
7492
7493 for (auto & p : mapWallet) {
7494 CWalletTx wtx = p.second;
7495
7496 // Filter the transactions before checking for notes
095eee4f
EOW
7497 if (!CheckFinalTx(wtx) ||
7498 wtx.GetBlocksToMaturity() > 0 ||
7499 wtx.GetDepthInMainChain() < minDepth ||
7500 wtx.GetDepthInMainChain() > maxDepth) {
a5ac2e25
S
7501 continue;
7502 }
7503
005f3ad1 7504 for (auto & pair : wtx.mapSproutNoteData) {
a5ac2e25 7505 JSOutPoint jsop = pair.first;
005f3ad1 7506 SproutNoteData nd = pair.second;
e5eab182 7507 SproutPaymentAddress pa = nd.address;
a5ac2e25
S
7508
7509 // skip notes which belong to a different payment address in the wallet
bdbe8e85 7510 if (!(filterAddresses.empty() || filterAddresses.count(pa))) {
a5ac2e25
S
7511 continue;
7512 }
7513
7514 // skip note which has been spent
3b6dd486 7515 if (ignoreSpent && nd.nullifier && IsSproutSpent(*nd.nullifier)) {
a5ac2e25
S
7516 continue;
7517 }
7518
9a2b8ae5 7519 // skip notes which cannot be spent
ef27d7e4 7520 if (requireSpendingKey && !HaveSproutSpendingKey(pa)) {
9a2b8ae5
JG
7521 continue;
7522 }
efb7662d 7523
4e6400bc 7524 // skip locked notes
ef27d7e4 7525 if (ignoreLocked && IsLockedNote(jsop)) {
4e6400bc
BM
7526 continue;
7527 }
9a2b8ae5 7528
f57f76d7 7529 int i = jsop.js; // Index into CTransaction.vJoinSplit
a5ac2e25
S
7530 int j = jsop.n; // Index into JSDescription.ciphertexts
7531
7532 // Get cached decryptor
7533 ZCNoteDecryption decryptor;
7534 if (!GetNoteDecryptor(pa, decryptor)) {
7535 // Note decryptors are created when the wallet is loaded, so it should always exist
80ed13d5 7536 throw std::runtime_error(strprintf("Could not find note decryptor for payment address %s", EncodePaymentAddress(pa)));
a5ac2e25
S
7537 }
7538
7539 // determine amount of funds in the note
f57f76d7 7540 auto hSig = wtx.vJoinSplit[i].h_sig(*pzcashParams, wtx.joinSplitPubKey);
a5ac2e25 7541 try {
5020a936 7542 SproutNotePlaintext plaintext = SproutNotePlaintext::decrypt(
a5ac2e25 7543 decryptor,
f57f76d7
DA
7544 wtx.vJoinSplit[i].ciphertexts[j],
7545 wtx.vJoinSplit[i].ephemeralKey,
a5ac2e25
S
7546 hSig,
7547 (unsigned char) j);
7548
a630f503
E
7549 sproutEntries.push_back(SproutNoteEntry {
7550 jsop, pa, plaintext.note(pa), plaintext.memo(), wtx.GetDepthInMainChain() });
a5ac2e25 7551
51fde9ea 7552 } catch (const note_decryption_failed &err) {
a5ac2e25 7553 // Couldn't decrypt with this spending key
80ed13d5 7554 throw std::runtime_error(strprintf("Could not decrypt note for payment address %s", EncodePaymentAddress(pa)));
51fde9ea
JG
7555 } catch (const std::exception &exc) {
7556 // Unexpected failure
80ed13d5 7557 throw std::runtime_error(strprintf("Error while decrypting note for payment address %s: %s", EncodePaymentAddress(pa), exc.what()));
a5ac2e25
S
7558 }
7559 }
94e99acd
JG
7560
7561 for (auto & pair : wtx.mapSaplingNoteData) {
7562 SaplingOutPoint op = pair.first;
7563 SaplingNoteData nd = pair.second;
7564
7565 auto maybe_pt = SaplingNotePlaintext::decrypt(
7566 wtx.vShieldedOutput[op.n].encCiphertext,
7567 nd.ivk,
7568 wtx.vShieldedOutput[op.n].ephemeralKey,
7569 wtx.vShieldedOutput[op.n].cm);
7570 assert(static_cast<bool>(maybe_pt));
7571 auto notePt = maybe_pt.get();
7572
7573 auto maybe_pa = nd.ivk.address(notePt.d);
7574 assert(static_cast<bool>(maybe_pa));
7575 auto pa = maybe_pa.get();
7576
7577 // skip notes which belong to a different payment address in the wallet
7578 if (!(filterAddresses.empty() || filterAddresses.count(pa))) {
7579 continue;
7580 }
7581
7582 if (ignoreSpent && nd.nullifier && IsSaplingSpent(*nd.nullifier)) {
7583 continue;
7584 }
7585
7586 // skip notes which cannot be spent
ef27d7e4 7587 if (requireSpendingKey) {
94e99acd
JG
7588 libzcash::SaplingIncomingViewingKey ivk;
7589 libzcash::SaplingFullViewingKey fvk;
7590 if (!(GetSaplingIncomingViewingKey(pa, ivk) &&
7591 GetSaplingFullViewingKey(ivk, fvk) &&
7592 HaveSaplingSpendingKey(fvk))) {
7593 continue;
7594 }
7595 }
7596
7597 // skip locked notes
0adb77d3
EOW
7598 if (ignoreLocked && IsLockedNote(op)) {
7599 continue;
7600 }
94e99acd
JG
7601
7602 auto note = notePt.note(nd.ivk).get();
7603 saplingEntries.push_back(SaplingNoteEntry {
94e99acd
JG
7604 op, pa, note, notePt.memo(), wtx.GetDepthInMainChain() });
7605 }
d72c19a6
S
7606 }
7607}
7608
d72c19a6 7609
053cb349
JG
7610//
7611// Shielded key and address generalizations
7612//
7613
7614bool PaymentAddressBelongsToWallet::operator()(const libzcash::SproutPaymentAddress &zaddr) const
7615{
7616 return m_wallet->HaveSproutSpendingKey(zaddr) || m_wallet->HaveSproutViewingKey(zaddr);
7617}
7618
7619bool PaymentAddressBelongsToWallet::operator()(const libzcash::SaplingPaymentAddress &zaddr) const
7620{
7621 libzcash::SaplingIncomingViewingKey ivk;
7622
70b4ad2d
JG
7623 // If we have a SaplingExtendedSpendingKey in the wallet, then we will
7624 // also have the corresponding SaplingFullViewingKey.
053cb349
JG
7625 return m_wallet->GetSaplingIncomingViewingKey(zaddr, ivk) &&
7626 m_wallet->HaveSaplingFullViewingKey(ivk);
7627}
7628
7629bool PaymentAddressBelongsToWallet::operator()(const libzcash::InvalidEncoding& no) const
7630{
7631 return false;
7632}
e22c115e 7633
81e0fd2e
JG
7634bool HaveSpendingKeyForPaymentAddress::operator()(const libzcash::SproutPaymentAddress &zaddr) const
7635{
7636 return m_wallet->HaveSproutSpendingKey(zaddr);
7637}
7638
7639bool HaveSpendingKeyForPaymentAddress::operator()(const libzcash::SaplingPaymentAddress &zaddr) const
7640{
7641 libzcash::SaplingIncomingViewingKey ivk;
7642 libzcash::SaplingFullViewingKey fvk;
7643
7644 return m_wallet->GetSaplingIncomingViewingKey(zaddr, ivk) &&
7645 m_wallet->GetSaplingFullViewingKey(ivk, fvk) &&
7646 m_wallet->HaveSaplingSpendingKey(fvk);
7647}
7648
7649bool HaveSpendingKeyForPaymentAddress::operator()(const libzcash::InvalidEncoding& no) const
7650{
7651 return false;
7652}
7653
e22c115e
JG
7654boost::optional<libzcash::SpendingKey> GetSpendingKeyForPaymentAddress::operator()(
7655 const libzcash::SproutPaymentAddress &zaddr) const
7656{
7657 libzcash::SproutSpendingKey k;
7658 if (m_wallet->GetSproutSpendingKey(zaddr, k)) {
7659 return libzcash::SpendingKey(k);
7660 } else {
7661 return boost::none;
a5ac2e25
S
7662 }
7663}
e22c115e
JG
7664
7665boost::optional<libzcash::SpendingKey> GetSpendingKeyForPaymentAddress::operator()(
7666 const libzcash::SaplingPaymentAddress &zaddr) const
7667{
5e360fb2
EOW
7668 libzcash::SaplingExtendedSpendingKey extsk;
7669 if (m_wallet->GetSaplingExtendedSpendingKey(zaddr, extsk)) {
7670 return libzcash::SpendingKey(extsk);
e22c115e
JG
7671 } else {
7672 return boost::none;
7673 }
7674}
7675
7676boost::optional<libzcash::SpendingKey> GetSpendingKeyForPaymentAddress::operator()(
7677 const libzcash::InvalidEncoding& no) const
7678{
7679 // Defaults to InvalidEncoding
7680 return libzcash::SpendingKey();
7681}
fcab001b 7682
0f03de55 7683SpendingKeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SproutSpendingKey &sk) const {
2fe39561 7684 auto addr = sk.address();
9bcf90e2
EOW
7685 if (log){
7686 LogPrint("zrpc", "Importing zaddr %s...\n", EncodePaymentAddress(addr));
7687 }
fcab001b 7688 if (m_wallet->HaveSproutSpendingKey(addr)) {
0f03de55
EOW
7689 return KeyAlreadyExists;
7690 } else if (m_wallet-> AddSproutZKey(sk)) {
9bcf90e2 7691 m_wallet->mapSproutZKeyMetadata[addr].nCreateTime = nTime;
0f03de55
EOW
7692 return KeyAdded;
7693 } else {
7694 return KeyNotAdded;
fcab001b
EOW
7695 }
7696}
7697
0f03de55 7698SpendingKeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SaplingExtendedSpendingKey &sk) const {
fcab001b
EOW
7699 auto fvk = sk.expsk.full_viewing_key();
7700 auto ivk = fvk.in_viewing_key();
7701 auto addr = sk.DefaultAddress();
7702 {
9bcf90e2
EOW
7703 if (log){
7704 LogPrint("zrpc", "Importing zaddr %s...\n", EncodePaymentAddress(addr));
7705 }
fcab001b
EOW
7706 // Don't throw error in case a key is already there
7707 if (m_wallet->HaveSaplingSpendingKey(fvk)) {
0f03de55 7708 return KeyAlreadyExists;
fcab001b 7709 } else {
fcab001b 7710 if (!m_wallet-> AddSaplingZKey(sk, addr)) {
0f03de55 7711 return KeyNotAdded;
fcab001b
EOW
7712 }
7713
7714 // Sapling addresses can't have been used in transactions prior to activation.
7715 if (params.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight == Consensus::NetworkUpgrade::ALWAYS_ACTIVE) {
9bcf90e2 7716 m_wallet->mapSaplingZKeyMetadata[ivk].nCreateTime = nTime;
fcab001b 7717 } else {
9bcf90e2
EOW
7718 // 154051200 seconds from epoch is Friday, 26 October 2018 00:00:00 GMT - definitely before Sapling activates
7719 m_wallet->mapSaplingZKeyMetadata[ivk].nCreateTime = std::max((int64_t) 154051200, nTime);
fcab001b 7720 }
2fe39561
EOW
7721 if (hdKeypath) {
7722 m_wallet->mapSaplingZKeyMetadata[ivk].hdKeypath = hdKeypath.get();
7723 }
7724 if (seedFpStr) {
7725 uint256 seedFp;
7726 seedFp.SetHex(seedFpStr.get());
7727 m_wallet->mapSaplingZKeyMetadata[ivk].seedFp = seedFp;
7728 }
0f03de55 7729 return KeyAdded;
fcab001b
EOW
7730 }
7731 }
7732}
7733
0f03de55 7734SpendingKeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::InvalidEncoding& no) const {
fcab001b
EOW
7735 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
7736}
This page took 2.010833 seconds and 4 git commands to generate.