aboutsummaryrefslogtreecommitdiff
path: root/src/wallet/coinselection.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet/coinselection.h')
-rw-r--r--src/wallet/coinselection.h46
1 files changed, 39 insertions, 7 deletions
diff --git a/src/wallet/coinselection.h b/src/wallet/coinselection.h
index e257d3f7c7..761c2be0b3 100644
--- a/src/wallet/coinselection.h
+++ b/src/wallet/coinselection.h
@@ -123,6 +123,10 @@ struct CoinSelectionParams {
/** Mininmum change to target in Knapsack solver: select coins to cover the payment and
* at least this value of change. */
CAmount m_min_change_target{0};
+ /** Minimum amount for creating a change output.
+ * If change budget is smaller than min_change then we forgo creation of change output.
+ */
+ CAmount min_viable_change{0};
/** Cost of creating the change output. */
CAmount m_change_fee{0};
/** Cost of creating the change output + cost of spending the change output in the future. */
@@ -252,6 +256,7 @@ struct OutputGroup
/** Choose a random change target for each transaction to make it harder to fingerprint the Core
* wallet based on the change output values of transactions it creates.
+ * Change target covers at least change fees and adds a random value on top of it.
* The random value is between 50ksat and min(2 * payment_value, 1milsat)
* When payment_value <= 25ksat, the value is just 50ksat.
*
@@ -261,8 +266,9 @@ struct OutputGroup
* coins selected are just sufficient to cover the payment amount ("unnecessary input" heuristic).
*
* @param[in] payment_value Average payment value of the transaction output(s).
+ * @param[in] change_fee Fee for creating a change output.
*/
-[[nodiscard]] CAmount GenerateChangeTarget(CAmount payment_value, FastRandomContext& rng);
+[[nodiscard]] CAmount GenerateChangeTarget(const CAmount payment_value, const CAmount change_fee, FastRandomContext& rng);
enum class SelectionAlgorithm : uint8_t
{
@@ -279,17 +285,16 @@ struct SelectionResult
private:
/** Set of inputs selected by the algorithm to use in the transaction */
std::set<COutput> m_selected_inputs;
+ /** The target the algorithm selected for. Equal to the recipient amount plus non-input fees */
+ CAmount m_target;
+ /** The algorithm used to produce this result */
+ SelectionAlgorithm m_algo;
/** Whether the input values for calculations should be the effective value (true) or normal value (false) */
bool m_use_effective{false};
/** The computed waste */
std::optional<CAmount> m_waste;
public:
- /** The target the algorithm selected for. Note that this may not be equal to the recipient amount as it can include non-input fees */
- const CAmount m_target;
- /** The algorithm used to produce this result */
- const SelectionAlgorithm m_algo;
-
explicit SelectionResult(const CAmount target, SelectionAlgorithm algo)
: m_target(target), m_algo(algo) {}
@@ -298,20 +303,47 @@ public:
/** Get the sum of the input values */
[[nodiscard]] CAmount GetSelectedValue() const;
+ [[nodiscard]] CAmount GetSelectedEffectiveValue() const;
+
void Clear();
void AddInput(const OutputGroup& group);
/** Calculates and stores the waste for this selection via GetSelectionWaste */
- void ComputeAndSetWaste(CAmount change_cost);
+ void ComputeAndSetWaste(const CAmount min_viable_change, const CAmount change_cost, const CAmount change_fee);
[[nodiscard]] CAmount GetWaste() const;
+ void Merge(const SelectionResult& other);
+
/** Get m_selected_inputs */
const std::set<COutput>& GetInputSet() const;
/** Get the vector of COutputs that will be used to fill in a CTransaction's vin */
std::vector<COutput> GetShuffledInputVector() const;
bool operator<(SelectionResult other) const;
+
+ /** Get the amount for the change output after paying needed fees.
+ *
+ * The change amount is not 100% precise due to discrepancies in fee calculation.
+ * The final change amount (if any) should be corrected after calculating the final tx fees.
+ * When there is a discrepancy, most of the time the final change would be slightly bigger than estimated.
+ *
+ * Following are the possible factors of discrepancy:
+ * + non-input fees always include segwit flags
+ * + input fee estimation always include segwit stack size
+ * + input fees are rounded individually and not collectively, which leads to small rounding errors
+ * - input counter size is always assumed to be 1vbyte
+ *
+ * @param[in] min_viable_change Minimum amount for change output, if change would be less then we forgo change
+ * @param[in] change_fee Fees to include change output in the tx
+ * @returns Amount for change output, 0 when there is no change.
+ *
+ */
+ CAmount GetChange(const CAmount min_viable_change, const CAmount change_fee) const;
+
+ CAmount GetTarget() const { return m_target; }
+
+ SelectionAlgorithm GetAlgo() const { return m_algo; }
};
std::optional<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, const CAmount& cost_of_change);