Skip to content

Commit e8cae94

Browse files
committed
Create basic coin selection algorithm class
1 parent a479321 commit e8cae94

File tree

2 files changed

+108
-0
lines changed

2 files changed

+108
-0
lines changed

divi/src/MinimumFeeCoinSelectionAlgorithm.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,90 @@ InputToSpendAndSigSize::InputToSpendAndSigSize(
2323
{
2424
}
2525

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+
26110
MinimumFeeCoinSelectionAlgorithm::MinimumFeeCoinSelectionAlgorithm(
27111
const CKeyStore& keyStore,
28112
const I_SignatureSizeEstimator& estimator,

divi/src/MinimumFeeCoinSelectionAlgorithm.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef MINIMUM_FEE_COIN_SELECTION_ALGORITHM_H
22
#define MINIMUM_FEE_COIN_SELECTION_ALGORITHM_H
33
#include <I_CoinSelectionAlgorithm.h>
4+
#include <I_UtxoPriorityAlgorithm.h>
45
class CKeyStore;
56
class I_SignatureSizeEstimator;
67
class CFeeRate;
@@ -22,6 +23,29 @@ struct InputToSpendAndSigSize
2223
const I_SignatureSizeEstimator& estimator);
2324
};
2425

26+
class BasicCoinSelectionAlgorithm final: public I_CoinSelectionAlgorithm
27+
{
28+
private:
29+
const CKeyStore& keyStore_;
30+
const I_SignatureSizeEstimator& estimator_;
31+
const CFeeRate& minRelayTxFee_;
32+
const ChangeOutputType changeOutputType_;
33+
const I_UtxoPriorityAlgorithm& utxoPriorityAlgorithm_;
34+
35+
public:
36+
BasicCoinSelectionAlgorithm(
37+
const CKeyStore& keyStore,
38+
const I_SignatureSizeEstimator& estimator,
39+
const CFeeRate& minRelayTxFee,
40+
const ChangeOutputType changeOutputType,
41+
const I_UtxoPriorityAlgorithm& utxoPriorityAlgorithm);
42+
bool isSelectable(const COutput& coin) const override { return true; };
43+
std::set<COutput> SelectCoins(
44+
const CMutableTransaction& transactionToSelectCoinsFor,
45+
const std::vector<COutput>& vCoins,
46+
CAmount& fees) const override;
47+
};
48+
2549
class MinimumFeeCoinSelectionAlgorithm final: public I_CoinSelectionAlgorithm
2650
{
2751
private:

0 commit comments

Comments
 (0)