diff --git a/configure.ac b/configure.ac index b6c6ea2f45..2832876bc7 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 0) define(_CLIENT_VERSION_MINOR, 11) define(_CLIENT_VERSION_REVISION, 1) -define(_CLIENT_VERSION_BUILD, 7) +define(_CLIENT_VERSION_BUILD, 8) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2015) AC_INIT([Darkcoin Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[info@darkcoin.io],[darkcoin]) diff --git a/doc/release-notes/release-notes-0.11.1.md b/doc/release-notes/release-notes-0.11.1.md index 69a281ddee..34cddc9ed2 100644 --- a/doc/release-notes/release-notes-0.11.1.md +++ b/doc/release-notes/release-notes-0.11.1.md @@ -16,6 +16,8 @@ and a new version of enforcement compatible with the newer Bitcoin architechure. - Added --instantxdepth, which will show X confirmations when a transaction lock is present - fix coin control crash https://github.com/bitcoin/bitcoin/pull/5700 - always get only confirmed coins by AvailableCoins for every DS relative action +- New languages supported Portuguese, German, Russian, Polish, Spanish, Vietnamese, French, +Italian, Catalan, Chinese, Danish, Finnish, Swedish, Czech, Turkish and Bavarian (and many more) Thanks to who contributed to this release, at least: @@ -23,6 +25,7 @@ Thanks to who contributed to this release, at least: - Vertoe - Udjin - Holger Schinzel +- Raze - Mario Müller - Crowning - Alexandre Devilliers diff --git a/src/clientversion.h b/src/clientversion.h index c16c9cfc6a..644c150a1e 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -12,7 +12,7 @@ #define CLIENT_VERSION_MAJOR 0 #define CLIENT_VERSION_MINOR 11 #define CLIENT_VERSION_REVISION 1 -#define CLIENT_VERSION_BUILD 7 +#define CLIENT_VERSION_BUILD 8 diff --git a/src/darksend.cpp b/src/darksend.cpp index 5cf066b316..2608e79182 100644 --- a/src/darksend.cpp +++ b/src/darksend.cpp @@ -1364,8 +1364,6 @@ void CDarkSendPool::NewBlock() darkSendPool.CheckTimeout(); - masternodePayments.ProcessBlock(chainActive.Tip()->nHeight+10); - if(!fEnableDarksend) return; if(!fMasterNode){ diff --git a/src/darksend.h b/src/darksend.h index 545af484ac..9fcf246c9c 100644 --- a/src/darksend.h +++ b/src/darksend.h @@ -222,7 +222,7 @@ class CDarksendSession class CDarkSendPool { public: - static const int MIN_PEER_PROTO_VERSION = 70057; + static const int MIN_PEER_PROTO_VERSION = 70058; // clients entries std::vector myEntries; diff --git a/src/instantx.cpp b/src/instantx.cpp index dfe1c7d18e..cbc39596ae 100644 --- a/src/instantx.cpp +++ b/src/instantx.cpp @@ -22,6 +22,7 @@ std::map mapTxLockReq; std::map mapTxLockReqRejected; std::map mapTxLockVote; std::map mapTxLocks; +std::map mapLockedInputs; std::map mapUnknownVotes; //track votes with no tx for DOS int nCompleteTXLocks; @@ -53,17 +54,6 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream& return; } - int nTxAge = 0; - BOOST_REVERSE_FOREACH(CTxIn i, tx.vin){ - nTxAge = GetInputAge(i); - if(nTxAge < 6) - { - LogPrintf("ProcessMessageInstantX::txlreq - Transaction not found / too new: %d / %s\n", nTxAge, tx.GetHash().ToString().c_str()); - return; - } - } - int nBlockHeight = chainActive.Tip()->nHeight - nTxAge; //calculate the height - BOOST_FOREACH(const CTxOut o, tx.vout){ if(!o.scriptPubKey.IsNormalPaymentScript()){ printf ("ProcessMessageInstantX::txlreq - Invalid Script %s\n", tx.ToString().c_str()); @@ -71,13 +61,16 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream& } } + int nBlockHeight = CreateNewLock(tx); + bool fMissingInputs = false; CValidationState state; + if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) { RelayTransactionLockReq(tx, tx.GetHash()); - DoConsensusVote(tx, true, nBlockHeight); + DoConsensusVote(tx, nBlockHeight); mapTxLockReq.insert(make_pair(tx.GetHash(), tx)); @@ -94,13 +87,18 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream& // can we get the conflicting transaction as proof? RelayTransactionLockReq(tx, inv.hash); - DoConsensusVote(tx, false, nBlockHeight); LogPrintf("ProcessMessageInstantX::txlreq - Transaction Lock Request: %s %s : rejected %s\n", pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(), tx.GetHash().ToString().c_str() ); + BOOST_FOREACH(const CTxIn& in, tx.vin){ + if(!mapLockedInputs.count(in.prevout)){ + mapLockedInputs.insert(make_pair(in.prevout, tx.GetHash())); + } + } + // resolve conflicts std::map::iterator i = mapTxLocks.find(tx.GetHash()); if (i != mapTxLocks.end()){ @@ -109,19 +107,8 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream& LogPrintf("ProcessMessageInstantX::txlreq - Found Existing Complete IX Lock\n"); CValidationState state; - bool fMissingInputs = false; DisconnectBlockAndInputs(state, tx); - - if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) - { - LogPrintf("ProcessMessageInstantX::txlreq - Transaction Lock Request : accepted (resolved) %s\n", - tx.GetHash().ToString().c_str() - ); - } else { - LogPrintf("ERROR: InstantX::ProcessConsensusVote - Transaction Lock Request : rejected (failed to resolve) %s\n", - tx.GetHash().ToString().c_str() - ); - } + mapTxLockReq.insert(make_pair(tx.GetHash(), tx)); } } @@ -217,12 +204,51 @@ bool IsIXTXValid(const CTransaction& txCollateral){ return true; } +int64_t CreateNewLock(CTransaction tx) +{ + + int64_t nTxAge = 0; + BOOST_REVERSE_FOREACH(CTxIn i, tx.vin){ + nTxAge = GetInputAge(i); + if(nTxAge < 6) + { + LogPrintf("CreateNewLock - Transaction not found / too new: %d / %s\n", nTxAge, tx.GetHash().ToString().c_str()); + return 0; + } + } + + /* + Use a blockheight newer than the input. + This prevents attackers from using transaction mallibility to predict which masternodes + they'll use. + */ + int nBlockHeight = (chainActive.Tip()->nHeight - nTxAge)+4; + + if (!mapTxLocks.count(tx.GetHash())){ + LogPrintf("CreateNewLock - New Transaction Lock %s !\n", tx.GetHash().ToString().c_str()); + + CTransactionLock newLock; + newLock.nBlockHeight = nBlockHeight; + newLock.nExpiration = GetTime()+(60*60); + newLock.txHash = tx.GetHash(); + mapTxLocks.insert(make_pair(tx.GetHash(), newLock)); + } else { + mapTxLocks[tx.GetHash()].nBlockHeight = nBlockHeight; + if(fDebug) LogPrintf("CreateNewLock - Transaction Lock Exists %s !\n", tx.GetHash().ToString().c_str()); + } + + return nBlockHeight; +} // check if we need to vote on this transaction -void DoConsensusVote(CTransaction& tx, bool approved, int64_t nBlockHeight) +void DoConsensusVote(CTransaction& tx, int64_t nBlockHeight) { if(!fMasterNode) return; + /* + nBlockHeight calculated from the transaction is the authoritive source + */ + CConsensusVote ctx; ctx.vinMasternode = activeMasternode.vin; ctx.txHash = tx.GetHash(); @@ -258,7 +284,7 @@ bool ProcessConsensusVote(CConsensusVote& ctx) if(n > 10) { - LogPrintf("InstantX::ProcessConsensusVote - Masternode not in the top 10\n"); + LogPrintf("InstantX::ProcessConsensusVote - Masternode not in the top 10 (%d)\n", n); return false; } @@ -272,7 +298,7 @@ bool ProcessConsensusVote(CConsensusVote& ctx) LogPrintf("InstantX::ProcessConsensusVote - New Transaction Lock %s !\n", ctx.txHash.ToString().c_str()); CTransactionLock newLock; - newLock.nBlockHeight = ctx.nBlockHeight; + newLock.nBlockHeight = 0; newLock.nExpiration = GetTime()+(60*60); newLock.txHash = ctx.txHash; mapTxLocks.insert(make_pair(ctx.txHash, newLock)); @@ -290,8 +316,21 @@ bool ProcessConsensusVote(CConsensusVote& ctx) if((*i).second.CountSignatures() >= INSTANTX_SIGNATURES_REQUIRED){ if(fDebug) LogPrintf("InstantX::ProcessConsensusVote - Transaction Lock Is Complete %s !\n", (*i).second.GetHash().ToString().c_str()); - if(pwalletMain->UpdatedTransaction((*i).second.txHash)){ - nCompleteTXLocks++; +#ifdef ENABLE_WALLET + if(pwalletMain){ + if(pwalletMain->UpdatedTransaction((*i).second.txHash)){ + nCompleteTXLocks++; + } + } +#endif + + if(mapTxLockReq.count(ctx.txHash)){ + CTransaction& tx = mapTxLockReq[ctx.txHash]; + BOOST_FOREACH(const CTxIn& in, tx.vin){ + if(!mapLockedInputs.count(in.prevout)){ + mapLockedInputs.insert(make_pair(in.prevout, ctx.txHash)); + } + } } // resolve conflicts @@ -299,20 +338,7 @@ bool ProcessConsensusVote(CConsensusVote& ctx) //if this tx lock was rejected, we need to remove the conflicting blocks if(mapTxLockReqRejected.count((*i).second.txHash)){ CValidationState state; - bool fMissingInputs = false; DisconnectBlockAndInputs(state, mapTxLockReqRejected[(*i).second.txHash]); - - if (AcceptToMemoryPool(mempool, state, mapTxLockReqRejected[(*i).second.txHash], true, &fMissingInputs)) - { - LogPrintf("ProcessMessageInstantX::txlreq - Transaction Lock Request : accepted (resolved) %s\n", - mapTxLockReqRejected[(*i).second.txHash].GetHash().ToString().c_str() - ); - - } else { - LogPrintf("ERROR: InstantX::ProcessConsensusVote - Transaction Lock Request : rejected (failed to resolve) %s\n", - mapTxLockReqRejected[(*i).second.txHash].GetHash().ToString().c_str() - ); - } } } return true; @@ -347,6 +373,17 @@ void CleanTransactionLocksList() while(it != mapTxLocks.end()) { if(GetTime() > it->second.nExpiration){ //keep them for an hour LogPrintf("Removing old transaction lock %s\n", it->second.txHash.ToString().c_str()); + + if(mapTxLockReq.count(it->second.txHash)){ + CTransaction& tx = mapTxLockReq[it->second.txHash]; + + BOOST_FOREACH(const CTxIn& in, tx.vin) + mapLockedInputs.erase(in.prevout); + + mapTxLockReq.erase(it->second.txHash); + mapTxLockReqRejected.erase(it->second.txHash); + } + mapTxLocks.erase(it++); } else { it++; @@ -466,5 +503,18 @@ void CTransactionLock::AddSignature(CConsensusVote cv) int CTransactionLock::CountSignatures() { - return vecConsensusVotes.size(); + /* + Only count signatures where the BlockHeight matches the transaction's blockheight. + The votes have no proof it's the correct blockheight + */ + + if(nBlockHeight == 0) return -1; + + int n = 0; + BOOST_FOREACH(CConsensusVote v, vecConsensusVotes){ + if(v.nBlockHeight == nBlockHeight){ + n++; + } + } + return n; } diff --git a/src/instantx.h b/src/instantx.h index 67938c1db7..fe1e69b4f8 100644 --- a/src/instantx.h +++ b/src/instantx.h @@ -23,18 +23,22 @@ class CConsensusVote; class CTransaction; class CTransactionLock; -static const int MIN_INSTANTX_PROTO_VERSION = 70057; +static const int MIN_INSTANTX_PROTO_VERSION = 70058; extern map mapTxLockReq; extern map mapTxLocks; +extern std::map mapLockedInputs; extern int nCompleteTXLocks; + +int64_t CreateNewLock(CTransaction tx); + bool IsIXTXValid(const CTransaction& txCollateral); void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream& vRecv); //check if we need to vote on this transaction -void DoConsensusVote(CTransaction& tx, bool approved, int64_t nBlockHeight); +void DoConsensusVote(CTransaction& tx, int64_t nBlockHeight); //process consensus vote message bool ProcessConsensusVote(CConsensusVote& ctx); diff --git a/src/main.cpp b/src/main.cpp index 34f3fe3326..fab81674c1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -894,6 +894,18 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa if (pool.exists(hash)) return false; + // ----------- instantX transaction scanning ----------- + + BOOST_FOREACH(const CTxIn& in, tx.vin){ + if(mapLockedInputs.count(in.prevout)){ + if(mapLockedInputs[in.prevout] != tx.GetHash()){ + return state.DoS(0, + error("AcceptToMemoryPool : conflicts with existing transaction lock: %s", reason), + REJECT_INVALID, "tx-lock-conflict"); + } + } + } + // Check for conflicts with in-memory transactions { LOCK(pool.cs); // protect pool.mapNextTx @@ -909,29 +921,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa } - // ----------- instantX transaction scanning ----------- - - std::map::iterator it = mapTxLocks.begin(); - - while(it != mapTxLocks.end()) { - if(mapTxLockReq.count((*it).second.txHash)){ - CTransaction& tx2 = mapTxLockReq[(*it).second.txHash]; - for (unsigned int a = 0; a < tx2.vin.size(); a++) { - //we found the locked tx in the block - if(tx2.GetHash() == tx.GetHash()) continue; - - //if there's a lock, look for conflicting inputs - for (unsigned int b = 0; b < tx.vin.size(); b++) { - if(tx2.vin[a].prevout == tx.vin[b].prevout) { - return false; - } - } - } - } - it++; - } - - { CCoinsView dummy; CCoinsViewCache view(dummy); @@ -2132,167 +2121,6 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex } -/* - DisconnectBlockAndInputs - - Remove conflicting blocks for successful InstantX transaction locks - This should be very rare (Probably will never happen) -*/ -bool DisconnectBlockAndInputs(CValidationState &state, CTransaction txLock) -{ - /* - // All modifications to the coin state will be done in this cache. - // Only when all have succeeded, we push it to pcoinsTip. - CCoinsViewCache view(*pcoinsTip, true); - - CBlockIndex* BlockReading = chainActive.Tip(); - CBlockIndex* pindexNew = NULL; - - int HeightMin = chainActive.Tip()->nHeight-5; - bool foundConflictingTx = false; - - //remove anything conflicting in the memory pool - list txConflicted; - mempool.removeConflicts(txLock, txConflicted); - - - // List of what to disconnect (typically nothing) - vector vDisconnect; - - for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0 && !foundConflictingTx; i++) { - vDisconnect.push_back(BlockReading); - pindexNew = BlockReading->pprev; //new best block - - CBlock block; - if (!ReadBlockFromDisk(block, BlockReading)) - return state.Abort(_("Failed to read block")); - - // Queue memory transactions to resurrect. - // We only do this for blocks after the last checkpoint (reorganisation before that - // point should only happen with -reindex/-loadblock, or a misbehaving peer. - BOOST_FOREACH(const CTransaction& tx, block.vtx){ - if (!tx.IsCoinBase() && BlockReading->nHeight > HeightMin){ - BOOST_FOREACH(const CTxIn& in1, txLock.vin){ - BOOST_FOREACH(const CTxIn& in2, tx.vin){ - if(in1 == in2) foundConflictingTx = true; - } - } - } - } - - if (BlockReading->pprev == NULL) { assert(BlockReading); break; } - BlockReading = BlockReading->pprev; - } - - if(!foundConflictingTx) { - LogPrintf("DisconnectBlockAndInputs: Can't find a conflicting transaction to inputs\n"); - return false; - } - - if (vDisconnect.size() > 0) { - LogPrintf("REORGANIZE: Disconnect Conflicting Blocks %lli blocks; %s..\n", vDisconnect.size(), pindexNew->GetBlockHash().ToString().c_str()); - BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) { - LogPrintf(" -- disconnect %s\n", pindex->GetBlockHash().ToString().c_str()); - } - } - - // Disconnect shorter branch - vector vResurrect; - BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) { - CBlock block; - if (!ReadBlockFromDisk(block, pindex)) - return state.Abort(_("Failed to read block")); - int64_t nStart = GetTimeMicros(); - if (!DisconnectBlock(block, state, pindex, view)) - return error("DisconnectBlockAndInputs/SetBestBlock() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().c_str()); - if (fBenchmark) - LogPrintf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001); - - // Queue memory transactions to resurrect. - // We only do this for blocks after the last checkpoint (reorganisation before that - // point should only happen with -reindex/-loadblock, or a misbehaving peer. - BOOST_FOREACH(const CTransaction& tx, block.vtx){ - if (!tx.IsCoinBase() && pindex->nHeight > HeightMin){ - bool isConflict = false; - BOOST_FOREACH(const CTxIn& in1, txLock.vin){ - BOOST_FOREACH(const CTxIn& in2, tx.vin){ - if(in1 != in2) isConflict = true; - } - } - if(!isConflict) vResurrect.push_back(tx); - } - } - - } - - mempool.check(pcoinsTip); - - // At this point, all changes have been done to the database. - // Proceed by updating the memory structures. - - // Disconnect shorter branch - BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) - if (pindex->pprev) - pindex->pprev->pnext = NULL; - - // Resurrect memory transactions that were in the disconnected branch - BOOST_FOREACH(CTransaction& tx, vResurrect) { - // ignore validation errors in resurrected transactions - CValidationState stateDummy; - if (!tx.AcceptToMemoryPool(mempool, stateDummy, tx, true, false)) - mempool.remove(tx, true); - } - - // Update best block in wallet (so we can detect restored wallets) - - if ((pindexNew->nHeight % 20160) == 0 || (!fIsInitialDownload && (pindexNew->nHeight % 144) == 0)) - { - const CBlockLocator locator(pindexNew); - ::SetBestChain(locator); - } - - // New best block - hashBestChain = pindexNew->GetBlockHash(); - chainActive.Tip() = pindexNew; - pblockindexFBBHLast = NULL; - chainActive.Tip()->nHeight = chainActive.Tip()->nHeight; - nBestChainWork = pindexNew->nChainWork; - nTimeBestReceived = GetTime(); - nTransactionsUpdated++; - LogPrintf("DisconnectBlockAndInputs / SetBestChain: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f\n", - hashBestChain.ToString().c_str(), chainActive.Tip()->nHeight, log(nBestChainWork.getdouble())/log(2.0), (unsigned long)pindexNew->nChainTx, - DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()).c_str(), - Checkpoints::GuessVerificationProgress(chainActive.Tip())); - - // Check the version of the last 100 blocks to see if we need to upgrade: - if (!fIsInitialDownload) - { - int nUpgraded = 0; - const CBlockIndex* pindex = chainActive.Tip(); - for (int i = 0; i < 100 && pindex != NULL; i++) - { - if (pindex->nVersion > CBlock::CURRENT_VERSION) - ++nUpgraded; - pindex = pindex->pprev; - } - if (nUpgraded > 0) - LogPrintf("DisconnectBlockAndInputs/SetBestChain: %d of last 100 blocks above version %d\n", nUpgraded, CBlock::CURRENT_VERSION); - if (nUpgraded > 100/2) - // strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user: - strMiscWarning = _("Warning: This version is obsolete, upgrade required!"); - } - - std::string strCmd = GetArg("-blocknotify", ""); - - if (!fIsInitialDownload && !strCmd.empty()) - { - boost::replace_all(strCmd, "%s", hashBestChain.GetHex()); - boost::thread t(runCommand, strCmd); // thread runs free - } - -*/ return true; -} - void static FlushBlockFile(bool fFinalize = false) { LOCK(cs_LastBlockFile); @@ -2632,6 +2460,74 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) { return true; } +/* + DisconnectBlockAndInputs + + Remove conflicting blocks for successful InstantX transaction locks + This should be very rare (Probably will never happen) +*/ +bool DisconnectBlockAndInputs(CValidationState &state, CTransaction txLock) +{ + + // All modifications to the coin state will be done in this cache. + // Only when all have succeeded, we push it to pcoinsTip. + CCoinsViewCache view(*pcoinsTip, true); + + CBlockIndex* BlockReading = chainActive.Tip(); + CBlockIndex* pindexNew = NULL; + + bool foundConflictingTx = false; + + //remove anything conflicting in the memory pool + list txConflicted; + mempool.removeConflicts(txLock, txConflicted); + + + // List of what to disconnect (typically nothing) + vector vDisconnect; + + for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0 && !foundConflictingTx && i < 6; i++) { + vDisconnect.push_back(BlockReading); + pindexNew = BlockReading->pprev; //new best block + + CBlock block; + if (!ReadBlockFromDisk(block, BlockReading)) + return state.Abort(_("Failed to read block")); + + // Queue memory transactions to resurrect. + // We only do this for blocks after the last checkpoint (reorganisation before that + // point should only happen with -reindex/-loadblock, or a misbehaving peer. + BOOST_FOREACH(const CTransaction& tx, block.vtx){ + if (!tx.IsCoinBase()){ + BOOST_FOREACH(const CTxIn& in1, txLock.vin){ + BOOST_FOREACH(const CTxIn& in2, tx.vin){ + if(in1.prevout == in2.prevout) foundConflictingTx = true; + } + } + } + } + + if (BlockReading->pprev == NULL) { assert(BlockReading); break; } + BlockReading = BlockReading->pprev; + } + + if(!foundConflictingTx) { + LogPrintf("DisconnectBlockAndInputs: Can't find a conflicting transaction to inputs\n"); + return false; + } + + if (vDisconnect.size() > 0) { + LogPrintf("REORGANIZE: Disconnect Conflicting Blocks %lli blocks; %s..\n", vDisconnect.size(), pindexNew->GetBlockHash().ToString().c_str()); + BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) { + LogPrintf(" -- disconnect %s\n", pindex->GetBlockHash().ToString().c_str()); + DisconnectTip(state); + } + } + + return true; +} + + // Make chainMostWork correspond to the chain with the most work in it, that isn't // known to be invalid (it's however far from certain to be valid). void static FindMostWorkChain() { @@ -2919,27 +2815,17 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo // ----------- instantX transaction scanning ----------- - std::map::iterator it = mapTxLocks.begin(); - - while(it != mapTxLocks.end()) { - if(mapTxLockReq.count((*it).second.txHash)){ - CTransaction& tx = mapTxLockReq[(*it).second.txHash]; - for (unsigned int a = 0; a < tx.vin.size(); a++) { - for (unsigned int b = 0; b < block.vtx.size(); b++) { - //we found the locked tx in the block - if(tx.GetHash() == block.vtx[b].GetHash()) continue; - - //if there's a lock, look for conflicting inputs - for (unsigned int c = 0; c < block.vtx[b].vin.size(); c++) { - if(tx.vin[a].prevout == block.vtx[b].vin[c].prevout) { - return state.DoS(100, error("CheckBlock() : found conflicting transaction with transaction lock"), - REJECT_INVALID, "conflicting-tx-ix"); - } + BOOST_FOREACH(const CTransaction& tx, block.vtx){ + if (!tx.IsCoinBase()){ + BOOST_FOREACH(const CTxIn& in, tx.vin){ + if(mapLockedInputs.count(in.prevout)){ + if(mapLockedInputs[in.prevout] != tx.GetHash()){ + return state.DoS(0, error("CheckBlock() : found conflicting transaction with transaction lock"), + REJECT_INVALID, "conflicting-tx-ix"); } } } } - it++; } @@ -3203,6 +3089,15 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl { AssertLockHeld(cs_main); +/* + block-a-block + + std::string s = "2600c8bebd2a300b2541b3720d8a30f20b61d01813a24f5934e10a2ab81b5ed9"; + if(pblock->GetHash().ToString() == s){ + printf("Nope, get outta here!\n"); + return false; + } +*/ // Check for duplicate uint256 hash = pblock->GetHash(); if (mapBlockIndex.count(hash)) @@ -3294,6 +3189,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl if(!fLiteMode){ if (!fImporting && !fReindex && chainActive.Height() > Checkpoints::GetTotalBlocksEstimate()){ darkSendPool.NewBlock(); + masternodePayments.ProcessBlock(GetHeight()+10); } } @@ -4593,6 +4489,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) CBlock block; vRecv >> block; + LogPrint("net", "received block %s\n", block.GetHash().ToString()); // block.print(); diff --git a/src/masternode.cpp b/src/masternode.cpp index 2b2aa73927..c06d99319e 100644 --- a/src/masternode.cpp +++ b/src/masternode.cpp @@ -717,6 +717,7 @@ void CMasternodePayments::CleanPaymentList() bool CMasternodePayments::ProcessBlock(int nBlockHeight) { + if(!enabled) return false; CMasternodePaymentWinner winner; @@ -749,7 +750,13 @@ bool CMasternodePayments::ProcessBlock(int nBlockHeight) break; } - if(winner.nBlockHeight == 0) return false; //no masternodes available + //if we can't find someone to get paid, pick randomly + if(winner.nBlockHeight == 0 && vecMasternodes.size() > 1) { + winner.score = 0; + winner.nBlockHeight = nBlockHeight; + winner.vin = vecMasternodes[0].vin; + winner.payee.SetDestination(vecMasternodes[0].pubkey.GetID()); + } if(Sign(winner)){ if(AddWinningMasternode(winner)){ diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 745ac2d69a..c3facbe5eb 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -360,7 +360,6 @@ void OverviewPage::darkSendStatus() /* ** @TODO this string creation really needs some clean ups ---vertoe ** */ std::ostringstream convert; - convert << tr("Last Darksend message:\n").toStdString(); if(state == POOL_STATUS_ACCEPTING_ENTRIES) { if(entries == 0) { @@ -408,13 +407,13 @@ void OverviewPage::darkSendStatus() if(state == POOL_STATUS_ERROR || state == POOL_STATUS_SUCCESS) darkSendPool.Check(); QString s(convert.str().c_str()); + s = tr("Last Darksend message:\n") + s; if(s != ui->darksendStatus->text()) - LogPrintf("%s\n", convert.str().c_str()); + LogPrintf("Last Darksend message: %s\n", convert.str().c_str()); ui->darksendStatus->setText(s); - if(darkSendPool.sessionDenom == 0){ ui->labelSubmittedDenom->setText(tr("N/A")); } else { diff --git a/src/version.h b/src/version.h index d316f07eaa..5cfc5039bb 100644 --- a/src/version.h +++ b/src/version.h @@ -27,7 +27,7 @@ extern const std::string CLIENT_DATE; // network protocol versioning // -static const int PROTOCOL_VERSION = 70057; +static const int PROTOCOL_VERSION = 70058; // intial proto version, to be increased after version/verack negotiation static const int INIT_PROTO_VERSION = 209; diff --git a/src/wallet.cpp b/src/wallet.cpp index ba4d853fe4..f1ac2911d1 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1001,10 +1001,11 @@ void CWalletTx::RelayWalletTransaction(std::string strCommand) LogPrintf("Relaying wtx %s\n", hash.ToString()); if(strCommand == "txlreq"){ - mapTxLockReq.insert(make_pair(hash, (CTransaction)*this)); - RelayTransactionLockReq((CTransaction)*this, hash, true); + mapTxLockReq.insert(make_pair(hash, ((CTransaction)*this))); + CreateNewLock(((CTransaction)*this)); + RelayTransactionLockReq(((CTransaction)*this), hash, true); } else { - RelayTransaction((CTransaction)*this, hash); + RelayTransaction(((CTransaction)*this), hash); } } } @@ -1484,6 +1485,10 @@ bool CWallet::SelectCoins(int64_t nTargetValue, setvout[out.i].nValue == v //make sure it's the denom we're looking for && nValueRet + out.tx->vout[out.i].nValue < nTargetValue + (0.1*COIN)+100 //round the amount up to .1DRK over && added <= 50){ //don't add more than 50 of one denom type + CTxIn vin = CTxIn(out.tx->GetHash(),out.i); + int rounds = GetInputDarksendRounds(vin); + // make sure it's actually anonymized + if(rounds < nDarksendRounds) continue; nValueRet += out.tx->vout[out.i].nValue; setCoinsRet.insert(make_pair(out.tx, out.i)); added++; @@ -1851,14 +1856,20 @@ bool CWallet::CreateTransaction(const vector >& vecSend, if (!SelectCoins(nTotalValue, setCoins, nValueIn, coinControl, coin_type, useIX)) { - if(coin_type == ALL_COINS) - strFailReason = _("Insufficient funds"); - else if (coin_type == ONLY_NONDENOMINATED) - strFailReason = _("Unable to locate enough Darksend non-denominated funds for this transaction"); - else if (coin_type == ONLY_NONDENOMINATED_NOTMN) - strFailReason = _("Unable to locate enough Darksend non-denominated funds for this transaction that are not equal 1000 DRK"); - else - strFailReason = _("Unable to locate enough Darksend denominated funds for this transaction"); + if(coin_type == ALL_COINS) { + strFailReason = _("Insufficient funds."); + } else if (coin_type == ONLY_NONDENOMINATED) { + strFailReason = _("Unable to locate enough Darksend non-denominated funds for this transaction."); + } else if (coin_type == ONLY_NONDENOMINATED_NOTMN) { + strFailReason = _("Unable to locate enough Darksend non-denominated funds for this transaction that are not equal 1000 DRK."); + } else { + strFailReason = _("Unable to locate enough Darksend denominated funds for this transaction."); + strFailReason += _("Darksend uses exact denominated amounts to send funds, you might simply need to anonymize some more coins."); + } + + if(useIX){ + strFailReason += _("InstantX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again."); + } return false; }