From 91349a94cf044fbfec34972927ee4473abeb8573 Mon Sep 17 00:00:00 2001 From: James Dorfman Date: Sat, 15 Apr 2023 07:04:22 +0000 Subject: [PATCH 1/7] wip --- src/wallet/interfaces.cpp | 12 ++-- src/wallet/receive.cpp | 20 +++---- src/wallet/receive.h | 10 +++- src/wallet/transaction.h | 115 -------------------------------------- src/wallet/wallet.cpp | 44 +++++++-------- src/wallet/wallet.h | 52 +++++++++++++++++ 6 files changed, 97 insertions(+), 156 deletions(-) diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index 0bd67d2125..6b4a48558f 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -61,9 +61,9 @@ WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) for (unsigned int i = 0; i < wtx.tx->vin.size(); ++i) { 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)); + wallet.GetIssuanceAssets(wtx, i, &result.txin_issuance_asset[i], &result.txin_issuance_token[i]); + result.txin_issuance_asset_amount.emplace_back(wallet.GetIssuanceAmount(wtx, i, false)); + result.txin_issuance_token_amount.emplace_back(wallet.GetIssuanceAmount(wtx, 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(wallet.GetOutputValueOut(wtx, i)); + result.txout_assets.emplace_back(wallet.GetOutputAsset(wtx, i)); } result.credit = CachedTxGetCredit(wallet, wtx, ISMINE_ALL); result.debit = CachedTxGetDebit(wallet, wtx, ISMINE_ALL); diff --git a/src/wallet/receive.cpp b/src/wallet/receive.cpp index 237848ab54..568e95f3a1 100644 --- a/src/wallet/receive.cpp +++ b/src/wallet/receive.cpp @@ -11,7 +11,7 @@ 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 +48,15 @@ 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 CWalletTx& wtx, 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)); + CAmount credit = std::max(0, wallet.GetOutputValueOut(wtx, i)); if (!MoneyRange(credit)) throw std::runtime_error(std::string(__func__) + ": value out of range"); - nCredit[wtx.GetOutputAsset(i)] += credit; + nCredit[wallet.GetOutputAsset(wtx, i)] += credit; if (!MoneyRange(nCredit)) throw std::runtime_error(std::string(__func__) + ": value out of range"); } @@ -64,11 +64,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 = wallet.GetOutputValueOut(wtx, i); if (change < 0) { continue; } @@ -76,7 +76,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[wallet.GetOutputAsset(wtx, i)] += change; if (!MoneyRange(nChange)) throw std::runtime_error(std::string(__func__) + ": value out of range"); } @@ -111,7 +111,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 +122,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; 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/transaction.h b/src/wallet/transaction.h index f01ff5565c..58794c1778 100644 --- a/src/wallet/transaction.h +++ b/src/wallet/transaction.h @@ -265,123 +265,8 @@ 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: - -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 - * @param[in] vchRangeproof - The rangeproof to unwind - * @param[in] conf_value - The value to unblind - * @param[in] conf_asset - The asset to unblind - * @param[in] nonce - The nonce used to ECDH with the blinding key. This is null for issuance as blinding key is directly used as nonce - * @param[in] scriptPubKey - The script being committed to by the rangeproof - * @param[out] blinding_pubkey_out - Pointer to the recovered pubkey of the destination - * @param[out] value_out - Pointer to the CAmount where the unblinded amount will be stored - * @param[out] value_factor_out - Pointer to the recovered value blinding factor of the output - * @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(); -public: - // For use in wallet transaction creation to remember 3rd party values - // Unneeded for issuance. - 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; - - //! 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; - //! 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; - // ! Returns receiver's blinding pubkey - CPubKey GetOutputBlindingPubKey(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; - //! Get the issuance amount for either the asset itself or the issuing tokens - CAmount GetIssuanceAmount(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; - - // 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; } - - /** - * @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() { diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 62ce286962..2cd745d2bd 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3445,10 +3445,10 @@ unsigned int CWalletTx::GetPseudoInputOffset(const unsigned int input_index, con return mapvalue_loc; } -void CWalletTx::SetBlindingData(const unsigned int map_index, const CPubKey& blinding_pubkey, const CAmount value, const uint256& value_factor, const CAsset& asset, const uint256& asset_factor) +void CWallet::SetBlindingData(const CWalletTx& wtx, const unsigned int map_index, const CPubKey& blinding_pubkey, const CAmount value, const uint256& value_factor, const CAsset& asset, const uint256& asset_factor) { if (mapValue["blindingdata"].size() < (map_index + 1) * 138) { - mapValue["blindingdata"].resize((tx->vout.size() + GetNumIssuances(*tx)) * 138); + mapValue["blindingdata"].resize((wtx->vout.size() + GetNumIssuances(*tx)) * 138); } unsigned char* it = (unsigned char*)(&mapValue["blindingdata"][0]) + 138 * map_index; @@ -3466,7 +3466,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 CWallet::GetBlindingData(const CWalletTx& wtx, 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. @@ -3480,7 +3480,7 @@ void CWalletTx::GetBlindingData(const unsigned int map_index, const std::vector< // This is really ugly, and should use CDataStream serialization instead. if (mapValue["blindingdata"].size() < (map_index + 1) * 138) { - mapValue["blindingdata"].resize((tx->vout.size() + GetNumIssuances(*tx)) * 138); + mapValue["blindingdata"].resize((tx->vout.size() + GetNumIssuances(*wtx)) * 138); } unsigned char* it = (unsigned char*)(&mapValue["blindingdata"][0]) + 138 * map_index; @@ -3522,10 +3522,10 @@ 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 { - assert(output_index < tx->vout.size()); - const CTxOut& out = tx->vout[output_index]; - const CTxWitness& wit = tx->witness; +void CWallet::GetNonIssuanceBlindingData(const CWalletTx& wtx, 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 < wtx->vout.size()); + const CTxOut& out = wtx->vout[output_index]; + const CTxWitness& wit = wtx->witness; GetBlindingData(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,39 +3736,39 @@ ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const Flat return spk_man; } -CAmount CWalletTx::GetOutputValueOut(unsigned int output_index) const { +CAmount CWalletTx::GetOutputValueOut(const CWalletTx& wtx, unsigned int output_index) const { CAmount ret; - GetNonIssuanceBlindingData(output_index, nullptr, &ret, nullptr, nullptr, nullptr); + GetNonIssuanceBlindingData(wtx, output_index, nullptr, &ret, nullptr, nullptr, nullptr); return ret; } -uint256 CWalletTx::GetOutputAmountBlindingFactor(unsigned int output_index) const { +uint256 CWalletTx::GetOutputAmountBlindingFactor(const CWalletTx& wtx, unsigned int output_index) const { uint256 ret; - GetNonIssuanceBlindingData(output_index, nullptr, nullptr, &ret, nullptr, nullptr); + GetNonIssuanceBlindingData(wtx, output_index, nullptr, nullptr, &ret, nullptr, nullptr); return ret; } -uint256 CWalletTx::GetOutputAssetBlindingFactor(unsigned int output_index) const { +uint256 CWalletTx::GetOutputAssetBlindingFactor(const CWalletTx& wtx, unsigned int output_index) const { uint256 ret; - GetNonIssuanceBlindingData(output_index, nullptr, nullptr, nullptr, nullptr, &ret); + GetNonIssuanceBlindingData(wtx, output_index, nullptr, nullptr, nullptr, nullptr, &ret); return ret; } -CAsset CWalletTx::GetOutputAsset(unsigned int output_index) const { +CAsset CWalletTx::GetOutputAsset(const CWalletTx& wtx, unsigned int output_index) const { CAsset ret; - GetNonIssuanceBlindingData(output_index, nullptr, nullptr, nullptr, &ret, nullptr); + GetNonIssuanceBlindingData(wtx, output_index, nullptr, nullptr, nullptr, &ret, nullptr); return ret; } -CPubKey CWalletTx::GetOutputBlindingPubKey(unsigned int output_index) const { +CPubKey CWalletTx::GetOutputBlindingPubKey(const CWalletTx& wtx, unsigned int output_index) const { CPubKey ret; - GetNonIssuanceBlindingData(output_index, &ret, nullptr, nullptr, nullptr, nullptr); + GetNonIssuanceBlindingData(wtx, output_index, &ret, nullptr, nullptr, nullptr, nullptr); return ret; } -void CWalletTx::GetIssuanceAssets(unsigned int input_index, CAsset* out_asset, CAsset* out_reissuance_token) const { - assert(input_index < tx->vin.size()); - const CAssetIssuance& issuance = tx->vin[input_index].assetIssuance; +void CWallet::GetIssuanceAssets(const CWalletTx& wtx, unsigned int input_index, CAsset* out_asset, CAsset* out_reissuance_token) const { + assert(input_index < wtx->vin.size()); + const CAssetIssuance& issuance = wtx->vin[input_index].assetIssuance; if (out_asset && issuance.nAmount.IsNull()) { out_asset->SetNull(); @@ -3782,7 +3782,7 @@ void CWalletTx::GetIssuanceAssets(unsigned int input_index, CAsset* out_asset, C if (issuance.assetBlindingNonce.IsNull()) { uint256 entropy; - GenerateAssetEntropy(entropy, tx->vin[input_index].prevout, issuance.assetEntropy); + GenerateAssetEntropy(entropy, wtx->vin[input_index].prevout, issuance.assetEntropy); if (out_reissuance_token) { CalculateReissuanceToken(*out_reissuance_token, entropy, issuance.nAmount.IsCommitment()); } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index b8f71c79c3..66365defaf 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -113,6 +113,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}; @@ -605,6 +608,55 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati /** Pass this transaction to node for mempool insertion and relay to peers if flag set to true */ bool SubmitTxMemoryPoolAndRelay(const CWalletTx& wtx, std::string& err_string, bool relay) const; + // 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 + * @param[in] vchRangeproof - The rangeproof to unwind + * @param[in] conf_value - The value to unblind + * @param[in] conf_asset - The asset to unblind + * @param[in] nonce - The nonce used to ECDH with the blinding key. This is null for issuance as blinding key is directly used as nonce + * @param[in] scriptPubKey - The script being committed to by the rangeproof + * @param[out] blinding_pubkey_out - Pointer to the recovered pubkey of the destination + * @param[out] value_out - Pointer to the CAmount where the unblinded amount will be stored + * @param[out] value_factor_out - Pointer to the recovered value blinding factor of the output + * @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 CWalletTx& wtx, 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(); + +public: + // For use in wallet transaction creation to remember 3rd party values + // Unneeded for issuance. + void SetBlindingData(const CWalletTx& wtx, 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 CWalletTx& wtx, 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(const CWalletTx& wtx, unsigned int ouput_index) const; + + //! Returns either the blinding factor (if it is to us) or 0 + uint256 GetOutputAmountBlindingFactor(const CWalletTx& wtx, unsigned int output_index) const; + uint256 GetOutputAssetBlindingFactor(const CWalletTx& wtx, unsigned int output_index) const; + //! Returns the underlying asset type, or 0 if unknown + CAsset GetOutputAsset(const CWalletTx& wtx, unsigned int output_index) const; + //! Get the issuance CAssets for both the asset itself and the issuing tokens + void GetIssuanceAssets(const CWalletTx& wtx, unsigned int vinIndex, CAsset* out_asset, CAsset* out_reissuance_token) const; + // ! Return map of issued assets at input_index + CAmountMap GetIssuanceAssets(const CWalletTx& wtx, unsigned int input_index) const; + // ! Returns receiver's blinding pubkey + CPubKey GetOutputBlindingPubKey(const CWalletTx& wtx, unsigned int output_index) const; + //! Get the issuance blinder for either the asset itself or the issuing tokens + uint256 GetIssuanceBlindingFactor(const CWalletTx& wtx, unsigned int input_index, bool reissuance_token) const; + //! Get the issuance amount for either the asset itself or the issuing tokens + CAmount GetIssuanceAmount(const CWalletTx& wtx, 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(const CWalletTx& wtx, unsigned int input_index, bool reissuance_token) const; + // END ELEMENTS + bool DummySignTx(CMutableTransaction &txNew, const std::set &txouts, const CCoinControl* coin_control = nullptr) const { std::vector v_txouts(txouts.size()); From a0db8529401510f24eb477fe4286bb9a5e577378 Mon Sep 17 00:00:00 2001 From: Byron Hambly Date: Sat, 15 Apr 2023 11:41:27 +0000 Subject: [PATCH 2/7] wip --- src/wallet/receive.cpp | 36 ++++++++++++++++----------------- src/wallet/spend.cpp | 46 +++++++++++++++++++++--------------------- src/wallet/wallet.cpp | 4 +++- 3 files changed, 44 insertions(+), 42 deletions(-) diff --git a/src/wallet/receive.cpp b/src/wallet/receive.cpp index 568e95f3a1..cb5c5b72a0 100644 --- a/src/wallet/receive.cpp +++ b/src/wallet/receive.cpp @@ -139,8 +139,8 @@ static CAmountMap GetCachableAmount(const CWallet& wallet, const CWalletTx& wtx, { 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) : CachedTxGetCredit(wallet, wtx, filter)); + wtx.m_is_cache_empty = false; } return amount.m_value[filter]; } @@ -199,7 +199,7 @@ 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; } @@ -240,13 +240,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, wallet.GetOutputValueOut(wtx, i)); if (!MoneyRange(credit)) throw std::runtime_error(std::string(__func__) + ": value out of range"); - nCredit[GetOutputAsset(i)] += std::max(0, GetOutputValueOut(i)); + nCredit[wallet.GetOutputAsset(wtx, i)] += std::max(0, wallet.GetOutputValueOut(wtx, i)); if (!MoneyRange(nCredit)) throw std::runtime_error(std::string(__func__) + ": value out of range"); } @@ -281,9 +281,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 = wallet.GetOutputValueOut(wtx, 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 +306,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, wallet.GetOutputAsset(wtx, i), wallet.GetOutputAmountBlindingFactor(wtx, i), wallet.GetOutputAssetBlindingFactor(wtx, i)}; // If we are debited by the transaction, add the output as a "sent" entry if (mapDebit > CAmountMap() && !txout.IsFee()) @@ -321,7 +321,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 +373,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 +421,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 : wallet.GetOutputValueOut(wtx, i); if (n < 0) { continue; } @@ -527,17 +527,17 @@ std::set< std::set > GetAddressGroupings(const CWallet& wallet) } // ELEMENTS -CAmountMap CWalletTx::GetIssuanceAssets(unsigned int input_index) const { +// todo: move this to wallet.cpp? +CAmountMap CWallet::GetIssuanceAssets(const CWalletTx& wtx, unsigned int input_index) const { CAmountMap ret; CAsset asset, token; - GetIssuanceAssets(input_index, &asset, &token); + GetIssuanceAssets(wtx, input_index, &asset, &token); if (!asset.IsNull()) { - ret[asset] = GetIssuanceAmount(input_index, false); + ret[asset] = GetIssuanceAmount(wtx, input_index, false); } if (!token.IsNull()) { - ret[token] = GetIssuanceAmount(input_index, true); + ret[token] = GetIssuanceAmount(wtx, input_index, true); } return ret; } // end ELEMENTS - diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp index 87c6829efc..046e89bbd6 100644 --- a/src/wallet/spend.cpp +++ b/src/wallet/spend.cpp @@ -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 = wallet.GetOutputValueOut(wtx, i); + CAsset asset = wallet.GetOutputAsset(wtx, 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 = wallet.GetOutputValueOut(*out.tx, out.i); if (amt < 0) { continue; } - balance[out.tx->GetOutputAsset(out.i)] += amt; + balance[wallet.GetOutputAsset(*out.tx, out.i)] += amt; } } return balance; @@ -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,11 +506,11 @@ bool SelectCoins(const CWallet& wallet, const std::vector& vAvailableCo if (!out.fSpendable) continue; - CAmount amt = out.tx->GetOutputValueOut(out.i); + CAmount amt = wallet.GetOutputValueOut(*out.tx, out.i); if (amt < 0) { continue; } - mapValueRet[out.tx->GetOutputAsset(out.i)] += amt; + mapValueRet[wallet.GetOutputAsset(*out.tx, out.i)] += amt; setCoinsRet.insert(out.GetInputCoin()); } return (mapValueRet >= mapTargetValue); @@ -539,7 +539,7 @@ 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 @@ -559,7 +559,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 @@ -642,7 +642,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 +898,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 +972,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 = wallet.GetOutputAsset(it->second, presetInput.n); } else if (coin_control.GetExternalOutput(presetInput, txout)) { asset = txout.nAsset.GetAsset(); } else { @@ -1240,7 +1240,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 +1334,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 +1343,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 +1373,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 +1383,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 +1395,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 +1458,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; } } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 2cd745d2bd..670aed0c42 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1317,7 +1317,9 @@ 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)); + CAsset asset = this->GetOutputAsset(prev, txin.prevout.n); + CAmount amount = this->GetOutputValueOut(prev, txin.prevout.n); + amounts[asset] = std::max(0, amount); return amounts; } } From 272dad3d8633dfbb9781a70d87c6a50bffe3bb14 Mon Sep 17 00:00:00 2001 From: James Dorfman Date: Sun, 16 Apr 2023 07:22:24 +0000 Subject: [PATCH 3/7] wip --- src/wallet/interfaces.cpp | 4 ++-- src/wallet/receive.cpp | 18 +++++++-------- src/wallet/rpcdump.cpp | 2 +- src/wallet/rpcwallet.cpp | 48 ++++++++++++--------------------------- src/wallet/spend.cpp | 18 +++++++-------- src/wallet/transaction.h | 8 +++++++ src/wallet/wallet.cpp | 14 ++++++------ src/wallet/wallet.h | 5 ---- 8 files changed, 51 insertions(+), 66 deletions(-) diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index 6b4a48558f..9338d3570d 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -78,8 +78,8 @@ WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) } // ELEMENTS: Retrieve unblinded information about outputs for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i) { - result.txout_amounts.emplace_back(wallet.GetOutputValueOut(wtx, i)); - result.txout_assets.emplace_back(wallet.GetOutputAsset(wtx, i)); + result.txout_amounts.emplace_back(wtx.GetOutputValueOut(i)); + result.txout_assets.emplace_back(wtx.GetOutputAsset(i)); } result.credit = CachedTxGetCredit(wallet, wtx, ISMINE_ALL); result.debit = CachedTxGetDebit(wallet, wtx, ISMINE_ALL); diff --git a/src/wallet/receive.cpp b/src/wallet/receive.cpp index cb5c5b72a0..e9bc13d863 100644 --- a/src/wallet/receive.cpp +++ b/src/wallet/receive.cpp @@ -52,11 +52,11 @@ CAmountMap OutputGetCredit(const CWallet& wallet, const CWalletTx& wtx, const is 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, wallet.GetOutputValueOut(wtx, i)); + CAmount credit = std::max(0, wtx.GetOutputValueOut(i)); if (!MoneyRange(credit)) throw std::runtime_error(std::string(__func__) + ": value out of range"); - nCredit[wallet.GetOutputAsset(wtx, i)] += credit; + nCredit[wtx.GetOutputAsset(i)] += credit; if (!MoneyRange(nCredit)) throw std::runtime_error(std::string(__func__) + ": value out of range"); } @@ -68,7 +68,7 @@ CAmountMap GetChange(const CWallet& wallet, const CWalletTx& wtx) { CAmountMap nChange; for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i) { if (OutputIsChange(wallet, wtx.tx->vout[i])) { - CAmount change = wallet.GetOutputValueOut(wtx, i); + CAmount change = wtx.GetOutputValueOut(i); if (change < 0) { continue; } @@ -76,7 +76,7 @@ CAmountMap GetChange(const CWallet& wallet, const CWalletTx& wtx) { if (!MoneyRange(change)) throw std::runtime_error(std::string(__func__) + ": value out of range"); - nChange[wallet.GetOutputAsset(wtx, i)] += change; + nChange[wtx.GetOutputAsset(i)] += change; if (!MoneyRange(nChange)) throw std::runtime_error(std::string(__func__) + ": value out of range"); } @@ -242,11 +242,11 @@ CAmountMap CachedTxGetAvailableCredit(const CWallet& wallet, const CWalletTx& wt { 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, wallet.GetOutputValueOut(wtx, i)); + CAmount credit = std::max(0, wtx.GetOutputValueOut(i)); if (!MoneyRange(credit)) throw std::runtime_error(std::string(__func__) + ": value out of range"); - nCredit[wallet.GetOutputAsset(wtx, i)] += std::max(0, wallet.GetOutputValueOut(wtx, i)); + nCredit[wtx.GetOutputAsset(i)] += std::max(0, wtx.GetOutputValueOut(i)); if (!MoneyRange(nCredit)) throw std::runtime_error(std::string(__func__) + ": value out of range"); } @@ -281,7 +281,7 @@ 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 = wallet.GetOutputValueOut(wtx, i); + CAmount output_value = wtx.GetOutputValueOut(i); // Don't list unknown assets isminetype fIsMine = output_value != -1 ? wallet.IsMine(txout) : ISMINE_NO; // Only need to handle txouts if AT LEAST one of these is true: @@ -306,7 +306,7 @@ void CachedTxGetAmounts(const CWallet& wallet, const CWalletTx& wtx, address = CNoDestination(); } - COutputEntry output = {address, output_value, (int)i, wallet.GetOutputAsset(wtx, i), wallet.GetOutputAmountBlindingFactor(wtx, i), wallet.GetOutputAssetBlindingFactor(wtx, i)}; + COutputEntry output = {address, output_value, (int)i, wtx.GetOutputAsset(i), wallet.GetOutputAmountBlindingFactor(wtx, i), wallet.GetOutputAssetBlindingFactor(wtx, i)}; // If we are debited by the transaction, add the output as a "sent" entry if (mapDebit > CAmountMap() && !txout.IsFee()) @@ -421,7 +421,7 @@ std::map GetAddressBalances(const CWallet& wallet) if(!ExtractDestination(wtx.tx->vout[i].scriptPubKey, addr)) continue; - CAmount n = wallet.IsSpent(walletEntry.first, i) ? 0 : wallet.GetOutputValueOut(wtx, i); + CAmount n = wallet.IsSpent(walletEntry.first, i) ? 0 : wtx.GetOutputValueOut(i); if (n < 0) { continue; } diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index b68e11cfc2..84ae1a92f5 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -2237,7 +2237,7 @@ 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 (pwallet->GetIssuanceAmount(*pcoin, 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); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 3c5b176317..36db3bf3f3 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,7 +767,7 @@ 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); if (amt < 0) { @@ -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)); @@ -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", pwallet->GetOutputAmountBlindingFactor(*out.tx, out.i).ToString()); + entry.pushKV("assetblinder", pwallet->GetOutputAssetBlindingFactor(*out.tx, 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,8 +6489,8 @@ 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_blinds.push_back(pwallet->GetOutputAmountBlindingFactor(it->second, prevout.n)); + input_asset_blinds.push_back(pwallet->GetOutputAssetBlindingFactor(it->second, prevout.n)); input_assets.push_back(it->second.GetOutputAsset(prevout.n)); input_amounts.push_back(it->second.GetOutputValueOut(prevout.n)); if (it->second.tx->vout[prevout.n].nValue.IsCommitment()) { @@ -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 = pwallet->GetIssuanceAmount(*pcoin, vinIndex, true); item.pushKV("tokenamount", (itamount == -1 ) ? -1 : ValueFromAmount(itamount)); - item.pushKV("tokenblinds", pcoin->GetIssuanceBlindingFactor(vinIndex, true).GetHex()); + item.pushKV("tokenblinds", pwallet->GetIssuanceBlindingFactor(*pcoin, 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 = pwallet->GetIssuanceAmount(*pcoin, vinIndex, false); item.pushKV("assetamount", (iaamount == -1 ) ? -1 : ValueFromAmount(iaamount)); - item.pushKV("assetblinds", pcoin->GetIssuanceBlindingFactor(vinIndex, false).GetHex()); + item.pushKV("assetblinds", pwallet->GetIssuanceBlindingFactor(*pcoin, vinIndex, false).GetHex()); if (!asset_filter.IsNull() && asset_filter != asset) { continue; } diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp index 046e89bbd6..a54d91d010 100644 --- a/src/wallet/spend.cpp +++ b/src/wallet/spend.cpp @@ -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 = wallet.GetOutputValueOut(wtx, i); - CAsset asset = wallet.GetOutputAsset(wtx, i); + CAmount outValue = wtx.GetOutputValueOut(i); + CAsset asset = wtx.GetOutputAsset(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 = wallet.GetOutputValueOut(*out.tx, out.i); + CAmount amt = out.tx->GetOutputValueOut(out.i); if (amt < 0) { continue; } - balance[wallet.GetOutputAsset(*out.tx, out.i)] += amt; + balance[out.tx->GetOutputAsset(out.i)] += amt; } } return balance; @@ -506,11 +506,11 @@ bool SelectCoins(const CWallet& wallet, const std::vector& vAvailableCo if (!out.fSpendable) continue; - CAmount amt = wallet.GetOutputValueOut(*out.tx, out.i); + CAmount amt = out.tx->GetOutputValueOut(out.i); if (amt < 0) { continue; } - mapValueRet[wallet.GetOutputAsset(*out.tx, out.i)] += amt; + mapValueRet[out.tx->GetOutputAsset(out.i)] += amt; setCoinsRet.insert(out.GetInputCoin()); } return (mapValueRet >= mapTargetValue); @@ -975,7 +975,7 @@ static bool CreateTransactionInternal( std::map::const_iterator it = wallet.mapWallet.find(presetInput.hash); CTxOut txout; if (it != wallet.mapWallet.end()) { - asset = wallet.GetOutputAsset(it->second, presetInput.n); + asset = it->second.GetOutputAsset(presetInput.n); } else if (coin_control.GetExternalOutput(presetInput, txout)) { asset = txout.nAsset.GetAsset(); } else { @@ -1383,7 +1383,7 @@ static bool CreateTransactionInternal( TxSize tx_sizes; CMutableTransaction tx_blinded = txNew; if (blind_details) { - if (!fillBlindDetails(blind_details, wallet, 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 diff --git a/src/wallet/transaction.h b/src/wallet/transaction.h index 58794c1778..472cc0ac6b 100644 --- a/src/wallet/transaction.h +++ b/src/wallet/transaction.h @@ -284,6 +284,14 @@ class CWalletTx const uint256& GetHash() const { return tx->GetHash(); } bool IsCoinBase() const { return tx->IsCoinBase(); } + // ELEMENTS + //! Returns either the value out (if it is known) or -1 + CAmount GetOutputValueOut(unsigned int ouput_index) const; + //! Returns the underlying asset type, or 0 if unknown + CAsset GetOutputAsset(unsigned int output_index) const; + + // 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 // wrong copy. diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 670aed0c42..db63969d59 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3738,31 +3738,31 @@ ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const Flat return spk_man; } -CAmount CWalletTx::GetOutputValueOut(const CWalletTx& wtx, unsigned int output_index) const { +CAmount CWalletTx::GetOutputValueOut(unsigned int output_index) { CAmount ret; - GetNonIssuanceBlindingData(wtx, output_index, nullptr, &ret, nullptr, nullptr, nullptr); + GetNonIssuanceBlindingData(*this, output_index, nullptr, &ret, nullptr, nullptr, nullptr); return ret; } -uint256 CWalletTx::GetOutputAmountBlindingFactor(const CWalletTx& wtx, unsigned int output_index) const { +uint256 CWallet::GetOutputAmountBlindingFactor(const CWalletTx& wtx, unsigned int output_index) { uint256 ret; GetNonIssuanceBlindingData(wtx, output_index, nullptr, nullptr, &ret, nullptr, nullptr); return ret; } -uint256 CWalletTx::GetOutputAssetBlindingFactor(const CWalletTx& wtx, unsigned int output_index) const { +uint256 CWallet::GetOutputAssetBlindingFactor(const CWalletTx& wtx, unsigned int output_index) { uint256 ret; GetNonIssuanceBlindingData(wtx, output_index, nullptr, nullptr, nullptr, nullptr, &ret); return ret; } -CAsset CWalletTx::GetOutputAsset(const CWalletTx& wtx, unsigned int output_index) const { +CAsset CWalletTx::GetOutputAsset(unsigned int output_index) { CAsset ret; - GetNonIssuanceBlindingData(wtx, output_index, nullptr, nullptr, nullptr, &ret, nullptr); + GetNonIssuanceBlindingData(*this, output_index, nullptr, nullptr, nullptr, &ret, nullptr); return ret; } -CPubKey CWalletTx::GetOutputBlindingPubKey(const CWalletTx& wtx, unsigned int output_index) const { +CPubKey CWallet::GetOutputBlindingPubKey(const CWalletTx& wtx, unsigned int output_index) { CPubKey ret; GetNonIssuanceBlindingData(wtx, output_index, &ret, nullptr, nullptr, nullptr, nullptr); return ret; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 66365defaf..b116aa274b 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -634,14 +634,9 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati // Convenience method to retrieve all blinding data at once, for an ordinary non-issuance tx void GetNonIssuanceBlindingData(const CWalletTx& wtx, 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(const CWalletTx& wtx, unsigned int ouput_index) const; - //! Returns either the blinding factor (if it is to us) or 0 uint256 GetOutputAmountBlindingFactor(const CWalletTx& wtx, unsigned int output_index) const; uint256 GetOutputAssetBlindingFactor(const CWalletTx& wtx, unsigned int output_index) const; - //! Returns the underlying asset type, or 0 if unknown - CAsset GetOutputAsset(const CWalletTx& wtx, unsigned int output_index) const; //! Get the issuance CAssets for both the asset itself and the issuing tokens void GetIssuanceAssets(const CWalletTx& wtx, unsigned int vinIndex, CAsset* out_asset, CAsset* out_reissuance_token) const; // ! Return map of issued assets at input_index From b0ac1acf1e353d6fa9e797be56a3cc5fa2e32e1d Mon Sep 17 00:00:00 2001 From: Byron Hambly Date: Sun, 16 Apr 2023 11:49:48 +0000 Subject: [PATCH 4/7] wip --- src/bench/coin_selection.cpp | 2 +- src/wallet/coinselection.cpp | 12 +-- src/wallet/coinselection.h | 5 +- src/wallet/interfaces.cpp | 10 +-- src/wallet/receive.cpp | 69 +++++++++------- src/wallet/rpcdump.cpp | 5 +- src/wallet/rpcwallet.cpp | 34 ++++---- src/wallet/spend.cpp | 38 ++++----- src/wallet/spend.h | 11 ++- src/wallet/test/coinselector_tests.cpp | 12 +-- src/wallet/test/wallet_tests.cpp | 64 ++++++--------- src/wallet/transaction.h | 53 ++++++++++-- src/wallet/wallet.cpp | 104 ++++++++++++------------ src/wallet/wallet.h | 45 +--------- test/lint/lint-circular-dependencies.sh | 12 --- 15 files changed, 229 insertions(+), 247 deletions(-) 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 9338d3570d..6ba84735c3 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -61,9 +61,9 @@ WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) for (unsigned int i = 0; i < wtx.tx->vin.size(); ++i) { const auto& txin = wtx.tx->vin[i]; result.txin_is_mine.emplace_back(InputIsMine(wallet, txin)); - wallet.GetIssuanceAssets(wtx, i, &result.txin_issuance_asset[i], &result.txin_issuance_token[i]); - result.txin_issuance_asset_amount.emplace_back(wallet.GetIssuanceAmount(wtx, i, false)); - result.txin_issuance_token_amount.emplace_back(wallet.GetIssuanceAmount(wtx, i, true)); + wtx.GetIssuanceAssets(i, &result.txin_issuance_asset[i], &result.txin_issuance_token[i]); + 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()); @@ -78,8 +78,8 @@ WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) } // 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/receive.cpp b/src/wallet/receive.cpp index e9bc13d863..a62f502068 100644 --- a/src/wallet/receive.cpp +++ b/src/wallet/receive.cpp @@ -7,6 +7,7 @@ #include #include #include +#include isminetype InputIsMine(const CWallet& wallet, const CTxIn &txin) { @@ -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) { +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"); } @@ -68,7 +70,7 @@ CAmountMap GetChange(const CWallet& wallet, const CWalletTx& wtx) { CAmountMap nChange; for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i) { if (OutputIsChange(wallet, wtx.tx->vout[i])) { - CAmount change = wtx.GetOutputValueOut(i); + CAmount change = wtx.GetOutputValueOut(wallet, i); if (change < 0) { continue; } @@ -76,7 +78,7 @@ CAmountMap GetChange(const CWallet& wallet, const CWalletTx& wtx) { 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"); } @@ -135,11 +137,11 @@ CAmountMap 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) : CachedTxGetCredit(wallet, wtx, filter)); + 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) { @@ -206,8 +210,16 @@ CAmountMap CachedTxGetChange(const CWallet& wallet, const CWalletTx& wtx) 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(); @@ -242,11 +254,11 @@ CAmountMap CachedTxGetAvailableCredit(const CWallet& wallet, const CWalletTx& wt { 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(i)); + 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)] += std::max(0, wtx.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,7 +293,7 @@ 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 = wtx.GetOutputValueOut(i); + CAmount output_value = wtx.GetOutputValueOut(wallet, i); // Don't list unknown assets isminetype fIsMine = output_value != -1 ? wallet.IsMine(txout) : ISMINE_NO; // Only need to handle txouts if AT LEAST one of these is true: @@ -306,7 +318,7 @@ void CachedTxGetAmounts(const CWallet& wallet, const CWalletTx& wtx, address = CNoDestination(); } - COutputEntry output = {address, output_value, (int)i, wtx.GetOutputAsset(i), wallet.GetOutputAmountBlindingFactor(wtx, i), wallet.GetOutputAssetBlindingFactor(wtx, 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()) @@ -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,16 +539,15 @@ std::set< std::set > GetAddressGroupings(const CWallet& wallet) } // ELEMENTS -// todo: move this to wallet.cpp? -CAmountMap CWallet::GetIssuanceAssets(const CWalletTx& wtx, unsigned int input_index) const { +CAmountMap CWalletTx::GetIssuanceAssets(const CWallet& wallet, unsigned int input_index) const { CAmountMap ret; CAsset asset, token; - GetIssuanceAssets(wtx, input_index, &asset, &token); + GetIssuanceAssets(input_index, &asset, &token); if (!asset.IsNull()) { - ret[asset] = GetIssuanceAmount(wtx, input_index, false); + ret[asset] = GetIssuanceAmount(wallet, input_index, false); } if (!token.IsNull()) { - ret[token] = GetIssuanceAmount(wtx, input_index, true); + ret[token] = GetIssuanceAmount(wallet, input_index, true); } return ret; } diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 84ae1a92f5..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 (pwallet->GetIssuanceAmount(*pcoin, 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 36db3bf3f3..a918e25967 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -769,11 +769,11 @@ static CAmountMap GetReceived(const CWallet& wallet, const UniValue& params, boo if (ExtractDestination(txout.scriptPubKey, address) && wallet.IsMine(address) && address_set.count(address)) { 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; } } @@ -1259,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) @@ -3283,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); @@ -3351,8 +3351,8 @@ static RPCHelpMan listunspent() if (tx_out.nValue.IsCommitment()) { entry.pushKV("amountcommitment", HexStr(tx_out.nValue.vchCommitment)); } - entry.pushKV("amountblinder", pwallet->GetOutputAmountBlindingFactor(*out.tx, out.i).ToString()); - entry.pushKV("assetblinder", pwallet->GetOutputAssetBlindingFactor(*out.tx, 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); @@ -6489,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(pwallet->GetOutputAmountBlindingFactor(it->second, prevout.n)); - input_asset_blinds.push_back(pwallet->GetOutputAssetBlindingFactor(it->second, 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; } @@ -6904,9 +6904,9 @@ static RPCHelpMan listissuances() CalculateReissuanceToken(token, entropy, issuance.nAmount.IsCommitment()); item.pushKV("isreissuance", false); item.pushKV("token", token.GetHex()); - CAmount itamount = pwallet->GetIssuanceAmount(*pcoin, vinIndex, true); + CAmount itamount = pcoin->GetIssuanceAmount(*pwallet, vinIndex, true); item.pushKV("tokenamount", (itamount == -1 ) ? -1 : ValueFromAmount(itamount)); - item.pushKV("tokenblinds", pwallet->GetIssuanceBlindingFactor(*pcoin, vinIndex, true).GetHex()); + item.pushKV("tokenblinds", pcoin->GetIssuanceBlindingFactor(*pwallet, vinIndex, true).GetHex()); item.pushKV("entropy", entropy.GetHex()); } else { CalculateAsset(asset, issuance.assetEntropy); @@ -6920,9 +6920,9 @@ static RPCHelpMan listissuances() if (label != "") { item.pushKV("assetlabel", label); } - CAmount iaamount = pwallet->GetIssuanceAmount(*pcoin, vinIndex, false); + CAmount iaamount = pcoin->GetIssuanceAmount(*pwallet, vinIndex, false); item.pushKV("assetamount", (iaamount == -1 ) ? -1 : ValueFromAmount(iaamount)); - item.pushKV("assetblinds", pwallet->GetIssuanceBlindingFactor(*pcoin, 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 a54d91d010..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) @@ -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]; @@ -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); } @@ -541,9 +541,7 @@ bool SelectCoins(const CWallet& wallet, const std::vector& vAvailableCo } 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 @@ -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 { @@ -975,7 +973,7 @@ static bool CreateTransactionInternal( std::map::const_iterator it = wallet.mapWallet.find(presetInput.hash); CTxOut txout; if (it != wallet.mapWallet.end()) { - asset = it->second.GetOutputAsset(presetInput.n); + asset = it->second.GetOutputAsset(wallet, presetInput.n); } else if (coin_control.GetExternalOutput(presetInput, txout)) { asset = txout.nAsset.GetAsset(); } else { @@ -1383,7 +1381,7 @@ static bool CreateTransactionInternal( TxSize tx_sizes; CMutableTransaction tx_blinded = txNew; if (blind_details) { - if (!fillBlindDetails(blind_details, *wallet, 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 @@ -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 472cc0ac6b..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,8 +265,6 @@ class CWalletTx int64_t GetTxTime() const; - void WipeUnknownBlindingData(); - bool isAbandoned() const { return m_confirm.status == CWalletTx::ABANDONED; } void setAbandoned() { @@ -285,10 +283,53 @@ class CWalletTx 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 + * @param[in] vchRangeproof - The rangeproof to unwind + * @param[in] conf_value - The value to unblind + * @param[in] conf_asset - The asset to unblind + * @param[in] nonce - The nonce used to ECDH with the blinding key. This is null for issuance as blinding key is directly used as nonce + * @param[in] scriptPubKey - The script being committed to by the rangeproof + * @param[out] blinding_pubkey_out - Pointer to the recovered pubkey of the destination + * @param[out] value_out - Pointer to the CAmount where the unblinded amount will be stored + * @param[out] value_factor_out - Pointer to the recovered value blinding factor of the output + * @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 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 + // Unneeded for issuance. + 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 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(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(const CWallet& wallet, unsigned int input_index) const; + // ! Returns receiver's blinding pubkey + 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(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(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 + //! Returns either the value out (if it is known) or -1 - CAmount GetOutputValueOut(unsigned int ouput_index) const; + CAmount GetOutputValueOut(const CWallet& wallet, unsigned int ouput_index) const; //! Returns the underlying asset type, or 0 if unknown - CAsset GetOutputAsset(unsigned int output_index) const; + CAsset GetOutputAsset(const CWallet& wallet, unsigned int output_index) const; // END ELEMENTS diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index db63969d59..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,9 +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; - CAsset asset = this->GetOutputAsset(prev, txin.prevout.n); - CAmount amount = this->GetOutputValueOut(prev, txin.prevout.n); - amounts[asset] = std::max(0, amount); + amounts[prev.GetOutputAsset(*this, txin.prevout.n)] = std::max(0, prev.GetOutputValueOut(*this, txin.prevout.n)); return amounts; } } @@ -1850,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); } } } @@ -1924,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; @@ -1935,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); } @@ -2222,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); } @@ -2461,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; } } @@ -3447,10 +3446,10 @@ unsigned int CWalletTx::GetPseudoInputOffset(const unsigned int input_index, con return mapvalue_loc; } -void CWallet::SetBlindingData(const CWalletTx& wtx, const unsigned int map_index, const CPubKey& blinding_pubkey, const CAmount value, const uint256& value_factor, const CAsset& asset, const uint256& asset_factor) +void CWalletTx::SetBlindingData(const unsigned int map_index, const CPubKey& blinding_pubkey, const CAmount value, const uint256& value_factor, const CAsset& asset, const uint256& asset_factor) { if (mapValue["blindingdata"].size() < (map_index + 1) * 138) { - mapValue["blindingdata"].resize((wtx->vout.size() + GetNumIssuances(*tx)) * 138); + mapValue["blindingdata"].resize((tx->vout.size() + GetNumIssuances(*tx)) * 138); } unsigned char* it = (unsigned char*)(&mapValue["blindingdata"][0]) + 138 * map_index; @@ -3468,7 +3467,7 @@ void CWallet::SetBlindingData(const CWalletTx& wtx, const unsigned int map_index } -void CWallet::GetBlindingData(const CWalletTx& wtx, 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. @@ -3482,7 +3481,7 @@ void CWallet::GetBlindingData(const CWalletTx& wtx, const unsigned int map_index // This is really ugly, and should use CDataStream serialization instead. if (mapValue["blindingdata"].size() < (map_index + 1) * 138) { - mapValue["blindingdata"].resize((tx->vout.size() + GetNumIssuances(*wtx)) * 138); + mapValue["blindingdata"].resize((tx->vout.size() + GetNumIssuances(*tx)) * 138); } unsigned char* it = (unsigned char*)(&mapValue["blindingdata"][0]) + 138 * map_index; @@ -3504,7 +3503,7 @@ void CWallet::GetBlindingData(const CWalletTx& wtx, const unsigned int map_index 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); @@ -3524,11 +3523,11 @@ void CWallet::GetBlindingData(const CWalletTx& wtx, const unsigned int map_index if (asset_out) *asset_out = asset_tag; } -void CWallet::GetNonIssuanceBlindingData(const CWalletTx& wtx, 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 < wtx->vout.size()); - const CTxOut& out = wtx->vout[output_index]; - const CTxWitness& wit = wtx->witness; - GetBlindingData(output_index, wit.vtxoutwit.size() <= output_index ? std::vector() : wit.vtxoutwit[output_index].vchRangeproof, out.nValue, out.nAsset, out.nNonce, out.scriptPubKey, +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(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); } @@ -3738,39 +3737,39 @@ ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const Flat return spk_man; } -CAmount CWalletTx::GetOutputValueOut(unsigned int output_index) { +CAmount CWalletTx::GetOutputValueOut(const CWallet& wallet, unsigned int output_index) const { CAmount ret; - GetNonIssuanceBlindingData(*this, output_index, nullptr, &ret, nullptr, nullptr, nullptr); + GetNonIssuanceBlindingData(wallet, output_index, nullptr, &ret, nullptr, nullptr, nullptr); return ret; } -uint256 CWallet::GetOutputAmountBlindingFactor(const CWalletTx& wtx, unsigned int output_index) { +uint256 CWalletTx::GetOutputAmountBlindingFactor(const CWallet& wallet, unsigned int output_index) const { uint256 ret; - GetNonIssuanceBlindingData(wtx, output_index, nullptr, nullptr, &ret, nullptr, nullptr); + GetNonIssuanceBlindingData(wallet, output_index, nullptr, nullptr, &ret, nullptr, nullptr); return ret; } -uint256 CWallet::GetOutputAssetBlindingFactor(const CWalletTx& wtx, unsigned int output_index) { +uint256 CWalletTx::GetOutputAssetBlindingFactor(const CWallet& wallet, unsigned int output_index) const { uint256 ret; - GetNonIssuanceBlindingData(wtx, 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) { +CAsset CWalletTx::GetOutputAsset(const CWallet& wallet, unsigned int output_index) const { CAsset ret; - GetNonIssuanceBlindingData(*this, output_index, nullptr, nullptr, nullptr, &ret, nullptr); + GetNonIssuanceBlindingData(wallet, output_index, nullptr, nullptr, nullptr, &ret, nullptr); return ret; } -CPubKey CWallet::GetOutputBlindingPubKey(const CWalletTx& wtx, unsigned int output_index) { +CPubKey CWalletTx::GetOutputBlindingPubKey(const CWallet& wallet, unsigned int output_index) const { CPubKey ret; - GetNonIssuanceBlindingData(wtx, output_index, &ret, nullptr, nullptr, nullptr, nullptr); + GetNonIssuanceBlindingData(wallet, output_index, &ret, nullptr, nullptr, nullptr, nullptr); return ret; } -void CWallet::GetIssuanceAssets(const CWalletTx& wtx, unsigned int input_index, CAsset* out_asset, CAsset* out_reissuance_token) const { - assert(input_index < wtx->vin.size()); - const CAssetIssuance& issuance = wtx->vin[input_index].assetIssuance; +void CWalletTx::GetIssuanceAssets(unsigned int input_index, CAsset* out_asset, CAsset* out_reissuance_token) const { + assert(input_index < tx->vin.size()); + const CAssetIssuance& issuance = tx->vin[input_index].assetIssuance; if (out_asset && issuance.nAmount.IsNull()) { out_asset->SetNull(); @@ -3784,7 +3783,7 @@ void CWallet::GetIssuanceAssets(const CWalletTx& wtx, unsigned int input_index, if (issuance.assetBlindingNonce.IsNull()) { uint256 entropy; - GenerateAssetEntropy(entropy, wtx->vin[input_index].prevout, issuance.assetEntropy); + GenerateAssetEntropy(entropy, tx->vin[input_index].prevout, issuance.assetEntropy); if (out_reissuance_token) { CalculateReissuanceToken(*out_reissuance_token, entropy, issuance.nAmount.IsCommitment()); } @@ -3803,7 +3802,7 @@ void CWallet::GetIssuanceAssets(const CWalletTx& wtx, unsigned int input_index, } } -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; @@ -3813,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; @@ -3830,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; } @@ -3867,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; } } @@ -3916,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 b116aa274b..784817c4bf 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -608,50 +609,6 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati /** Pass this transaction to node for mempool insertion and relay to peers if flag set to true */ bool SubmitTxMemoryPoolAndRelay(const CWalletTx& wtx, std::string& err_string, bool relay) const; - // 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 - * @param[in] vchRangeproof - The rangeproof to unwind - * @param[in] conf_value - The value to unblind - * @param[in] conf_asset - The asset to unblind - * @param[in] nonce - The nonce used to ECDH with the blinding key. This is null for issuance as blinding key is directly used as nonce - * @param[in] scriptPubKey - The script being committed to by the rangeproof - * @param[out] blinding_pubkey_out - Pointer to the recovered pubkey of the destination - * @param[out] value_out - Pointer to the CAmount where the unblinded amount will be stored - * @param[out] value_factor_out - Pointer to the recovered value blinding factor of the output - * @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 CWalletTx& wtx, 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(); - -public: - // For use in wallet transaction creation to remember 3rd party values - // Unneeded for issuance. - void SetBlindingData(const CWalletTx& wtx, 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 CWalletTx& wtx, 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(const CWalletTx& wtx, unsigned int output_index) const; - uint256 GetOutputAssetBlindingFactor(const CWalletTx& wtx, unsigned int output_index) const; - //! Get the issuance CAssets for both the asset itself and the issuing tokens - void GetIssuanceAssets(const CWalletTx& wtx, unsigned int vinIndex, CAsset* out_asset, CAsset* out_reissuance_token) const; - // ! Return map of issued assets at input_index - CAmountMap GetIssuanceAssets(const CWalletTx& wtx, unsigned int input_index) const; - // ! Returns receiver's blinding pubkey - CPubKey GetOutputBlindingPubKey(const CWalletTx& wtx, unsigned int output_index) const; - //! Get the issuance blinder for either the asset itself or the issuing tokens - uint256 GetIssuanceBlindingFactor(const CWalletTx& wtx, unsigned int input_index, bool reissuance_token) const; - //! Get the issuance amount for either the asset itself or the issuing tokens - CAmount GetIssuanceAmount(const CWalletTx& wtx, 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(const CWalletTx& wtx, unsigned int input_index, bool reissuance_token) const; - // END ELEMENTS - bool DummySignTx(CMutableTransaction &txNew, const std::set &txouts, const CCoinControl* coin_control = nullptr) const { std::vector v_txouts(txouts.size()); 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 From fdcd91194ef370d486875376e6a73d03eaec0cf3 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 19 Jan 2022 15:21:25 -0500 Subject: [PATCH 5/7] fs: Make compatible with boost 1.78 backport of https://github.com/bitcoin/bitcoin/pull/24104 --- src/wallet/load.cpp | 2 +- test/functional/wallet_multiwallet.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/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) From b92eb547d8587787e2d9080ca08e9830431292eb Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 8 Dec 2021 14:14:15 -0500 Subject: [PATCH 6/7] Add pure Python RIPEMD-160 --- test/functional/test_framework/ripemd160.py | 130 ++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 test/functional/test_framework/ripemd160.py 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) From 0d01592217d26df6fb8406a777083d79df6c43e8 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 8 Dec 2021 14:17:08 -0500 Subject: [PATCH 7/7] Swap out hashlib.ripemd160 for own implementation Github-Pull: 23716 Rebased-From: 5b559dc7ecf37ab1604b75ec8ffe8436377a5fb1 --- test/functional/test_framework/script.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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."""