diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp index 30e109a6f0..b25210d436 100644 --- a/src/bench/coin_selection.cpp +++ b/src/bench/coin_selection.cpp @@ -91,7 +91,7 @@ static void add_coin(const CAmount& nValue, int nInput, std::vector tx.vout[nInput].nValue = nValue; std::unique_ptr wtx = std::make_unique(MakeTransactionRef(std::move(tx))); set.emplace_back(); - set.back().Insert(COutput(testWallet, *wtx, nInput, 0, true, true, true).GetInputCoin(), 0, true, 0, 0, false); + set.back().Insert(COutput(testWallet, *wtx, nInput, 0, true, true, true).GetInputCoin(testWallet), 0, true, 0, 0, false); wtxn.emplace_back(std::move(wtx)); } // Copied from src/wallet/test/coinselector_tests.cpp diff --git a/src/wallet/coinselection.cpp b/src/wallet/coinselection.cpp index 94021deb0d..6668e4c4ae 100644 --- a/src/wallet/coinselection.cpp +++ b/src/wallet/coinselection.cpp @@ -12,7 +12,7 @@ #include -CInputCoin::CInputCoin(const CWalletTx* wtx, unsigned int i) { +CInputCoin::CInputCoin(const CWallet& wallet, const CWalletTx* wtx, unsigned int i) { if (!wtx || !wtx->tx) throw std::invalid_argument("tx should not be null"); if (i >= wtx->tx->vout.size()) @@ -20,11 +20,11 @@ CInputCoin::CInputCoin(const CWalletTx* wtx, unsigned int i) { outpoint = COutPoint(wtx->tx->GetHash(), i); txout = wtx->tx->vout[i]; - effective_value = std::max(0, wtx->GetOutputValueOut(i)); - value = wtx->GetOutputValueOut(i); - asset = wtx->GetOutputAsset(i); - bf_value = wtx->GetOutputAmountBlindingFactor(i); - bf_asset = wtx->GetOutputAssetBlindingFactor(i); + effective_value = std::max(0, wtx->GetOutputValueOut(wallet, i)); + value = wtx->GetOutputValueOut(wallet, i); + asset = wtx->GetOutputAsset(wallet, i); + bf_value = wtx->GetOutputAmountBlindingFactor(wallet, i); + bf_asset = wtx->GetOutputAssetBlindingFactor(wallet, i); } // Descending order comparator diff --git a/src/wallet/coinselection.h b/src/wallet/coinselection.h index 183d706b55..f957e2d691 100644 --- a/src/wallet/coinselection.h +++ b/src/wallet/coinselection.h @@ -17,15 +17,16 @@ static constexpr CAmount MIN_CHANGE{COIN / 100}; //! final minimum change amount after paying for fees static const CAmount MIN_FINAL_CHANGE = MIN_CHANGE/2; +class CWallet; class CWalletTx; class uint256; /** A UTXO under consideration for use in funding a new transaction. */ class CInputCoin { public: - CInputCoin(const CWalletTx* wtx, unsigned int i); + CInputCoin(const CWallet& wallet, const CWalletTx* wtx, unsigned int i); - CInputCoin(const CWalletTx* wtx, unsigned int i, int input_bytes) : CInputCoin(wtx, i) + CInputCoin(const CWallet& wallet, const CWalletTx* wtx, unsigned int i, int input_bytes) : CInputCoin(wallet, wtx, i) { m_input_bytes = input_bytes; } diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index 0bd67d2125..6ba84735c3 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -62,8 +62,8 @@ WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) const auto& txin = wtx.tx->vin[i]; result.txin_is_mine.emplace_back(InputIsMine(wallet, txin)); wtx.GetIssuanceAssets(i, &result.txin_issuance_asset[i], &result.txin_issuance_token[i]); - result.txin_issuance_asset_amount.emplace_back(wtx.GetIssuanceAmount(i, false)); - result.txin_issuance_token_amount.emplace_back(wtx.GetIssuanceAmount(i, true)); + result.txin_issuance_asset_amount.emplace_back(wtx.GetIssuanceAmount(wallet, i, false)); + result.txin_issuance_token_amount.emplace_back(wtx.GetIssuanceAmount(wallet, i, true)); } result.txout_is_mine.reserve(wtx.tx->vout.size()); result.txout_address.reserve(wtx.tx->vout.size()); @@ -74,12 +74,12 @@ WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) result.txout_address_is_mine.emplace_back(ExtractDestination(txout.scriptPubKey, result.txout_address.back()) ? wallet.IsMine(result.txout_address.back()) : ISMINE_NO); - result.txout_is_change.push_back(wallet.IsChange(txout)); + result.txout_is_change.push_back(OutputIsChange(wallet, txout)); } // ELEMENTS: Retrieve unblinded information about outputs for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i) { - result.txout_amounts.emplace_back(wtx.GetOutputValueOut(i)); - result.txout_assets.emplace_back(wtx.GetOutputAsset(i)); + result.txout_amounts.emplace_back(wtx.GetOutputValueOut(wallet, i)); + result.txout_assets.emplace_back(wtx.GetOutputAsset(wallet, i)); } result.credit = CachedTxGetCredit(wallet, wtx, ISMINE_ALL); result.debit = CachedTxGetDebit(wallet, wtx, ISMINE_ALL); diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp index a994976394..3880a7ae2e 100644 --- a/src/wallet/load.cpp +++ b/src/wallet/load.cpp @@ -28,7 +28,7 @@ bool VerifyWallets(WalletContext& context) fs::path wallet_dir = args.GetArg("-walletdir", ""); boost::system::error_code error; // The canonical path cleans the path, preventing >1 Berkeley environment instances for the same directory - fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error); + fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error).remove_trailing_separator(); if (error || !fs::exists(wallet_dir)) { chain.initError(strprintf(_("Specified -walletdir \"%s\" does not exist"), wallet_dir.string())); return false; diff --git a/src/wallet/receive.cpp b/src/wallet/receive.cpp index 237848ab54..a62f502068 100644 --- a/src/wallet/receive.cpp +++ b/src/wallet/receive.cpp @@ -7,11 +7,12 @@ #include #include #include +#include isminetype InputIsMine(const CWallet& wallet, const CTxIn &txin) { AssertLockHeld(wallet.cs_wallet); - return IsMine(wallet, txin.prevout); + return InputIsMine(wallet, txin.prevout); } isminetype InputIsMine(const CWallet& wallet, const COutPoint &outpoint) @@ -48,15 +49,16 @@ bool AllInputsMine(const CWallet& wallet, const CTransaction& tx, const isminefi return true; } -CAmountMap OutputGetCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter) const { +CAmountMap OutputGetCredit(const CWallet& wallet, const CTransaction& tx, const size_t out_index, const isminefilter& filter) { CAmountMap nCredit; - for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i) { - if (wallet.IsMine(wtx.tx->vout[i]) & filter) { - CAmount credit = std::max(0, wtx.GetOutputValueOut(i)); + for (unsigned int i = 0; i < tx.vout.size(); ++i) { + if (wallet.IsMine(tx.vout[i]) & filter) { + CWalletTx wtx(MakeTransactionRef(std::move(tx))); + CAmount credit = std::max(0, wtx.GetOutputValueOut(wallet, i)); if (!MoneyRange(credit)) throw std::runtime_error(std::string(__func__) + ": value out of range"); - nCredit[wtx.GetOutputAsset(i)] += credit; + nCredit[wtx.GetOutputAsset(wallet, i)] += credit; if (!MoneyRange(nCredit)) throw std::runtime_error(std::string(__func__) + ": value out of range"); } @@ -64,11 +66,11 @@ CAmountMap OutputGetCredit(const CWallet& wallet, const CWalletTx& wtx, const is return nCredit; } -CAmountMap CWallet::GetChange(const CWalletTx& wtx) const { +CAmountMap GetChange(const CWallet& wallet, const CWalletTx& wtx) { CAmountMap nChange; for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i) { - if (IsChange(wtx.tx->vout[i])) { - CAmount change = wtx.GetOutputValueOut(i); + if (OutputIsChange(wallet, wtx.tx->vout[i])) { + CAmount change = wtx.GetOutputValueOut(wallet, i); if (change < 0) { continue; } @@ -76,7 +78,7 @@ CAmountMap CWallet::GetChange(const CWalletTx& wtx) const { if (!MoneyRange(change)) throw std::runtime_error(std::string(__func__) + ": value out of range"); - nChange[wtx.GetOutputAsset(i)] += change; + nChange[wtx.GetOutputAsset(wallet, i)] += change; if (!MoneyRange(nChange)) throw std::runtime_error(std::string(__func__) + ": value out of range"); } @@ -111,7 +113,7 @@ bool ScriptIsChange(const CWallet& wallet, const CScript& script) return false; } -CAmount OutputGetChange(const CWallet& wallet, const CTxOut& txout) +CAmountMap OutputGetChange(const CWallet& wallet, const CTxOut& txout) { AssertLockHeld(wallet.cs_wallet); @@ -122,7 +124,7 @@ CAmount OutputGetChange(const CWallet& wallet, const CTxOut& txout) return (OutputIsChange(wallet, txout) ? change : CAmountMap()); } -CAmount TxGetChange(const CWallet& wallet, const CTransaction& tx) +CAmountMap TxGetChange(const CWallet& wallet, const CTransaction& tx) { LOCK(wallet.cs_wallet); CAmountMap nChange; @@ -135,12 +137,12 @@ CAmount TxGetChange(const CWallet& wallet, const CTransaction& tx) return nChange; } -static CAmountMap GetCachableAmount(const CWallet& wallet, const CWalletTx& wtx, CWalletTx::AmountType type, const isminefilter& filter, bool recalculate = false) NO_THREAD_SAFETY_ANALYSIS +static CAmountMap GetCachableAmount(const CWallet& wallet, const CWalletTx& wtx, CWalletTx::AmountType type, const isminefilter& filter, bool recalculate = false) { auto& amount = wtx.m_amounts[type]; if (recalculate || !amount.m_cached[filter]) { - amount.Set(filter, type == CWalletTx::DEBIT ? wallet.GetDebit(*wtx.tx, filter) : TxGetCredit(wallet, *this, filter));//JAMES DELETE ME: TxGetCredit(wallet, *wtx.tx, filter)); - m_is_cache_empty = false; + amount.Set(filter, type == CWalletTx::DEBIT ? wallet.GetDebit(*wtx.tx, filter) : TxGetCredit(wallet, *wtx.tx, filter)); + wtx.m_is_cache_empty = false; } return amount.m_value[filter]; } @@ -162,23 +164,25 @@ CAmountMap CachedTxGetCredit(const CWallet& wallet, const CWalletTx& wtx, const return credit; } -/*CAmountMap CWallet::GetCredit(const CTransaction& tx, const size_t out_index, const isminefilter& filter) const +CAmountMap TxGetCredit(const CWallet& wallet, const CTransaction& tx, const isminefilter& filter) { { - LOCK(cs_wallet); - std::map::const_iterator mi = mapWallet.find(tx.GetHash()); - if (mi != mapWallet.end()) + LOCK(wallet.cs_wallet); + std::map::const_iterator mi = wallet.mapWallet.find(tx.GetHash()); + if (mi != wallet.mapWallet.end()) { const CWalletTx& wtx = (*mi).second; - if (out_index < wtx.tx->vout.size() && IsMine(wtx.tx->vout[out_index]) & filter) { - CAmountMap amounts; - amounts[wtx.GetOutputAsset(out_index)] = std::max(0, wtx.GetOutputValueOut(out_index)); - return amounts; + for (size_t i = 0; i < wtx.tx->vout.size(); ++i) { + if (wallet.IsMine(wtx.tx->vout[i]) & filter) { + CAmountMap amounts; + amounts[wtx.GetOutputAsset(wallet, i)] = std::max(0, wtx.GetOutputValueOut(wallet, i)); + return amounts; + } } } } return CAmountMap(); -}*/ +} CAmountMap CachedTxGetDebit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter) { @@ -199,15 +203,23 @@ CAmountMap CachedTxGetChange(const CWallet& wallet, const CWalletTx& wtx) { if (wtx.fChangeCached) return wtx.nChangeCached; - wtx.nChangeCached = TxGetChange(wallet, *this); //DELETEME (JAMES): *wtx.tx + wtx.nChangeCached = TxGetChange(wallet, *wtx.tx); wtx.fChangeCached = true; return wtx.nChangeCached; } CAmountMap CachedTxGetImmatureCredit(const CWallet& wallet, const CWalletTx& wtx, bool fUseCache) { + std::cout << "CachedTxGetImmatureCredit: " << wallet.IsTxImmatureCoinBase(wtx) << " " << wallet.IsTxInMainChain(wtx) << std::endl; if (wallet.IsTxImmatureCoinBase(wtx) && wallet.IsTxInMainChain(wtx)) { - return GetCachableAmount(wallet, wtx, CWalletTx::IMMATURE_CREDIT, ISMINE_SPENDABLE, !fUseCache); + std::cout << "in if statement" << std::endl; + auto temp = GetCachableAmount(wallet, wtx, CWalletTx::IMMATURE_CREDIT, ISMINE_SPENDABLE, !fUseCache); + std::cout << "size: " << temp.size() << std::endl; + for (auto& pair : temp) { + std::cout << "key: " << pair.first.GetHex() << std::endl; + std::cout << "value: " << pair.second << std::endl; + } + return temp; } return CAmountMap(); @@ -240,13 +252,13 @@ CAmountMap CachedTxGetAvailableCredit(const CWallet& wallet, const CWalletTx& wt uint256 hashTx = wtx.GetHash(); for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) { - if (!wallet->IsSpent(hashTx, i) && (allow_used_addresses || !wallet->IsSpentKey(hashTx, i))) { - if (wallet->IsMine(tx->vout[i]) & filter) { - CAmount credit = std::max(0, GetOutputValueOut(i)); + if (!wallet.IsSpent(hashTx, i) && (allow_used_addresses || !wallet.IsSpentKey(hashTx, i))) { + if (wallet.IsMine(wtx.tx->vout[i]) & filter) { + CAmount credit = std::max(0, wtx.GetOutputValueOut(wallet, i)); if (!MoneyRange(credit)) throw std::runtime_error(std::string(__func__) + ": value out of range"); - nCredit[GetOutputAsset(i)] += std::max(0, GetOutputValueOut(i)); + nCredit[wtx.GetOutputAsset(wallet, i)] += std::max(0, wtx.GetOutputValueOut(wallet, i)); if (!MoneyRange(nCredit)) throw std::runtime_error(std::string(__func__) + ": value out of range"); } @@ -281,9 +293,9 @@ void CachedTxGetAmounts(const CWallet& wallet, const CWalletTx& wtx, for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i) { const CTxOut& txout = wtx.tx->vout[i]; - CAmount output_value = GetOutputValueOut(i); + CAmount output_value = wtx.GetOutputValueOut(wallet, i); // Don't list unknown assets - isminetype fIsMine = output_value != -1 ? wallet->IsMine(txout) : ISMINE_NO; + isminetype fIsMine = output_value != -1 ? wallet.IsMine(txout) : ISMINE_NO; // Only need to handle txouts if AT LEAST one of these is true: // 1) they debit from us (sent) // 2) the output is to us (received) @@ -306,7 +318,7 @@ void CachedTxGetAmounts(const CWallet& wallet, const CWalletTx& wtx, address = CNoDestination(); } - COutputEntry output = {address, output_value, (int)i, GetOutputAsset(i), GetOutputAmountBlindingFactor(i), GetOutputAssetBlindingFactor(i)}; + COutputEntry output = {address, output_value, (int)i, wtx.GetOutputAsset(wallet, i), wtx.GetOutputAmountBlindingFactor(wallet, i), wtx.GetOutputAssetBlindingFactor(wallet, i)}; // If we are debited by the transaction, add the output as a "sent" entry if (mapDebit > CAmountMap() && !txout.IsFee()) @@ -321,7 +333,7 @@ void CachedTxGetAmounts(const CWallet& wallet, const CWalletTx& wtx, bool CachedTxIsFromMe(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter) { - return (CachedTxGetDebit(wallet, wtx, filter) > 0); + return (CachedTxGetDebit(wallet, wtx, filter) > CAmountMap()); } bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx, std::set& trusted_parents) @@ -373,7 +385,7 @@ Balance GetBalance(const CWallet& wallet, const int min_depth, bool avoid_reuse) for (const auto& entry : wallet.mapWallet) { const CWalletTx& wtx = entry.second; - const bool is_trusted{IsTrusted(wtx, trusted_parents)}; + const bool is_trusted{CachedTxIsTrusted(wallet, wtx, trusted_parents)}; const int tx_depth{wallet.GetTxDepthInMainChain(wtx)}; const CAmountMap tx_credit_mine{CachedTxGetAvailableCredit(wallet, wtx, /* fUseCache */ true, ISMINE_SPENDABLE | reuse_filter)}; const CAmountMap tx_credit_watchonly{CachedTxGetAvailableCredit(wallet, wtx, /* fUseCache */ true, ISMINE_WATCH_ONLY | reuse_filter)}; @@ -421,7 +433,7 @@ std::map GetAddressBalances(const CWallet& wallet) if(!ExtractDestination(wtx.tx->vout[i].scriptPubKey, addr)) continue; - CAmount n = wallet.IsSpent(walletEntry.first, i) ? 0 : wtx.GetOutputValueOut(i); + CAmount n = wallet.IsSpent(walletEntry.first, i) ? 0 : wtx.GetOutputValueOut(wallet, i); if (n < 0) { continue; } @@ -527,17 +539,16 @@ std::set< std::set > GetAddressGroupings(const CWallet& wallet) } // ELEMENTS -CAmountMap CWalletTx::GetIssuanceAssets(unsigned int input_index) const { +CAmountMap CWalletTx::GetIssuanceAssets(const CWallet& wallet, unsigned int input_index) const { CAmountMap ret; CAsset asset, token; GetIssuanceAssets(input_index, &asset, &token); if (!asset.IsNull()) { - ret[asset] = GetIssuanceAmount(input_index, false); + ret[asset] = GetIssuanceAmount(wallet, input_index, false); } if (!token.IsNull()) { - ret[token] = GetIssuanceAmount(input_index, true); + ret[token] = GetIssuanceAmount(wallet, input_index, true); } return ret; } // end ELEMENTS - diff --git a/src/wallet/receive.h b/src/wallet/receive.h index 3a703dc1fa..033a0796b5 100644 --- a/src/wallet/receive.h +++ b/src/wallet/receive.h @@ -24,13 +24,17 @@ bool OutputIsChange(const CWallet& wallet, const CTxOut& txout) EXCLUSIVE_LOCKS_ CAmountMap OutputGetChange(const CWallet& wallet, const CTxOut& txout) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); CAmountMap TxGetChange(const CWallet& wallet, const CTransaction& tx); // ELEMENTS: -CAmountMap GetCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter) const EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); -CAmountMap GetChange(const CWallet& wallet, const CWalletTx& wtx) const EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); +CAmountMap GetCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); +CAmountMap GetChange(const CWallet& wallet, const CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); CAmountMap CachedTxGetCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter); //! filter decides which addresses will count towards the debit CAmountMap CachedTxGetDebit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter); -CAmountMap CachedTxGetChange(const CWallet& wallet, const CWalletTx& wtx) const NO_THREAD_SAFETY_ANALYSIS; +// TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct +// annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The +// annotation "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid +// having to resolve the issue of member access into incomplete type CWallet. +CAmountMap CachedTxGetChange(const CWallet& wallet, const CWalletTx& wtx) NO_THREAD_SAFETY_ANALYSIS; CAmountMap CachedTxGetImmatureCredit(const CWallet& wallet, const CWalletTx& wtx, bool fUseCache = true); CAmountMap CachedTxGetImmatureWatchOnlyCredit(const CWallet& wallet, const CWalletTx& wtx, const bool fUseCache = true); // TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index b68e11cfc2..5f8adb0638 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -2237,10 +2237,10 @@ RPCHelpMan dumpissuanceblindingkey() throw JSONRPCError(RPC_WALLET_ERROR, "Transaction input has no issuance"); } // We can actually deblind the input - if (pcoin->GetIssuanceAmount(vindex, false) != -1 ) { + if (pcoin->GetIssuanceAmount(*pwallet, vindex, false) != -1 ) { CScript blindingScript(CScript() << OP_RETURN << std::vector(pcoin->tx->vin[vindex].prevout.hash.begin(), pcoin->tx->vin[vindex].prevout.hash.end()) << pcoin->tx->vin[vindex].prevout.n); CKey key; - key = pwallet->GetBlindingKey(&blindingScript); + key = wallet->GetBlindingKey(&blindingScript); return HexStr(Span(key.begin(), key.size())); } else { // We don't know how to deblind this using our wallet @@ -2254,4 +2254,3 @@ RPCHelpMan dumpissuanceblindingkey() // END ELEMENTS // - diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 3c5b176317..a918e25967 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -476,15 +476,9 @@ UniValue SendMoney(CWallet& wallet, const CCoinControl &coin_control, std::vecto bilingual_str error; CTransactionRef tx; FeeCalculation fee_calc_out; -<<<<<<< HEAD auto blind_details = g_con_elementsmode ? std::make_unique() : nullptr; if (blind_details) blind_details->ignore_blind_failure = ignore_blind_fail; - const bool fCreated = wallet.CreateTransaction(recipients, tx, nFeeRequired, nChangePosRet, error, coin_control, fee_calc_out, true, blind_details.get()); -||||||| dd097c42df - const bool fCreated = wallet.CreateTransaction(recipients, tx, nFeeRequired, nChangePosRet, error, coin_control, fee_calc_out, true); -======= - const bool fCreated = CreateTransaction(wallet, recipients, tx, nFeeRequired, nChangePosRet, error, coin_control, fee_calc_out, true); ->>>>>>> 629c4ab2e3 + const bool fCreated = CreateTransaction(wallet, recipients, tx, nFeeRequired, nChangePosRet, error, coin_control, fee_calc_out, true, blind_details.get()); if (!fCreated) { throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, error.original); } @@ -762,22 +756,10 @@ static CAmountMap GetReceived(const CWallet& wallet, const UniValue& params, boo min_depth = params[1].get_int(); // Tally -<<<<<<< HEAD CAmountMap amounts; for (auto& pairWtx : wallet.mapWallet) { const CWalletTx& wtx = pairWtx.second; if (wtx.IsCoinBase() || !wallet.chain().checkFinalTx(*wtx.tx)) { -||||||| dd097c42df - CAmount amount = 0; - for (const std::pair& wtx_pair : wallet.mapWallet) { - const CWalletTx& wtx = wtx_pair.second; - if (wtx.IsCoinBase() || !wallet.chain().checkFinalTx(*wtx.tx) || wtx.GetDepthInMainChain() < min_depth) { -======= - CAmount amount = 0; - for (const std::pair& wtx_pair : wallet.mapWallet) { - const CWalletTx& wtx = wtx_pair.second; - if (wtx.IsCoinBase() || !wallet.chain().checkFinalTx(*wtx.tx) || wallet.GetTxDepthInMainChain(wtx) < min_depth) { ->>>>>>> 629c4ab2e3 continue; } @@ -785,13 +767,13 @@ static CAmountMap GetReceived(const CWallet& wallet, const UniValue& params, boo const CTxOut& txout = wtx.tx->vout[i]; CTxDestination address; if (ExtractDestination(txout.scriptPubKey, address) && wallet.IsMine(address) && address_set.count(address)) { - if (wtx.GetDepthInMainChain() >= min_depth) { + if (wallet.GetTxDepthInMainChain(wtx) >= min_depth) { CAmountMap wtxValue; - CAmount amt = wtx.GetOutputValueOut(i); + CAmount amt = wtx.GetOutputValueOut(wallet, i); if (amt < 0) { continue; } - wtxValue[wtx.GetOutputAsset(i)] = amt; + wtxValue[wtx.GetOutputAsset(wallet, i)] = amt; amounts += wtxValue; } } @@ -1277,17 +1259,17 @@ static UniValue ListReceived(const CWallet& wallet, const UniValue& params, bool if(!(mine & filter)) continue; - CAmount amt = wtx.GetOutputValueOut(index); + CAmount amt = wtx.GetOutputValueOut(wallet, index); if (amt < 0) { continue; } - if (strasset != "" && wtx.GetOutputAsset(index) != asset) { + if (strasset != "" && wtx.GetOutputAsset(wallet, index) != asset) { continue; } tallyitem& item = mapTally[address]; - item.mapAmount[wtx.GetOutputAsset(index)] += amt; + item.mapAmount[wtx.GetOutputAsset(wallet, index)] += amt; item.nConf = std::min(item.nConf, nDepth); item.txids.push_back(wtx.GetHash()); if (mine & ISMINE_WATCH_ONLY) @@ -1947,7 +1929,7 @@ static RPCHelpMan gettransaction() total_out += output.nValue.GetAmount(); } nFee = CAmountMap(); - nFee[::policyAsset] = wtx.IsFromMe(filter) ? total_out - nDebit[::policyAsset] : 0; + nFee[::policyAsset] = CachedTxIsFromMe(*pwallet, wtx, filter) ? total_out - nDebit[::policyAsset] : 0; } entry.pushKV("amount", AmountMapToUniv(nNet - nFee, asset)); @@ -3301,8 +3283,8 @@ static RPCHelpMan listunspent() continue; // Elements - CAmount amount = out.tx->GetOutputValueOut(out.i); - CAsset assetid = out.tx->GetOutputAsset(out.i); + CAmount amount = out.tx->GetOutputValueOut(*pwallet, out.i); + CAsset assetid = out.tx->GetOutputAsset(*pwallet, out.i); // Only list known outputs that match optional filter if (g_con_elementsmode && (amount < 0 || assetid.IsNull())) { pwallet->WalletLogPrintf("Unable to unblind output: %s:%d\n", out.tx->tx->GetHash().GetHex(), out.i); @@ -3369,8 +3351,8 @@ static RPCHelpMan listunspent() if (tx_out.nValue.IsCommitment()) { entry.pushKV("amountcommitment", HexStr(tx_out.nValue.vchCommitment)); } - entry.pushKV("amountblinder", out.tx->GetOutputAmountBlindingFactor(out.i).ToString()); - entry.pushKV("assetblinder", out.tx->GetOutputAssetBlindingFactor(out.i).ToString()); + entry.pushKV("amountblinder", out.tx->GetOutputAmountBlindingFactor(*pwallet, out.i).ToString()); + entry.pushKV("assetblinder", out.tx->GetOutputAssetBlindingFactor(*pwallet, out.i).ToString()); } entry.pushKV("confirmations", out.nDepth); entry.pushKV("spendable", out.fSpendable); @@ -5141,7 +5123,7 @@ static RPCHelpMan walletcreatefundedpsbt() LOCK(wallet.cs_wallet); for (; blinder_index < rawTx.vin.size(); ++blinder_index) { const CTxIn& txin = rawTx.vin[blinder_index]; - if (wallet.IsMine(txin) != ISMINE_NO) { + if (InputIsMine(wallet, txin) != ISMINE_NO) { break; } } @@ -6492,7 +6474,7 @@ static RPCHelpMan blindrawtransaction() } std::map::iterator it = pwallet->mapWallet.find(prevout.hash); - if (it == pwallet->mapWallet.end() || pwallet->IsMine(tx.vin[nIn]) == ISMINE_NO) { + if (it == pwallet->mapWallet.end() || InputIsMine(*pwallet, tx.vin[nIn]) == ISMINE_NO) { // For inputs we don't own, input assetcommitments for the surjection must be supplied. if (auxiliary_generators.size() > 0) { input_blinds.push_back(uint256()); @@ -6507,10 +6489,10 @@ static RPCHelpMan blindrawtransaction() if (prevout.n >= it->second.tx->vout.size()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter: transaction spends non-existing output"); } - input_blinds.push_back(it->second.GetOutputAmountBlindingFactor(prevout.n)); - input_asset_blinds.push_back(it->second.GetOutputAssetBlindingFactor(prevout.n)); - input_assets.push_back(it->second.GetOutputAsset(prevout.n)); - input_amounts.push_back(it->second.GetOutputValueOut(prevout.n)); + input_blinds.push_back(it->second.GetOutputAmountBlindingFactor(*pwallet, prevout.n)); + input_asset_blinds.push_back(it->second.GetOutputAssetBlindingFactor(*pwallet, prevout.n)); + input_assets.push_back(it->second.GetOutputAsset(*pwallet, prevout.n)); + input_amounts.push_back(it->second.GetOutputValueOut(*pwallet, prevout.n)); if (it->second.tx->vout[prevout.n].nValue.IsCommitment()) { n_blinded_ins += 1; } @@ -6621,7 +6603,7 @@ static RPCHelpMan unblindrawtransaction() static CTransactionRef SendGenerationTransaction(const CScript& asset_script, const CPubKey &asset_pubkey, const CScript& token_script, const CPubKey &token_pubkey, CAmount asset_amount, CAmount token_amount, IssuanceDetails* issuance_details, CWallet* pwallet) { CAsset reissue_token = issuance_details->reissuance_token; - CAmount curBalance = pwallet->GetBalance().m_mine_trusted[reissue_token]; + CAmount curBalance = GetBalance(*pwallet).m_mine_trusted[reissue_token]; if (!reissue_token.IsNull() && curBalance <= 0) { throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "No available reissuance tokens in wallet."); @@ -6654,7 +6636,7 @@ static CTransactionRef SendGenerationTransaction(const CScript& asset_script, co CCoinControl dummy_control; BlindDetails blind_details; CTransactionRef tx_ref; - if (!pwallet->CreateTransaction(vecSend, tx_ref, nFeeRequired, nChangePosRet, error, dummy_control, fee_calc_out, true, &blind_details, issuance_details)) { + if (!CreateTransaction(*pwallet, vecSend, tx_ref, nFeeRequired, nChangePosRet, error, dummy_control, fee_calc_out, true, &blind_details, issuance_details)) { throw JSONRPCError(RPC_WALLET_ERROR, error.original); } @@ -6922,9 +6904,9 @@ static RPCHelpMan listissuances() CalculateReissuanceToken(token, entropy, issuance.nAmount.IsCommitment()); item.pushKV("isreissuance", false); item.pushKV("token", token.GetHex()); - CAmount itamount = pcoin->GetIssuanceAmount(vinIndex, true); + CAmount itamount = pcoin->GetIssuanceAmount(*pwallet, vinIndex, true); item.pushKV("tokenamount", (itamount == -1 ) ? -1 : ValueFromAmount(itamount)); - item.pushKV("tokenblinds", pcoin->GetIssuanceBlindingFactor(vinIndex, true).GetHex()); + item.pushKV("tokenblinds", pcoin->GetIssuanceBlindingFactor(*pwallet, vinIndex, true).GetHex()); item.pushKV("entropy", entropy.GetHex()); } else { CalculateAsset(asset, issuance.assetEntropy); @@ -6938,9 +6920,9 @@ static RPCHelpMan listissuances() if (label != "") { item.pushKV("assetlabel", label); } - CAmount iaamount = pcoin->GetIssuanceAmount(vinIndex, false); + CAmount iaamount = pcoin->GetIssuanceAmount(*pwallet, vinIndex, false); item.pushKV("assetamount", (iaamount == -1 ) ? -1 : ValueFromAmount(iaamount)); - item.pushKV("assetblinds", pcoin->GetIssuanceBlindingFactor(vinIndex, false).GetHex()); + item.pushKV("assetblinds", pcoin->GetIssuanceBlindingFactor(*pwallet, vinIndex, false).GetHex()); if (!asset_filter.IsNull() && asset_filter != asset) { continue; } diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp index 87c6829efc..f1dddb5866 100644 --- a/src/wallet/spend.cpp +++ b/src/wallet/spend.cpp @@ -29,9 +29,9 @@ int GetTxSpendSize(const CWallet& wallet, const CWalletTx& wtx, unsigned int out return CalculateMaximumSignedInputSize(wtx.tx->vout[out], &wallet, use_max_sig); } -std::string COutput::ToString() const +std::string COutput::ToString(const CWallet& wallet) const { - return strprintf("COutput(%s, %d, %d) [%s] [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->GetOutputValueOut(i)), tx->GetOutputAsset(i).GetHex()); + return strprintf("COutput(%s, %d, %d) [%s] [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->GetOutputValueOut(wallet, i)), tx->GetOutputAsset(wallet, i).GetHex()); } // Helper for producing a max-sized low-S low-R signature (eg 71 bytes) @@ -121,7 +121,7 @@ TxSize CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *walle return TxSize{vsize, weight}; } -void AvailableCoins(const CWallet& wallet, std::vector &vCoins, const CCoinControl *coinControl, const CAmount &nMinimumAmount, const CAmount &nMaximumAmount, const CAmount &nMinimumSumAmount, const uint64_t nMaximumCount, const CAsset* asset_filter) const +void AvailableCoins(const CWallet& wallet, std::vector &vCoins, const CCoinControl *coinControl, const CAmount &nMinimumAmount, const CAmount &nMaximumAmount, const CAmount &nMinimumSumAmount, const uint64_t nMaximumCount, const CAsset* asset_filter) { AssertLockHeld(wallet.cs_wallet); @@ -203,8 +203,8 @@ void AvailableCoins(const CWallet& wallet, std::vector &vCoins, const C continue; } - CAmount outValue = wtx.GetOutputValueOut(i); - CAsset asset = wtx.GetOutputAsset(i); + CAmount outValue = wtx.GetOutputValueOut(wallet, i); + CAsset asset = wtx.GetOutputAsset(wallet, i); if (asset_filter && asset != *asset_filter) { continue; } @@ -263,11 +263,11 @@ CAmountMap GetAvailableBalance(const CWallet& wallet, const CCoinControl* coinCo AvailableCoins(wallet, vCoins, coinControl); for (const COutput& out : vCoins) { if (out.fSpendable) { - CAmount amt = out.tx->GetOutputValueOut(out.i); + CAmount amt = out.tx->GetOutputValueOut(wallet, out.i); if (amt < 0) { continue; } - balance[out.tx->GetOutputAsset(out.i)] += amt; + balance[out.tx->GetOutputAsset(wallet, out.i)] += amt; } } return balance; @@ -344,7 +344,7 @@ std::vector GroupOutputs(const CWallet& wallet, const std::vectorGetHash(), ancestors, descendants); - CInputCoin input_coin = output.GetInputCoin(); + CInputCoin input_coin = output.GetInputCoin(wallet); // Make an OutputGroup containing just this output OutputGroup group{coin_sel_params}; @@ -370,7 +370,7 @@ std::vector GroupOutputs(const CWallet& wallet, const std::vectorGetHash(), ancestors, descendants); - CInputCoin input_coin = output.GetInputCoin(); + CInputCoin input_coin = output.GetInputCoin(wallet); CScript spk = input_coin.txout.scriptPubKey; std::vector& groups = spk_to_groups_map[spk]; @@ -494,7 +494,7 @@ bool AttemptSelection(const CWallet& wallet, const CAmountMap& mapTargetValue, c bool SelectCoins(const CWallet& wallet, const std::vector& vAvailableCoins, const CAmountMap& mapTargetValue, std::set& setCoinsRet, CAmountMap& mapValueRet, const CCoinControl& coin_control, CoinSelectionParams& coin_selection_params, bilingual_str& error) { - AssertLockHeld(cs_wallet); // mapWallet + AssertLockHeld(wallet.cs_wallet); std::vector vCoins(vAvailableCoins); CAmountMap value_to_select = mapTargetValue; @@ -506,12 +506,12 @@ bool SelectCoins(const CWallet& wallet, const std::vector& vAvailableCo if (!out.fSpendable) continue; - CAmount amt = out.tx->GetOutputValueOut(out.i); + CAmount amt = out.tx->GetOutputValueOut(wallet, out.i); if (amt < 0) { continue; } - mapValueRet[out.tx->GetOutputAsset(out.i)] += amt; - setCoinsRet.insert(out.GetInputCoin()); + mapValueRet[out.tx->GetOutputAsset(wallet, out.i)] += amt; + setCoinsRet.insert(out.GetInputCoin(wallet)); } return (mapValueRet >= mapTargetValue); } @@ -539,11 +539,9 @@ bool SelectCoins(const CWallet& wallet, const std::vector& vAvailableCo if (GetTxSpendSize(wallet, wtx, outpoint.n, outpoint.n) < 0) { continue; } - input_bytes = wtx.GetSpendSize(outpoint.n, false); + input_bytes = GetTxSpendSize(wallet, wtx, outpoint.n, false); txout = wtx.tx->vout[outpoint.n]; - // ELEMENTS: must assign coin from wtx if we can, so the wallet - // can look up any confidential amounts/assets - coin = CInputCoin(&wtx, outpoint.n, input_bytes); + coin = CInputCoin(wallet, &wtx, outpoint.n, input_bytes); } if (input_bytes == -1) { // The input is external. We either did not find the tx in mapWallet, or we did but couldn't compute the input size with wallet data @@ -559,7 +557,7 @@ bool SelectCoins(const CWallet& wallet, const std::vector& vAvailableCo // after they called getpeginaddress). So try estimating size with // the wallet rather than the external provider. if (input_bytes == -1) { - input_bytes = CalculateMaximumSignedInputSize(txout, this, /* use_max_sig */ true); + input_bytes = CalculateMaximumSignedInputSize(txout, &wallet, /* use_max_sig */ true); } if (!txout.nValue.IsExplicit() || !txout.nAsset.IsExplicit()) { return false; // We can't get its value, so abort @@ -584,7 +582,7 @@ bool SelectCoins(const CWallet& wallet, const std::vector& vAvailableCo // remove preset inputs from vCoins so that Coin Selection doesn't pick them. for (std::vector::iterator it = vCoins.begin(); it != vCoins.end() && coin_control.HasSelected();) { - if (setPresetCoins.count(it->GetInputCoin())) + if (setPresetCoins.count(it->GetInputCoin(wallet))) it = vCoins.erase(it); else ++it; @@ -599,7 +597,7 @@ bool SelectCoins(const CWallet& wallet, const std::vector& vAvailableCo // ELEMENTS: filter coins for assets we are interested in; always keep policyAsset for fees for (std::vector::iterator it = vCoins.begin(); it != vCoins.end() && coin_control.HasSelected();) { - CAsset asset = it->GetInputCoin().asset; + CAsset asset = it->GetInputCoin(wallet).asset; if (asset != ::policyAsset && mapTargetValue.find(asset) == mapTargetValue.end()) { it = vCoins.erase(it); } else { @@ -642,7 +640,7 @@ bool SelectCoins(const CWallet& wallet, const std::vector& vAvailableCo // Fall back to using zero confirmation change (but with as few ancestors in the mempool as // possible) if we cannot fund the transaction otherwise. - if (m_spend_zero_conf_change) { + if (wallet.m_spend_zero_conf_change) { if (AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(0, 1, 2), vCoins, setCoinsRet, mapValueRet, coin_selection_params)) return true; if (AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(0, 1, std::min((size_t)4, max_ancestors/3), std::min((size_t)4, max_descendants/3)), vCoins, setCoinsRet, mapValueRet, coin_selection_params)) { @@ -898,7 +896,7 @@ static bool CreateTransactionInternal( // Pad change keys to cover total possible number of assets // One already exists(for policyAsset), so one for each destination if (assets_seen.insert(recipient.asset).second) { - reservedest.emplace_back(new ReserveDestination(this, change_type)); + reservedest.emplace_back(new ReserveDestination(&wallet, change_type)); } // Skip over issuance outputs, no need to select those coins @@ -972,10 +970,10 @@ static bool CreateTransactionInternal( coin_control.ListSelected(vPresetInputs); for (const COutPoint& presetInput : vPresetInputs) { CAsset asset; - std::map::const_iterator it = mapWallet.find(presetInput.hash); + std::map::const_iterator it = wallet.mapWallet.find(presetInput.hash); CTxOut txout; - if (it != mapWallet.end()) { - asset = it->second.GetOutputAsset(presetInput.n); + if (it != wallet.mapWallet.end()) { + asset = it->second.GetOutputAsset(wallet, presetInput.n); } else if (coin_control.GetExternalOutput(presetInput, txout)) { asset = txout.nAsset.GetAsset(); } else { @@ -1240,7 +1238,7 @@ static bool CreateTransactionInternal( } else { // Otherwise, we generated it from our own wallet, so get the // blinding key from our own wallet. - blind_pub = GetBlindingPubKey(itScript->second.second); + blind_pub = wallet.GetBlindingPubKey(itScript->second.second); } } else { assert(asset == policyAsset); @@ -1334,7 +1332,7 @@ static bool CreateTransactionInternal( txNew.vout[asset_index].nAsset = asset; if (issuance_details->blind_issuance && blind_details) { - issuance_asset_keys.push_back(GetBlindingKey(&blindingScript)); + issuance_asset_keys.push_back(wallet.GetBlindingKey(&blindingScript)); blind_details->num_to_blind++; } } @@ -1343,14 +1341,14 @@ static bool CreateTransactionInternal( txNew.vin[0].assetIssuance.nInflationKeys = txNew.vout[token_index].nValue; txNew.vout[token_index].nAsset = token; if (issuance_details->blind_issuance && blind_details) { - issuance_token_keys.push_back(GetBlindingKey(&blindingScript)); + issuance_token_keys.push_back(wallet.GetBlindingKey(&blindingScript)); blind_details->num_to_blind++; // If we're blinding a token issuance and no assets, we must make // the asset issuance a blinded commitment to 0 if (asset_index == -1) { txNew.vin[0].assetIssuance.nAmount = 0; - issuance_asset_keys.push_back(GetBlindingKey(&blindingScript)); + issuance_asset_keys.push_back(wallet.GetBlindingKey(&blindingScript)); blind_details->num_to_blind++; } } @@ -1373,7 +1371,7 @@ static bool CreateTransactionInternal( if (temp_token == issuance_details->reissuance_token && blind_details) { CScript blindingScript(CScript() << OP_RETURN << std::vector(txNew.vin[reissuance_index].prevout.hash.begin(), txNew.vin[reissuance_index].prevout.hash.end()) << txNew.vin[reissuance_index].prevout.n); issuance_asset_keys.resize(reissuance_index); - issuance_asset_keys.push_back(GetBlindingKey(&blindingScript)); + issuance_asset_keys.push_back(wallet.GetBlindingKey(&blindingScript)); blind_details->num_to_blind++; } } @@ -1383,7 +1381,7 @@ static bool CreateTransactionInternal( TxSize tx_sizes; CMutableTransaction tx_blinded = txNew; if (blind_details) { - if (!fillBlindDetails(blind_details, this, tx_blinded, selected_coins, error)) { + if (!fillBlindDetails(blind_details, &wallet, tx_blinded, selected_coins, error)) { return false; } txNew = tx_blinded; // sigh, `fillBlindDetails` may have modified txNew @@ -1395,9 +1393,9 @@ static bool CreateTransactionInternal( return false; } - tx_sizes = CalculateMaximumSignedTxSize(CTransaction(tx_blinded), this, &coin_control); + tx_sizes = CalculateMaximumSignedTxSize(CTransaction(tx_blinded), &wallet, &coin_control); } else { - tx_sizes = CalculateMaximumSignedTxSize(CTransaction(txNew), this, &coin_control); + tx_sizes = CalculateMaximumSignedTxSize(CTransaction(txNew), &wallet, &coin_control); } // end ELEMENTS @@ -1458,7 +1456,7 @@ static bool CreateTransactionInternal( // by a complete rewriting of the wallet blinding logic. if (blind_details->num_to_blind < 2) { resetBlindDetails(blind_details, true /* don't wipe output data */); - if (!fillBlindDetails(blind_details, this, txNew, selected_coins, error)) { + if (!fillBlindDetails(blind_details, &wallet, txNew, selected_coins, error)) { return false; } } @@ -1577,7 +1575,7 @@ static bool CreateTransactionInternal( blind_details->o_pubkeys[i].IsValid() ? "blinded" : "explicit" ); } - WalletLogPrintf(summary+"\n"); + wallet.WalletLogPrintf(summary+"\n"); // Wipe output blinding factors and start over blind_details->o_amount_blinds.clear(); @@ -1591,7 +1589,7 @@ static bool CreateTransactionInternal( int ret = BlindTransaction(blind_details->i_amount_blinds, blind_details->i_asset_blinds, blind_details->i_assets, blind_details->i_amounts, blind_details->o_amount_blinds, blind_details->o_asset_blinds, blind_details->o_pubkeys, issuance_asset_keys, issuance_token_keys, txNew); assert(ret != -1); if (ret != blind_details->num_to_blind) { - WalletLogPrintf("ERROR: tried to blind %d outputs but only blinded %d\n", (int) blind_details->num_to_blind, (int) ret); + wallet.WalletLogPrintf("ERROR: tried to blind %d outputs but only blinded %d\n", (int) blind_details->num_to_blind, (int) ret); error = _("Unable to blind the transaction properly. This should not happen."); return false; } diff --git a/src/wallet/spend.h b/src/wallet/spend.h index 465f716077..058a776db4 100644 --- a/src/wallet/spend.h +++ b/src/wallet/spend.h @@ -5,10 +5,13 @@ #ifndef BITCOIN_WALLET_SPEND_H #define BITCOIN_WALLET_SPEND_H +#include #include #include #include +class CRecipient; + /** Get the marginal bytes if spending the specified output from this transaction */ int GetTxSpendSize(const CWallet& wallet, const CWalletTx& wtx, unsigned int out, bool use_max_sig = false); @@ -56,11 +59,11 @@ class COutput } } - std::string ToString() const; + std::string ToString(const CWallet& wallet) const; - inline CInputCoin GetInputCoin() const + inline CInputCoin GetInputCoin(const CWallet& wallet) const { - return CInputCoin(tx, i, nInputBytes); + return CInputCoin(wallet, tx, i, nInputBytes); } }; @@ -152,7 +155,7 @@ std::vector GroupOutputs(const CWallet& wallet, const std::vector coins, +bool AttemptSelection(const CWallet& wallet, const CAmountMap& mapTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector coins, std::set& setCoinsRet, CAmountMap& mapValueRet, const CoinSelectionParams& coin_selection_params); /** diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp index e111882baf..57c1f7a700 100644 --- a/src/wallet/test/coinselector_tests.cpp +++ b/src/wallet/test/coinselector_tests.cpp @@ -48,7 +48,7 @@ static bool SimpleAttemptSelection(const CWallet& wallet, const CAmount& nTarget CAmountMap mapTargetValue; mapTargetValue[CAsset()] = nTargetValue; CAmountMap mapValueRet; - bool ret = wallet.AttemptSelection(mapTargetValue, eligibility_filter, coins, setCoinsRet, mapValueRet, coin_selection_params); + bool ret = AttemptSelection(wallet, mapTargetValue, eligibility_filter, coins, setCoinsRet, mapValueRet, coin_selection_params); nValueRet = mapValueRet[CAsset()]; return ret; } @@ -58,8 +58,8 @@ static void add_coin(const CAmount& nValue, int nInput, std::vector& CMutableTransaction tx; tx.vout.resize(nInput + 1); tx.vout[nInput].nValue = nValue; - CWalletTx wtx(&testWallet, MakeTransactionRef(tx)); - set.emplace_back(&wtx, nInput); + CWalletTx wtx(MakeTransactionRef(tx)); + set.emplace_back(testWallet, &wtx, nInput); } static void add_coin(const CAmount& nValue, int nInput, CoinSet& set, CAmount fee = 0, CAmount long_term_fee = 0) @@ -67,8 +67,8 @@ static void add_coin(const CAmount& nValue, int nInput, CoinSet& set, CAmount fe CMutableTransaction tx; tx.vout.resize(nInput + 1); tx.vout[nInput].nValue = nValue; - CWalletTx wtx(&testWallet, MakeTransactionRef(tx)); - CInputCoin coin(&wtx, nInput); + CWalletTx wtx(MakeTransactionRef(tx)); + CInputCoin coin(testWallet, &wtx, nInput); coin.effective_value = nValue - fee; coin.m_fee = fee; coin.m_long_term_fee = long_term_fee; @@ -152,7 +152,7 @@ inline std::vector& GroupCoins(const std::vector& coins) static_groups.clear(); for (auto& coin : coins) { static_groups.emplace_back(); - static_groups.back().Insert(coin.GetInputCoin(), coin.nDepth, coin.tx->m_amounts[CWalletTx::DEBIT].m_cached[ISMINE_SPENDABLE] && coin.tx->m_amounts[CWalletTx::DEBIT].m_value[ISMINE_SPENDABLE][CAsset()] == 1 /* HACK: we can't figure out the is_me flag so we use the conditions defined above; perhaps set safe to false for !fIsFromMe in add_coin() */, 0, 0, false); + static_groups.back().Insert(coin.GetInputCoin(testWallet), coin.nDepth, coin.tx->m_amounts[CWalletTx::DEBIT].m_cached[ISMINE_SPENDABLE] && coin.tx->m_amounts[CWalletTx::DEBIT].m_value[ISMINE_SPENDABLE][CAsset()] == 1 /* HACK: we can't figure out the is_me flag so we use the conditions defined above; perhaps set safe to false for !fIsFromMe in add_coin() */, 0, 0, false); } return static_groups; } diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 8b8aefd200..3d23868d5f 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -28,6 +28,7 @@ #include #include +#include RPCHelpMan importmulti(); RPCHelpMan dumpwallet(); @@ -109,7 +110,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) BOOST_CHECK(result.last_failed_block.IsNull()); BOOST_CHECK(result.last_scanned_block.IsNull()); BOOST_CHECK(!result.last_scanned_height); - BOOST_CHECK_EQUAL(GetBalance(wallet).m_mine_immature[CAsset()], 0); + BOOST_CHECK_EQUAL(GetBalance(wallet).m_mine_immature[::policyAsset], 0); } // Verify ScanForWalletTransactions picks up transactions in both the old @@ -128,7 +129,12 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) BOOST_CHECK(result.last_failed_block.IsNull()); BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash()); BOOST_CHECK_EQUAL(*result.last_scanned_height, newTip->nHeight); - BOOST_CHECK_EQUAL(GetBalance(wallet).m_mine_immature[CAsset()], 100 * COIN); + auto balance = GetBalance(wallet); + for (auto& pair : balance.m_mine_immature) { + std::cout << "key: " << pair.first.GetHex() << std::endl; + std::cout << "value: " << pair.second << std::endl; + } + BOOST_CHECK_EQUAL(GetBalance(wallet).m_mine_immature[::policyAsset], 100 * COIN); } // Prune the older block file. @@ -154,13 +160,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) BOOST_CHECK_EQUAL(result.last_failed_block, oldTip->GetBlockHash()); BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash()); BOOST_CHECK_EQUAL(*result.last_scanned_height, newTip->nHeight); -<<<<<<< HEAD - BOOST_CHECK_EQUAL(wallet.GetBalance().m_mine_immature[CAsset()], 50 * COIN); -||||||| dd097c42df - BOOST_CHECK_EQUAL(wallet.GetBalance().m_mine_immature, 50 * COIN); -======= - BOOST_CHECK_EQUAL(GetBalance(wallet).m_mine_immature, 50 * COIN); ->>>>>>> 629c4ab2e3 + BOOST_CHECK_EQUAL(GetBalance(wallet).m_mine_immature[CAsset()], 50 * COIN); } // Prune the remaining block file. @@ -185,13 +185,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) BOOST_CHECK_EQUAL(result.last_failed_block, newTip->GetBlockHash()); BOOST_CHECK(result.last_scanned_block.IsNull()); BOOST_CHECK(!result.last_scanned_height); -<<<<<<< HEAD - BOOST_CHECK_EQUAL(wallet.GetBalance().m_mine_immature[CAsset()], 0); -||||||| dd097c42df - BOOST_CHECK_EQUAL(wallet.GetBalance().m_mine_immature, 0); -======= - BOOST_CHECK_EQUAL(GetBalance(wallet).m_mine_immature, 0); ->>>>>>> 629c4ab2e3 + BOOST_CHECK_EQUAL(GetBalance(wallet).m_mine_immature[CAsset()], 0); } } @@ -335,6 +329,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) // debit functions. BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup) { + std::cout << "dirty immature credit test" << std::endl; CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase()); auto spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan(); CWalletTx wtx(m_coinbase_txns.back()); @@ -347,25 +342,22 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup) // Call GetImmatureCredit() once before adding the key to the wallet to // cache the current immature credit amount, which is 0. -<<<<<<< HEAD - BOOST_CHECK_EQUAL(wtx.GetImmatureCredit()[CAsset()], 0); -||||||| dd097c42df - BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(), 0); -======= - BOOST_CHECK_EQUAL(CachedTxGetImmatureCredit(wallet, wtx), 0); ->>>>>>> 629c4ab2e3 - + std::cout << "BEFORE" << std::endl; + BOOST_CHECK_EQUAL(CachedTxGetImmatureCredit(wallet, wtx)[::policyAsset], 0); + std::cout << "AFTER" << std::endl; // Invalidate the cached value, add the key, and make sure a new immature // credit amount is calculated. - wtx.MarkDirty(); + wtx.MarkDirty(wallet); BOOST_CHECK(spk_man->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey())); -<<<<<<< HEAD - BOOST_CHECK_EQUAL(wtx.GetImmatureCredit()[CAsset()], 50*COIN); -||||||| dd097c42df - BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(), 50*COIN); -======= - BOOST_CHECK_EQUAL(CachedTxGetImmatureCredit(wallet, wtx), 50*COIN); ->>>>>>> 629c4ab2e3 + auto temp = CachedTxGetImmatureCredit(wallet, wtx); + std::cout << "size: " << temp.size() << std::endl; + for (auto& pair : temp) { + std::cout << "key: " << pair.first.GetHex() << std::endl; + std::cout << "value: " << pair.second << std::endl; + } + std::cout << "policy assset = " << ::policyAsset.GetHex() << std::endl; + std::cout << "50 * COIN = " << 50*COIN << std::endl; + BOOST_CHECK_EQUAL(CachedTxGetImmatureCredit(wallet, wtx)[::policyAsset], 50*COIN); } static int64_t AddTx(ChainstateManager& chainman, CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64_t blockTime) @@ -574,13 +566,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoinsTest, ListCoinsTestingSetup) BOOST_CHECK_EQUAL(list.begin()->second.size(), 1U); // Check initial balance from one mature coinbase transaction. -<<<<<<< HEAD - BOOST_CHECK_EQUAL(50 * COIN, wallet->GetAvailableBalance()[CAsset()]); -||||||| dd097c42df - BOOST_CHECK_EQUAL(50 * COIN, wallet->GetAvailableBalance()); -======= - BOOST_CHECK_EQUAL(50 * COIN, GetAvailableBalance(*wallet)); ->>>>>>> 629c4ab2e3 + BOOST_CHECK_EQUAL(50 * COIN, GetAvailableBalance(*wallet)[CAsset()]); // Add a transaction creating a change address, and confirm ListCoins still // returns the coin associated with the change address underneath the diff --git a/src/wallet/transaction.h b/src/wallet/transaction.h index f01ff5565c..885354dc96 100644 --- a/src/wallet/transaction.h +++ b/src/wallet/transaction.h @@ -247,7 +247,7 @@ class CWalletTx } //! make sure balances are recalculated - void MarkDirty() + void MarkDirty(const CWallet& wallet) { m_amounts[DEBIT].Reset(); m_amounts[CREDIT].Reset(); @@ -255,7 +255,7 @@ class CWalletTx m_amounts[AVAILABLE_CREDIT].Reset(); fChangeCached = false; m_is_cache_empty = true; - WipeUnknownBlindingData(); + WipeUnknownBlindingData(wallet); } /** True if only scriptSigs are different */ @@ -265,12 +265,24 @@ class CWalletTx int64_t GetTxTime() const; -<<<<<<< HEAD - /** Pass this transaction to node for mempool insertion and relay to peers if flag set to true */ - bool SubmitMemoryPoolAndRelay(std::string& err_string, bool relay); - - // ELEMENTS: + bool isAbandoned() const { return m_confirm.status == CWalletTx::ABANDONED; } + void setAbandoned() + { + m_confirm.status = CWalletTx::ABANDONED; + m_confirm.hashBlock = uint256(); + m_confirm.block_height = 0; + m_confirm.nIndex = 0; + } + bool isConflicted() const { return m_confirm.status == CWalletTx::CONFLICTED; } + void setConflicted() { m_confirm.status = CWalletTx::CONFLICTED; } + bool isUnconfirmed() const { return m_confirm.status == CWalletTx::UNCONFIRMED; } + void setUnconfirmed() { m_confirm.status = CWalletTx::UNCONFIRMED; } + bool isConfirmed() const { return m_confirm.status == CWalletTx::CONFIRMED; } + void setConfirmed() { m_confirm.status = CWalletTx::CONFIRMED; } + const uint256& GetHash() const { return tx->GetHash(); } + bool IsCoinBase() const { return tx->IsCoinBase(); } + // ELEMENTS private: /* Computes, stores and returns the unblinded info, or retrieves if already computed previously. * @param[in] map_index - Where to store the blinding data. Issuance data is stored after the output data, with additional index offset calculated via GetPseudoInputOffset @@ -285,8 +297,8 @@ class CWalletTx * @param[out] asset_out - Pointer to the recovered underlying asset type * @param[out] asset_factor_out - Pointer to the recovered asset blinding factor of the output */ - void GetBlindingData(const unsigned int map_index, const std::vector& vchRangeproof, const CConfidentialValue& conf_value, const CConfidentialAsset& conf_asset, const CConfidentialNonce nonce, const CScript& scriptPubKey, CPubKey* blinding_pubkey_out, CAmount* value_out, uint256* value_factor_out, CAsset* asset_out, uint256* asset_factor_out) const; - void WipeUnknownBlindingData(); + void GetBlindingData(const CWallet& wallet, const unsigned int map_index, const std::vector& vchRangeproof, const CConfidentialValue& conf_value, const CConfidentialAsset& conf_asset, const CConfidentialNonce nonce, const CScript& scriptPubKey, CPubKey* blinding_pubkey_out, CAmount* value_out, uint256* value_factor_out, CAsset* asset_out, uint256* asset_factor_out) const; + void WipeUnknownBlindingData(const CWallet& wallet); public: // For use in wallet transaction creation to remember 3rd party values @@ -294,110 +306,32 @@ class CWalletTx void SetBlindingData(const unsigned int output_index, const CPubKey& blinding_pubkey, const CAmount value, const uint256& value_factor, const CAsset& asset, const uint256& asset_factor); // Convenience method to retrieve all blinding data at once, for an ordinary non-issuance tx - void GetNonIssuanceBlindingData(const unsigned int output_index, CPubKey* blinding_pubkey_out, CAmount* value_out, uint256* value_factor_out, CAsset* asset_out, uint256* asset_factor_out) const; - - //! Returns either the value out (if it is known) or -1 - CAmount GetOutputValueOut(unsigned int ouput_index) const; + void GetNonIssuanceBlindingData(const CWallet& wallet, const unsigned int output_index, CPubKey* blinding_pubkey_out, CAmount* value_out, uint256* value_factor_out, CAsset* asset_out, uint256* asset_factor_out) const; //! Returns either the blinding factor (if it is to us) or 0 - uint256 GetOutputAmountBlindingFactor(unsigned int output_index) const; - uint256 GetOutputAssetBlindingFactor(unsigned int output_index) const; - //! Returns the underlying asset type, or 0 if unknown - CAsset GetOutputAsset(unsigned int output_index) const; + uint256 GetOutputAmountBlindingFactor(const CWallet& wallet, unsigned int output_index) const; + uint256 GetOutputAssetBlindingFactor(const CWallet& wallet, unsigned int output_index) const; //! Get the issuance CAssets for both the asset itself and the issuing tokens void GetIssuanceAssets(unsigned int vinIndex, CAsset* out_asset, CAsset* out_reissuance_token) const; // ! Return map of issued assets at input_index - CAmountMap GetIssuanceAssets(unsigned int input_index) const; + CAmountMap GetIssuanceAssets(const CWallet& wallet, unsigned int input_index) const; // ! Returns receiver's blinding pubkey - CPubKey GetOutputBlindingPubKey(unsigned int output_index) const; + CPubKey GetOutputBlindingPubKey(const CWallet& wallet, unsigned int output_index) const; //! Get the issuance blinder for either the asset itself or the issuing tokens - uint256 GetIssuanceBlindingFactor(unsigned int input_index, bool reissuance_token) const; + uint256 GetIssuanceBlindingFactor(const CWallet& wallet, unsigned int input_index, bool reissuance_token) const; //! Get the issuance amount for either the asset itself or the issuing tokens - CAmount GetIssuanceAmount(unsigned int input_index, bool reissuance_token) const; + CAmount GetIssuanceAmount(const CWallet& wallet, unsigned int input_index, bool reissuance_token) const; //! Get the mapValue offset for a specific vin index and type of issuance pseudo-input unsigned int GetPseudoInputOffset(unsigned int input_index, bool reissuance_token) const; + // END ELEMENTS - // TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct - // annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation - // "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid having to - // resolve the issue of member access into incomplete type CWallet. Note - // that we still have the runtime check "AssertLockHeld(pwallet->cs_wallet)" - // in place. - std::set GetConflicts() const NO_THREAD_SAFETY_ANALYSIS; - - /** - * Return depth of transaction in blockchain: - * <0 : conflicts with a transaction this deep in the blockchain - * 0 : in memory pool, waiting to be included in a block - * >=1 : this many blocks deep in the main chain - */ - // TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct - // annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation - // "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid having to - // resolve the issue of member access into incomplete type CWallet. Note - // that we still have the runtime check "AssertLockHeld(pwallet->cs_wallet)" - // in place. - int GetDepthInMainChain() const NO_THREAD_SAFETY_ANALYSIS; - bool IsInMainChain() const { return GetDepthInMainChain() > 0; } - - /** - * @return number of blocks to maturity for this transaction: - * 0 : is not a coinbase transaction, or is a mature coinbase transaction - * >0 : is a coinbase transaction which matures in this many blocks - */ - int GetBlocksToMaturity() const; -||||||| dd097c42df - /** Pass this transaction to node for mempool insertion and relay to peers if flag set to true */ - bool SubmitMemoryPoolAndRelay(std::string& err_string, bool relay); - - // TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct - // annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation - // "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid having to - // resolve the issue of member access into incomplete type CWallet. Note - // that we still have the runtime check "AssertLockHeld(pwallet->cs_wallet)" - // in place. - std::set GetConflicts() const NO_THREAD_SAFETY_ANALYSIS; - - /** - * Return depth of transaction in blockchain: - * <0 : conflicts with a transaction this deep in the blockchain - * 0 : in memory pool, waiting to be included in a block - * >=1 : this many blocks deep in the main chain - */ - // TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct - // annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation - // "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid having to - // resolve the issue of member access into incomplete type CWallet. Note - // that we still have the runtime check "AssertLockHeld(pwallet->cs_wallet)" - // in place. - int GetDepthInMainChain() const NO_THREAD_SAFETY_ANALYSIS; - bool IsInMainChain() const { return GetDepthInMainChain() > 0; } + //! Returns either the value out (if it is known) or -1 + CAmount GetOutputValueOut(const CWallet& wallet, unsigned int ouput_index) const; + //! Returns the underlying asset type, or 0 if unknown + CAsset GetOutputAsset(const CWallet& wallet, unsigned int output_index) const; - /** - * @return number of blocks to maturity for this transaction: - * 0 : is not a coinbase transaction, or is a mature coinbase transaction - * >0 : is a coinbase transaction which matures in this many blocks - */ - int GetBlocksToMaturity() const; -======= ->>>>>>> 629c4ab2e3 - bool isAbandoned() const { return m_confirm.status == CWalletTx::ABANDONED; } - void setAbandoned() - { - m_confirm.status = CWalletTx::ABANDONED; - m_confirm.hashBlock = uint256(); - m_confirm.block_height = 0; - m_confirm.nIndex = 0; - } - bool isConflicted() const { return m_confirm.status == CWalletTx::CONFLICTED; } - void setConflicted() { m_confirm.status = CWalletTx::CONFLICTED; } - bool isUnconfirmed() const { return m_confirm.status == CWalletTx::UNCONFIRMED; } - void setUnconfirmed() { m_confirm.status = CWalletTx::UNCONFIRMED; } - bool isConfirmed() const { return m_confirm.status == CWalletTx::CONFIRMED; } - void setConfirmed() { m_confirm.status = CWalletTx::CONFIRMED; } - const uint256& GetHash() const { return tx->GetHash(); } - bool IsCoinBase() const { return tx->IsCoinBase(); } + // END ELEMENTS // Disable copying of CWalletTx objects to prevent bugs where instances get // copied in and out of the mapWallet map, and fields are updated in the diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 62ce286962..d84c776ab2 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include @@ -798,7 +799,7 @@ void CWallet::MarkDirty() { LOCK(cs_wallet); for (std::pair& item : mapWallet) - item.second.MarkDirty(); + item.second.MarkDirty(*this); } } @@ -955,7 +956,7 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmatio return nullptr; // Break debit/credit balance caches: - wtx.MarkDirty(); + wtx.MarkDirty(*this); // Notify UI of new or updated transaction NotifyTransactionChanged(hash, fInsertedNew ? CT_NEW : CT_UPDATED); @@ -1091,7 +1092,7 @@ void CWallet::MarkInputsDirty(const CTransactionRef& tx) for (const CTxIn& txin : tx->vin) { auto it = mapWallet.find(txin.prevout.hash); if (it != mapWallet.end()) { - it->second.MarkDirty(); + it->second.MarkDirty(*this); } } } @@ -1130,7 +1131,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx) // If the orig tx was not in block/mempool, none of its spends can be in mempool assert(!wtx.InMempool()); wtx.setAbandoned(); - wtx.MarkDirty(); + wtx.MarkDirty(*this); batch.WriteTx(wtx); NotifyTransactionChanged(wtx.GetHash(), CT_UPDATED); // Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too @@ -1185,7 +1186,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, c wtx.m_confirm.hashBlock = hashBlock; wtx.m_confirm.block_height = conflicting_height; wtx.setConflicted(); - wtx.MarkDirty(); + wtx.MarkDirty(*this); batch.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)); @@ -1317,7 +1318,7 @@ CAmountMap CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) cons if (txin.prevout.n < prev.tx->vout.size()) if (IsMine(prev.tx->vout[txin.prevout.n]) & filter) { CAmountMap amounts; - amounts[prev.GetOutputAsset(txin.prevout.n)] = std::max(0, prev.GetOutputValueOut(txin.prevout.n)); + amounts[prev.GetOutputAsset(*this, txin.prevout.n)] = std::max(0, prev.GetOutputValueOut(*this, txin.prevout.n)); return amounts; } } @@ -1848,13 +1849,13 @@ TransactionError CWallet::FillPSBTData(PartiallySignedTransaction& psbtx, bool b } const CTxOut& utxo = wtx.tx->vout[*input.prev_out]; if (include_explicit && utxo.nAsset.IsCommitment()) { - const CAsset asset = wtx.GetOutputAsset(*input.prev_out); + const CAsset asset = wtx.GetOutputAsset(*this, *input.prev_out); input.m_explicit_asset = asset.id; - CreateBlindAssetProof(input.m_asset_proof, asset, utxo.nAsset, wtx.GetOutputAssetBlindingFactor(*input.prev_out)); + CreateBlindAssetProof(input.m_asset_proof, asset, utxo.nAsset, wtx.GetOutputAssetBlindingFactor(*this, *input.prev_out)); if (utxo.nValue.IsCommitment()) { - input.m_explicit_value = wtx.GetOutputValueOut(*input.prev_out); - CreateBlindValueProof(input.m_value_proof, wtx.GetOutputAmountBlindingFactor(*input.prev_out), *input.m_explicit_value, utxo.nValue, utxo.nAsset); + input.m_explicit_value = wtx.GetOutputValueOut(*this, *input.prev_out); + CreateBlindValueProof(input.m_value_proof, wtx.GetOutputAmountBlindingFactor(*this, *input.prev_out), *input.m_explicit_value, utxo.nValue, utxo.nAsset); } } } @@ -1922,10 +1923,10 @@ BlindingStatus CWallet::WalletBlindPSBT(PartiallySignedTransaction& psbtx) const PSBTInput& input = psbtx.inputs[i]; if (input.m_peg_in_value && !input.m_peg_in_claim_script.empty()) { - if (!IsMine(CTxOut(Params().GetConsensus().pegged_asset, *input.m_peg_in_value, input.m_peg_in_claim_script))) continue; + if (!this->IsMine(CTxOut(Params().GetConsensus().pegged_asset, *input.m_peg_in_value, input.m_peg_in_claim_script))) continue; our_input_data[i] = std::make_tuple(*input.m_peg_in_value, Params().GetConsensus().pegged_asset, uint256(), uint256()); } else { - if (!IsMine(COutPoint(input.prev_txid, *input.prev_out))) continue; + if (!InputIsMine(*this, COutPoint(input.prev_txid, *input.prev_out))) continue; const CWalletTx* wtx = GetWalletTx(input.prev_txid); if (!wtx) continue; CPubKey blinding_pubkey; @@ -1933,7 +1934,7 @@ BlindingStatus CWallet::WalletBlindPSBT(PartiallySignedTransaction& psbtx) const uint256 value_blinder; CAsset asset; uint256 asset_blinder; - wtx->GetNonIssuanceBlindingData(*input.prev_out, &blinding_pubkey, &amount, &value_blinder, &asset, &asset_blinder); + wtx->GetNonIssuanceBlindingData(*this, *input.prev_out, &blinding_pubkey, &amount, &value_blinder, &asset, &asset_blinder); our_input_data[i] = std::make_tuple(amount, asset, asset_blinder, value_blinder); } @@ -2220,7 +2221,7 @@ void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve continue; CWalletTx &coin = mapWallet.at(txin.prevout.hash); - coin.MarkDirty(); + coin.MarkDirty(*this); NotifyTransactionChanged(coin.GetHash(), CT_UPDATED); } @@ -2459,7 +2460,7 @@ void CWallet::MarkDestinationsDirty(const std::set& destinations for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) { CTxDestination dst; if (ExtractDestination(wtx.tx->vout[i].scriptPubKey, dst) && destinations.count(dst)) { - wtx.MarkDirty(); + wtx.MarkDirty(*this); break; } } @@ -3466,7 +3467,7 @@ void CWalletTx::SetBlindingData(const unsigned int map_index, const CPubKey& bli } -void CWalletTx::GetBlindingData(const unsigned int map_index, const std::vector& vchRangeproof, const CConfidentialValue& conf_value, const CConfidentialAsset& conf_asset, const CConfidentialNonce nonce, const CScript& scriptPubKey, CPubKey* blinding_pubkey_out, CAmount* value_out, uint256* value_factor_out, CAsset* asset_out, uint256* asset_factor_out) const +void CWalletTx::GetBlindingData(const CWallet& wallet, const unsigned int map_index, const std::vector& vchRangeproof, const CConfidentialValue& conf_value, const CConfidentialAsset& conf_asset, const CConfidentialNonce nonce, const CScript& scriptPubKey, CPubKey* blinding_pubkey_out, CAmount* value_out, uint256* value_factor_out, CAsset* asset_out, uint256* asset_factor_out) const { // Blinding data is cached in a serialized record mapWallet["blindingdata"]. // It contains a concatenation byte vectors, 74 bytes per txout or pseudo-input. @@ -3502,7 +3503,7 @@ void CWalletTx::GetBlindingData(const unsigned int map_index, const std::vector< assert(conf_value.GetAmount() == amount); } } else { - pwallet->ComputeBlindingData(conf_value, conf_asset, nonce, scriptPubKey, vchRangeproof, amount, pubkey, value_factor, asset_tag, asset_factor); + wallet.ComputeBlindingData(conf_value, conf_asset, nonce, scriptPubKey, vchRangeproof, amount, pubkey, value_factor, asset_tag, asset_factor); *it = 1; memcpy(&*(it + 1), &amount, 8); memcpy(&*(it + 9), value_factor.begin(), 32); @@ -3522,11 +3523,11 @@ void CWalletTx::GetBlindingData(const unsigned int map_index, const std::vector< if (asset_out) *asset_out = asset_tag; } -void CWalletTx::GetNonIssuanceBlindingData(const unsigned int output_index, CPubKey* blinding_pubkey_out, CAmount* value_out, uint256* value_factor_out, CAsset* asset_out, uint256* asset_factor_out) const { +void CWalletTx::GetNonIssuanceBlindingData(const CWallet& wallet, const unsigned int output_index, CPubKey* blinding_pubkey_out, CAmount* value_out, uint256* value_factor_out, CAsset* asset_out, uint256* asset_factor_out) const { assert(output_index < tx->vout.size()); const CTxOut& out = tx->vout[output_index]; const CTxWitness& wit = tx->witness; - GetBlindingData(output_index, wit.vtxoutwit.size() <= output_index ? std::vector() : wit.vtxoutwit[output_index].vchRangeproof, out.nValue, out.nAsset, out.nNonce, out.scriptPubKey, + GetBlindingData(wallet, output_index, wit.vtxoutwit.size() <= output_index ? std::vector() : wit.vtxoutwit[output_index].vchRangeproof, out.nValue, out.nAsset, out.nNonce, out.scriptPubKey, blinding_pubkey_out, value_out, value_factor_out, asset_out, asset_factor_out); } @@ -3736,33 +3737,33 @@ ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const Flat return spk_man; } -CAmount CWalletTx::GetOutputValueOut(unsigned int output_index) const { +CAmount CWalletTx::GetOutputValueOut(const CWallet& wallet, unsigned int output_index) const { CAmount ret; - GetNonIssuanceBlindingData(output_index, nullptr, &ret, nullptr, nullptr, nullptr); + GetNonIssuanceBlindingData(wallet, output_index, nullptr, &ret, nullptr, nullptr, nullptr); return ret; } -uint256 CWalletTx::GetOutputAmountBlindingFactor(unsigned int output_index) const { +uint256 CWalletTx::GetOutputAmountBlindingFactor(const CWallet& wallet, unsigned int output_index) const { uint256 ret; - GetNonIssuanceBlindingData(output_index, nullptr, nullptr, &ret, nullptr, nullptr); + GetNonIssuanceBlindingData(wallet, output_index, nullptr, nullptr, &ret, nullptr, nullptr); return ret; } -uint256 CWalletTx::GetOutputAssetBlindingFactor(unsigned int output_index) const { +uint256 CWalletTx::GetOutputAssetBlindingFactor(const CWallet& wallet, unsigned int output_index) const { uint256 ret; - GetNonIssuanceBlindingData(output_index, nullptr, nullptr, nullptr, nullptr, &ret); + GetNonIssuanceBlindingData(wallet, output_index, nullptr, nullptr, nullptr, nullptr, &ret); return ret; } -CAsset CWalletTx::GetOutputAsset(unsigned int output_index) const { +CAsset CWalletTx::GetOutputAsset(const CWallet& wallet, unsigned int output_index) const { CAsset ret; - GetNonIssuanceBlindingData(output_index, nullptr, nullptr, nullptr, &ret, nullptr); + GetNonIssuanceBlindingData(wallet, output_index, nullptr, nullptr, nullptr, &ret, nullptr); return ret; } -CPubKey CWalletTx::GetOutputBlindingPubKey(unsigned int output_index) const { +CPubKey CWalletTx::GetOutputBlindingPubKey(const CWallet& wallet, unsigned int output_index) const { CPubKey ret; - GetNonIssuanceBlindingData(output_index, &ret, nullptr, nullptr, nullptr, nullptr); + GetNonIssuanceBlindingData(wallet, output_index, &ret, nullptr, nullptr, nullptr, nullptr); return ret; } @@ -3801,7 +3802,7 @@ void CWalletTx::GetIssuanceAssets(unsigned int input_index, CAsset* out_asset, C } } -uint256 CWalletTx::GetIssuanceBlindingFactor(unsigned int input_index, bool reissuance_token) const { +uint256 CWalletTx::GetIssuanceBlindingFactor(const CWallet& wallet, unsigned int input_index, bool reissuance_token) const { assert(input_index < tx->vin.size()); CAsset asset; const CAssetIssuance& issuance = tx->vin[input_index].assetIssuance; @@ -3811,15 +3812,15 @@ uint256 CWalletTx::GetIssuanceBlindingFactor(unsigned int input_index, bool reis return uint256(); } const std::vector& rangeproof = wit.vtxinwit.size() <= input_index ? std::vector() : (reissuance_token ? wit.vtxinwit[input_index].vchInflationKeysRangeproof : wit.vtxinwit[input_index].vchIssuanceAmountRangeproof); - unsigned int mapValueInd = GetPseudoInputOffset(input_index, reissuance_token)+tx->vout.size(); + unsigned int mapValueInd = GetPseudoInputOffset(input_index, reissuance_token) + tx->vout.size(); uint256 ret; CScript blindingScript(CScript() << OP_RETURN << std::vector(tx->vin[input_index].prevout.hash.begin(), tx->vin[input_index].prevout.hash.end()) << tx->vin[input_index].prevout.n); - GetBlindingData(mapValueInd, rangeproof, reissuance_token ? issuance.nInflationKeys : issuance.nAmount, CConfidentialAsset(asset), CConfidentialNonce(), blindingScript, nullptr, nullptr, &ret, nullptr, nullptr); + GetBlindingData(wallet, mapValueInd, rangeproof, reissuance_token ? issuance.nInflationKeys : issuance.nAmount, CConfidentialAsset(asset), CConfidentialNonce(), blindingScript, nullptr, nullptr, &ret, nullptr, nullptr); return ret; } -CAmount CWalletTx::GetIssuanceAmount(unsigned int input_index, bool reissuance_token) const { +CAmount CWalletTx::GetIssuanceAmount(const CWallet& wallet, unsigned int input_index, bool reissuance_token) const { assert(input_index < tx->vin.size()); CAsset asset; const CAssetIssuance& issuance = tx->vin[input_index].assetIssuance; @@ -3828,12 +3829,12 @@ CAmount CWalletTx::GetIssuanceAmount(unsigned int input_index, bool reissuance_t if (asset.IsNull()) { return -1; } - unsigned int mapValueInd = GetPseudoInputOffset(input_index, reissuance_token)+tx->vout.size(); + unsigned int mapValueInd = GetPseudoInputOffset(input_index, reissuance_token) + tx->vout.size(); const std::vector& rangeproof = wit.vtxinwit.size() <= input_index ? std::vector() : (reissuance_token ? wit.vtxinwit[input_index].vchInflationKeysRangeproof : wit.vtxinwit[input_index].vchIssuanceAmountRangeproof); CAmount ret; CScript blindingScript(CScript() << OP_RETURN << std::vector(tx->vin[input_index].prevout.hash.begin(), tx->vin[input_index].prevout.hash.end()) << tx->vin[input_index].prevout.n); - GetBlindingData(mapValueInd, rangeproof, reissuance_token ? issuance.nInflationKeys : issuance.nAmount, CConfidentialAsset(asset), CConfidentialNonce(), blindingScript, nullptr, &ret, nullptr, nullptr, nullptr); + GetBlindingData(wallet, mapValueInd, rangeproof, reissuance_token ? issuance.nInflationKeys : issuance.nAmount, CConfidentialAsset(asset), CConfidentialNonce(), blindingScript, nullptr, &ret, nullptr, nullptr, nullptr); return ret; } @@ -3865,21 +3866,21 @@ void CWallet::ComputeBlindingData(const CConfidentialValue& conf_value, const CC asset_factor.SetNull(); } -void CWalletTx::WipeUnknownBlindingData() +void CWalletTx::WipeUnknownBlindingData(const CWallet& wallet) { for (unsigned int n = 0; n < tx->vout.size(); n++) { - if (GetOutputValueOut(n) == -1) { + if (GetOutputValueOut(wallet, n) == -1) { mapValue["blindingdata"][138 * n] = 0; } } for (unsigned int n = 0; n < tx->vin.size(); n++) { if (!tx->vin[n].assetIssuance.nAmount.IsNull()) { - if (GetIssuanceAmount(n, false) == -1) { + if (GetIssuanceAmount(wallet, n, false) == -1) { mapValue["blindingdata"][138 * (tx->vout.size() + GetPseudoInputOffset(n, false))] = 0; } } if (!tx->vin[n].assetIssuance.nInflationKeys.IsNull()) { - if (GetIssuanceAmount(n, true) == -1) { + if (GetIssuanceAmount(wallet, n, true) == -1) { mapValue["blindingdata"][138 * (tx->vout.size() + GetPseudoInputOffset(n, true))] = 0; } } @@ -3914,8 +3915,7 @@ std::map > CWallet::GetReissuanceTokenTypes() return tokenMap; } -CKey CWallet::GetBlindingKey(const CScript* script) const -{ +CKey CWallet::GetBlindingKey(const CScript* script) const { CKey key; if (script != NULL) { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index b8f71c79c3..784817c4bf 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -113,6 +114,9 @@ class CWalletTx; struct FeeCalculation; enum class FeeEstimateMode; class ReserveDestination; +// ELEMENTS +class WalletRescanReserver; +struct BlindDetails; //! Default for -addresstype constexpr OutputType DEFAULT_ADDRESS_TYPE{OutputType::BECH32}; diff --git a/test/functional/test_framework/ripemd160.py b/test/functional/test_framework/ripemd160.py new file mode 100644 index 0000000000..12801364b4 --- /dev/null +++ b/test/functional/test_framework/ripemd160.py @@ -0,0 +1,130 @@ +# Copyright (c) 2021 Pieter Wuille +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test-only pure Python RIPEMD160 implementation.""" + +import unittest + +# Message schedule indexes for the left path. +ML = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, + 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, + 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, + 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 +] + +# Message schedule indexes for the right path. +MR = [ + 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, + 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, + 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, + 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, + 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 +] + +# Rotation counts for the left path. +RL = [ + 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, + 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, + 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, + 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, + 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 +] + +# Rotation counts for the right path. +RR = [ + 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, + 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, + 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, + 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, + 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 +] + +# K constants for the left path. +KL = [0, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e] + +# K constants for the right path. +KR = [0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9, 0] + + +def fi(x, y, z, i): + """The f1, f2, f3, f4, and f5 functions from the specification.""" + if i == 0: + return x ^ y ^ z + elif i == 1: + return (x & y) | (~x & z) + elif i == 2: + return (x | ~y) ^ z + elif i == 3: + return (x & z) | (y & ~z) + elif i == 4: + return x ^ (y | ~z) + else: + assert False + + +def rol(x, i): + """Rotate the bottom 32 bits of x left by i bits.""" + return ((x << i) | ((x & 0xffffffff) >> (32 - i))) & 0xffffffff + + +def compress(h0, h1, h2, h3, h4, block): + """Compress state (h0, h1, h2, h3, h4) with block.""" + # Left path variables. + al, bl, cl, dl, el = h0, h1, h2, h3, h4 + # Right path variables. + ar, br, cr, dr, er = h0, h1, h2, h3, h4 + # Message variables. + x = [int.from_bytes(block[4*i:4*(i+1)], 'little') for i in range(16)] + + # Iterate over the 80 rounds of the compression. + for j in range(80): + rnd = j >> 4 + # Perform left side of the transformation. + al = rol(al + fi(bl, cl, dl, rnd) + x[ML[j]] + KL[rnd], RL[j]) + el + al, bl, cl, dl, el = el, al, bl, rol(cl, 10), dl + # Perform right side of the transformation. + ar = rol(ar + fi(br, cr, dr, 4 - rnd) + x[MR[j]] + KR[rnd], RR[j]) + er + ar, br, cr, dr, er = er, ar, br, rol(cr, 10), dr + + # Compose old state, left transform, and right transform into new state. + return h1 + cl + dr, h2 + dl + er, h3 + el + ar, h4 + al + br, h0 + bl + cr + + +def ripemd160(data): + """Compute the RIPEMD-160 hash of data.""" + # Initialize state. + state = (0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0) + # Process full 64-byte blocks in the input. + for b in range(len(data) >> 6): + state = compress(*state, data[64*b:64*(b+1)]) + # Construct final blocks (with padding and size). + pad = b"\x80" + b"\x00" * ((119 - len(data)) & 63) + fin = data[len(data) & ~63:] + pad + (8 * len(data)).to_bytes(8, 'little') + # Process final blocks. + for b in range(len(fin) >> 6): + state = compress(*state, fin[64*b:64*(b+1)]) + # Produce output. + return b"".join((h & 0xffffffff).to_bytes(4, 'little') for h in state) + + +class TestFrameworkKey(unittest.TestCase): + def test_ripemd160(self): + """RIPEMD-160 test vectors.""" + # See https://homes.esat.kuleuven.be/~bosselae/ripemd160.html + for msg, hexout in [ + (b"", "9c1185a5c5e9fc54612808977ee8f548b2258d31"), + (b"a", "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe"), + (b"abc", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"), + (b"message digest", "5d0689ef49d2fae572b881b123a85ffa21595f36"), + (b"abcdefghijklmnopqrstuvwxyz", + "f71c27109c692c1b56bbdceb5b9d2865b3708dbc"), + (b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "12a053384a9c0c88e405a06c27dcf49ada62eb2b"), + (b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "b0e20b6e3116640286ed3a87a5713079b21f5189"), + (b"1234567890" * 8, "9b752e45573d4b39f4dbd3323cab82bf63326bfb"), + (b"a" * 1000000, "52783243c1697bdbe16d37f97f68f08325dc1528") + ]: + self.assertEqual(ripemd160(msg).hex(), hexout) diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py index d5c318455b..a0a26d4a6d 100644 --- a/test/functional/test_framework/script.py +++ b/test/functional/test_framework/script.py @@ -8,7 +8,6 @@ """ from collections import namedtuple -import hashlib import struct import unittest from typing import List, Dict @@ -29,6 +28,8 @@ uint256_from_str, ) +from .ripemd160 import ripemd160 + MAX_SCRIPT_ELEMENT_SIZE = 520 LOCKTIME_THRESHOLD = 500000000 ANNEX_TAG = 0x50 @@ -36,7 +37,7 @@ LEAF_VERSION_TAPSCRIPT = 0xc4 def hash160(s): - return hashlib.new('ripemd160', sha256(s)).digest() + return ripemd160(sha256(s)) def bn2vch(v): """Convert number to bitcoin-specific little endian format.""" diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py index f49dc0211f..6b30829414 100755 --- a/test/functional/wallet_multiwallet.py +++ b/test/functional/wallet_multiwallet.py @@ -141,7 +141,7 @@ def wallet_file(name): # should raise rpc error if wallet path can't be created err_code = -4 if self.options.descriptors else -1 - assert_raises_rpc_error(err_code, "boost::filesystem::create_directory:", self.nodes[0].createwallet, "w8/bad") + assert_raises_rpc_error(err_code, "boost::filesystem::create_director", self.nodes[0].createwallet, "w8/bad") # check that all requested wallets were created self.stop_node(0) diff --git a/test/lint/lint-circular-dependencies.sh b/test/lint/lint-circular-dependencies.sh index bfef1eef08..52f3a443b9 100755 --- a/test/lint/lint-circular-dependencies.sh +++ b/test/lint/lint-circular-dependencies.sh @@ -24,11 +24,6 @@ EXPECTED_CIRCULAR_DEPENDENCIES=( "wallet/fees -> wallet/wallet -> wallet/fees" "wallet/wallet -> wallet/walletdb -> wallet/wallet" "node/coinstats -> validation -> node/coinstats" -<<<<<<< HEAD - # Temporary circular dependencies that allow wallet.h/wallet.cpp to be - # split up in a MOVEONLY commit. These are removed in #21206. - "wallet/receive -> wallet/wallet -> wallet/receive" - "wallet/spend -> wallet/wallet -> wallet/spend" # ELEMENTS: will be fixed by blinding cleanup "blindpsbt -> psbt -> blindpsbt" # ELEMENTS: not so easy to fix, caused by us doing asset ID lookups in the @@ -36,13 +31,6 @@ EXPECTED_CIRCULAR_DEPENDENCIES=( # multi-asset transaction or not. Probably this check should be done in # CreateTransaction instead. "wallet/coinselection -> wallet/wallet -> wallet/coinselection" -||||||| dd097c42df - # Temporary circular dependencies that allow wallet.h/wallet.cpp to be - # split up in a MOVEONLY commit. These are removed in #21206. - "wallet/receive -> wallet/wallet -> wallet/receive" - "wallet/spend -> wallet/wallet -> wallet/spend" -======= ->>>>>>> 629c4ab2e3 ) EXIT_CODE=0