@@ -656,18 +656,16 @@ static void DiscourageFeeSniping(CMutableTransaction& tx, FastRandomContext& rng
656
656
}
657
657
}
658
658
659
- static std::optional <CreatedTransactionResult> CreateTransactionInternal (
659
+ static BResult <CreatedTransactionResult> CreateTransactionInternal (
660
660
CWallet& wallet,
661
661
const std::vector<CRecipient>& vecSend,
662
662
int change_pos,
663
- bilingual_str& error,
664
663
const CCoinControl& coin_control,
665
664
bool sign) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
666
665
{
667
666
AssertLockHeld (wallet.cs_wallet );
668
667
669
668
// out variables, to be packed into returned result structure
670
- CTransactionRef tx;
671
669
CAmount nFeeRet;
672
670
int nChangePosInOut = change_pos;
673
671
@@ -696,6 +694,7 @@ static std::optional<CreatedTransactionResult> CreateTransactionInternal(
696
694
697
695
// Create change script that will be used if we need change
698
696
CScript scriptChange;
697
+ bilingual_str error; // possible error str
699
698
700
699
// coin control: send change to custom address
701
700
if (!std::get_if<CNoDestination>(&coin_control.destChange )) {
@@ -743,13 +742,11 @@ static std::optional<CreatedTransactionResult> CreateTransactionInternal(
743
742
// Do not, ever, assume that it's fine to change the fee rate if the user has explicitly
744
743
// provided one
745
744
if (coin_control.m_feerate && coin_selection_params.m_effective_feerate > *coin_control.m_feerate ) {
746
- error = strprintf (_ (" Fee rate (%s) is lower than the minimum fee rate setting (%s)" ), coin_control.m_feerate ->ToString (FeeEstimateMode::SAT_VB), coin_selection_params.m_effective_feerate .ToString (FeeEstimateMode::SAT_VB));
747
- return std::nullopt;
745
+ return strprintf (_ (" Fee rate (%s) is lower than the minimum fee rate setting (%s)" ), coin_control.m_feerate ->ToString (FeeEstimateMode::SAT_VB), coin_selection_params.m_effective_feerate .ToString (FeeEstimateMode::SAT_VB));
748
746
}
749
747
if (feeCalc.reason == FeeReason::FALLBACK && !wallet.m_allow_fallback_fee ) {
750
748
// eventually allow a fallback fee
751
- error = _ (" Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee." );
752
- return std::nullopt;
749
+ return _ (" Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee." );
753
750
}
754
751
755
752
// Calculate the cost of change
@@ -774,10 +771,8 @@ static std::optional<CreatedTransactionResult> CreateTransactionInternal(
774
771
coin_selection_params.tx_noinputs_size += ::GetSerializeSize (txout, PROTOCOL_VERSION);
775
772
}
776
773
777
- if (IsDust (txout, wallet.chain ().relayDustFee ()))
778
- {
779
- error = _ (" Transaction amount too small" );
780
- return std::nullopt;
774
+ if (IsDust (txout, wallet.chain ().relayDustFee ())) {
775
+ return _ (" Transaction amount too small" );
781
776
}
782
777
txNew.vout .push_back (txout);
783
778
}
@@ -798,8 +793,7 @@ static std::optional<CreatedTransactionResult> CreateTransactionInternal(
798
793
// Choose coins to use
799
794
std::optional<SelectionResult> result = SelectCoins (wallet, res_available_coins.coins , /* nTargetValue=*/ selection_target, coin_control, coin_selection_params);
800
795
if (!result) {
801
- error = _ (" Insufficient funds" );
802
- return std::nullopt;
796
+ return _ (" Insufficient funds" );
803
797
}
804
798
TRACE5 (coin_selection, selected_coins, wallet.GetName ().c_str (), GetAlgorithmName (result->m_algo ).c_str (), result->m_target , result->GetWaste (), result->GetSelectedValue ());
805
799
@@ -813,10 +807,8 @@ static std::optional<CreatedTransactionResult> CreateTransactionInternal(
813
807
// Insert change txn at random position:
814
808
nChangePosInOut = rng_fast.randrange (txNew.vout .size () + 1 );
815
809
}
816
- else if ((unsigned int )nChangePosInOut > txNew.vout .size ())
817
- {
818
- error = _ (" Transaction change output index out of range" );
819
- return std::nullopt;
810
+ else if ((unsigned int )nChangePosInOut > txNew.vout .size ()) {
811
+ return _ (" Transaction change output index out of range" );
820
812
}
821
813
822
814
assert (nChangePosInOut != -1 );
@@ -843,8 +835,7 @@ static std::optional<CreatedTransactionResult> CreateTransactionInternal(
843
835
TxSize tx_sizes = CalculateMaximumSignedTxSize (CTransaction (txNew), &wallet, &coin_control);
844
836
int nBytes = tx_sizes.vsize ;
845
837
if (nBytes == -1 ) {
846
- error = _ (" Missing solving data for estimating transaction size" );
847
- return std::nullopt;
838
+ return _ (" Missing solving data for estimating transaction size" );
848
839
}
849
840
nFeeRet = coin_selection_params.m_effective_feerate .GetFee (nBytes);
850
841
@@ -904,11 +895,10 @@ static std::optional<CreatedTransactionResult> CreateTransactionInternal(
904
895
// Error if this output is reduced to be below dust
905
896
if (IsDust (txout, wallet.chain ().relayDustFee ())) {
906
897
if (txout.nValue < 0 ) {
907
- error = _ (" The transaction amount is too small to pay the fee" );
898
+ return _ (" The transaction amount is too small to pay the fee" );
908
899
} else {
909
- error = _ (" The transaction amount is too small to send after the fee has been deducted" );
900
+ return _ (" The transaction amount is too small to send after the fee has been deducted" );
910
901
}
911
- return std::nullopt;
912
902
}
913
903
}
914
904
++i;
@@ -918,35 +908,31 @@ static std::optional<CreatedTransactionResult> CreateTransactionInternal(
918
908
919
909
// Give up if change keypool ran out and change is required
920
910
if (scriptChange.empty () && nChangePosInOut != -1 ) {
921
- return std::nullopt ;
911
+ return error ;
922
912
}
923
913
924
914
if (sign && !wallet.SignTransaction (txNew)) {
925
- error = _ (" Signing transaction failed" );
926
- return std::nullopt;
915
+ return _ (" Signing transaction failed" );
927
916
}
928
917
929
918
// Return the constructed transaction data.
930
- tx = MakeTransactionRef (std::move (txNew));
919
+ CTransactionRef tx = MakeTransactionRef (std::move (txNew));
931
920
932
921
// Limit size
933
922
if ((sign && GetTransactionWeight (*tx) > MAX_STANDARD_TX_WEIGHT) ||
934
923
(!sign && tx_sizes.weight > MAX_STANDARD_TX_WEIGHT))
935
924
{
936
- error = _ (" Transaction too large" );
937
- return std::nullopt;
925
+ return _ (" Transaction too large" );
938
926
}
939
927
940
928
if (nFeeRet > wallet.m_default_max_tx_fee ) {
941
- error = TransactionErrorString (TransactionError::MAX_FEE_EXCEEDED);
942
- return std::nullopt;
929
+ return TransactionErrorString (TransactionError::MAX_FEE_EXCEEDED);
943
930
}
944
931
945
932
if (gArgs .GetBoolArg (" -walletrejectlongchains" , DEFAULT_WALLET_REJECT_LONG_CHAINS)) {
946
933
// Lastly, ensure this tx will pass the mempool's chain limits
947
934
if (!wallet.chain ().checkChainLimits (tx)) {
948
- error = _ (" Transaction has too long of a mempool chain" );
949
- return std::nullopt;
935
+ return _ (" Transaction has too long of a mempool chain" );
950
936
}
951
937
}
952
938
@@ -965,48 +951,47 @@ static std::optional<CreatedTransactionResult> CreateTransactionInternal(
965
951
return CreatedTransactionResult (tx, nFeeRet, nChangePosInOut, feeCalc);
966
952
}
967
953
968
- std::optional <CreatedTransactionResult> CreateTransaction (
954
+ BResult <CreatedTransactionResult> CreateTransaction (
969
955
CWallet& wallet,
970
956
const std::vector<CRecipient>& vecSend,
971
957
int change_pos,
972
- bilingual_str& error,
973
958
const CCoinControl& coin_control,
974
959
bool sign)
975
960
{
976
961
if (vecSend.empty ()) {
977
- error = _ (" Transaction must have at least one recipient" );
978
- return std::nullopt;
962
+ return _ (" Transaction must have at least one recipient" );
979
963
}
980
964
981
965
if (std::any_of (vecSend.cbegin (), vecSend.cend (), [](const auto & recipient){ return recipient.nAmount < 0 ; })) {
982
- error = _ (" Transaction amounts must not be negative" );
983
- return std::nullopt;
966
+ return _ (" Transaction amounts must not be negative" );
984
967
}
985
968
986
969
LOCK (wallet.cs_wallet );
987
970
988
- std::optional<CreatedTransactionResult> txr_ungrouped = CreateTransactionInternal (wallet, vecSend, change_pos, error, coin_control, sign);
989
- TRACE4 (coin_selection, normal_create_tx_internal, wallet.GetName ().c_str (), txr_ungrouped.has_value (),
990
- txr_ungrouped.has_value () ? txr_ungrouped->fee : 0 , txr_ungrouped.has_value () ? txr_ungrouped->change_pos : 0 );
991
- if (!txr_ungrouped) return std::nullopt;
971
+ auto res = CreateTransactionInternal (wallet, vecSend, change_pos, coin_control, sign);
972
+ TRACE4 (coin_selection, normal_create_tx_internal, wallet.GetName ().c_str (), res.HasRes (),
973
+ res ? res.GetObj ().fee : 0 , res ? res.GetObj ().change_pos : 0 );
974
+ if (!res) return res;
975
+ const auto & txr_ungrouped = res.GetObj ();
992
976
// try with avoidpartialspends unless it's enabled already
993
- if (txr_ungrouped-> fee > 0 /* 0 means non-functional fee rate estimation */ && wallet.m_max_aps_fee > -1 && !coin_control.m_avoid_partial_spends ) {
977
+ if (txr_ungrouped. fee > 0 /* 0 means non-functional fee rate estimation */ && wallet.m_max_aps_fee > -1 && !coin_control.m_avoid_partial_spends ) {
994
978
TRACE1 (coin_selection, attempting_aps_create_tx, wallet.GetName ().c_str ());
995
979
CCoinControl tmp_cc = coin_control;
996
980
tmp_cc.m_avoid_partial_spends = true ;
997
- bilingual_str error2; // fired and forgotten; if an error occurs, we discard the results
998
- std::optional<CreatedTransactionResult> txr_grouped = CreateTransactionInternal (wallet, vecSend, change_pos, error2, tmp_cc, sign);
981
+ auto res_tx_grouped = CreateTransactionInternal (wallet, vecSend, change_pos, tmp_cc, sign);
982
+ // Helper optional class for now
983
+ std::optional<CreatedTransactionResult> txr_grouped{res_tx_grouped.HasRes () ? std::make_optional (res_tx_grouped.GetObj ()) : std::nullopt};
999
984
// if fee of this alternative one is within the range of the max fee, we use this one
1000
- const bool use_aps{txr_grouped.has_value () ? (txr_grouped->fee <= txr_ungrouped-> fee + wallet.m_max_aps_fee ) : false };
985
+ const bool use_aps{txr_grouped.has_value () ? (txr_grouped->fee <= txr_ungrouped. fee + wallet.m_max_aps_fee ) : false };
1001
986
TRACE5 (coin_selection, aps_create_tx_internal, wallet.GetName ().c_str (), use_aps, txr_grouped.has_value (),
1002
987
txr_grouped.has_value () ? txr_grouped->fee : 0 , txr_grouped.has_value () ? txr_grouped->change_pos : 0 );
1003
988
if (txr_grouped) {
1004
989
wallet.WalletLogPrintf (" Fee non-grouped = %lld, grouped = %lld, using %s\n " ,
1005
- txr_ungrouped-> fee , txr_grouped->fee , use_aps ? " grouped" : " non-grouped" );
1006
- if (use_aps) return txr_grouped ;
990
+ txr_ungrouped. fee , txr_grouped->fee , use_aps ? " grouped" : " non-grouped" );
991
+ if (use_aps) return res_tx_grouped ;
1007
992
}
1008
993
}
1009
- return txr_ungrouped ;
994
+ return res ;
1010
995
}
1011
996
1012
997
bool FundTransaction (CWallet& wallet, CMutableTransaction& tx, CAmount& nFeeRet, int & nChangePosInOut, bilingual_str& error, bool lockUnspents, const std::set<int >& setSubtractFeeFromOutputs, CCoinControl coinControl)
@@ -1042,11 +1027,15 @@ bool FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& nFeeRet,
1042
1027
}
1043
1028
}
1044
1029
1045
- std::optional<CreatedTransactionResult> txr = CreateTransaction (wallet, vecSend, nChangePosInOut, error, coinControl, false );
1046
- if (!txr) return false ;
1047
- CTransactionRef tx_new = txr->tx ;
1048
- nFeeRet = txr->fee ;
1049
- nChangePosInOut = txr->change_pos ;
1030
+ auto res = CreateTransaction (wallet, vecSend, nChangePosInOut, coinControl, false );
1031
+ if (!res) {
1032
+ error = res.GetError ();
1033
+ return false ;
1034
+ }
1035
+ const auto & txr = res.GetObj ();
1036
+ CTransactionRef tx_new = txr.tx ;
1037
+ nFeeRet = txr.fee ;
1038
+ nChangePosInOut = txr.change_pos ;
1050
1039
1051
1040
if (nChangePosInOut != -1 ) {
1052
1041
tx.vout .insert (tx.vout .begin () + nChangePosInOut, tx_new->vout [nChangePosInOut]);
0 commit comments