diff options
Diffstat (limited to 'src/wallet/coinselection.h')
-rw-r--r-- | src/wallet/coinselection.h | 46 |
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); |