merge downstream 0.11.1
This commit is contained in:
commit
78d47c04fe
@ -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])
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
@ -1364,8 +1364,6 @@ void CDarkSendPool::NewBlock()
|
||||
|
||||
darkSendPool.CheckTimeout();
|
||||
|
||||
masternodePayments.ProcessBlock(chainActive.Tip()->nHeight+10);
|
||||
|
||||
if(!fEnableDarksend) return;
|
||||
|
||||
if(!fMasterNode){
|
||||
|
@ -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<CDarkSendEntry> myEntries;
|
||||
|
134
src/instantx.cpp
134
src/instantx.cpp
@ -22,6 +22,7 @@ std::map<uint256, CTransaction> mapTxLockReq;
|
||||
std::map<uint256, CTransaction> mapTxLockReqRejected;
|
||||
std::map<uint256, int> mapTxLockVote;
|
||||
std::map<uint256, CTransactionLock> mapTxLocks;
|
||||
std::map<COutPoint, uint256> mapLockedInputs;
|
||||
std::map<uint256, int64_t> 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<uint256, CTransactionLock>::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,29 +316,29 @@ 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());
|
||||
|
||||
#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
|
||||
|
||||
//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;
|
||||
}
|
||||
|
@ -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<uint256, CTransaction> mapTxLockReq;
|
||||
extern map<uint256, CTransactionLock> mapTxLocks;
|
||||
extern std::map<COutPoint, uint256> 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);
|
||||
|
297
src/main.cpp
297
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<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;
|
||||
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)
|
||||
{
|
||||
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<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
|
||||
// known to be invalid (it's however far from certain to be valid).
|
||||
void static FindMostWorkChain() {
|
||||
@ -2919,28 +2815,18 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
|
||||
|
||||
// ----------- instantX transaction scanning -----------
|
||||
|
||||
std::map<uint256, CTransactionLock>::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"),
|
||||
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++;
|
||||
}
|
||||
|
||||
|
||||
// ----------- masternode payments -----------
|
||||
@ -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();
|
||||
|
||||
|
@ -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)){
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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, set<pair<const CWalletTx*,unsign
|
||||
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
|
||||
&& 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<pair<CScript, int64_t> >& 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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user