aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Chow <achow101-github@achow101.com>2021-12-20 14:40:00 -0500
committerAndrew Chow <achow101-github@achow101.com>2021-12-20 14:48:22 -0500
commit3ac38058ce0e80a9f4276bfa82951decdb237e9a (patch)
treea0bb6697b1fd82fac83cb6431635d11a30dc74f4 /src
parent9ac064d245f0fd4cb0362cfc472b65836328bffe (diff)
parentfada6c65d23f7bd4682fac281026612b835c4f8b (diff)
downloadbitcoin-3ac38058ce0e80a9f4276bfa82951decdb237e9a.tar.xz
Merge bitcoin/bitcoin#23789: wallet: Strictly match tx change type to improve privacy
fada6c65d23f7bd4682fac281026612b835c4f8b wallet: Strictly match tx change type to improve privacy (MarcoFalke) Pull request description: Currently the change type will only match a destination by accident, making it easier to determine the change. Fix that by strictly matching one of the destinations. ACKs for top commit: S3RK: Concept & Approach ACK fada6c6. Also did light code review . achow101: ACK fada6c65d23f7bd4682fac281026612b835c4f8b prayank23: tACK https://github.com/bitcoin/bitcoin/pull/23789/commits/fada6c65d23f7bd4682fac281026612b835c4f8b w0xlt: tACK fada6c6 Tree-SHA512: 2b072c3c32debac7b0bef07a6df9a8f1a631e0f7d556b859973f18894ca490225582dc13e4588b29fa205ffbcd30fb632d5313b304d10ad17a26adc3f7684471
Diffstat (limited to 'src')
-rw-r--r--src/wallet/wallet.cpp61
1 files changed, 45 insertions, 16 deletions
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index decdbc7090..6e1552abd7 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1967,29 +1967,58 @@ OutputType CWallet::TransactionChangeType(const std::optional<OutputType>& chang
return *change_type;
}
- // if m_default_address_type is legacy, use legacy address as change (even
- // if some of the outputs are P2WPKH or P2WSH).
+ // if m_default_address_type is legacy, use legacy address as change.
if (m_default_address_type == OutputType::LEGACY) {
return OutputType::LEGACY;
}
- // if any destination is P2WPKH or P2WSH, use P2WPKH for the change
- // output.
+ bool any_tr{false};
+ bool any_wpkh{false};
+ bool any_sh{false};
+ bool any_pkh{false};
+
for (const auto& recipient : vecSend) {
- // Check if any destination contains a witness program:
- int witnessversion = 0;
- std::vector<unsigned char> witnessprogram;
- if (recipient.scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
- if (GetScriptPubKeyMan(OutputType::BECH32M, true)) {
- return OutputType::BECH32M;
- } else if (GetScriptPubKeyMan(OutputType::BECH32, true)) {
- return OutputType::BECH32;
- } else {
- return m_default_address_type;
- }
- }
+ std::vector<std::vector<uint8_t>> dummy;
+ const TxoutType type{Solver(recipient.scriptPubKey, dummy)};
+ if (type == TxoutType::WITNESS_V1_TAPROOT) {
+ any_tr = true;
+ } else if (type == TxoutType::WITNESS_V0_KEYHASH) {
+ any_wpkh = true;
+ } else if (type == TxoutType::SCRIPTHASH) {
+ any_sh = true;
+ } else if (type == TxoutType::PUBKEYHASH) {
+ any_pkh = true;
+ }
+ }
+
+ const bool has_bech32m_spkman(GetScriptPubKeyMan(OutputType::BECH32M, /*internal=*/true));
+ if (has_bech32m_spkman && any_tr) {
+ // Currently tr is the only type supported by the BECH32M spkman
+ return OutputType::BECH32M;
+ }
+ const bool has_bech32_spkman(GetScriptPubKeyMan(OutputType::BECH32, /*internal=*/true));
+ if (has_bech32_spkman && any_wpkh) {
+ // Currently wpkh is the only type supported by the BECH32 spkman
+ return OutputType::BECH32;
+ }
+ const bool has_p2sh_segwit_spkman(GetScriptPubKeyMan(OutputType::P2SH_SEGWIT, /*internal=*/true));
+ if (has_p2sh_segwit_spkman && any_sh) {
+ // Currently sh_wpkh is the only type supported by the P2SH_SEGWIT spkman
+ // As of 2021 about 80% of all SH are wrapping WPKH, so use that
+ return OutputType::P2SH_SEGWIT;
+ }
+ const bool has_legacy_spkman(GetScriptPubKeyMan(OutputType::LEGACY, /*internal=*/true));
+ if (has_legacy_spkman && any_pkh) {
+ // Currently pkh is the only type supported by the LEGACY spkman
+ return OutputType::LEGACY;
}
+ if (has_bech32m_spkman) {
+ return OutputType::BECH32M;
+ }
+ if (has_bech32_spkman) {
+ return OutputType::BECH32;
+ }
// else use m_default_address_type for change
return m_default_address_type;
}