diff --git a/src/init.cpp b/src/init.cpp index bf5e5a95297f..a627fca9e722 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1823,7 +1823,7 @@ bool AppInit2() copyTo->fFromMe = copyFrom->fFromMe; copyTo->strFromAccount = copyFrom->strFromAccount; copyTo->nOrderPos = copyFrom->nOrderPos; - copyTo->WriteToDisk(&walletdb); + walletdb.WriteTx(*copyTo); } } } diff --git a/src/main.cpp b/src/main.cpp index 66ededc3d7c1..ea8611063be6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2440,7 +2440,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin CWalletTx wtx(pwalletMain, tx); wtx.nTimeReceived = pindex->GetBlockTime(); wtx.SetMerkleBranch(block); - pwalletMain->AddToWallet(wtx, false, nullptr); + pwalletMain->AddToWallet(wtx, nullptr); setAddedTx.insert(pSpend.second); } } diff --git a/src/test/accounting_tests.cpp b/src/test/accounting_tests.cpp index 7cdc656566fc..d97176cb1d94 100644 --- a/src/test/accounting_tests.cpp +++ b/src/test/accounting_tests.cpp @@ -48,7 +48,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) pwalletMain->AddAccountingEntry(ae, walletdb); wtx.mapValue["comment"] = "z"; - pwalletMain->AddToWallet(wtx, false, &walletdb); + pwalletMain->AddToWallet(wtx, &walletdb); vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]); vpwtx[0]->nTimeReceived = (unsigned int)1333333335; vpwtx[0]->nOrderPos = -1; @@ -90,7 +90,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) --tx.nLockTime; // Just to change the hash :) *static_cast(&wtx) = CTransaction(tx); } - pwalletMain->AddToWallet(wtx, false, &walletdb); + pwalletMain->AddToWallet(wtx, &walletdb); vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]); vpwtx[1]->nTimeReceived = (unsigned int)1333333336; @@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) --tx.nLockTime; // Just to change the hash :) *static_cast(&wtx) = CTransaction(tx); } - pwalletMain->AddToWallet(wtx, false, &walletdb); + pwalletMain->AddToWallet(wtx, &walletdb); vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]); vpwtx[2]->nTimeReceived = (unsigned int)1333333329; vpwtx[2]->nOrderPos = -1; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 62e0c73d2a39..db8e0d293cd9 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -811,83 +811,89 @@ void CWallet::MarkDirty() } } -bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb) +bool CWallet::AddToWallet(const CWalletTx& wtxIn, CWalletDB* pwalletdb) { uint256 hash = wtxIn.GetHash(); - - if (fFromLoadWallet) { - mapWallet[hash] = wtxIn; - CWalletTx& wtx = mapWallet[hash]; - wtx.BindWallet(this); + LOCK(cs_wallet); + // Inserts only if not already there, returns tx inserted or tx found + std::pair::iterator, bool> ret = mapWallet.insert(std::make_pair(hash, wtxIn)); + CWalletTx& wtx = (*ret.first).second; + wtx.BindWallet(this); + bool fInsertedNew = ret.second; + if (fInsertedNew) { + wtx.nTimeReceived = GetAdjustedTime(); + wtx.nOrderPos = IncOrderPosNext(pwalletdb); wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); + wtx.UpdateTimeSmart(); AddToSpends(hash); - for (const CTxIn& txin : wtx.vin) { - if (mapWallet.count(txin.prevout.hash)) { - CWalletTx& prevtx = mapWallet[txin.prevout.hash]; - if (prevtx.nIndex == -1 && !prevtx.hashUnset()) { - MarkConflicted(prevtx.hashBlock, wtx.GetHash()); - } - } - } - } else { - LOCK(cs_wallet); - // Inserts only if not already there, returns tx inserted or tx found - std::pair::iterator, bool> ret = mapWallet.insert(std::make_pair(hash, wtxIn)); - CWalletTx& wtx = (*ret.first).second; - wtx.BindWallet(this); - bool fInsertedNew = ret.second; - if (fInsertedNew) { - wtx.nTimeReceived = GetAdjustedTime(); - wtx.nOrderPos = IncOrderPosNext(pwalletdb); - wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); + } + + bool fUpdated = false; + if (!fInsertedNew) { + // Merge + if (!wtxIn.hashUnset() && wtxIn.hashBlock != wtx.hashBlock) { + wtx.hashBlock = wtxIn.hashBlock; wtx.UpdateTimeSmart(); - AddToSpends(hash); + fUpdated = true; } - - bool fUpdated = false; - if (!fInsertedNew) { - // Merge - if (!wtxIn.hashUnset() && wtxIn.hashBlock != wtx.hashBlock) { - wtx.hashBlock = wtxIn.hashBlock; - wtx.UpdateTimeSmart(); - fUpdated = true; - } - // If no longer abandoned, update - if (wtxIn.hashBlock.IsNull() && wtx.isAbandoned()) { - wtx.hashBlock = wtxIn.hashBlock; - if (!fUpdated) wtx.UpdateTimeSmart(); - fUpdated = true; - } - if (wtxIn.nIndex != -1 && wtxIn.nIndex != wtx.nIndex) { - wtx.nIndex = wtxIn.nIndex; - fUpdated = true; - } - if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe) { - wtx.fFromMe = wtxIn.fFromMe; - fUpdated = true; - } + // If no longer abandoned, update + if (wtxIn.hashBlock.IsNull() && wtx.isAbandoned()) { + wtx.hashBlock = wtxIn.hashBlock; + if (!fUpdated) wtx.UpdateTimeSmart(); + fUpdated = true; } + if (wtxIn.nIndex != -1 && wtxIn.nIndex != wtx.nIndex) { + wtx.nIndex = wtxIn.nIndex; + fUpdated = true; + } + if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe) { + wtx.fFromMe = wtxIn.fFromMe; + fUpdated = true; + } + } - //// debug print - LogPrintf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : "")); + //// debug print + LogPrintf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : "")); - // Write to disk - if (fInsertedNew || fUpdated) - if (!wtx.WriteToDisk(pwalletdb)) - return false; + // Write to disk + if (fInsertedNew || fUpdated) { + if (!pwalletdb) { + CWalletDB(strWalletFile).WriteTx(wtx); + } else if (!pwalletdb->WriteTx(wtx)) { + return false; + } + } - // Break debit/credit balance caches: - wtx.MarkDirty(); + // Break debit/credit balance caches: + wtx.MarkDirty(); - // Notify UI of new or updated transaction - NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED); + // Notify UI of new or updated transaction + NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED); - // notify an external script when a wallet transaction comes in or is updated - std::string strCmd = GetArg("-walletnotify", ""); + // notify an external script when a wallet transaction comes in or is updated + std::string strCmd = GetArg("-walletnotify", ""); - if (!strCmd.empty()) { - boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex()); - boost::thread t(runCommand, strCmd); // thread runs free + if (!strCmd.empty()) { + boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex()); + boost::thread t(runCommand, strCmd); // thread runs free + } + return true; +} + +bool CWallet::LoadToWallet(const CWalletTx& wtxIn) +{ + uint256 hash = wtxIn.GetHash(); + mapWallet[hash] = wtxIn; + CWalletTx& wtx = mapWallet[hash]; + wtx.BindWallet(this); + wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); + AddToSpends(hash); + for (const CTxIn& txin : wtx.vin) { + if (mapWallet.count(txin.prevout.hash)) { + CWalletTx& prevtx = mapWallet[txin.prevout.hash]; + if (prevtx.nIndex == -1 && !prevtx.hashUnset()) { + MarkConflicted(prevtx.hashBlock, wtx.GetHash()); + } } } return true; @@ -939,7 +945,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl // this is safe, as in case of a crash, we rescan the necessary blocks on startup through our SetBestChain-mechanism CWalletDB walletdb(strWalletFile, "r+", false); - return AddToWallet(wtx, false, &walletdb); + return AddToWallet(wtx, &walletdb); } } return false; @@ -979,7 +985,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx) wtx.nIndex = -1; wtx.setAbandoned(); wtx.MarkDirty(); - wtx.WriteToDisk(&walletdb); + walletdb.WriteTx(wtx); NotifyTransactionChanged(this, wtx.GetHash(), CT_UPDATED); // Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0)); @@ -1036,7 +1042,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx) wtx.nIndex = -1; wtx.hashBlock = hashBlock; wtx.MarkDirty(); - wtx.WriteToDisk(&walletdb); + walletdb.WriteTx(wtx); // Iterate over all its outputs, and mark transactions in the wallet that spend them conflicted too TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0)); while (iter != mapTxSpends.end() && iter->first.hash == now) { @@ -1573,13 +1579,6 @@ void CWalletTx::GetAmounts(std::list& listReceived, } } -bool CWalletTx::WriteToDisk(CWalletDB *pwalletdb) -{ - if (pwalletdb) - return pwalletdb->WriteTx(GetHash(), *this); - return CWalletDB(pwallet->strWalletFile).WriteTx(GetHash(), *this); -} - bool CWallet::Upgrade(std::string& error, const int& prevVersion) { LOCK(cs_wallet); @@ -2304,18 +2303,10 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int return true; } -bool CWallet::SelectCoinsToSpend(const CAmount& nTargetValue, std::set >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl, AvailableCoinsType coin_type, bool useIX, bool fIncludeColdStaking, bool fIncludeDelegated) const +bool CWallet::SelectCoinsToSpend(const std::vector& vAvailableCoins, const CAmount& nTargetValue, std::set >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl) const { // Note: this function should never be used for "always free" tx types like dstx - std::vector vCoins; - AvailableCoins(&vCoins, - coinControl, - fIncludeDelegated, - fIncludeColdStaking, - coin_type, - true, // fOnlyConfirmed - false, // fIncludeZeroValue - useIX); + std::vector vCoins(vAvailableCoins); // coin control -> return all selected outputs (we want all selected to go into the transaction for sure) if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs) { @@ -2500,6 +2491,16 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, { LOCK2(cs_main, cs_wallet); { + std::vector vAvailableCoins; + AvailableCoins(&vAvailableCoins, + coinControl, + fIncludeDelegated, + false, // fIncludeColdStaking + coin_type, + true, // fOnlyConfirmed + false, // fIncludeZeroValue + useIX); + nFeeRet = 0; if (nFeePay > 0) nFeeRet = nFeePay; while (true) { @@ -2545,7 +2546,7 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, std::set > setCoins; CAmount nValueIn = 0; - if (!SelectCoinsToSpend(nTotalValue, setCoins, nValueIn, coinControl, coin_type, useIX, false, fIncludeDelegated)) { + if (!SelectCoinsToSpend(vAvailableCoins, nTotalValue, setCoins, nValueIn, coinControl)) { if (coin_type == ALL_COINS) { strFailReason = _("Insufficient funds."); } @@ -2934,7 +2935,7 @@ CWallet::CommitResult CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& // Add tx to wallet, because if it has change it's also ours, // otherwise just for transaction history. - AddToWallet(wtxNew, false, pwalletdb); + AddToWallet(wtxNew, pwalletdb); // Notify that old coins are spent if (!wtxNew.HasZerocoinSpendInputs()) { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index cccec47c6302..0653714e0009 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -355,7 +355,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface int nWatchonlyConfig = 1 ) const; //! >> Available coins (spending) - bool SelectCoinsToSpend(const CAmount& nTargetValue, std::set >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl = nullptr, AvailableCoinsType coin_type = ALL_COINS, bool useIX = true, bool fIncludeColdStaking = false, bool fIncludeDelegated = true) const; + bool SelectCoinsToSpend(const std::vector& vAvailableCoins, const CAmount& nTargetValue, std::set >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl = nullptr) const; bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector vCoins, std::set >& setCoinsRet, CAmount& nValueRet) const; //! >> Available coins (staking) bool StakeableCoins(std::vector* pCoins = nullptr); @@ -432,7 +432,8 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool GetLabelDestination(CTxDestination& dest, const std::string& label, bool bForceNew = false); void MarkDirty(); - bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb); + bool AddToWallet(const CWalletTx& wtxIn, CWalletDB* pwalletdb = nullptr); + bool LoadToWallet(const CWalletTx& wtxIn); void SyncTransaction(const CTransaction& tx, const CBlock* pblock); bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate); void EraseFromWallet(const uint256& hash); @@ -937,8 +938,6 @@ class CWalletTx : public CMerkleTx bool IsTrusted() const; bool IsTrusted(int& nDepth, bool& fConflicted) const; - bool WriteToDisk(CWalletDB *pwalletdb); - int64_t GetTxTime() const; void UpdateTimeSmart(); int GetRequestCount() const; diff --git a/src/wallet/wallet_zerocoin.cpp b/src/wallet/wallet_zerocoin.cpp index fa006d154500..e830c11a020b 100644 --- a/src/wallet/wallet_zerocoin.cpp +++ b/src/wallet/wallet_zerocoin.cpp @@ -117,7 +117,7 @@ void CWallet::doZPivRescan(const CBlockIndex* pindex, const CBlock& block, CWalletTx wtx(this, tx); wtx.nTimeReceived = block.GetBlockTime(); wtx.SetMerkleBranch(block); - AddToWallet(wtx, false, &walletdb); + AddToWallet(wtx, &walletdb); setAddedToWallet.insert(txid); } } @@ -137,7 +137,7 @@ void CWallet::doZPivRescan(const CBlockIndex* pindex, const CBlock& block, wtx.SetMerkleBranch(blockSpend); wtx.nTimeReceived = pindexSpend->nTime; - AddToWallet(wtx, false, &walletdb); + AddToWallet(wtx, &walletdb); setAddedToWallet.emplace(txidSpend); } } @@ -302,10 +302,14 @@ bool CWallet::CreateZerocoinMintTransaction(const CAmount nValue, // calculate fee CAmount nTotalValue = nValue + Params().GetConsensus().ZC_MinMintFee * txNew.vout.size(); + // Get the available coins + std::vector vAvailableCoins; + AvailableCoins(&vAvailableCoins, coinControl); + CAmount nValueIn = 0; std::set > setCoins; // select UTXO's to use - if (!SelectCoinsToSpend(nTotalValue, setCoins, nValueIn, coinControl)) { + if (!SelectCoinsToSpend(vAvailableCoins, nTotalValue, setCoins, nValueIn, coinControl)) { strFailReason = _("Insufficient or insufficient confirmed funds, you might need to wait a few minutes and try again."); return false; } diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 7fd89e3841a3..502f84922270 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -56,10 +56,10 @@ bool CWalletDB::ErasePurpose(const std::string& strPurpose) return Erase(std::make_pair(std::string("purpose"), strPurpose)); } -bool CWalletDB::WriteTx(uint256 hash, const CWalletTx& wtx) +bool CWalletDB::WriteTx(const CWalletTx& wtx) { nWalletDBUpdated++; - return Write(std::make_pair(std::string("tx"), hash), wtx); + return Write(std::make_pair(std::string("tx"), wtx.GetHash()), wtx); } bool CWalletDB::EraseTx(uint256 hash) @@ -400,7 +400,7 @@ DBErrors CWalletDB::ReorderTransactions(CWallet* pwallet) nOrderPosOffsets.push_back(nOrderPos); if (pwtx) { - if (!WriteTx(pwtx->GetHash(), *pwtx)) + if (!WriteTx(*pwtx)) return DB_LOAD_FAIL; } else if (!WriteAccountingEntry(pacentry->nEntryNo, *pacentry)) return DB_LOAD_FAIL; @@ -418,7 +418,7 @@ DBErrors CWalletDB::ReorderTransactions(CWallet* pwallet) // Since we're changing the order, write it back if (pwtx) { - if (!WriteTx(pwtx->GetHash(), *pwtx)) + if (!WriteTx(*pwtx)) return DB_LOAD_FAIL; } else if (!WriteAccountingEntry(pacentry->nEntryNo, *pacentry)) return DB_LOAD_FAIL; @@ -491,7 +491,7 @@ bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, CW if (wtx.nOrderPos == -1) wss.fAnyUnordered = true; - pwallet->AddToWallet(wtx, true, nullptr); + pwallet->LoadToWallet(wtx); } else if (strType == "acentry") { std::string strAccount; ssKey >> strAccount; @@ -776,7 +776,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) pwallet->nTimeFirstKey = 1; // 0 would be considered 'no value' for (uint256 hash : wss.vWalletUpgrade) - WriteTx(hash, pwallet->mapWallet[hash]); + WriteTx(pwallet->mapWallet[hash]); // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc: if (wss.fIsEncrypted && (wss.nFileVersion == 40000 || wss.nFileVersion == 50000)) diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 6fc27ac549d3..3e03ded5fad6 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -113,7 +113,7 @@ class CWalletDB : public CDB bool WritePurpose(const std::string& strAddress, const std::string& purpose); bool ErasePurpose(const std::string& strAddress); - bool WriteTx(uint256 hash, const CWalletTx& wtx); + bool WriteTx(const CWalletTx& wtx); bool EraseTx(uint256 hash); bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta); diff --git a/src/zpiv/zpivwallet.cpp b/src/zpiv/zpivwallet.cpp index 9b184ed16963..279af47622e8 100644 --- a/src/zpiv/zpivwallet.cpp +++ b/src/zpiv/zpivwallet.cpp @@ -267,7 +267,7 @@ void CzPIVWallet::SyncWithChain(bool fGenerateMintPool) //Fill out wtx so that a transaction record can be created wtx.nTimeReceived = pindex->GetBlockTime(); - wallet->AddToWallet(wtx, false, &walletdb); + wallet->AddToWallet(wtx, &walletdb); setAddedTx.insert(txHash); } @@ -324,7 +324,7 @@ bool CzPIVWallet::SetMintSeen(const CBigNum& bnValue, const int& nHeight, const wtx.nTimeReceived = pindex->nTime; CWalletDB walletdb(wallet->strWalletFile); - wallet->AddToWallet(wtx, false, &walletdb); + wallet->AddToWallet(wtx, &walletdb); } // Add to zpivTracker which also adds to database diff --git a/src/zpivchain.cpp b/src/zpivchain.cpp index 0ef6991d80f9..ba8dac7109c5 100644 --- a/src/zpivchain.cpp +++ b/src/zpivchain.cpp @@ -443,7 +443,7 @@ bool UpdateZPIVSupplyConnect(const CBlock& block, CBlockIndex* pindex, bool fJus CWalletTx wtx(pwalletMain, tx); wtx.nTimeReceived = block.GetBlockTime(); wtx.SetMerkleBranch(block); - pwalletMain->AddToWallet(wtx, false, nullptr); + pwalletMain->AddToWallet(wtx, nullptr); setAddedToWallet.insert(txid); } }