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());
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.
// If this just happened - lock inputs, resolve conflicting locks, update transaction status
// forcing external script notification.
TryToFinalizeLockCandidate(txLockCandidate);
std::map<uint256, CTxLockCandidate>::iterator itLockCandidate = mapTxLockCandidates.find(txHash);
TryToFinalizeLockCandidate(itLockCandidate->second);
return true;
}
@ -182,6 +178,18 @@ void CInstantSend::CreateEmptyTxLockCandidate(const uint256& txHash)
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)
{
if(!fMasterNode) return;
@ -190,6 +198,8 @@ void CInstantSend::Vote(CTxLockCandidate& txLockCandidate, CConnman& connman)
LOCK2(cs_main, cs_instantsend);
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,
// it's possible that we need to vote for several of them
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);
bool ProcessTxLockRequest(const CTxLockRequest& txLockRequest, CConnman& connman);
void Vote(const uint256& txHash, CConnman& connman);
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",
tx.GetHash().ToString(), pfrom->id);
instantsend.AcceptLockRequest(txLockRequest);
instantsend.Vote(tx.GetHash(), connman);
}
mempool.check(pcoinsTip);

View File

@ -873,23 +873,19 @@ bool CPrivateSendClient::JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CCon
vecMasternodesUsed.push_back(dsq.vin.prevout);
CNode* pnodeFound = NULL;
bool fDisconnect = false;
connman.ForNode(infoMn.addr, CConnman::AllNodes, [&pnodeFound, &fDisconnect](CNode* pnode) {
pnodeFound = pnode;
if(pnodeFound->fDisconnect) {
fDisconnect = true;
} else {
pnodeFound->AddRef();
}
bool fSkip = false;
connman.ForNode(infoMn.addr, CConnman::AllNodes, [&fSkip](CNode* pnode) {
fSkip = pnode->fDisconnect || pnode->fMasternode;
return true;
});
if (fDisconnect)
if (fSkip) {
LogPrintf("CPrivateSendClient::JoinExistingQueue -- skipping masternode connection, addr=%s\n", infoMn.addr.ToString());
continue;
}
LogPrintf("CPrivateSendClient::JoinExistingQueue -- attempt to connect to masternode from queue, addr=%s\n", infoMn.addr.ToString());
// 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) {
infoMixingMasternode = infoMn;
nSessionDenom = dsq.nDenom;
@ -900,9 +896,6 @@ bool CPrivateSendClient::JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CCon
strAutoDenomResult = _("Mixing in progress...");
SetState(POOL_STATE_QUEUE);
nTimeLastSuccessfulStep = GetTimeMillis();
if(pnodeFound) {
pnodeFound->Release();
}
return true;
} else {
LogPrintf("CPrivateSendClient::JoinExistingQueue -- can't connect, addr=%s\n", infoMn.addr.ToString());
@ -947,24 +940,19 @@ bool CPrivateSendClient::StartNewQueue(CAmount nValueMin, CAmount nBalanceNeedsA
continue;
}
CNode* pnodeFound = NULL;
bool fDisconnect = false;
connman.ForNode(infoMn.addr, CConnman::AllNodes, [&pnodeFound, &fDisconnect](CNode* pnode) {
pnodeFound = pnode;
if(pnodeFound->fDisconnect) {
fDisconnect = true;
} else {
pnodeFound->AddRef();
}
bool fSkip = false;
connman.ForNode(infoMn.addr, CConnman::AllNodes, [&fSkip](CNode* pnode) {
fSkip = pnode->fDisconnect || pnode->fMasternode;
return true;
});
if (fDisconnect) {
if (fSkip) {
LogPrintf("CPrivateSendClient::StartNewQueue -- skipping masternode connection, addr=%s\n", infoMn.addr.ToString());
nTries++;
continue;
}
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) {
LogPrintf("CPrivateSendClient::StartNewQueue -- connected, addr=%s\n", infoMn.addr.ToString());
infoMixingMasternode = infoMn;
@ -982,9 +970,6 @@ bool CPrivateSendClient::StartNewQueue(CAmount nValueMin, CAmount nBalanceNeedsA
strAutoDenomResult = _("Mixing in progress...");
SetState(POOL_STATE_QUEUE);
nTimeLastSuccessfulStep = GetTimeMillis();
if(pnodeFound) {
pnodeFound->Release();
}
return true;
} else {
LogPrintf("CPrivateSendClient::StartNewQueue -- can't connect, addr=%s\n", infoMn.addr.ToString());
@ -1002,13 +987,24 @@ bool CPrivateSendClient::SubmitDenominate(CConnman& connman)
std::vector<CTxOut> vecTxOutRet;
// Submit transaction to the pool if we get here
// 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--) {
if(PrepareDenominate(i - 1, i, strError, vecTxDSInRet, vecTxOutRet)) {
LogPrintf("CPrivateSendClient::SubmitDenominate -- Running PrivateSend denominate for %d rounds, success\n", i);
return SendDenominate(vecTxDSInRet, vecTxOutRet, connman);
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
for(int i = nPrivateSendRounds; i > 0; i--) {
if(PrepareDenominate(i - 1, i, 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);
}
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
@ -1100,7 +1096,7 @@ bool CPrivateSendClient::PrepareDenominate(int nMinRounds, int nMaxRounds, std::
vecTxDSIn.erase(it);
vCoins.erase(it2);
CScript scriptDenom = keyHolderStorage.AddKey(pwalletMain).GetScriptForDestination();
CScript scriptDenom = keyHolderStorage.AddKey(pwalletMain);
// add new output
CTxOut txout(nValueDenom, scriptDenom);
@ -1276,7 +1272,7 @@ bool CPrivateSendClient::CreateDenominated(const CompactTallyItem& tallyItem, bo
// ****** Add an output for mixing collaterals ************ /
if(fCreateMixingCollaterals) {
CScript scriptCollateral = keyHolderStorageDenom.AddKey(pwalletMain).GetScriptForDestination();
CScript scriptCollateral = keyHolderStorageDenom.AddKey(pwalletMain);
vecSend.push_back((CRecipient){ scriptCollateral, CPrivateSend::GetMaxCollateralAmount(), false });
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
while(nValueLeft - nDenomValue >= 0 && nOutputs <= 10) {
CScript scriptDenom = keyHolderStorageDenom.AddKey(pwalletMain).GetScriptForDestination();
CScript scriptDenom = keyHolderStorageDenom.AddKey(pwalletMain);
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)));
LogPrintf("CKeyHolderStorage::%s -- storage size %lld\n", __func__, storage.size());
return *storage.back();
return storage.back()->GetScriptForDestination();
}
void CKeyHolderStorage::KeepAll(){
LOCK(cs_storage);
if (storage.size() > 0) {
for (auto &key : storage) {
key->KeepKey();
@ -44,6 +46,7 @@ void CKeyHolderStorage::KeepAll(){
void CKeyHolderStorage::ReturnAll()
{
LOCK(cs_storage);
if (storage.size() > 0) {
for (auto &key : storage) {
key->ReturnKey();

View File

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

View File

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

View File

@ -404,6 +404,8 @@ void TransactionView::contextualMenu(const QPoint &point)
{
QModelIndex index = transactionView->indexAt(point);
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
uint256 hash;

View File

@ -204,7 +204,7 @@ struct mempoolentry_txid
class CompareTxMemPoolEntryByDescendantScore
{
public:
bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b)
bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const
{
bool fUseADescendants = UseDescendantScore(a);
bool fUseBDescendants = UseDescendantScore(b);
@ -226,7 +226,7 @@ public:
}
// 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 f2 = (double)a.GetModFeesWithDescendants() * a.GetTxSize();
@ -241,7 +241,7 @@ public:
class CompareTxMemPoolEntryByScore
{
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 f2 = (double)b.GetModifiedFee() * a.GetTxSize();
@ -255,7 +255,7 @@ public:
class CompareTxMemPoolEntryByEntryTime
{
public:
bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b)
bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const
{
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,
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;