diff options
Diffstat (limited to 'src/wallet/wallet.cpp')
-rw-r--r-- | src/wallet/wallet.cpp | 314 |
1 files changed, 103 insertions, 211 deletions
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 61d0686228..7f7a88e986 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -35,6 +35,8 @@ #include <boost/algorithm/string/replace.hpp> +static const size_t OUTPUT_GROUP_MAX_ENTRIES = 10; + static CCriticalSection cs_wallets; static std::vector<std::shared_ptr<CWallet>> vpwallets GUARDED_BY(cs_wallets); @@ -583,7 +585,6 @@ void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> ran // nTimeReceived not copied on purpose copyTo->nTimeSmart = copyFrom->nTimeSmart; copyTo->fFromMe = copyFrom->fFromMe; - copyTo->strFromAccount = copyFrom->strFromAccount; // nOrderPos not copied on purpose // cached members not copied on purpose } @@ -686,6 +687,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) { encrypted_batch->TxnAbort(); delete encrypted_batch; + encrypted_batch = nullptr; // We now probably have half of our keys encrypted in memory, and half not... // die and let the user reload the unencrypted wallet. assert(false); @@ -696,6 +698,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) if (!encrypted_batch->TxnCommit()) { delete encrypted_batch; + encrypted_batch = nullptr; // We now have keys encrypted in memory, but not on disk... // die to avoid confusion and let the user reload the unencrypted wallet. assert(false); @@ -738,44 +741,30 @@ DBErrors CWallet::ReorderTransactions() // Old wallets didn't have any defined order for transactions // Probably a bad idea to change the output of this - // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap. - typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair; - typedef std::multimap<int64_t, TxPair > TxItems; + // First: get all CWalletTx into a sorted-by-time multimap. + typedef std::multimap<int64_t, CWalletTx*> TxItems; TxItems txByTime; for (auto& entry : mapWallet) { CWalletTx* wtx = &entry.second; - txByTime.insert(std::make_pair(wtx->nTimeReceived, TxPair(wtx, nullptr))); - } - std::list<CAccountingEntry> acentries; - batch.ListAccountCreditDebit("", acentries); - for (CAccountingEntry& entry : acentries) - { - txByTime.insert(std::make_pair(entry.nTime, TxPair(nullptr, &entry))); + txByTime.insert(std::make_pair(wtx->nTimeReceived, wtx)); } nOrderPosNext = 0; std::vector<int64_t> nOrderPosOffsets; for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it) { - CWalletTx *const pwtx = (*it).second.first; - CAccountingEntry *const pacentry = (*it).second.second; - int64_t& nOrderPos = (pwtx != nullptr) ? pwtx->nOrderPos : pacentry->nOrderPos; + CWalletTx *const pwtx = (*it).second; + int64_t& nOrderPos = pwtx->nOrderPos; if (nOrderPos == -1) { nOrderPos = nOrderPosNext++; nOrderPosOffsets.push_back(nOrderPos); - if (pwtx) - { - if (!batch.WriteTx(*pwtx)) - return DBErrors::LOAD_FAIL; - } - else - if (!batch.WriteAccountingEntry(pacentry->nEntryNo, *pacentry)) - return DBErrors::LOAD_FAIL; + if (!batch.WriteTx(*pwtx)) + return DBErrors::LOAD_FAIL; } else { @@ -792,14 +781,8 @@ DBErrors CWallet::ReorderTransactions() continue; // Since we're changing the order, write it back - if (pwtx) - { - if (!batch.WriteTx(*pwtx)) - return DBErrors::LOAD_FAIL; - } - else - if (!batch.WriteAccountingEntry(pacentry->nEntryNo, *pacentry)) - return DBErrors::LOAD_FAIL; + if (!batch.WriteTx(*pwtx)) + return DBErrors::LOAD_FAIL; } } batch.WriteOrderPosNext(nOrderPosNext); @@ -819,80 +802,6 @@ int64_t CWallet::IncOrderPosNext(WalletBatch *batch) return nRet; } -bool CWallet::AccountMove(std::string strFrom, std::string strTo, CAmount nAmount, std::string strComment) -{ - WalletBatch batch(*database); - if (!batch.TxnBegin()) - return false; - - int64_t nNow = GetAdjustedTime(); - - // Debit - CAccountingEntry debit; - debit.nOrderPos = IncOrderPosNext(&batch); - debit.strAccount = strFrom; - debit.nCreditDebit = -nAmount; - debit.nTime = nNow; - debit.strOtherAccount = strTo; - debit.strComment = strComment; - AddAccountingEntry(debit, &batch); - - // Credit - CAccountingEntry credit; - credit.nOrderPos = IncOrderPosNext(&batch); - credit.strAccount = strTo; - credit.nCreditDebit = nAmount; - credit.nTime = nNow; - credit.strOtherAccount = strFrom; - credit.strComment = strComment; - AddAccountingEntry(credit, &batch); - - if (!batch.TxnCommit()) - return false; - - return true; -} - -bool CWallet::GetLabelDestination(CTxDestination &dest, const std::string& label, bool bForceNew) -{ - WalletBatch batch(*database); - - CAccount account; - batch.ReadAccount(label, account); - - if (!bForceNew) { - if (!account.vchPubKey.IsValid()) - bForceNew = true; - else { - // Check if the current key has been used (TODO: check other addresses with the same key) - CScript scriptPubKey = GetScriptForDestination(GetDestinationForKey(account.vchPubKey, m_default_address_type)); - for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin(); - it != mapWallet.end() && account.vchPubKey.IsValid(); - ++it) - for (const CTxOut& txout : (*it).second.tx->vout) - if (txout.scriptPubKey == scriptPubKey) { - bForceNew = true; - break; - } - } - } - - // Generate a new key - if (bForceNew) { - if (!GetKeyFromPool(account.vchPubKey, false)) - return false; - - LearnRelatedScripts(account.vchPubKey, m_default_address_type); - dest = GetDestinationForKey(account.vchPubKey, m_default_address_type); - SetAddressBook(dest, label, "receive"); - batch.WriteAccount(label, account); - } else { - dest = GetDestinationForKey(account.vchPubKey, m_default_address_type); - } - - return true; -} - void CWallet::MarkDirty() { { @@ -947,7 +856,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose) if (fInsertedNew) { wtx.nTimeReceived = GetAdjustedTime(); wtx.nOrderPos = IncOrderPosNext(&batch); - wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr))); + wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx)); wtx.nTimeSmart = ComputeTimeSmart(wtx); AddToSpends(hash); } @@ -1022,7 +931,7 @@ void CWallet::LoadToWallet(const CWalletTx& wtxIn) CWalletTx& wtx = ins.first->second; wtx.BindWallet(this); if (/* insertion took place */ ins.second) { - wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr))); + wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx)); } AddToSpends(hash); for (const CTxIn& txin : wtx.tx->vin) { @@ -1545,30 +1454,29 @@ int64_t CWalletTx::GetTxTime() const return n ? n : nTimeReceived; } -// Helper for producing a max-sized low-S signature (eg 72 bytes) -bool CWallet::DummySignInput(CTxIn &tx_in, const CTxOut &txout) const +// Helper for producing a max-sized low-S low-R signature (eg 71 bytes) +// or a max-sized low-S signature (e.g. 72 bytes) if use_max_sig is true +bool CWallet::DummySignInput(CTxIn &tx_in, const CTxOut &txout, bool use_max_sig) const { // Fill in dummy signatures for fee calculation. const CScript& scriptPubKey = txout.scriptPubKey; SignatureData sigdata; - if (!ProduceSignature(*this, DUMMY_SIGNATURE_CREATOR, scriptPubKey, sigdata)) - { + if (!ProduceSignature(*this, use_max_sig ? DUMMY_MAXIMUM_SIGNATURE_CREATOR : DUMMY_SIGNATURE_CREATOR, scriptPubKey, sigdata)) { return false; - } else { - UpdateInput(tx_in, sigdata); } + UpdateInput(tx_in, sigdata); return true; } -// Helper for producing a bunch of max-sized low-S signatures (eg 72 bytes) -bool CWallet::DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> &txouts) const +// Helper for producing a bunch of max-sized low-S low-R signatures (eg 71 bytes) +bool CWallet::DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> &txouts, bool use_max_sig) const { // Fill in dummy signatures for fee calculation. int nIn = 0; for (const auto& txout : txouts) { - if (!DummySignInput(txNew.vin[nIn], txout)) { + if (!DummySignInput(txNew.vin[nIn], txout, use_max_sig)) { return false; } @@ -1577,13 +1485,13 @@ bool CWallet::DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> return true; } -int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet) +int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, bool use_max_sig) { std::vector<CTxOut> txouts; // Look up the inputs. We should have already checked that this transaction // IsAllFromMe(ISMINE_SPENDABLE), so every input should already be in our // wallet, with a valid index into the vout array, and the ability to sign. - for (auto& input : tx.vin) { + for (const CTxIn& input : tx.vin) { const auto mi = wallet->mapWallet.find(input.prevout.hash); if (mi == wallet->mapWallet.end()) { return -1; @@ -1591,14 +1499,14 @@ int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wall assert(input.prevout.n < mi->second.tx->vout.size()); txouts.emplace_back(mi->second.tx->vout[input.prevout.n]); } - return CalculateMaximumSignedTxSize(tx, wallet, txouts); + return CalculateMaximumSignedTxSize(tx, wallet, txouts, use_max_sig); } // txouts needs to be in the order of tx.vin -int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts) +int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts, bool use_max_sig) { CMutableTransaction txNew(tx); - if (!wallet->DummySignTx(txNew, txouts)) { + if (!wallet->DummySignTx(txNew, txouts, use_max_sig)) { // This should never happen, because IsAllFromMe(ISMINE_SPENDABLE) // implies that we can sign for every input. return -1; @@ -1606,11 +1514,11 @@ int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wall return GetVirtualTransactionSize(txNew); } -int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet) +int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet, bool use_max_sig) { CMutableTransaction txn; txn.vin.push_back(CTxIn(COutPoint())); - if (!wallet->DummySignInput(txn.vin[0], txout)) { + if (!wallet->DummySignInput(txn.vin[0], txout, use_max_sig)) { // This should never happen, because IsAllFromMe(ISMINE_SPENDABLE) // implies that we can sign for every input. return -1; @@ -1619,12 +1527,11 @@ int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet) } void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived, - std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const + std::list<COutputEntry>& listSent, CAmount& nFee, const isminefilter& filter) const { nFee = 0; listReceived.clear(); listSent.clear(); - strSentAccount = strFromAccount; // Compute fee: CAmount nDebit = GetDebit(filter); @@ -1823,7 +1730,7 @@ void CWallet::ReacceptWalletTransactions() } // Try to add wallet transactions to memory pool - for (std::pair<const int64_t, CWalletTx*>& item : mapSorted) { + for (const std::pair<const int64_t, CWalletTx*>& item : mapSorted) { CWalletTx& wtx = *(item.second); CValidationState state; wtx.AcceptToMemoryPool(maxTxFee, state); @@ -1898,7 +1805,7 @@ CAmount CWalletTx::GetDebit(const isminefilter& filter) const CAmount CWalletTx::GetCredit(const isminefilter& filter) const { // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) + if (IsImmatureCoinBase()) return 0; CAmount credit = 0; @@ -1930,8 +1837,7 @@ CAmount CWalletTx::GetCredit(const isminefilter& filter) const CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const { - if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain()) - { + if (IsImmatureCoinBase() && IsInMainChain()) { if (fUseCache && fImmatureCreditCached) return nImmatureCreditCached; nImmatureCreditCached = pwallet->GetCredit(*tx, ISMINE_SPENDABLE); @@ -1948,7 +1854,7 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache, const isminefilter& filter return 0; // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) + if (IsImmatureCoinBase()) return 0; CAmount* cache = nullptr; @@ -1989,8 +1895,7 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache, const isminefilter& filter CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool fUseCache) const { - if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain()) - { + if (IsImmatureCoinBase() && IsInMainChain()) { if (fUseCache && fImmatureWatchCreditCached) return nImmatureWatchCreditCached; nImmatureWatchCreditCached = pwallet->GetCredit(*tx, ISMINE_WATCH_ONLY); @@ -2071,7 +1976,7 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime, CCon continue; mapSorted.insert(std::make_pair(wtx.nTimeReceived, &wtx)); } - for (std::pair<const unsigned int, CWalletTx*>& item : mapSorted) + for (const std::pair<const unsigned int, CWalletTx*>& item : mapSorted) { CWalletTx& wtx = *item.second; if (wtx.RelayWalletTransaction(connman)) @@ -2195,7 +2100,7 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const // wallet, and then subtracts the values of TxIns spending from the wallet. This // also has fewer restrictions on which unconfirmed transactions are considered // trusted. -CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth, const std::string* account) const +CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth) const { LOCK2(cs_main, cs_wallet); @@ -2203,7 +2108,7 @@ CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth, cons for (const auto& entry : mapWallet) { const CWalletTx& wtx = entry.second; const int depth = wtx.GetDepthInMainChain(); - if (depth < 0 || !CheckFinalTx(*wtx.tx) || wtx.GetBlocksToMaturity() > 0) { + if (depth < 0 || !CheckFinalTx(*wtx.tx) || wtx.IsImmatureCoinBase()) { continue; } @@ -2214,21 +2119,17 @@ CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth, cons for (const CTxOut& out : wtx.tx->vout) { if (outgoing && IsChange(out)) { debit -= out.nValue; - } else if (IsMine(out) & filter && depth >= minDepth && (!account || *account == GetLabelName(out.scriptPubKey))) { + } else if (IsMine(out) & filter && depth >= minDepth) { balance += out.nValue; } } // For outgoing txs, subtract amount debited. - if (outgoing && (!account || *account == wtx.strFromAccount)) { + if (outgoing) { balance -= debit; } } - if (account) { - balance += WalletBatch(*database).GetAccountCreditDebit(*account); - } - return balance; } @@ -2263,7 +2164,7 @@ void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const if (!CheckFinalTx(*pcoin->tx)) continue; - if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) + if (pcoin->IsImmatureCoinBase()) continue; int nDepth = pcoin->GetDepthInMainChain(); @@ -2337,7 +2238,7 @@ void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const bool solvable = IsSolvable(*this, pcoin->tx->vout[i].scriptPubKey); bool spendable = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (((mine & ISMINE_WATCH_ONLY) != ISMINE_NO) && (coinControl && coinControl->fAllowWatchOnly && solvable)); - vCoins.push_back(COutput(pcoin, i, nDepth, spendable, solvable, safeTx)); + vCoins.push_back(COutput(pcoin, i, nDepth, spendable, solvable, safeTx, (coinControl && coinControl->fAllowWatchOnly))); // Checks the sum amount of all UTXO's. if (nMinimumSumAmount != MAX_MONEY) { @@ -2358,23 +2259,15 @@ void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const std::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins() const { - // TODO: Add AssertLockHeld(cs_wallet) here. - // - // Because the return value from this function contains pointers to - // CWalletTx objects, callers to this function really should acquire the - // cs_wallet lock before calling it. However, the current caller doesn't - // acquire this lock yet. There was an attempt to add the missing lock in - // https://github.com/bitcoin/bitcoin/pull/10340, but that change has been - // postponed until after https://github.com/bitcoin/bitcoin/pull/10244 to - // avoid adding some extra complexity to the Qt code. + AssertLockHeld(cs_main); + AssertLockHeld(cs_wallet); std::map<CTxDestination, std::vector<COutput>> result; std::vector<COutput> availableCoins; - LOCK2(cs_main, cs_wallet); AvailableCoins(availableCoins); - for (auto& coin : availableCoins) { + for (const COutput& coin : availableCoins) { CTxDestination address; if (coin.fSpendable && ExtractDestination(FindNonChangeParentOutput(*coin.tx->tx, coin.i).scriptPubKey, address)) { @@ -2384,7 +2277,7 @@ std::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins() const std::vector<COutPoint> lockedCoins; ListLockedCoins(lockedCoins); - for (const auto& output : lockedCoins) { + for (const COutPoint& output : lockedCoins) { auto it = mapWallet.find(output.hash); if (it != mapWallet.end()) { int depth = it->second.GetDepthInMainChain(); @@ -2530,6 +2423,12 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm // form groups from remaining coins; note that preset coins will not // automatically have their associated (same address) coins included + if (coin_control.m_avoid_partial_spends && vCoins.size() > OUTPUT_GROUP_MAX_ENTRIES) { + // Cases where we have 11+ outputs all pointing to the same destination may result in + // privacy leaks as they will potentially be deterministically sorted. We solve that by + // explicitly shuffling the outputs before processing + std::shuffle(vCoins.begin(), vCoins.end(), FastRandomContext()); + } std::vector<OutputGroup> groups = GroupOutputs(vCoins, !coin_control.m_avoid_partial_spends); size_t max_ancestors = (size_t)std::max<int64_t>(1, gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT)); @@ -2763,7 +2662,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac scriptChange = GetScriptForDestination(GetDestinationForKey(vchPubKey, change_type)); } CTxOut change_prototype_txout(0, scriptChange); - coin_selection_params.change_output_size = GetSerializeSize(change_prototype_txout, SER_DISK, 0); + coin_selection_params.change_output_size = GetSerializeSize(change_prototype_txout); CFeeRate discard_rate = GetDiscardRate(*this, ::feeEstimator); @@ -2807,7 +2706,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac } } // Include the fee cost for outputs. Note this is only used for BnB right now - coin_selection_params.tx_noinputs_size += ::GetSerializeSize(txout, SER_NETWORK, PROTOCOL_VERSION); + coin_selection_params.tx_noinputs_size += ::GetSerializeSize(txout, PROTOCOL_VERSION); if (IsDust(txout, ::dustRelayFee)) { @@ -2886,7 +2785,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac txNew.vin.push_back(CTxIn(coin.outpoint,CScript())); } - nBytes = CalculateMaximumSignedTxSize(txNew, this); + nBytes = CalculateMaximumSignedTxSize(txNew, this, coin_control.fAllowWatchOnly); if (nBytes < 0) { strFailReason = _("Signing transaction failed"); return false; @@ -3054,7 +2953,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac /** * Call after CreateTransaction unless you want to abort */ -bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm, std::string fromAccount, CReserveKey& reservekey, CConnman* connman, CValidationState& state) +bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm, CReserveKey& reservekey, CConnman* connman, CValidationState& state) { { LOCK2(cs_main, cs_wallet); @@ -3062,7 +2961,6 @@ bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve CWalletTx wtxNew(this, std::move(tx)); wtxNew.mapValue = std::move(mapValue); wtxNew.vOrderForm = std::move(orderForm); - wtxNew.strFromAccount = std::move(fromAccount); wtxNew.fTimeReceivedIsTxTime = true; wtxNew.fFromMe = true; @@ -3102,31 +3000,6 @@ bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve return true; } -void CWallet::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries) { - WalletBatch batch(*database); - return batch.ListAccountCreditDebit(strAccount, entries); -} - -bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry) -{ - WalletBatch batch(*database); - - return AddAccountingEntry(acentry, &batch); -} - -bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, WalletBatch *batch) -{ - if (!batch->WriteAccountingEntry(++nAccountingEntryNumber, acentry)) { - return false; - } - - laccentries.push_back(acentry); - CAccountingEntry & entry = laccentries.back(); - wtxOrdered.insert(std::make_pair(entry.nOrderPos, TxPair(nullptr, &entry))); - - return true; -} - DBErrors CWallet::LoadWallet(bool& fFirstRunRet) { LOCK2(cs_main, cs_wallet); @@ -3280,17 +3153,17 @@ bool CWallet::NewKeyPool() LOCK(cs_wallet); WalletBatch batch(*database); - for (int64_t nIndex : setInternalKeyPool) { + for (const int64_t nIndex : setInternalKeyPool) { batch.ErasePool(nIndex); } setInternalKeyPool.clear(); - for (int64_t nIndex : setExternalKeyPool) { + for (const int64_t nIndex : setExternalKeyPool) { batch.ErasePool(nIndex); } setExternalKeyPool.clear(); - for (int64_t nIndex : set_pre_split_keypool) { + for (const int64_t nIndex : set_pre_split_keypool) { batch.ErasePool(nIndex); } set_pre_split_keypool.clear(); @@ -3526,7 +3399,7 @@ std::map<CTxDestination, CAmount> CWallet::GetAddressBalances() if (!pcoin->IsTrusted()) continue; - if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) + if (pcoin->IsImmatureCoinBase()) continue; int nDepth = pcoin->GetDepthInMainChain(); @@ -3567,7 +3440,7 @@ std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings() { bool any_mine = false; // group all input addresses with each other - for (CTxIn txin : pcoin->tx->vin) + for (const CTxIn& txin : pcoin->tx->vin) { CTxDestination address; if(!IsMine(txin)) /* If this input isn't mine, ignore it */ @@ -3581,7 +3454,7 @@ std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings() // group change with input addresses if (any_mine) { - for (CTxOut txout : pcoin->tx->vout) + for (const CTxOut& txout : pcoin->tx->vout) if (IsChange(txout)) { CTxDestination txoutAddr; @@ -3617,7 +3490,7 @@ std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings() // make a set of all the groups hit by this new group std::set< std::set<CTxDestination>* > hits; std::map< CTxDestination, std::set<CTxDestination>* >::iterator it; - for (CTxDestination address : _grouping) + for (const CTxDestination& address : _grouping) if ((it = setmap.find(address)) != setmap.end()) hits.insert((*it).second); @@ -3632,12 +3505,12 @@ std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings() uniqueGroupings.insert(merged); // update setmap - for (CTxDestination element : *merged) + for (const CTxDestination& element : *merged) setmap[element] = merged; } std::set< std::set<CTxDestination> > ret; - for (std::set<CTxDestination>* uniqueGrouping : uniqueGroupings) + for (const std::set<CTxDestination>* uniqueGrouping : uniqueGroupings) { ret.insert(*uniqueGrouping); delete uniqueGrouping; @@ -3660,12 +3533,6 @@ std::set<CTxDestination> CWallet::GetLabelAddresses(const std::string& label) co return result; } -void CWallet::DeleteLabel(const std::string& label) -{ - WalletBatch batch(*database); - batch.EraseAccount(label); -} - bool CReserveKey::GetReservedKey(CPubKey& pubkey, bool internal) { if (nIndex == -1) @@ -3856,19 +3723,14 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const int64_t latestTolerated = latestNow + 300; const TxItems& txOrdered = wtxOrdered; for (auto it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { - CWalletTx* const pwtx = it->second.first; + CWalletTx* const pwtx = it->second; if (pwtx == &wtx) { continue; } - CAccountingEntry* const pacentry = it->second.second; int64_t nSmartTime; - if (pwtx) { - nSmartTime = pwtx->nTimeSmart; - if (!nSmartTime) { - nSmartTime = pwtx->nTimeReceived; - } - } else { - nSmartTime = pacentry->nTime; + nSmartTime = pwtx->nTimeSmart; + if (!nSmartTime) { + nSmartTime = pwtx->nTimeReceived; } if (nSmartTime <= latestTolerated) { latestEntry = nSmartTime; @@ -3992,7 +3854,7 @@ bool CWallet::Verify(std::string wallet_file, bool salvage_wallet, std::string& return false; } } catch (const fs::filesystem_error& e) { - error_string = strprintf("Error loading wallet %s. %s", wallet_file, e.what()); + error_string = strprintf("Error loading wallet %s. %s", wallet_file, fsbridge::get_filesystem_error_message(e)); return false; } @@ -4313,7 +4175,6 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(const std::string& name, copyTo->nTimeReceived = copyFrom->nTimeReceived; copyTo->nTimeSmart = copyFrom->nTimeSmart; copyTo->fFromMe = copyFrom->fFromMe; - copyTo->strFromAccount = copyFrom->strFromAccount; copyTo->nOrderPos = copyFrom->nOrderPos; batch.WriteTx(*copyTo); } @@ -4404,6 +4265,11 @@ int CMerkleTx::GetBlocksToMaturity() const return std::max(0, (COINBASE_MATURITY+1) - chain_depth); } +bool CMerkleTx::IsImmatureCoinBase() const +{ + // note GetBlocksToMaturity is 0 for non-coinbase tx + return GetBlocksToMaturity() > 0; +} bool CWalletTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state) { @@ -4449,7 +4315,7 @@ std::vector<OutputGroup> CWallet::GroupOutputs(const std::vector<COutput>& outpu // Limit output groups to no more than 10 entries, to protect // against inadvertently creating a too-large transaction // when using -avoidpartialspends - if (gmap[dst].m_outputs.size() >= 10) { + if (gmap[dst].m_outputs.size() >= OUTPUT_GROUP_MAX_ENTRIES) { groups.push_back(gmap[dst]); gmap.erase(dst); } @@ -4464,3 +4330,29 @@ std::vector<OutputGroup> CWallet::GroupOutputs(const std::vector<COutput>& outpu } return groups; } + +bool CWallet::GetKeyOrigin(const CKeyID& keyID, KeyOriginInfo& info) const +{ + CKeyMetadata meta; + { + LOCK(cs_wallet); + auto it = mapKeyMetadata.find(keyID); + if (it != mapKeyMetadata.end()) { + meta = it->second; + } + } + if (!meta.hdKeypath.empty()) { + if (!ParseHDKeypath(meta.hdKeypath, info.path)) return false; + // Get the proper master key id + CKey key; + GetKey(meta.hd_seed_id, key); + CExtKey masterKey; + masterKey.SetSeed(key.begin(), key.size()); + // Compute identifier + CKeyID masterid = masterKey.key.GetPubKey().GetID(); + std::copy(masterid.begin(), masterid.begin() + 4, info.fingerprint); + } else { // Single pubkeys get the master fingerprint of themselves + std::copy(keyID.begin(), keyID.begin() + 4, info.fingerprint); + } + return true; +} |