Skip to content

Commit 44c21c1

Browse files
josibakeEunovo
authored andcommitted
use silent payments change when sending
1 parent 9504d17 commit 44c21c1

File tree

2 files changed

+36
-20
lines changed

2 files changed

+36
-20
lines changed

src/wallet/spend.cpp

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,12 +1180,12 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
11801180
}
11811181

11821182
// Create change script that will be used if we need change
1183-
CScript scriptChange;
1183+
CTxDestination change_dest;
11841184
bilingual_str error; // possible error str
11851185

11861186
// coin control: send change to custom address
11871187
if (!std::get_if<CNoDestination>(&coin_control.destChange)) {
1188-
scriptChange = GetScriptForDestination(coin_control.destChange);
1188+
change_dest = coin_control.destChange;
11891189
} else { // no coin control: send change to newly generated address
11901190
// Note: We use a new key here to keep it from being obvious which side is the change.
11911191
// The drawback is that by not reusing a previous key, the change may be lost if a
@@ -1196,20 +1196,18 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
11961196

11971197
// Reserve a new key pair from key pool. If it fails, provide a dummy
11981198
// destination in case we don't need change.
1199-
CTxDestination dest;
12001199
auto op_dest = reservedest.GetReservedDestination(true);
12011200
if (!op_dest) {
12021201
error = _("Transaction needs a change address, but we can't generate it.") + Untranslated(" ") + util::ErrorString(op_dest);
12031202
} else {
1204-
dest = *op_dest;
1205-
scriptChange = GetScriptForDestination(dest);
1203+
change_dest = *op_dest;
12061204
}
1207-
// A valid destination implies a change script (and
1208-
// vice-versa). An empty change script will abort later, if the
1209-
// change keypool ran out, but change is required.
1210-
CHECK_NONFATAL(IsValidDestination(dest) != scriptChange.empty());
12111205
}
1212-
CTxOut change_prototype_txout(0, scriptChange);
1206+
CScript change_prototype_script = GetScriptForDestination(change_dest);
1207+
if (std::get_if<V0SilentPaymentDestination>(&change_dest)) {
1208+
change_prototype_script = GetScriptForDestination(WitnessV1Taproot());
1209+
}
1210+
CTxOut change_prototype_txout(0, change_prototype_script);
12131211
coin_selection_params.change_output_size = GetSerializeSize(change_prototype_txout);
12141212

12151213
// Get size of spending the change output
@@ -1314,17 +1312,33 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
13141312
assert(out_idx < mutableVecSend.size());
13151313
mutableVecSend[out_idx].dest = tr_dest;
13161314
}
1317-
13181315
}
13191316
// vouts to the payees
13201317
txNew.vout.reserve(vecSend.size() + 1); // + 1 because of possible later insert
1321-
for (const auto& recipient : mutableVecSend)
1322-
{
1318+
for (const auto& recipient : mutableVecSend) {
13231319
txNew.vout.emplace_back(recipient.nAmount, GetScriptForDestination(recipient.dest));
13241320
}
13251321
const CAmount change_amount = result.GetChange(coin_selection_params.min_viable_change, coin_selection_params.m_change_fee);
13261322
if (change_amount > 0) {
1327-
CTxOut newTxOut(change_amount, scriptChange);
1323+
// Give up if change keypool ran out as change is required
1324+
if (!IsValidDestination(change_dest)) {
1325+
return util::Error{error};
1326+
}
1327+
if (const auto* sp = std::get_if<V0SilentPaymentDestination>(&change_dest)) {
1328+
// Since we will be getting the final destination
1329+
// for only the change output, the index doesn't matter.
1330+
std::map<size_t, V0SilentPaymentDestination> change_sp_dest;
1331+
change_sp_dest[0] = *sp;
1332+
auto taproot_change = CreateSilentPaymentOutputs(wallet, change_sp_dest, result.GetInputSet(), error);
1333+
if (taproot_change.has_value()) {
1334+
change_dest = taproot_change->at(0);
1335+
}
1336+
}
1337+
1338+
CScript change_script = GetScriptForDestination(change_dest);
1339+
Assert(!change_script.empty());
1340+
1341+
CTxOut newTxOut(change_amount, change_script);
13281342
if (!change_pos) {
13291343
// Insert change txn at random position:
13301344
change_pos = rng_fast.randrange(txNew.vout.size() + 1);
@@ -1465,11 +1479,6 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
14651479
return util::Error{Untranslated(STR_INTERNAL_BUG("Fee needed > fee paid"))};
14661480
}
14671481

1468-
// Give up if change keypool ran out and change is required
1469-
if (scriptChange.empty() && change_pos) {
1470-
return util::Error{error};
1471-
}
1472-
14731482
if (sign && !wallet.SignTransaction(txNew)) {
14741483
return util::Error{_("Signing transaction failed")};
14751484
}

src/wallet/wallet.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2258,13 +2258,16 @@ OutputType CWallet::TransactionChangeType(const std::optional<OutputType>& chang
22582258
return OutputType::LEGACY;
22592259
}
22602260

2261+
bool any_sp{false};
22612262
bool any_tr{false};
22622263
bool any_wpkh{false};
22632264
bool any_sh{false};
22642265
bool any_pkh{false};
22652266

22662267
for (const auto& recipient : vecSend) {
2267-
if (std::get_if<WitnessV1Taproot>(&recipient.dest) || std::get_if<V0SilentPaymentDestination>(&recipient.dest)) {
2268+
if (std::get_if<V0SilentPaymentDestination>(&recipient.dest)) {
2269+
any_sp = true;
2270+
} else if (std::get_if<WitnessV1Taproot>(&recipient.dest)) {
22682271
any_tr = true;
22692272
} else if (std::get_if<WitnessV0KeyHash>(&recipient.dest)) {
22702273
any_wpkh = true;
@@ -2275,6 +2278,10 @@ OutputType CWallet::TransactionChangeType(const std::optional<OutputType>& chang
22752278
}
22762279
}
22772280

2281+
const bool has_sp_spkman(GetScriptPubKeyMan(OutputType::SILENT_PAYMENTS, /*internal=*/true));
2282+
if (has_sp_spkman && any_sp) {
2283+
return OutputType::SILENT_PAYMENTS;
2284+
}
22782285
const bool has_bech32m_spkman(GetScriptPubKeyMan(OutputType::BECH32M, /*internal=*/true));
22792286
if (has_bech32m_spkman && any_tr) {
22802287
// Currently tr is the only type supported by the BECH32M spkman

0 commit comments

Comments
 (0)