@@ -23,6 +23,90 @@ InputToSpendAndSigSize::InputToSpendAndSigSize(
23
23
{
24
24
}
25
25
26
+ BasicCoinSelectionAlgorithm::BasicCoinSelectionAlgorithm (
27
+ const CKeyStore& keyStore,
28
+ const I_SignatureSizeEstimator& estimator,
29
+ const CFeeRate& minRelayTxFee,
30
+ const ChangeOutputType changeOutputType,
31
+ const I_UtxoPriorityAlgorithm& utxoPriorityAlgorithm
32
+ ): keyStore_(keyStore)
33
+ , estimator_(estimator)
34
+ , minRelayTxFee_(minRelayTxFee)
35
+ , changeOutputType_(changeOutputType)
36
+ , utxoPriorityAlgorithm_(utxoPriorityAlgorithm)
37
+ {
38
+ }
39
+
40
+ std::set<COutput> BasicCoinSelectionAlgorithm::SelectCoins (
41
+ const CMutableTransaction& transactionToSelectCoinsFor,
42
+ const std::vector<COutput>& vCoins,
43
+ CAmount& fees) const
44
+ {
45
+ const unsigned nominalChangeOutputSize = static_cast <unsigned >(changeOutputType_); // Vault? Vault-Change : P2PKH change address
46
+ CTransaction initialTransaction = CTransaction (transactionToSelectCoinsFor);
47
+ const unsigned initialByteSize = ::GetSerializeSize (initialTransaction, SER_NETWORK, PROTOCOL_VERSION);
48
+
49
+ CAmount maximumAmountAvailable = 0 ;
50
+ std::vector<InputToSpendAndSigSize> inputsToSpendAndSignatureSizeEstimates;
51
+ inputsToSpendAndSignatureSizeEstimates.reserve (vCoins.size ());
52
+ std::set<COutPoint> outputsUsed;
53
+ for (const CTxIn& txInput: initialTransaction.vin )
54
+ {
55
+ outputsUsed.insert (txInput.prevout );
56
+ }
57
+ CAmount amountAlreadyCovered = 0 ;
58
+ fees += minRelayTxFee_.GetFee (initialByteSize);
59
+ for (const COutput& input: vCoins)
60
+ {
61
+ if (outputsUsed.count (COutPoint (input.tx ->GetHash (),input.i ))>0 )
62
+ {
63
+ InputToSpendAndSigSize inputWithSigSize (input,keyStore_,estimator_);
64
+ amountAlreadyCovered += inputWithSigSize.outputRef ->Value ();
65
+ fees += minRelayTxFee_.GetFee (inputWithSigSize.sigSize );
66
+ continue ;
67
+ }
68
+ inputsToSpendAndSignatureSizeEstimates.emplace_back (input,keyStore_,estimator_);
69
+ maximumAmountAvailable+= input.Value ();
70
+ }
71
+ const CAmount nTargetValue = transactionToSelectCoinsFor.GetValueOut () - amountAlreadyCovered;
72
+
73
+ std::set<COutput> inputsSelected;
74
+ inputsSelected.clear ();
75
+ const CAmount minimumNoDustChange = FeeAndPriorityCalculator::instance ().MinimumValueForNonDust ();
76
+ const CAmount totalAmountNeeded = nTargetValue + minimumNoDustChange + fees;
77
+ if (totalAmountNeeded > maximumAmountAvailable) return {};
78
+
79
+ std::sort (
80
+ inputsToSpendAndSignatureSizeEstimates.begin (),
81
+ inputsToSpendAndSignatureSizeEstimates.end (),
82
+ [totalAmountNeeded, this ](const InputToSpendAndSigSize& inputA, const InputToSpendAndSigSize& inputB)
83
+ {
84
+ return utxoPriorityAlgorithm_ (totalAmountNeeded,inputA,inputB);
85
+ });
86
+ CAmount amountCovered =0 ;
87
+ unsigned cummulativeByteSize = nominalChangeOutputSize;
88
+ for (const InputToSpendAndSigSize& inputAndSigSize: inputsToSpendAndSignatureSizeEstimates)
89
+ {
90
+ inputsSelected.insert (*inputAndSigSize.outputRef );
91
+ amountCovered += inputAndSigSize.outputRef ->Value () - minRelayTxFee_.GetFee (inputAndSigSize.sigSize );
92
+ cummulativeByteSize += inputAndSigSize.sigSize ;
93
+ if (cummulativeByteSize >= MAX_STANDARD_TX_SIZE) return {};
94
+ if ( amountCovered >= totalAmountNeeded )
95
+ {
96
+ fees += minRelayTxFee_.GetFee (cummulativeByteSize);
97
+ if (minRelayTxFee_.GetMaxTxFee () < fees)
98
+ {
99
+ return {};
100
+ }
101
+ else
102
+ {
103
+ return inputsSelected;
104
+ }
105
+ }
106
+ }
107
+ return {};
108
+ }
109
+
26
110
MinimumFeeCoinSelectionAlgorithm::MinimumFeeCoinSelectionAlgorithm (
27
111
const CKeyStore& keyStore,
28
112
const I_SignatureSizeEstimator& estimator,
0 commit comments