mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +01:00
Implement significantly improved createdenominations algorithm (#3479)
* Allow the creation of denoms on regtest. Ignore the fact there are no MNs on regtest Signed-off-by: pasta <pasta@dashboost.org> * implement significantly improved createdenominations algorithm Signed-off-by: pasta <pasta@dashboost.org> * change int denomsToCreate Signed-off-by: pasta <pasta@dashboost.org> * Remove debugging code and use a const iterator instead of calling find multiple times Signed-off-by: pasta <pasta@dashboost.org> * vecDenominationsSkipped and *DenomSkipped are nolonger used Signed-off-by: Pasta <pasta@dashboost.org> Signed-off-by: pasta <pasta@dashboost.org> * inputs -> outputs Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com> Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
This commit is contained in:
parent
fe208c98e3
commit
926087aac6
@ -661,21 +661,6 @@ void CPrivateSendClientManager::UpdatedSuccessBlock()
|
||||
nCachedLastSuccessBlock = nCachedBlockHeight;
|
||||
}
|
||||
|
||||
bool CPrivateSendClientManager::IsDenomSkipped(const CAmount& nDenomValue)
|
||||
{
|
||||
return std::find(vecDenominationsSkipped.begin(), vecDenominationsSkipped.end(), nDenomValue) != vecDenominationsSkipped.end();
|
||||
}
|
||||
|
||||
void CPrivateSendClientManager::AddSkippedDenom(const CAmount& nDenomValue)
|
||||
{
|
||||
vecDenominationsSkipped.push_back(nDenomValue);
|
||||
}
|
||||
|
||||
void CPrivateSendClientManager::RemoveSkippedDenom(const CAmount& nDenomValue)
|
||||
{
|
||||
vecDenominationsSkipped.erase(std::remove(vecDenominationsSkipped.begin(), vecDenominationsSkipped.end(), nDenomValue), vecDenominationsSkipped.end());
|
||||
}
|
||||
|
||||
bool CPrivateSendClientManager::WaitForAnotherBlock()
|
||||
{
|
||||
if (!masternodeSync.IsBlockchainSynced()) return true;
|
||||
@ -789,7 +774,8 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool
|
||||
return false;
|
||||
}
|
||||
|
||||
if (deterministicMNManager->GetListAtChainTip().GetValidMNsCount() == 0) {
|
||||
if (deterministicMNManager->GetListAtChainTip().GetValidMNsCount() == 0 &&
|
||||
Params().NetworkIDString() != CBaseChainParams::REGTEST) {
|
||||
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::DoAutomaticDenominating -- No Masternodes detected\n");
|
||||
strAutoDenomResult = _("No Masternodes detected.");
|
||||
return false;
|
||||
@ -1537,55 +1523,109 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate,
|
||||
bool fAddFinal = true;
|
||||
std::vector<CAmount> vecStandardDenoms = CPrivateSend::GetStandardDenominations();
|
||||
|
||||
for (auto it = vecStandardDenoms.rbegin(); it != vecStandardDenoms.rend(); ++it) {
|
||||
CAmount nDenomValue = *it;
|
||||
|
||||
// Note: denoms are skipped if there are already nPrivateSendDenoms of them
|
||||
// and there are still larger denoms which can be used for mixing
|
||||
|
||||
// check skipped denoms
|
||||
if (privateSendClient.IsDenomSkipped(nDenomValue)) {
|
||||
strAutoDenomResult = strprintf(_("Too many %f denominations, skipping."), (float)nDenomValue / COIN);
|
||||
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::CreateDenominated -- %s\n", strAutoDenomResult);
|
||||
continue;
|
||||
}
|
||||
|
||||
// find new denoms to skip if any (ignore the largest one)
|
||||
if (nDenomValue != vecStandardDenoms.front() && GetWallets()[0]->CountInputsWithAmount(nDenomValue) > privateSendClient.nPrivateSendDenoms) {
|
||||
strAutoDenomResult = strprintf(_("Too many %f denominations, removing."), (float)nDenomValue / COIN);
|
||||
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::CreateDenominated -- %s\n", strAutoDenomResult);
|
||||
privateSendClient.AddSkippedDenom(nDenomValue);
|
||||
continue;
|
||||
}
|
||||
|
||||
int nOutputs = 0;
|
||||
|
||||
auto needMoreOutputs = [&]() {
|
||||
bool fRegular = (nValueLeft >= nDenomValue && nBalanceToDenominate >= nDenomValue);
|
||||
bool fFinal = (fAddFinal
|
||||
&& nValueLeft >= nDenomValue
|
||||
&& nBalanceToDenominate > 0
|
||||
&& nBalanceToDenominate < nDenomValue);
|
||||
fAddFinal = false; // add final denom only once, only the smalest possible one
|
||||
return fRegular || fFinal;
|
||||
};
|
||||
|
||||
// add each output up to 11 times until it can't be added again
|
||||
while (needMoreOutputs() && nOutputs <= 10) {
|
||||
CScript scriptDenom = keyHolderStorageDenom.AddKey(GetWallets()[0]);
|
||||
|
||||
vecSend.push_back((CRecipient){scriptDenom, nDenomValue, false});
|
||||
|
||||
//increment outputs and subtract denomination amount
|
||||
nOutputs++;
|
||||
nValueLeft -= nDenomValue;
|
||||
nBalanceToDenominate -= nDenomValue;
|
||||
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::CreateDenominated -- 1 - totalOutputs: %d, nOutputsTotal: %d, nOutputs: %d, nValueLeft: %f\n", nOutputsTotal + nOutputs, nOutputsTotal, nOutputs, (float)nValueLeft / COIN);
|
||||
}
|
||||
|
||||
nOutputsTotal += nOutputs;
|
||||
if (nValueLeft == 0 || nBalanceToDenominate <= 0) break;
|
||||
std::map<CAmount, int> mapDenomCount;
|
||||
for (auto nDenomValue : vecStandardDenoms) {
|
||||
mapDenomCount.insert(std::pair<CAmount, int>(nDenomValue, GetWallets()[0]->CountInputsWithAmount(nDenomValue)));
|
||||
}
|
||||
|
||||
// NOTE: We do not allow txes larger than 100kB, so we have to limit the number of outputs here.
|
||||
// We still want to create a lot of outputs though.
|
||||
// Knowing that each CTxOut is ~35b big, 400 outputs should take 400 x ~35b = ~17.5kb.
|
||||
// More than 500 outputs starts to make qt quite laggy.
|
||||
// Additionally to need all 500 outputs (assuming a max per denom of 50) you'd need to be trying to
|
||||
// create denominations for over 3000 dash!
|
||||
|
||||
// Will generate outputs for the createdenoms up to privatesendmaxdenoms per denom
|
||||
|
||||
// This works in the way creating PS denoms has traditionally worked, assuming enough funds,
|
||||
// it will start with the smallest denom then create 11 of those, then go up to the next biggest denom create 11
|
||||
// and repeat. Previously, once the largest denom was reached, as many would be created were created as possible and
|
||||
// then any remaining was put into a change address and denominations were created in the same manner a block later.
|
||||
// Now, in this system, so long as we don't reach 500 outputs the process repeats in the same transaction,
|
||||
// creating up to privatesenddenoms per denomination in a single transaction.
|
||||
while (nValueLeft >= CPrivateSend::GetSmallestDenomination() && nOutputsTotal <= 500) {
|
||||
for (auto it = vecStandardDenoms.rbegin(); it != vecStandardDenoms.rend(); ++it) {
|
||||
CAmount nDenomValue = *it;
|
||||
auto currentDenomIt = mapDenomCount.find(nDenomValue);
|
||||
|
||||
int nOutputs = 0;
|
||||
|
||||
auto needMoreOutputs = [&]() {
|
||||
bool fRegular = (nValueLeft >= nDenomValue && nBalanceToDenominate >= nDenomValue);
|
||||
bool fFinal = (fAddFinal
|
||||
&& nValueLeft >= nDenomValue
|
||||
&& nBalanceToDenominate > 0
|
||||
&& nBalanceToDenominate < nDenomValue);
|
||||
fAddFinal = false; // add final denom only once, only the smalest possible one
|
||||
|
||||
return fRegular || fFinal;
|
||||
};
|
||||
|
||||
// add each output up to 11 times or until it can't be added again or until we reach nPrivateSendDenoms
|
||||
while (needMoreOutputs() && nOutputs <= 10 && currentDenomIt->second <= privateSendClient.nPrivateSendDenoms) {
|
||||
CScript scriptDenom = keyHolderStorageDenom.AddKey(GetWallets()[0]);
|
||||
|
||||
vecSend.push_back((CRecipient) {scriptDenom, nDenomValue, false});
|
||||
|
||||
// increment outputs and subtract denomination amount
|
||||
nOutputs++;
|
||||
currentDenomIt->second++;
|
||||
nValueLeft -= nDenomValue;
|
||||
nBalanceToDenominate -= nDenomValue;
|
||||
LogPrint(BCLog::PRIVATESEND,
|
||||
"CPrivateSendClientSession::CreateDenominated -- 1 - totalOutputs: %d, nOutputsTotal: %d, nOutputs: %d, nValueLeft: %f\n",
|
||||
nOutputsTotal + nOutputs, nOutputsTotal, nOutputs, (float) nValueLeft / COIN);
|
||||
}
|
||||
|
||||
nOutputsTotal += nOutputs;
|
||||
if (nValueLeft == 0 || nBalanceToDenominate <= 0) break;
|
||||
}
|
||||
|
||||
bool finished = true;
|
||||
for (auto it : mapDenomCount) {
|
||||
// Check if this specific denom could use another loop, check that there aren't nPrivateSendDenoms of this
|
||||
// denom and that our nValueLeft/nBalanceToDenominate is enough to create one of these denoms, if so, loop again.
|
||||
if (it.second <= privateSendClient.nPrivateSendDenoms && nValueLeft >= it.first && nBalanceToDenominate >= it.first) {
|
||||
finished = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (finished) break;
|
||||
}
|
||||
|
||||
// Now that nPrivateSendDenoms worth of each denom have been created, do something with the remainder.
|
||||
while (nValueLeft >= CPrivateSend::GetSmallestDenomination() && nBalanceToDenominate >= CPrivateSend::GetSmallestDenomination()
|
||||
&& nOutputsTotal <= 500) {
|
||||
|
||||
// Go big to small
|
||||
for (long nDenomValue : vecStandardDenoms) {
|
||||
int nOutputs = 0;
|
||||
|
||||
// Number of denoms we can create given our denom and the amount of funds we have left
|
||||
int denomsToCreateValue = nValueLeft / nDenomValue;
|
||||
int denomsToCreateBal = nBalanceToDenominate / nDenomValue;
|
||||
// Use the smaller value
|
||||
int denomsToCreate = denomsToCreateValue > denomsToCreateBal ? denomsToCreateBal : denomsToCreateValue;
|
||||
for (int i = 0; i < denomsToCreate; i++) {
|
||||
CScript scriptDenom = keyHolderStorageDenom.AddKey(GetWallets()[0]);
|
||||
|
||||
vecSend.push_back((CRecipient) {scriptDenom, nDenomValue, false});
|
||||
|
||||
// increment outputs and subtract denomination amount
|
||||
nOutputs++;
|
||||
mapDenomCount.find(nDenomValue)->second++;
|
||||
nValueLeft -= nDenomValue;
|
||||
nBalanceToDenominate -= nDenomValue;
|
||||
LogPrint(BCLog::PRIVATESEND,
|
||||
"CPrivateSendClientSession::CreateDenominated -- 1 - totalOutputs: %d, nOutputsTotal: %d, nOutputs: %d, nValueLeft: %f\n",
|
||||
nOutputsTotal + nOutputs, nOutputsTotal, nOutputs, (float) nValueLeft / COIN);
|
||||
|
||||
}
|
||||
nOutputsTotal += nOutputs;
|
||||
}
|
||||
}
|
||||
|
||||
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::CreateDenominated -- 2 - nOutputsTotal: %d, nValueLeft: %f\n", nOutputsTotal, (float)nValueLeft / COIN);
|
||||
|
||||
// No reasons to create mixing collaterals if we can't create denoms to mix
|
||||
|
@ -172,8 +172,6 @@ private:
|
||||
// Keep track of the used Masternodes
|
||||
std::vector<COutPoint> vecMasternodesUsed;
|
||||
|
||||
std::vector<CAmount> vecDenominationsSkipped;
|
||||
|
||||
// TODO: or map<denom, CPrivateSendClientSession> ??
|
||||
std::deque<CPrivateSendClientSession> deqSessions;
|
||||
mutable CCriticalSection cs_deqsessions;
|
||||
@ -204,7 +202,6 @@ public:
|
||||
|
||||
CPrivateSendClientManager() :
|
||||
vecMasternodesUsed(),
|
||||
vecDenominationsSkipped(),
|
||||
deqSessions(),
|
||||
nCachedLastSuccessBlock(0),
|
||||
nMinBlocksToWait(1),
|
||||
@ -223,10 +220,6 @@ public:
|
||||
|
||||
void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman);
|
||||
|
||||
bool IsDenomSkipped(const CAmount& nDenomValue);
|
||||
void AddSkippedDenom(const CAmount& nDenomValue);
|
||||
void RemoveSkippedDenom(const CAmount& nDenomValue);
|
||||
|
||||
void ResetPool();
|
||||
|
||||
std::string GetStatuses();
|
||||
|
@ -4091,7 +4091,6 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CCon
|
||||
coin.BindWallet(this);
|
||||
NotifyTransactionChanged(this, txin.prevout.hash, CT_UPDATED);
|
||||
updated_hahes.insert(txin.prevout.hash);
|
||||
privateSendClient.RemoveSkippedDenom(coin.tx->vout[txin.prevout.n].nValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user