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