@@ -965,15 +965,12 @@ static void DiscourageFeeSniping(CMutableTransaction& tx, FastRandomContext& rng
965965static util::Result<CreatedTransactionResult> CreateTransactionInternal (
966966 CWallet& wallet,
967967 const std::vector<CRecipient>& vecSend,
968- int change_pos,
968+ std::optional< unsigned int > change_pos,
969969 const CCoinControl& coin_control,
970970 bool sign) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
971971{
972972 AssertLockHeld (wallet.cs_wallet );
973973
974- // out variables, to be packed into returned result structure
975- int nChangePosInOut = change_pos;
976-
977974 FastRandomContext rng_fast;
978975 CMutableTransaction txNew; // The resulting transaction that we make
979976
@@ -1132,15 +1129,15 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
11321129 const CAmount change_amount = result.GetChange (coin_selection_params.min_viable_change , coin_selection_params.m_change_fee );
11331130 if (change_amount > 0 ) {
11341131 CTxOut newTxOut (change_amount, scriptChange);
1135- if (nChangePosInOut == - 1 ) {
1132+ if (!change_pos ) {
11361133 // Insert change txn at random position:
1137- nChangePosInOut = rng_fast.randrange (txNew.vout .size () + 1 );
1138- } else if ((unsigned int )nChangePosInOut > txNew.vout .size ()) {
1134+ change_pos = rng_fast.randrange (txNew.vout .size () + 1 );
1135+ } else if ((unsigned int )*change_pos > txNew.vout .size ()) {
11391136 return util::Error{_ (" Transaction change output index out of range" )};
11401137 }
1141- txNew.vout .insert (txNew.vout .begin () + nChangePosInOut , newTxOut);
1138+ txNew.vout .insert (txNew.vout .begin () + *change_pos , newTxOut);
11421139 } else {
1143- nChangePosInOut = - 1 ;
1140+ change_pos = std:: nullopt ;
11441141 }
11451142
11461143 // Shuffle selected coins and fill in final vin
@@ -1217,8 +1214,8 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
12171214 }
12181215
12191216 // If there is a change output and we overpay the fees then increase the change to match the fee needed
1220- if (nChangePosInOut != - 1 && fee_needed < current_fee) {
1221- auto & change = txNew.vout .at (nChangePosInOut );
1217+ if (change_pos && fee_needed < current_fee) {
1218+ auto & change = txNew.vout .at (*change_pos );
12221219 change.nValue += current_fee - fee_needed;
12231220 current_fee = result.GetSelectedValue () - CalculateOutputValue (txNew);
12241221 if (fee_needed != current_fee) {
@@ -1229,11 +1226,11 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
12291226 // Reduce output values for subtractFeeFromAmount
12301227 if (coin_selection_params.m_subtract_fee_outputs ) {
12311228 CAmount to_reduce = fee_needed - current_fee;
1232- int i = 0 ;
1229+ unsigned int i = 0 ;
12331230 bool fFirst = true ;
12341231 for (const auto & recipient : vecSend)
12351232 {
1236- if (i == nChangePosInOut ) {
1233+ if (change_pos && i == *change_pos ) {
12371234 ++i;
12381235 }
12391236 CTxOut& txout = txNew.vout [i];
@@ -1272,7 +1269,7 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
12721269 }
12731270
12741271 // Give up if change keypool ran out and change is required
1275- if (scriptChange.empty () && nChangePosInOut != - 1 ) {
1272+ if (scriptChange.empty () && change_pos ) {
12761273 return util::Error{error};
12771274 }
12781275
@@ -1313,13 +1310,13 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
13131310 feeCalc.est .fail .start , feeCalc.est .fail .end ,
13141311 (feeCalc.est .fail .totalConfirmed + feeCalc.est .fail .inMempool + feeCalc.est .fail .leftMempool ) > 0.0 ? 100 * feeCalc.est .fail .withinTarget / (feeCalc.est .fail .totalConfirmed + feeCalc.est .fail .inMempool + feeCalc.est .fail .leftMempool ) : 0.0 ,
13151312 feeCalc.est .fail .withinTarget , feeCalc.est .fail .totalConfirmed , feeCalc.est .fail .inMempool , feeCalc.est .fail .leftMempool );
1316- return CreatedTransactionResult (tx, current_fee, nChangePosInOut , feeCalc);
1313+ return CreatedTransactionResult (tx, current_fee, change_pos , feeCalc);
13171314}
13181315
13191316util::Result<CreatedTransactionResult> CreateTransaction (
13201317 CWallet& wallet,
13211318 const std::vector<CRecipient>& vecSend,
1322- int change_pos,
1319+ std::optional< unsigned int > change_pos,
13231320 const CCoinControl& coin_control,
13241321 bool sign)
13251322{
@@ -1335,7 +1332,7 @@ util::Result<CreatedTransactionResult> CreateTransaction(
13351332
13361333 auto res = CreateTransactionInternal (wallet, vecSend, change_pos, coin_control, sign);
13371334 TRACE4 (coin_selection, normal_create_tx_internal, wallet.GetName ().c_str (), bool (res),
1338- res ? res->fee : 0 , res ? res->change_pos : 0 );
1335+ res ? res->fee : 0 , res && res-> change_pos . has_value () ? * res->change_pos : 0 );
13391336 if (!res) return res;
13401337 const auto & txr_ungrouped = *res;
13411338 // try with avoidpartialspends unless it's enabled already
@@ -1345,16 +1342,15 @@ util::Result<CreatedTransactionResult> CreateTransaction(
13451342 tmp_cc.m_avoid_partial_spends = true ;
13461343
13471344 // Reuse the change destination from the first creation attempt to avoid skipping BIP44 indexes
1348- const int ungrouped_change_pos = txr_ungrouped.change_pos ;
1349- if (ungrouped_change_pos != -1 ) {
1350- ExtractDestination (txr_ungrouped.tx ->vout [ungrouped_change_pos].scriptPubKey , tmp_cc.destChange );
1345+ if (txr_ungrouped.change_pos ) {
1346+ ExtractDestination (txr_ungrouped.tx ->vout [*txr_ungrouped.change_pos ].scriptPubKey , tmp_cc.destChange );
13511347 }
13521348
13531349 auto txr_grouped = CreateTransactionInternal (wallet, vecSend, change_pos, tmp_cc, sign);
13541350 // if fee of this alternative one is within the range of the max fee, we use this one
13551351 const bool use_aps{txr_grouped.has_value () ? (txr_grouped->fee <= txr_ungrouped.fee + wallet.m_max_aps_fee ) : false };
13561352 TRACE5 (coin_selection, aps_create_tx_internal, wallet.GetName ().c_str (), use_aps, txr_grouped.has_value (),
1357- txr_grouped.has_value () ? txr_grouped->fee : 0 , txr_grouped.has_value () ? txr_grouped->change_pos : 0 );
1353+ txr_grouped.has_value () ? txr_grouped->fee : 0 , txr_grouped.has_value () && txr_grouped-> change_pos . has_value () ? * txr_grouped->change_pos : 0 );
13581354 if (txr_grouped) {
13591355 wallet.WalletLogPrintf (" Fee non-grouped = %lld, grouped = %lld, using %s\n " ,
13601356 txr_ungrouped.fee , txr_grouped->fee , use_aps ? " grouped" : " non-grouped" );
@@ -1412,15 +1408,15 @@ bool FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& nFeeRet,
14121408 preset_txin.SetScriptWitness (txin.scriptWitness );
14131409 }
14141410
1415- auto res = CreateTransaction (wallet, vecSend, nChangePosInOut, coinControl, false );
1411+ auto res = CreateTransaction (wallet, vecSend, nChangePosInOut == - 1 ? std:: nullopt : std::optional< unsigned int >(( unsigned int )nChangePosInOut) , coinControl, false );
14161412 if (!res) {
14171413 error = util::ErrorString (res);
14181414 return false ;
14191415 }
14201416 const auto & txr = *res;
14211417 CTransactionRef tx_new = txr.tx ;
14221418 nFeeRet = txr.fee ;
1423- nChangePosInOut = txr.change_pos ;
1419+ nChangePosInOut = txr.change_pos ? *txr. change_pos : - 1 ;
14241420
14251421 if (nChangePosInOut != -1 ) {
14261422 tx.vout .insert (tx.vout .begin () + nChangePosInOut, tx_new->vout [nChangePosInOut]);
0 commit comments