coincontrol.h raw

   1  // Copyright (c) 2011-2022 The Limenka developers
   2  // Distributed under the MIT software license, see the accompanying
   3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   4  
   5  #ifndef LIMENKA_WALLET_COINCONTROL_H
   6  #define LIMENKA_WALLET_COINCONTROL_H
   7  
   8  #include <outputtype.h>
   9  #include <policy/feerate.h>
  10  #include <policy/fees.h>
  11  #include <primitives/transaction.h>
  12  #include <script/keyorigin.h>
  13  #include <script/signingprovider.h>
  14  
  15  #include <algorithm>
  16  #include <map>
  17  #include <optional>
  18  #include <set>
  19  
  20  namespace wallet {
  21  const int DEFAULT_MIN_DEPTH = 0;
  22  const int DEFAULT_MAX_DEPTH = 9999999;
  23  
  24  //! Default for -avoidpartialspends
  25  static constexpr bool DEFAULT_AVOIDPARTIALSPENDS = false;
  26  
  27  class PreselectedInput
  28  {
  29  private:
  30      //! The previous output being spent by this input
  31      std::optional<CTxOut> m_txout;
  32      //! The input weight for spending this input
  33      std::optional<int64_t> m_weight;
  34      //! The sequence number for this input
  35      std::optional<uint32_t> m_sequence;
  36      //! The scriptSig for this input
  37      std::optional<CScript> m_script_sig;
  38      //! The scriptWitness for this input
  39      std::optional<CScriptWitness> m_script_witness;
  40      //! The position in the inputs vector for this input
  41      std::optional<unsigned int> m_pos;
  42  
  43  public:
  44      /**
  45       * Set the previous output for this input.
  46       * Only necessary if the input is expected to be an external input.
  47       */
  48      void SetTxOut(const CTxOut& txout);
  49      /** Retrieve the previous output for this input. */
  50      CTxOut GetTxOut() const;
  51      /** Return whether the previous output is set for this input. */
  52      bool HasTxOut() const;
  53  
  54      /** Set the weight for this input. */
  55      void SetInputWeight(int64_t weight);
  56      /** Retrieve the input weight for this input. */
  57      std::optional<int64_t> GetInputWeight() const;
  58  
  59      /** Set the sequence for this input. */
  60      void SetSequence(uint32_t sequence);
  61      /** Retrieve the sequence for this input. */
  62      std::optional<uint32_t> GetSequence() const;
  63  
  64      /** Set the scriptSig for this input. */
  65      void SetScriptSig(const CScript& script);
  66      /** Set the scriptWitness for this input. */
  67      void SetScriptWitness(const CScriptWitness& script_wit);
  68      /** Return whether either the scriptSig or scriptWitness are set for this input. */
  69      bool HasScripts() const;
  70      /** Retrieve both the scriptSig and the scriptWitness. */
  71      std::pair<std::optional<CScript>, std::optional<CScriptWitness>> GetScripts() const;
  72  
  73      /** Store the position of this input. */
  74      void SetPosition(unsigned int pos);
  75      /** Retrieve the position of this input. */
  76      std::optional<unsigned int> GetPosition() const;
  77  };
  78  
  79  /** Coin Control Features. */
  80  class CCoinControl
  81  {
  82  public:
  83      //! Custom change destination, if not set an address is generated
  84      CTxDestination destChange = CNoDestination();
  85      //! Override the default change type if set, ignored if destChange is set
  86      std::optional<OutputType> m_change_type;
  87      //! If false, only safe inputs will be used
  88      bool m_include_unsafe_inputs = false;
  89      //! If true, only segwit inputs are selected
  90      bool m_segwit_inputs_only = false;
  91      //! If true, the selection process can add extra unselected inputs from the wallet
  92      //! while requires all selected inputs be used
  93      bool m_allow_other_inputs = true;
  94      //! Includes watch only addresses which are solvable
  95      bool fAllowWatchOnly = false;
  96      //! Override automatic min/max checks on fee, m_feerate must be set if true
  97      bool fOverrideFeeRate = false;
  98      //! Override the wallet's m_pay_tx_fee if set
  99      std::optional<CFeeRate> m_feerate;
 100      //! Override the default confirmation target if set
 101      std::optional<unsigned int> m_confirm_target;
 102      //! Override the wallet's m_signal_rbf if set
 103      std::optional<bool> m_signal_bip125_rbf;
 104      //! Avoid partial use of funds sent to a given address
 105      bool m_avoid_partial_spends = DEFAULT_AVOIDPARTIALSPENDS;
 106      //! Forbids inclusion of dirty (previously used) addresses
 107      bool m_avoid_address_reuse = false;
 108      
 109      // Privacy-focused coin selection settings
 110      //! Number of change outputs to generate when single coin covers spend (1-8)
 111      int m_change_output_count = 1;
 112      //! Target number of outputs when merging UTXOs (minimize inputs, target outputs)
 113      int m_target_merge_outputs = 2;
 114      //! Time window for temporal clustering (seconds) - prefer UTXOs created within this window
 115      int64_t m_temporal_window = 3600;  // 1 hour default
 116      //! Enable privacy-first coin selection (minimize inputs, prefer temporal clusters)
 117      bool m_privacy_first = true;
 118      //! Fee estimation mode to control arguments to estimateSmartFee
 119      FeeEstimateMode m_fee_mode = FeeEstimateMode::UNSET;
 120      //! Minimum chain depth value for coin availability
 121      int m_min_depth = DEFAULT_MIN_DEPTH;
 122      //! Maximum chain depth value for coin availability
 123      int m_max_depth = DEFAULT_MAX_DEPTH;
 124      //! SigningProvider that has pubkeys and scripts to do spend size estimation for external inputs
 125      FlatSigningProvider m_external_provider;
 126      //! Locktime
 127      std::optional<uint32_t> m_locktime;
 128      //! Version
 129      std::optional<uint32_t> m_version;
 130      //! Caps weight of resulting tx
 131      std::optional<int> m_max_tx_weight{std::nullopt};
 132  
 133      CCoinControl();
 134  
 135      /**
 136       * Returns true if there are pre-selected inputs.
 137       */
 138      bool HasSelected() const;
 139      /**
 140       * Returns true if the given output is pre-selected.
 141       */
 142      bool IsSelected(const COutPoint& outpoint) const;
 143      /**
 144       * Returns true if the given output is selected as an external input.
 145       */
 146      bool IsExternalSelected(const COutPoint& outpoint) const;
 147      /**
 148       * Returns the external output for the given outpoint if it exists.
 149       */
 150      std::optional<CTxOut> GetExternalOutput(const COutPoint& outpoint) const;
 151      /**
 152       * Lock-in the given output for spending.
 153       * The output will be included in the transaction even if it's not the most optimal choice.
 154       */
 155      PreselectedInput& Select(const COutPoint& outpoint);
 156      /**
 157       * Unselects the given output.
 158       */
 159      void UnSelect(const COutPoint& outpoint);
 160      /**
 161       * Unselects all outputs.
 162       */
 163      void UnSelectAll();
 164      /**
 165       * List the selected inputs.
 166       */
 167      std::vector<COutPoint> ListSelected() const;
 168      /**
 169       * Set an input's weight.
 170       */
 171      void SetInputWeight(const COutPoint& outpoint, int64_t weight);
 172      /**
 173       * Returns the input weight.
 174       */
 175      std::optional<int64_t> GetInputWeight(const COutPoint& outpoint) const;
 176      /** Retrieve the sequence for an input */
 177      std::optional<uint32_t> GetSequence(const COutPoint& outpoint) const;
 178      /** Retrieves the scriptSig and scriptWitness for an input. */
 179      std::pair<std::optional<CScript>, std::optional<CScriptWitness>> GetScripts(const COutPoint& outpoint) const;
 180  
 181      bool HasSelectedOrder() const
 182      {
 183          return m_selection_pos > 0;
 184      }
 185  
 186      std::optional<unsigned int> GetSelectionPos(const COutPoint& outpoint) const
 187      {
 188          const auto it = m_selected.find(outpoint);
 189          if (it == m_selected.end()) {
 190              return std::nullopt;
 191          }
 192          return it->second.GetPosition();
 193      }
 194  
 195  private:
 196      //! Selected inputs (inputs that will be used, regardless of whether they're optimal or not)
 197      std::map<COutPoint, PreselectedInput> m_selected;
 198      unsigned int m_selection_pos{0};
 199  };
 200  } // namespace wallet
 201  
 202  #endif // LIMENKA_WALLET_COINCONTROL_H
 203