Merge pull request #1828 from UdjinM6/bp_1810_1819

Backport critical fixes from develop
This commit is contained in:
UdjinM6 2018-01-10 12:21:06 +03:00 committed by GitHub
commit 57e7cc4c63
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 68 additions and 53 deletions

View File

@ -122,15 +122,11 @@ bool CInstantSend::ProcessTxLockRequest(const CTxLockRequest& txLockRequest, CCo
} }
LogPrintf("CInstantSend::ProcessTxLockRequest -- accepted, txid=%s\n", txHash.ToString()); LogPrintf("CInstantSend::ProcessTxLockRequest -- accepted, txid=%s\n", txHash.ToString());
std::map<uint256, CTxLockCandidate>::iterator itLockCandidate = mapTxLockCandidates.find(txHash);
CTxLockCandidate& txLockCandidate = itLockCandidate->second;
Vote(txLockCandidate, connman);
ProcessOrphanTxLockVotes(connman);
// Masternodes will sometimes propagate votes before the transaction is known to the client. // Masternodes will sometimes propagate votes before the transaction is known to the client.
// If this just happened - lock inputs, resolve conflicting locks, update transaction status // If this just happened - lock inputs, resolve conflicting locks, update transaction status
// forcing external script notification. // forcing external script notification.
TryToFinalizeLockCandidate(txLockCandidate); std::map<uint256, CTxLockCandidate>::iterator itLockCandidate = mapTxLockCandidates.find(txHash);
TryToFinalizeLockCandidate(itLockCandidate->second);
return true; return true;
} }
@ -182,6 +178,18 @@ void CInstantSend::CreateEmptyTxLockCandidate(const uint256& txHash)
mapTxLockCandidates.insert(std::make_pair(txHash, CTxLockCandidate(txLockRequest))); mapTxLockCandidates.insert(std::make_pair(txHash, CTxLockCandidate(txLockRequest)));
} }
void CInstantSend::Vote(const uint256& txHash, CConnman& connman)
{
AssertLockHeld(cs_main);
LOCK(cs_instantsend);
std::map<uint256, CTxLockCandidate>::iterator itLockCandidate = mapTxLockCandidates.find(txHash);
if (itLockCandidate == mapTxLockCandidates.end()) return;
Vote(itLockCandidate->second, connman);
// Let's see if our vote changed smth
TryToFinalizeLockCandidate(itLockCandidate->second);
}
void CInstantSend::Vote(CTxLockCandidate& txLockCandidate, CConnman& connman) void CInstantSend::Vote(CTxLockCandidate& txLockCandidate, CConnman& connman)
{ {
if(!fMasterNode) return; if(!fMasterNode) return;
@ -190,6 +198,8 @@ void CInstantSend::Vote(CTxLockCandidate& txLockCandidate, CConnman& connman)
LOCK2(cs_main, cs_instantsend); LOCK2(cs_main, cs_instantsend);
uint256 txHash = txLockCandidate.GetHash(); uint256 txHash = txLockCandidate.GetHash();
// We should never vote on a Transaction Lock Request that was not (yet) accepted by the mempool
if(mapLockRequestAccepted.find(txHash) == mapLockRequestAccepted.end()) return;
// check if we need to vote on this candidate's outpoints, // check if we need to vote on this candidate's outpoints,
// it's possible that we need to vote for several of them // it's possible that we need to vote for several of them
std::map<COutPoint, COutPointLock>::iterator itOutpointLock = txLockCandidate.mapOutPointLocks.begin(); std::map<COutPoint, COutPointLock>::iterator itOutpointLock = txLockCandidate.mapOutPointLocks.begin();

View File

@ -86,6 +86,7 @@ public:
void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, CConnman& connman); void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, CConnman& connman);
bool ProcessTxLockRequest(const CTxLockRequest& txLockRequest, CConnman& connman); bool ProcessTxLockRequest(const CTxLockRequest& txLockRequest, CConnman& connman);
void Vote(const uint256& txHash, CConnman& connman);
bool AlreadyHave(const uint256& hash); bool AlreadyHave(const uint256& hash);

View File

@ -1635,6 +1635,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
LogPrintf("TXLOCKREQUEST -- Transaction Lock Request accepted, txid=%s, peer=%d\n", LogPrintf("TXLOCKREQUEST -- Transaction Lock Request accepted, txid=%s, peer=%d\n",
tx.GetHash().ToString(), pfrom->id); tx.GetHash().ToString(), pfrom->id);
instantsend.AcceptLockRequest(txLockRequest); instantsend.AcceptLockRequest(txLockRequest);
instantsend.Vote(tx.GetHash(), connman);
} }
mempool.check(pcoinsTip); mempool.check(pcoinsTip);

View File

@ -873,23 +873,19 @@ bool CPrivateSendClient::JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CCon
vecMasternodesUsed.push_back(dsq.vin.prevout); vecMasternodesUsed.push_back(dsq.vin.prevout);
CNode* pnodeFound = NULL; bool fSkip = false;
bool fDisconnect = false; connman.ForNode(infoMn.addr, CConnman::AllNodes, [&fSkip](CNode* pnode) {
connman.ForNode(infoMn.addr, CConnman::AllNodes, [&pnodeFound, &fDisconnect](CNode* pnode) { fSkip = pnode->fDisconnect || pnode->fMasternode;
pnodeFound = pnode;
if(pnodeFound->fDisconnect) {
fDisconnect = true;
} else {
pnodeFound->AddRef();
}
return true; return true;
}); });
if (fDisconnect) if (fSkip) {
LogPrintf("CPrivateSendClient::JoinExistingQueue -- skipping masternode connection, addr=%s\n", infoMn.addr.ToString());
continue; continue;
}
LogPrintf("CPrivateSendClient::JoinExistingQueue -- attempt to connect to masternode from queue, addr=%s\n", infoMn.addr.ToString()); LogPrintf("CPrivateSendClient::JoinExistingQueue -- attempt to connect to masternode from queue, addr=%s\n", infoMn.addr.ToString());
// connect to Masternode and submit the queue request // connect to Masternode and submit the queue request
CNode* pnode = (pnodeFound && pnodeFound->fMasternode) ? pnodeFound : connman.ConnectNode(CAddress(infoMn.addr, NODE_NETWORK), NULL, true); CNode* pnode = connman.ConnectNode(CAddress(infoMn.addr, NODE_NETWORK), NULL, true);
if(pnode) { if(pnode) {
infoMixingMasternode = infoMn; infoMixingMasternode = infoMn;
nSessionDenom = dsq.nDenom; nSessionDenom = dsq.nDenom;
@ -900,9 +896,6 @@ bool CPrivateSendClient::JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CCon
strAutoDenomResult = _("Mixing in progress..."); strAutoDenomResult = _("Mixing in progress...");
SetState(POOL_STATE_QUEUE); SetState(POOL_STATE_QUEUE);
nTimeLastSuccessfulStep = GetTimeMillis(); nTimeLastSuccessfulStep = GetTimeMillis();
if(pnodeFound) {
pnodeFound->Release();
}
return true; return true;
} else { } else {
LogPrintf("CPrivateSendClient::JoinExistingQueue -- can't connect, addr=%s\n", infoMn.addr.ToString()); LogPrintf("CPrivateSendClient::JoinExistingQueue -- can't connect, addr=%s\n", infoMn.addr.ToString());
@ -947,24 +940,19 @@ bool CPrivateSendClient::StartNewQueue(CAmount nValueMin, CAmount nBalanceNeedsA
continue; continue;
} }
CNode* pnodeFound = NULL; bool fSkip = false;
bool fDisconnect = false; connman.ForNode(infoMn.addr, CConnman::AllNodes, [&fSkip](CNode* pnode) {
connman.ForNode(infoMn.addr, CConnman::AllNodes, [&pnodeFound, &fDisconnect](CNode* pnode) { fSkip = pnode->fDisconnect || pnode->fMasternode;
pnodeFound = pnode;
if(pnodeFound->fDisconnect) {
fDisconnect = true;
} else {
pnodeFound->AddRef();
}
return true; return true;
}); });
if (fDisconnect) { if (fSkip) {
LogPrintf("CPrivateSendClient::StartNewQueue -- skipping masternode connection, addr=%s\n", infoMn.addr.ToString());
nTries++; nTries++;
continue; continue;
} }
LogPrintf("CPrivateSendClient::StartNewQueue -- attempt %d connection to Masternode %s\n", nTries, infoMn.addr.ToString()); LogPrintf("CPrivateSendClient::StartNewQueue -- attempt %d connection to Masternode %s\n", nTries, infoMn.addr.ToString());
CNode* pnode = (pnodeFound && pnodeFound->fMasternode) ? pnodeFound : connman.ConnectNode(CAddress(infoMn.addr, NODE_NETWORK), NULL, true); CNode* pnode = connman.ConnectNode(CAddress(infoMn.addr, NODE_NETWORK), NULL, true);
if(pnode) { if(pnode) {
LogPrintf("CPrivateSendClient::StartNewQueue -- connected, addr=%s\n", infoMn.addr.ToString()); LogPrintf("CPrivateSendClient::StartNewQueue -- connected, addr=%s\n", infoMn.addr.ToString());
infoMixingMasternode = infoMn; infoMixingMasternode = infoMn;
@ -982,9 +970,6 @@ bool CPrivateSendClient::StartNewQueue(CAmount nValueMin, CAmount nBalanceNeedsA
strAutoDenomResult = _("Mixing in progress..."); strAutoDenomResult = _("Mixing in progress...");
SetState(POOL_STATE_QUEUE); SetState(POOL_STATE_QUEUE);
nTimeLastSuccessfulStep = GetTimeMillis(); nTimeLastSuccessfulStep = GetTimeMillis();
if(pnodeFound) {
pnodeFound->Release();
}
return true; return true;
} else { } else {
LogPrintf("CPrivateSendClient::StartNewQueue -- can't connect, addr=%s\n", infoMn.addr.ToString()); LogPrintf("CPrivateSendClient::StartNewQueue -- can't connect, addr=%s\n", infoMn.addr.ToString());
@ -1002,6 +987,16 @@ bool CPrivateSendClient::SubmitDenominate(CConnman& connman)
std::vector<CTxOut> vecTxOutRet; std::vector<CTxOut> vecTxOutRet;
// Submit transaction to the pool if we get here // Submit transaction to the pool if we get here
if (nLiquidityProvider) {
// Try to use only inputs with the same number of rounds starting from the lowest number of rounds possible
for(int i = 0; i< nPrivateSendRounds; i++) {
if(PrepareDenominate(i, i + 1, strError, vecTxDSInRet, vecTxOutRet)) {
LogPrintf("CPrivateSendClient::SubmitDenominate -- Running PrivateSend denominate for %d rounds, success\n", i);
return SendDenominate(vecTxDSInRet, vecTxOutRet, connman);
}
LogPrint("privatesend", "CPrivateSendClient::SubmitDenominate -- Running PrivateSend denominate for %d rounds, error: %s\n", i, strError);
}
} else {
// Try to use only inputs with the same number of rounds starting from the highest number of rounds possible // Try to use only inputs with the same number of rounds starting from the highest number of rounds possible
for(int i = nPrivateSendRounds; i > 0; i--) { for(int i = nPrivateSendRounds; i > 0; i--) {
if(PrepareDenominate(i - 1, i, strError, vecTxDSInRet, vecTxOutRet)) { if(PrepareDenominate(i - 1, i, strError, vecTxDSInRet, vecTxOutRet)) {
@ -1010,6 +1005,7 @@ bool CPrivateSendClient::SubmitDenominate(CConnman& connman)
} }
LogPrint("privatesend", "CPrivateSendClient::SubmitDenominate -- Running PrivateSend denominate for %d rounds, error: %s\n", i, strError); LogPrint("privatesend", "CPrivateSendClient::SubmitDenominate -- Running PrivateSend denominate for %d rounds, error: %s\n", i, strError);
} }
}
// We failed? That's strange but let's just make final attempt and try to mix everything // We failed? That's strange but let's just make final attempt and try to mix everything
if(PrepareDenominate(0, nPrivateSendRounds, strError, vecTxDSInRet, vecTxOutRet)) { if(PrepareDenominate(0, nPrivateSendRounds, strError, vecTxDSInRet, vecTxOutRet)) {
@ -1100,7 +1096,7 @@ bool CPrivateSendClient::PrepareDenominate(int nMinRounds, int nMaxRounds, std::
vecTxDSIn.erase(it); vecTxDSIn.erase(it);
vCoins.erase(it2); vCoins.erase(it2);
CScript scriptDenom = keyHolderStorage.AddKey(pwalletMain).GetScriptForDestination(); CScript scriptDenom = keyHolderStorage.AddKey(pwalletMain);
// add new output // add new output
CTxOut txout(nValueDenom, scriptDenom); CTxOut txout(nValueDenom, scriptDenom);
@ -1276,7 +1272,7 @@ bool CPrivateSendClient::CreateDenominated(const CompactTallyItem& tallyItem, bo
// ****** Add an output for mixing collaterals ************ / // ****** Add an output for mixing collaterals ************ /
if(fCreateMixingCollaterals) { if(fCreateMixingCollaterals) {
CScript scriptCollateral = keyHolderStorageDenom.AddKey(pwalletMain).GetScriptForDestination(); CScript scriptCollateral = keyHolderStorageDenom.AddKey(pwalletMain);
vecSend.push_back((CRecipient){ scriptCollateral, CPrivateSend::GetMaxCollateralAmount(), false }); vecSend.push_back((CRecipient){ scriptCollateral, CPrivateSend::GetMaxCollateralAmount(), false });
nValueLeft -= CPrivateSend::GetMaxCollateralAmount(); nValueLeft -= CPrivateSend::GetMaxCollateralAmount();
} }
@ -1311,7 +1307,7 @@ bool CPrivateSendClient::CreateDenominated(const CompactTallyItem& tallyItem, bo
// add each output up to 11 times until it can't be added again // add each output up to 11 times until it can't be added again
while(nValueLeft - nDenomValue >= 0 && nOutputs <= 10) { while(nValueLeft - nDenomValue >= 0 && nOutputs <= 10) {
CScript scriptDenom = keyHolderStorageDenom.AddKey(pwalletMain).GetScriptForDestination(); CScript scriptDenom = keyHolderStorageDenom.AddKey(pwalletMain);
vecSend.push_back((CRecipient){ scriptDenom, nDenomValue, false }); vecSend.push_back((CRecipient){ scriptDenom, nDenomValue, false });

View File

@ -25,14 +25,16 @@ CScript CKeyHolder::GetScriptForDestination() const
} }
const CKeyHolder& CKeyHolderStorage::AddKey(CWallet* pwallet) CScript CKeyHolderStorage::AddKey(CWallet* pwallet)
{ {
LOCK(cs_storage);
storage.emplace_back(std::unique_ptr<CKeyHolder>(new CKeyHolder(pwallet))); storage.emplace_back(std::unique_ptr<CKeyHolder>(new CKeyHolder(pwallet)));
LogPrintf("CKeyHolderStorage::%s -- storage size %lld\n", __func__, storage.size()); LogPrintf("CKeyHolderStorage::%s -- storage size %lld\n", __func__, storage.size());
return *storage.back(); return storage.back()->GetScriptForDestination();
} }
void CKeyHolderStorage::KeepAll(){ void CKeyHolderStorage::KeepAll(){
LOCK(cs_storage);
if (storage.size() > 0) { if (storage.size() > 0) {
for (auto &key : storage) { for (auto &key : storage) {
key->KeepKey(); key->KeepKey();
@ -44,6 +46,7 @@ void CKeyHolderStorage::KeepAll(){
void CKeyHolderStorage::ReturnAll() void CKeyHolderStorage::ReturnAll()
{ {
LOCK(cs_storage);
if (storage.size() > 0) { if (storage.size() > 0) {
for (auto &key : storage) { for (auto &key : storage) {
key->ReturnKey(); key->ReturnKey();

View File

@ -27,9 +27,10 @@ class CKeyHolderStorage
{ {
private: private:
std::vector<std::unique_ptr<CKeyHolder> > storage; std::vector<std::unique_ptr<CKeyHolder> > storage;
mutable CCriticalSection cs_storage;
public: public:
const CKeyHolder& AddKey(CWallet* pwalletIn); CScript AddKey(CWallet* pwalletIn);
void KeepAll(); void KeepAll();
void ReturnAll(); void ReturnAll();

View File

@ -132,7 +132,8 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent)
currentWatchOnlyBalance(-1), currentWatchOnlyBalance(-1),
currentWatchUnconfBalance(-1), currentWatchUnconfBalance(-1),
currentWatchImmatureBalance(-1), currentWatchImmatureBalance(-1),
txdelegate(new TxViewDelegate(platformStyle, this)) txdelegate(new TxViewDelegate(platformStyle, this)),
timer(nullptr)
{ {
ui->setupUi(this); ui->setupUi(this);
QString theme = GUIUtil::getThemeName(); QString theme = GUIUtil::getThemeName();
@ -195,7 +196,7 @@ void OverviewPage::handleOutOfSyncWarningClicks()
OverviewPage::~OverviewPage() OverviewPage::~OverviewPage()
{ {
if(!fLiteMode && !fMasterNode) disconnect(timer, SIGNAL(timeout()), this, SLOT(privateSendStatus())); if(timer) disconnect(timer, SIGNAL(timeout()), this, SLOT(privateSendStatus()));
delete ui; delete ui;
} }

View File

@ -404,6 +404,8 @@ void TransactionView::contextualMenu(const QPoint &point)
{ {
QModelIndex index = transactionView->indexAt(point); QModelIndex index = transactionView->indexAt(point);
QModelIndexList selection = transactionView->selectionModel()->selectedRows(0); QModelIndexList selection = transactionView->selectionModel()->selectedRows(0);
if (selection.empty())
return;
// check if transaction can be abandoned, disable context menu action in case it doesn't // check if transaction can be abandoned, disable context menu action in case it doesn't
uint256 hash; uint256 hash;

View File

@ -204,7 +204,7 @@ struct mempoolentry_txid
class CompareTxMemPoolEntryByDescendantScore class CompareTxMemPoolEntryByDescendantScore
{ {
public: public:
bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const
{ {
bool fUseADescendants = UseDescendantScore(a); bool fUseADescendants = UseDescendantScore(a);
bool fUseBDescendants = UseDescendantScore(b); bool fUseBDescendants = UseDescendantScore(b);
@ -226,7 +226,7 @@ public:
} }
// Calculate which score to use for an entry (avoiding division). // Calculate which score to use for an entry (avoiding division).
bool UseDescendantScore(const CTxMemPoolEntry &a) bool UseDescendantScore(const CTxMemPoolEntry &a) const
{ {
double f1 = (double)a.GetModifiedFee() * a.GetSizeWithDescendants(); double f1 = (double)a.GetModifiedFee() * a.GetSizeWithDescendants();
double f2 = (double)a.GetModFeesWithDescendants() * a.GetTxSize(); double f2 = (double)a.GetModFeesWithDescendants() * a.GetTxSize();
@ -241,7 +241,7 @@ public:
class CompareTxMemPoolEntryByScore class CompareTxMemPoolEntryByScore
{ {
public: public:
bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const
{ {
double f1 = (double)a.GetModifiedFee() * b.GetTxSize(); double f1 = (double)a.GetModifiedFee() * b.GetTxSize();
double f2 = (double)b.GetModifiedFee() * a.GetTxSize(); double f2 = (double)b.GetModifiedFee() * a.GetTxSize();
@ -255,7 +255,7 @@ public:
class CompareTxMemPoolEntryByEntryTime class CompareTxMemPoolEntryByEntryTime
{ {
public: public:
bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const
{ {
return a.GetTime() < b.GetTime(); return a.GetTime() < b.GetTime();
} }

View File

@ -2410,7 +2410,7 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
} }
static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,unsigned int> > >vValue, const CAmount& nTotalLower, const CAmount& nTargetValue, static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,unsigned int> > >vValue, const CAmount& nTotalLower, const CAmount& nTargetValue,
vector<char>& vfBest, CAmount& nBest, int iterations = 1000, bool fUseInstantSend = false) vector<char>& vfBest, CAmount& nBest, bool fUseInstantSend = false, int iterations = 1000)
{ {
vector<char> vfIncluded; vector<char> vfIncluded;