@@ -112,89 +112,37 @@ MinimumFeeCoinSelectionAlgorithm::MinimumFeeCoinSelectionAlgorithm(
112
112
const I_SignatureSizeEstimator& estimator,
113
113
const CFeeRate& minRelayTxFee,
114
114
const ChangeOutputType changeOutputType
115
- ): keyStore_(keyStore)
116
- , estimator_(estimator)
117
- , minRelayTxFee_(minRelayTxFee)
115
+ ): minRelayTxFee_(minRelayTxFee)
118
116
, changeOutputType_(changeOutputType)
117
+ , basicCoinSelectionAlgorithm_(
118
+ new BasicCoinSelectionAlgorithm(
119
+ keyStore,
120
+ estimator,
121
+ minRelayTxFee,
122
+ changeOutputType,
123
+ *static_cast <I_UtxoPriorityAlgorithm*>(this )))
119
124
{
120
125
}
121
126
127
+ bool MinimumFeeCoinSelectionAlgorithm::operator ()(const CAmount targetAmount, const InputToSpendAndSigSize& first, const InputToSpendAndSigSize& second) const
128
+ {
129
+ if (changeOutputType_ == ChangeOutputType::VAULT && first.outputRef ->nDepth != second.outputRef ->nDepth )
130
+ {
131
+ return first.outputRef ->nDepth < second.outputRef ->nDepth ;
132
+ }
133
+ const CAmount gapA = first.outputRef ->Value () - minRelayTxFee_.GetFee (first.sigSize );
134
+ const CAmount gapB = second.outputRef ->Value () - minRelayTxFee_.GetFee (second.sigSize );
135
+ const bool inputAShouldBePrioritized =
136
+ (gapA >= targetAmount && gapB >= targetAmount)
137
+ ? first.sigSize < second.sigSize
138
+ : gapA > gapB || (gapA == gapB && first.sigSize < second.sigSize );
139
+ return inputAShouldBePrioritized;
140
+ }
141
+
122
142
std::set<COutput> MinimumFeeCoinSelectionAlgorithm::SelectCoins (
123
143
const CMutableTransaction& transactionToSelectCoinsFor,
124
144
const std::vector<COutput>& vCoins,
125
145
CAmount& fees) const
126
146
{
127
- const unsigned nominalChangeOutputSize = static_cast <unsigned >(changeOutputType_); // Vault? Vault-Change : P2PKH change address
128
- CTransaction initialTransaction = CTransaction (transactionToSelectCoinsFor);
129
- const unsigned initialByteSize = ::GetSerializeSize (initialTransaction, SER_NETWORK, PROTOCOL_VERSION);
130
-
131
- CAmount maximumAmountAvailable = 0 ;
132
- std::vector<InputToSpendAndSigSize> inputsToSpendAndSignatureSizeEstimates;
133
- inputsToSpendAndSignatureSizeEstimates.reserve (vCoins.size ());
134
- std::set<COutPoint> outputsUsed;
135
- for (const CTxIn& txInput: initialTransaction.vin )
136
- {
137
- outputsUsed.insert (txInput.prevout );
138
- }
139
- CAmount amountAlreadyCovered = 0 ;
140
- fees += minRelayTxFee_.GetFee (initialByteSize);
141
- for (const COutput& input: vCoins)
142
- {
143
- if (outputsUsed.count (COutPoint (input.tx ->GetHash (),input.i ))>0 )
144
- {
145
- InputToSpendAndSigSize inputWithSigSize (input,keyStore_,estimator_);
146
- amountAlreadyCovered += inputWithSigSize.outputRef ->Value ();
147
- fees += minRelayTxFee_.GetFee (inputWithSigSize.sigSize );
148
- continue ;
149
- }
150
- inputsToSpendAndSignatureSizeEstimates.emplace_back (input,keyStore_,estimator_);
151
- maximumAmountAvailable+= input.Value ();
152
- }
153
- const CAmount nTargetValue = transactionToSelectCoinsFor.GetValueOut () - amountAlreadyCovered;
154
-
155
- std::set<COutput> inputsSelected;
156
- inputsSelected.clear ();
157
- const CAmount minimumNoDustChange = FeeAndPriorityCalculator::instance ().MinimumValueForNonDust ();
158
- const CAmount totalAmountNeeded = nTargetValue + minimumNoDustChange + fees;
159
- if (totalAmountNeeded > maximumAmountAvailable) return {};
160
-
161
- std::sort (
162
- inputsToSpendAndSignatureSizeEstimates.begin (),
163
- inputsToSpendAndSignatureSizeEstimates.end (),
164
- [totalAmountNeeded,this ](const InputToSpendAndSigSize& inputA, const InputToSpendAndSigSize& inputB)
165
- {
166
- if (changeOutputType_ == ChangeOutputType::VAULT && inputA.outputRef ->nDepth != inputB.outputRef ->nDepth )
167
- {
168
- return inputA.outputRef ->nDepth < inputB.outputRef ->nDepth ;
169
- }
170
- const CAmount gapA = inputA.outputRef ->Value () - minRelayTxFee_.GetFee (inputA.sigSize );
171
- const CAmount gapB = inputB.outputRef ->Value () - minRelayTxFee_.GetFee (inputB.sigSize );
172
- const bool inputAShouldBePrioritized =
173
- (gapA >= totalAmountNeeded && gapB >= totalAmountNeeded)
174
- ? inputA.sigSize < inputB.sigSize
175
- : gapA > gapB || (gapA == gapB && inputA.sigSize < inputB.sigSize );
176
- return inputAShouldBePrioritized;
177
- });
178
- CAmount amountCovered =0 ;
179
- unsigned cummulativeByteSize = nominalChangeOutputSize;
180
- for (const InputToSpendAndSigSize& inputAndSigSize: inputsToSpendAndSignatureSizeEstimates)
181
- {
182
- inputsSelected.insert (*inputAndSigSize.outputRef );
183
- amountCovered += inputAndSigSize.outputRef ->Value () - minRelayTxFee_.GetFee (inputAndSigSize.sigSize );
184
- cummulativeByteSize += inputAndSigSize.sigSize ;
185
- if (cummulativeByteSize >= MAX_STANDARD_TX_SIZE) return {};
186
- if ( amountCovered >= totalAmountNeeded )
187
- {
188
- fees += minRelayTxFee_.GetFee (cummulativeByteSize);
189
- if (minRelayTxFee_.GetMaxTxFee () < fees)
190
- {
191
- return {};
192
- }
193
- else
194
- {
195
- return inputsSelected;
196
- }
197
- }
198
- }
199
- return {};
147
+ return basicCoinSelectionAlgorithm_->SelectCoins (transactionToSelectCoinsFor,vCoins,fees);
200
148
}
0 commit comments