Skip to content

Commit

Permalink
Fee estimation function optimized
Browse files Browse the repository at this point in the history
  • Loading branch information
levonpetrosyan93 committed Feb 22, 2021
1 parent ae1210b commit 305d2d0
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 36 deletions.
3 changes: 2 additions & 1 deletion src/elysium/wallettxs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,8 @@ int64_t SelectCoins(const std::string& fromAddress, CCoinControl& coinControl, i
std::vector<CSigmaEntry> coinsToSpend;
std::vector<sigma::CoinDenomination> remints;
try {
pwalletMain->GetCoinsToSpend(nMax, coinsToSpend, remints);
std::list<CSigmaEntry> sigmaCoins = pwalletMain->GetAvailableCoins();
pwalletMain->GetCoinsToSpend(nMax, coinsToSpend, remints, sigmaCoins);
} catch (std::exception const &err) {
LogPrintf("SelectCoins() fail to get coin to spend: %s\n", err.what());
return nTotal;
Expand Down
11 changes: 6 additions & 5 deletions src/wallet/lelantusjoinsplitbuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ CWalletTx LelantusJoinSplitBuilder::Build(
}

std::tie(fee, std::ignore) = wallet.EstimateJoinSplitFee(vOut + mint, recipientsToSubtractFee, coinControl);

std::list<CSigmaEntry> sigmaCoins = pwalletMain->GetAvailableCoins(coinControl);
std::list<CLelantusEntry> coins = pwalletMain->GetAvailableLelantusCoins(coinControl);

for (;;) {
// In case of not enough fee, reset mint seed counter
Expand Down Expand Up @@ -187,9 +188,8 @@ CWalletTx LelantusJoinSplitBuilder::Build(

std::vector<sigma::CoinDenomination> denomChanges;
try {
std::list<CSigmaEntry> coins = pwalletMain->GetAvailableCoins(coinControl);
CAmount availableBalance(0);
for (auto coin : coins) {
for (auto coin : sigmaCoins) {
availableBalance += coin.get_denomination_value();
}
if(availableBalance > 0) {
Expand All @@ -199,9 +199,10 @@ CWalletTx LelantusJoinSplitBuilder::Build(
else
inputFromSigma = required;

wallet.GetCoinsToSpend(inputFromSigma, sigmaSpendCoins, denomChanges, //try to spend sigma first
wallet.GetCoinsToSpend(inputFromSigma, sigmaSpendCoins, denomChanges, sigmaCoins, //try to spend sigma first
consensusParams.nMaxLelantusInputPerTransaction,
consensusParams.nMaxValueLelantusSpendPerTransaction, coinControl);

required -= inputFromSigma;

isSigmaToLelantusJoinSplit = true;
Expand All @@ -210,7 +211,7 @@ CWalletTx LelantusJoinSplitBuilder::Build(
}

if(required > 0) {
if (!wallet.GetCoinsToJoinSplit(required, spendCoins, changeToMint,
if (!wallet.GetCoinsToJoinSplit(required, spendCoins, changeToMint, coins,
consensusParams.nMaxLelantusInputPerTransaction,
consensusParams.nMaxValueLelantusSpendPerTransaction, coinControl)) {
throw InsufficientFunds();
Expand Down
3 changes: 2 additions & 1 deletion src/wallet/sigmaspendbuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,9 @@ CAmount SigmaSpendBuilder::GetInputs(std::vector<std::unique_ptr<InputSigner>>&
denomChanges.clear();

auto& consensusParams = Params().GetConsensus();
std::list<CSigmaEntry> sigmaCoins = pwalletMain->GetAvailableCoins(coinControl);

if (!wallet.GetCoinsToSpend(required, selected, denomChanges,
if (!wallet.GetCoinsToSpend(required, selected, denomChanges, sigmaCoins,
consensusParams.nMaxSigmaInputPerTransaction, consensusParams.nMaxValueSigmaSpendPerTransaction, coinControl)) {
throw InsufficientFunds();
}
Expand Down
36 changes: 27 additions & 9 deletions src/wallet/test/sigma_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,9 @@ BOOST_AUTO_TEST_CASE(get_coin_no_coin)

std::vector<CSigmaEntry> coins;
std::vector<sigma::CoinDenomination> coinsToMint;
BOOST_CHECK_THROW(pwalletMain->GetCoinsToSpend(require, coins, coinsToMint), InsufficientFunds);
std::list<CSigmaEntry> availableCoins = pwalletMain->GetAvailableCoins();

BOOST_CHECK_THROW(pwalletMain->GetCoinsToSpend(require, coins, coinsToMint, availableCoins), InsufficientFunds);

std::vector<std::pair<sigma::CoinDenomination, int>> needCoins;

Expand All @@ -270,7 +272,9 @@ BOOST_AUTO_TEST_CASE(get_coin_different_denomination)

std::vector<CSigmaEntry> coins;
std::vector<sigma::CoinDenomination> coinsToMint;
BOOST_CHECK_NO_THROW(pwalletMain->GetCoinsToSpend(require, coins, coinsToMint));
std::list<CSigmaEntry> availableCoins = pwalletMain->GetAvailableCoins();

BOOST_CHECK_NO_THROW(pwalletMain->GetCoinsToSpend(require, coins, coinsToMint, availableCoins));
sigmaState->Reset();
}

Expand All @@ -287,7 +291,9 @@ BOOST_AUTO_TEST_CASE(get_coin_round_up)

std::vector<CSigmaEntry> coinsToSpend;
std::vector<sigma::CoinDenomination> coinsToMint;
BOOST_CHECK_MESSAGE(pwalletMain->GetCoinsToSpend(require, coinsToSpend, coinsToMint),
std::list<CSigmaEntry> availableCoins = pwalletMain->GetAvailableCoins();

BOOST_CHECK_MESSAGE(pwalletMain->GetCoinsToSpend(require, coinsToSpend, coinsToMint, availableCoins),
"Expect enough for requirement");

// We would expect to spend 100 + 10 + 1 + 0.5 + 0.1 + 0.05
Expand All @@ -312,7 +318,9 @@ BOOST_AUTO_TEST_CASE(get_coin_not_enough)

std::vector<CSigmaEntry> coins;
std::vector<sigma::CoinDenomination> coinsToMint;
BOOST_CHECK_THROW(pwalletMain->GetCoinsToSpend(require, coins, coinsToMint), InsufficientFunds);
std::list<CSigmaEntry> availableCoins = pwalletMain->GetAvailableCoins();

BOOST_CHECK_THROW(pwalletMain->GetCoinsToSpend(require, coins, coinsToMint, availableCoins), InsufficientFunds);
sigmaState->Reset();
}

Expand All @@ -329,7 +337,9 @@ BOOST_AUTO_TEST_CASE(get_coin_cannot_spend_unconfirmed_coins)

std::vector<CSigmaEntry> coins;
std::vector<sigma::CoinDenomination> coinsToMint;
BOOST_CHECK_THROW(pwalletMain->GetCoinsToSpend(require, coins, coinsToMint), InsufficientFunds);
std::list<CSigmaEntry> availableCoins = pwalletMain->GetAvailableCoins();

BOOST_CHECK_THROW(pwalletMain->GetCoinsToSpend(require, coins, coinsToMint, availableCoins), InsufficientFunds);
sigmaState->Reset();
}

Expand All @@ -345,7 +355,9 @@ BOOST_AUTO_TEST_CASE(get_coin_minimize_coins_spend_fit_amount)

std::vector<CSigmaEntry> coins;
std::vector<sigma::CoinDenomination> coinsToMint;
BOOST_CHECK_MESSAGE(pwalletMain->GetCoinsToSpend(require, coins,coinsToMint),
std::list<CSigmaEntry> availableCoins = pwalletMain->GetAvailableCoins();

BOOST_CHECK_MESSAGE(pwalletMain->GetCoinsToSpend(require, coins,coinsToMint, availableCoins),
"Expect enough coin and equal to one SIGMA_DENOM_100");

std::vector<std::pair<sigma::CoinDenomination, int>> expectedCoins;
Expand All @@ -368,7 +380,9 @@ BOOST_AUTO_TEST_CASE(get_coin_minimize_coins_spend)

std::vector<CSigmaEntry> coins;
std::vector<sigma::CoinDenomination> coinsToMint;
BOOST_CHECK_MESSAGE(pwalletMain->GetCoinsToSpend(require, coins, coinsToMint),
std::list<CSigmaEntry> availableCoins = pwalletMain->GetAvailableCoins();

BOOST_CHECK_MESSAGE(pwalletMain->GetCoinsToSpend(require, coins, coinsToMint, availableCoins),
"Coins to spend value is not equal to required amount.");

std::vector<std::pair<sigma::CoinDenomination, int>> expectedCoins;
Expand All @@ -391,7 +405,9 @@ BOOST_AUTO_TEST_CASE(get_coin_choose_smallest_enough)

std::vector<CSigmaEntry> coins;
std::vector<sigma::CoinDenomination> coinsToMint;
BOOST_CHECK_MESSAGE(pwalletMain->GetCoinsToSpend(require, coins,coinsToMint),
std::list<CSigmaEntry> availableCoins = pwalletMain->GetAvailableCoins();

BOOST_CHECK_MESSAGE(pwalletMain->GetCoinsToSpend(require, coins,coinsToMint, availableCoins),
"Expect enough coin and equal one SIGMA_DENOM_1");

std::vector<std::pair<sigma::CoinDenomination, int>> expectedCoins;
Expand All @@ -414,7 +430,9 @@ BOOST_AUTO_TEST_CASE(get_coin_by_limit_max_to_1)

std::vector<CSigmaEntry> coins;
std::vector<sigma::CoinDenomination> coinsToMint;
BOOST_CHECK_EXCEPTION(pwalletMain->GetCoinsToSpend(require, coins, coinsToMint, 1),
std::list<CSigmaEntry> availableCoins = pwalletMain->GetAvailableCoins();

BOOST_CHECK_EXCEPTION(pwalletMain->GetCoinsToSpend(require, coins, coinsToMint, availableCoins, 1),
std::runtime_error,
[](const std::runtime_error& e) {
return e.what() == std::string("Can not choose coins within limit.");
Expand Down
28 changes: 12 additions & 16 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3027,10 +3027,10 @@ bool CWallet::GetCoinsToSpend(
CAmount required,
std::vector<CSigmaEntry>& coinsToSpend_out,
std::vector<sigma::CoinDenomination>& coinsToMint_out,
std::list<CSigmaEntry>& coins,
const size_t coinsToSpendLimit,
const CAmount amountToSpendLimit,
const CCoinControl *coinControl,
bool forEstimation) const
const CCoinControl *coinControl) const
{
// Sanity check to make sure this function is never called with a too large
// amount to spend, resulting to a possible crash due to out of memory condition.
Expand Down Expand Up @@ -3059,8 +3059,6 @@ bool CWallet::GetCoinsToSpend(
_("Required amount exceed value spend limit"));
}

std::list<CSigmaEntry> coins = GetAvailableCoins(coinControl, false, forEstimation);

CAmount availableBalance = CalculateCoinsBalance(coins.begin(), coins.end());

if (roundedRequired * zeros > availableBalance) {
Expand Down Expand Up @@ -3159,10 +3157,10 @@ bool CWallet::GetCoinsToJoinSplit(
CAmount required,
std::vector<CLelantusEntry>& coinsToSpend_out,
CAmount& changeToMint,
std::list<CLelantusEntry>& coins,
const size_t coinsToSpendLimit,
const CAmount amountToSpendLimit,
const CCoinControl *coinControl,
bool forEstimation) const
const CCoinControl *coinControl) const
{
// Sanity check to make sure this function is never called with a too large
// amount to spend, resulting to a possible crash due to out of memory condition.
Expand All @@ -3181,8 +3179,6 @@ bool CWallet::GetCoinsToJoinSplit(
_("The required amount exceeds spend limit"));
}

std::list<CLelantusEntry> coins = GetAvailableLelantusCoins(coinControl, false, forEstimation);

CAmount availableBalance = CalculateLelantusCoinsBalance(coins.begin(), coins.end());

if (required > availableBalance) {
Expand Down Expand Up @@ -6875,13 +6871,14 @@ std::pair<CAmount, unsigned int> CWallet::EstimateJoinSplitFee(CAmount required,
unsigned size;
std::vector<CLelantusEntry> spendCoins;
std::vector<CSigmaEntry> sigmaSpendCoins;

std::list<CSigmaEntry> coins = this->GetAvailableCoins(coinControl, false, true);
std::list<CSigmaEntry> sigmaCoins = this->GetAvailableCoins(coinControl, false, true);
CAmount availableSigmaBalance(0);
for (auto coin : coins) {
for (auto coin : sigmaCoins) {
availableSigmaBalance += coin.get_denomination_value();
}

std::list<CLelantusEntry> coins = GetAvailableLelantusCoins(coinControl, false, true);

for (fee = payTxFee.GetFeePerK();;) {
CAmount currentRequired = required;

Expand All @@ -6901,17 +6898,16 @@ std::pair<CAmount, unsigned int> CWallet::EstimateJoinSplitFee(CAmount required,
inputFromSigma = availableSigmaBalance;
else
inputFromSigma = currentRequired;

this->GetCoinsToSpend(inputFromSigma, sigmaSpendCoins, denomChanges, //try to spend sigma first
this->GetCoinsToSpend(inputFromSigma, sigmaSpendCoins, denomChanges, sigmaCoins, //try to spend sigma first
consensusParams.nMaxLelantusInputPerTransaction,
consensusParams.nMaxValueLelantusSpendPerTransaction, coinControl, true);
consensusParams.nMaxValueLelantusSpendPerTransaction, coinControl);
currentRequired -= inputFromSigma;
}

if (currentRequired > 0) {
if (!this->GetCoinsToJoinSplit(currentRequired, spendCoins, changeToMint,
if (!this->GetCoinsToJoinSplit(currentRequired, spendCoins, changeToMint, coins,
consensusParams.nMaxLelantusInputPerTransaction,
consensusParams.nMaxValueLelantusSpendPerTransaction, coinControl, true)) {
consensusParams.nMaxValueLelantusSpendPerTransaction, coinControl)) {
return std::make_pair(0, 0);
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -943,19 +943,19 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
CAmount required,
std::vector<CSigmaEntry>& coinsToSpend_out,
std::vector<sigma::CoinDenomination>& coinsToMint_out,
std::list<CSigmaEntry>& coins,
const size_t coinsLimit = SIZE_MAX,
const CAmount amountLimit = MAX_MONEY,
const CCoinControl *coinControl = NULL,
bool forEstimation = false) const;
const CCoinControl *coinControl = NULL) const;

bool GetCoinsToJoinSplit(
CAmount required,
std::vector<CLelantusEntry>& coinsToSpend_out,
CAmount& changeToMint,
std::list<CLelantusEntry>& coins,
const size_t coinsToSpendLimit = SIZE_MAX,
const CAmount amountToSpendLimit = MAX_MONEY,
const CCoinControl *coinControl = NULL,
bool forEstimation = false) const;
const CCoinControl *coinControl = NULL) const;

/**
* Insert additional inputs into the transaction by
Expand Down

0 comments on commit 305d2d0

Please sign in to comment.