merge downstream 0.11.1

This commit is contained in:
vertoe 2015-02-05 16:13:05 +01:00
commit 78d47c04fe
12 changed files with 237 additions and 268 deletions

View File

@ -3,7 +3,7 @@ AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 0) define(_CLIENT_VERSION_MAJOR, 0)
define(_CLIENT_VERSION_MINOR, 11) define(_CLIENT_VERSION_MINOR, 11)
define(_CLIENT_VERSION_REVISION, 1) define(_CLIENT_VERSION_REVISION, 1)
define(_CLIENT_VERSION_BUILD, 7) define(_CLIENT_VERSION_BUILD, 8)
define(_CLIENT_VERSION_IS_RELEASE, true) define(_CLIENT_VERSION_IS_RELEASE, true)
define(_COPYRIGHT_YEAR, 2015) define(_COPYRIGHT_YEAR, 2015)
AC_INIT([Darkcoin Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[info@darkcoin.io],[darkcoin]) AC_INIT([Darkcoin Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[info@darkcoin.io],[darkcoin])

View File

@ -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 - Added --instantxdepth, which will show X confirmations when a transaction lock is present
- fix coin control crash https://github.com/bitcoin/bitcoin/pull/5700 - fix coin control crash https://github.com/bitcoin/bitcoin/pull/5700
- always get only confirmed coins by AvailableCoins for every DS relative action - 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: Thanks to who contributed to this release, at least:
@ -23,6 +25,7 @@ Thanks to who contributed to this release, at least:
- Vertoe - Vertoe
- Udjin - Udjin
- Holger Schinzel - Holger Schinzel
- Raze
- Mario Müller - Mario Müller
- Crowning - Crowning
- Alexandre Devilliers - Alexandre Devilliers

View File

@ -12,7 +12,7 @@
#define CLIENT_VERSION_MAJOR 0 #define CLIENT_VERSION_MAJOR 0
#define CLIENT_VERSION_MINOR 11 #define CLIENT_VERSION_MINOR 11
#define CLIENT_VERSION_REVISION 1 #define CLIENT_VERSION_REVISION 1
#define CLIENT_VERSION_BUILD 7 #define CLIENT_VERSION_BUILD 8

View File

@ -1364,8 +1364,6 @@ void CDarkSendPool::NewBlock()
darkSendPool.CheckTimeout(); darkSendPool.CheckTimeout();
masternodePayments.ProcessBlock(chainActive.Tip()->nHeight+10);
if(!fEnableDarksend) return; if(!fEnableDarksend) return;
if(!fMasterNode){ if(!fMasterNode){

View File

@ -222,7 +222,7 @@ class CDarksendSession
class CDarkSendPool class CDarkSendPool
{ {
public: public:
static const int MIN_PEER_PROTO_VERSION = 70057; static const int MIN_PEER_PROTO_VERSION = 70058;
// clients entries // clients entries
std::vector<CDarkSendEntry> myEntries; std::vector<CDarkSendEntry> myEntries;

View File

@ -22,6 +22,7 @@ std::map<uint256, CTransaction> mapTxLockReq;
std::map<uint256, CTransaction> mapTxLockReqRejected; std::map<uint256, CTransaction> mapTxLockReqRejected;
std::map<uint256, int> mapTxLockVote; std::map<uint256, int> mapTxLockVote;
std::map<uint256, CTransactionLock> mapTxLocks; std::map<uint256, CTransactionLock> mapTxLocks;
std::map<COutPoint, uint256> mapLockedInputs;
std::map<uint256, int64_t> mapUnknownVotes; //track votes with no tx for DOS std::map<uint256, int64_t> mapUnknownVotes; //track votes with no tx for DOS
int nCompleteTXLocks; int nCompleteTXLocks;
@ -53,17 +54,6 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
return; 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){ BOOST_FOREACH(const CTxOut o, tx.vout){
if(!o.scriptPubKey.IsNormalPaymentScript()){ if(!o.scriptPubKey.IsNormalPaymentScript()){
printf ("ProcessMessageInstantX::txlreq - Invalid Script %s\n", tx.ToString().c_str()); 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; bool fMissingInputs = false;
CValidationState state; CValidationState state;
if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs))
{ {
RelayTransactionLockReq(tx, tx.GetHash()); RelayTransactionLockReq(tx, tx.GetHash());
DoConsensusVote(tx, true, nBlockHeight); DoConsensusVote(tx, nBlockHeight);
mapTxLockReq.insert(make_pair(tx.GetHash(), tx)); 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? // can we get the conflicting transaction as proof?
RelayTransactionLockReq(tx, inv.hash); RelayTransactionLockReq(tx, inv.hash);
DoConsensusVote(tx, false, nBlockHeight);
LogPrintf("ProcessMessageInstantX::txlreq - Transaction Lock Request: %s %s : rejected %s\n", LogPrintf("ProcessMessageInstantX::txlreq - Transaction Lock Request: %s %s : rejected %s\n",
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(), pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
tx.GetHash().ToString().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 // resolve conflicts
std::map<uint256, CTransactionLock>::iterator i = mapTxLocks.find(tx.GetHash()); std::map<uint256, CTransactionLock>::iterator i = mapTxLocks.find(tx.GetHash());
if (i != mapTxLocks.end()){ 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"); LogPrintf("ProcessMessageInstantX::txlreq - Found Existing Complete IX Lock\n");
CValidationState state; CValidationState state;
bool fMissingInputs = false;
DisconnectBlockAndInputs(state, tx); DisconnectBlockAndInputs(state, tx);
mapTxLockReq.insert(make_pair(tx.GetHash(), 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()
);
}
} }
} }
@ -217,12 +204,51 @@ bool IsIXTXValid(const CTransaction& txCollateral){
return true; 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 // 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; if(!fMasterNode) return;
/*
nBlockHeight calculated from the transaction is the authoritive source
*/
CConsensusVote ctx; CConsensusVote ctx;
ctx.vinMasternode = activeMasternode.vin; ctx.vinMasternode = activeMasternode.vin;
ctx.txHash = tx.GetHash(); ctx.txHash = tx.GetHash();
@ -258,7 +284,7 @@ bool ProcessConsensusVote(CConsensusVote& ctx)
if(n > 10) 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; return false;
} }
@ -272,7 +298,7 @@ bool ProcessConsensusVote(CConsensusVote& ctx)
LogPrintf("InstantX::ProcessConsensusVote - New Transaction Lock %s !\n", ctx.txHash.ToString().c_str()); LogPrintf("InstantX::ProcessConsensusVote - New Transaction Lock %s !\n", ctx.txHash.ToString().c_str());
CTransactionLock newLock; CTransactionLock newLock;
newLock.nBlockHeight = ctx.nBlockHeight; newLock.nBlockHeight = 0;
newLock.nExpiration = GetTime()+(60*60); newLock.nExpiration = GetTime()+(60*60);
newLock.txHash = ctx.txHash; newLock.txHash = ctx.txHash;
mapTxLocks.insert(make_pair(ctx.txHash, newLock)); mapTxLocks.insert(make_pair(ctx.txHash, newLock));
@ -290,8 +316,21 @@ bool ProcessConsensusVote(CConsensusVote& ctx)
if((*i).second.CountSignatures() >= INSTANTX_SIGNATURES_REQUIRED){ 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(fDebug) LogPrintf("InstantX::ProcessConsensusVote - Transaction Lock Is Complete %s !\n", (*i).second.GetHash().ToString().c_str());
if(pwalletMain->UpdatedTransaction((*i).second.txHash)){ #ifdef ENABLE_WALLET
nCompleteTXLocks++; 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 // resolve conflicts
@ -299,20 +338,7 @@ bool ProcessConsensusVote(CConsensusVote& ctx)
//if this tx lock was rejected, we need to remove the conflicting blocks //if this tx lock was rejected, we need to remove the conflicting blocks
if(mapTxLockReqRejected.count((*i).second.txHash)){ if(mapTxLockReqRejected.count((*i).second.txHash)){
CValidationState state; CValidationState state;
bool fMissingInputs = false;
DisconnectBlockAndInputs(state, mapTxLockReqRejected[(*i).second.txHash]); 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; return true;
@ -347,6 +373,17 @@ void CleanTransactionLocksList()
while(it != mapTxLocks.end()) { while(it != mapTxLocks.end()) {
if(GetTime() > it->second.nExpiration){ //keep them for an hour if(GetTime() > it->second.nExpiration){ //keep them for an hour
LogPrintf("Removing old transaction lock %s\n", it->second.txHash.ToString().c_str()); 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++); mapTxLocks.erase(it++);
} else { } else {
it++; it++;
@ -466,5 +503,18 @@ void CTransactionLock::AddSignature(CConsensusVote cv)
int CTransactionLock::CountSignatures() 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;
} }

View File

@ -23,18 +23,22 @@ class CConsensusVote;
class CTransaction; class CTransaction;
class CTransactionLock; class CTransactionLock;
static const int MIN_INSTANTX_PROTO_VERSION = 70057; static const int MIN_INSTANTX_PROTO_VERSION = 70058;
extern map<uint256, CTransaction> mapTxLockReq; extern map<uint256, CTransaction> mapTxLockReq;
extern map<uint256, CTransactionLock> mapTxLocks; extern map<uint256, CTransactionLock> mapTxLocks;
extern std::map<COutPoint, uint256> mapLockedInputs;
extern int nCompleteTXLocks; extern int nCompleteTXLocks;
int64_t CreateNewLock(CTransaction tx);
bool IsIXTXValid(const CTransaction& txCollateral); bool IsIXTXValid(const CTransaction& txCollateral);
void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream& vRecv); void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
//check if we need to vote on this transaction //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 //process consensus vote message
bool ProcessConsensusVote(CConsensusVote& ctx); bool ProcessConsensusVote(CConsensusVote& ctx);

View File

@ -894,6 +894,18 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
if (pool.exists(hash)) if (pool.exists(hash))
return false; 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 // Check for conflicts with in-memory transactions
{ {
LOCK(pool.cs); // protect pool.mapNextTx LOCK(pool.cs); // protect pool.mapNextTx
@ -909,29 +921,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
} }
// ----------- instantX transaction scanning -----------
std::map<uint256, CTransactionLock>::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; CCoinsView dummy;
CCoinsViewCache view(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<CTransaction> txConflicted;
mempool.removeConflicts(txLock, txConflicted);
// List of what to disconnect (typically nothing)
vector<CBlockIndex*> 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<CTransaction> 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) void static FlushBlockFile(bool fFinalize = false)
{ {
LOCK(cs_LastBlockFile); LOCK(cs_LastBlockFile);
@ -2632,6 +2460,74 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) {
return true; 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<CTransaction> txConflicted;
mempool.removeConflicts(txLock, txConflicted);
// List of what to disconnect (typically nothing)
vector<CBlockIndex*> 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 // 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). // known to be invalid (it's however far from certain to be valid).
void static FindMostWorkChain() { void static FindMostWorkChain() {
@ -2919,27 +2815,17 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
// ----------- instantX transaction scanning ----------- // ----------- instantX transaction scanning -----------
std::map<uint256, CTransactionLock>::iterator it = mapTxLocks.begin(); BOOST_FOREACH(const CTransaction& tx, block.vtx){
if (!tx.IsCoinBase()){
while(it != mapTxLocks.end()) { BOOST_FOREACH(const CTxIn& in, tx.vin){
if(mapTxLockReq.count((*it).second.txHash)){ if(mapLockedInputs.count(in.prevout)){
CTransaction& tx = mapTxLockReq[(*it).second.txHash]; if(mapLockedInputs[in.prevout] != tx.GetHash()){
for (unsigned int a = 0; a < tx.vin.size(); a++) { return state.DoS(0, error("CheckBlock() : found conflicting transaction with transaction lock"),
for (unsigned int b = 0; b < block.vtx.size(); b++) { REJECT_INVALID, "conflicting-tx-ix");
//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");
}
} }
} }
} }
} }
it++;
} }
@ -3203,6 +3089,15 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
{ {
AssertLockHeld(cs_main); 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 // Check for duplicate
uint256 hash = pblock->GetHash(); uint256 hash = pblock->GetHash();
if (mapBlockIndex.count(hash)) if (mapBlockIndex.count(hash))
@ -3294,6 +3189,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
if(!fLiteMode){ if(!fLiteMode){
if (!fImporting && !fReindex && chainActive.Height() > Checkpoints::GetTotalBlocksEstimate()){ if (!fImporting && !fReindex && chainActive.Height() > Checkpoints::GetTotalBlocksEstimate()){
darkSendPool.NewBlock(); darkSendPool.NewBlock();
masternodePayments.ProcessBlock(GetHeight()+10);
} }
} }
@ -4593,6 +4489,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CBlock block; CBlock block;
vRecv >> block; vRecv >> block;
LogPrint("net", "received block %s\n", block.GetHash().ToString()); LogPrint("net", "received block %s\n", block.GetHash().ToString());
// block.print(); // block.print();

View File

@ -717,6 +717,7 @@ void CMasternodePayments::CleanPaymentList()
bool CMasternodePayments::ProcessBlock(int nBlockHeight) bool CMasternodePayments::ProcessBlock(int nBlockHeight)
{ {
if(!enabled) return false; if(!enabled) return false;
CMasternodePaymentWinner winner; CMasternodePaymentWinner winner;
@ -749,7 +750,13 @@ bool CMasternodePayments::ProcessBlock(int nBlockHeight)
break; 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(Sign(winner)){
if(AddWinningMasternode(winner)){ if(AddWinningMasternode(winner)){

View File

@ -360,7 +360,6 @@ void OverviewPage::darkSendStatus()
/* ** @TODO this string creation really needs some clean ups ---vertoe ** */ /* ** @TODO this string creation really needs some clean ups ---vertoe ** */
std::ostringstream convert; std::ostringstream convert;
convert << tr("Last Darksend message:\n").toStdString();
if(state == POOL_STATUS_ACCEPTING_ENTRIES) { if(state == POOL_STATUS_ACCEPTING_ENTRIES) {
if(entries == 0) { if(entries == 0) {
@ -408,13 +407,13 @@ void OverviewPage::darkSendStatus()
if(state == POOL_STATUS_ERROR || state == POOL_STATUS_SUCCESS) darkSendPool.Check(); if(state == POOL_STATUS_ERROR || state == POOL_STATUS_SUCCESS) darkSendPool.Check();
QString s(convert.str().c_str()); QString s(convert.str().c_str());
s = tr("Last Darksend message:\n") + s;
if(s != ui->darksendStatus->text()) 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); ui->darksendStatus->setText(s);
if(darkSendPool.sessionDenom == 0){ if(darkSendPool.sessionDenom == 0){
ui->labelSubmittedDenom->setText(tr("N/A")); ui->labelSubmittedDenom->setText(tr("N/A"));
} else { } else {

View File

@ -27,7 +27,7 @@ extern const std::string CLIENT_DATE;
// network protocol versioning // 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 // intial proto version, to be increased after version/verack negotiation
static const int INIT_PROTO_VERSION = 209; static const int INIT_PROTO_VERSION = 209;

View File

@ -1001,10 +1001,11 @@ void CWalletTx::RelayWalletTransaction(std::string strCommand)
LogPrintf("Relaying wtx %s\n", hash.ToString()); LogPrintf("Relaying wtx %s\n", hash.ToString());
if(strCommand == "txlreq"){ if(strCommand == "txlreq"){
mapTxLockReq.insert(make_pair(hash, (CTransaction)*this)); mapTxLockReq.insert(make_pair(hash, ((CTransaction)*this)));
RelayTransactionLockReq((CTransaction)*this, hash, true); CreateNewLock(((CTransaction)*this));
RelayTransactionLockReq(((CTransaction)*this), hash, true);
} else { } else {
RelayTransaction((CTransaction)*this, hash); RelayTransaction(((CTransaction)*this), hash);
} }
} }
} }
@ -1484,6 +1485,10 @@ bool CWallet::SelectCoins(int64_t nTargetValue, set<pair<const CWalletTx*,unsign
if(out.tx->vout[out.i].nValue == v //make sure it's the denom we're looking for if(out.tx->vout[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 && 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 && 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; nValueRet += out.tx->vout[out.i].nValue;
setCoinsRet.insert(make_pair(out.tx, out.i)); setCoinsRet.insert(make_pair(out.tx, out.i));
added++; added++;
@ -1851,14 +1856,20 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
if (!SelectCoins(nTotalValue, setCoins, nValueIn, coinControl, coin_type, useIX)) if (!SelectCoins(nTotalValue, setCoins, nValueIn, coinControl, coin_type, useIX))
{ {
if(coin_type == ALL_COINS) if(coin_type == ALL_COINS) {
strFailReason = _("Insufficient funds"); strFailReason = _("Insufficient funds.");
else if (coin_type == ONLY_NONDENOMINATED) } else if (coin_type == ONLY_NONDENOMINATED) {
strFailReason = _("Unable to locate enough Darksend non-denominated funds for this transaction"); strFailReason = _("Unable to locate enough Darksend non-denominated funds for this transaction.");
else if (coin_type == ONLY_NONDENOMINATED_NOTMN) } 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"); strFailReason = _("Unable to locate enough Darksend non-denominated funds for this transaction that are not equal 1000 DRK.");
else } else {
strFailReason = _("Unable to locate enough Darksend denominated funds for this transaction"); 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; return false;
} }