mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 20:12:57 +01:00
remove conflicting blocks for lock
This commit is contained in:
parent
ca4f75e0eb
commit
35cf5f9e54
@ -116,6 +116,7 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
|
||||
|
||||
printf(" -- ProcessMessageInstantX::txlock %d %s\n", mapTxLocks.count(inv.hash), inv.hash.ToString().c_str());
|
||||
|
||||
|
||||
if(!mapTxLocks.count(inv.hash)){
|
||||
if(ctxl.CountSignatures() < INSTANTX_SIGNATURES_REQUIRED){
|
||||
printf("InstantX::txlock - not enough signatures\n");
|
||||
@ -129,9 +130,34 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
|
||||
printf("InstantX::txlock - not all in favor of lock, rejected\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mapTxLocks.insert(make_pair(inv.hash, ctxl));
|
||||
|
||||
//we should have the lock request in place
|
||||
if(!mapTxLockReq.count(inv.hash)){
|
||||
//if we don't
|
||||
bool fMissingInputs = false;
|
||||
CValidationState state;
|
||||
if (ctxl.tx.AcceptToMemoryPool(state, true, true, &fMissingInputs))
|
||||
{
|
||||
mapTxLockReq.insert(make_pair(inv.hash, ctxl.tx));
|
||||
|
||||
printf("ProcessMessageInstantX::txlock - Transaction Lock Request: %s %s : accepted %s\n",
|
||||
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
|
||||
ctxl.tx.GetHash().ToString().c_str()
|
||||
);
|
||||
|
||||
} else {
|
||||
// we have a conflicting transaction (an attack)
|
||||
CValidationState state;
|
||||
if(!DisconnectBlockAndInputs(state, ctxl.tx.vin)){
|
||||
printf("ProcessMessageInstantX::txlock - Couldn't reverse conflicting transaction: %s %s : failed %s\n",
|
||||
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
|
||||
ctxl.tx.GetHash().ToString().c_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//broadcast the new lock
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
|
165
src/main.cpp
165
src/main.cpp
@ -2470,6 +2470,171 @@ bool SetBestChain(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, std::vector<CTxIn> vecInputs)
|
||||
{
|
||||
// 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 = pindexBest;
|
||||
CBlockIndex* pindexNew = NULL;
|
||||
|
||||
int HeightMin = pindexBest->nHeight-5;
|
||||
bool foundConflictingTx = false;
|
||||
|
||||
// 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 (!block.ReadFromDisk(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, vecInputs){
|
||||
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 %"PRIszu" blocks; %s..\n", vDisconnect.size(), pindexNew->GetBlockHash().ToString().c_str());
|
||||
}
|
||||
|
||||
// Disconnect shorter branch
|
||||
vector<CTransaction> vResurrect;
|
||||
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) {
|
||||
CBlock block;
|
||||
if (!block.ReadFromDisk(pindex))
|
||||
return state.Abort(_("Failed to read block"));
|
||||
int64 nStart = GetTimeMicros();
|
||||
if (!block.DisconnectBlock(state, pindex, view))
|
||||
return error("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, vecInputs){
|
||||
BOOST_FOREACH(const CTxIn& in2, tx.vin){
|
||||
if(in1 != in2) isConflict = true;
|
||||
}
|
||||
}
|
||||
if(!isConflict) vResurrect.push_back(tx);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Make sure it's successfully written to disk before changing memory structure
|
||||
bool fIsInitialDownload = IsInitialBlockDownload();
|
||||
if (!fIsInitialDownload || pcoinsTip->GetCacheSize() > nCoinCacheSize) {
|
||||
// Typical CCoins structures on disk are around 100 bytes in size.
|
||||
// Pushing a new one to the database can cause it to be written
|
||||
// twice (once in the log, and once in the tables). This is already
|
||||
// an overestimation, as most will delete an existing entry or
|
||||
// overwrite one. Still, use a conservative safety factor of 2.
|
||||
if (!CheckDiskSpace(100 * 2 * 2 * pcoinsTip->GetCacheSize()))
|
||||
return state.Error();
|
||||
FlushBlockFile();
|
||||
pblocktree->Sync();
|
||||
if (!pcoinsTip->Flush())
|
||||
return state.Abort(_("Failed to write to coin database"));
|
||||
}
|
||||
|
||||
// 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(stateDummy, 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();
|
||||
pindexBest = pindexNew;
|
||||
pblockindexFBBHLast = NULL;
|
||||
nBestHeight = pindexBest->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(), nBestHeight, log(nBestChainWork.getdouble())/log(2.0), (unsigned long)pindexNew->nChainTx,
|
||||
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexBest->GetBlockTime()).c_str(),
|
||||
Checkpoints::GuessVerificationProgress(pindexBest));
|
||||
|
||||
// Check the version of the last 100 blocks to see if we need to upgrade:
|
||||
if (!fIsInitialDownload)
|
||||
{
|
||||
int nUpgraded = 0;
|
||||
const CBlockIndex* pindex = pindexBest;
|
||||
for (int i = 0; i < 100 && pindex != NULL; i++)
|
||||
{
|
||||
if (pindex->nVersion > CBlock::CURRENT_VERSION)
|
||||
++nUpgraded;
|
||||
pindex = pindex->pprev;
|
||||
}
|
||||
if (nUpgraded > 0)
|
||||
LogPrintf("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;
|
||||
}
|
||||
|
||||
|
||||
bool CBlock::AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos)
|
||||
{
|
||||
|
@ -194,6 +194,8 @@ bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, b
|
||||
int64 GetTransactionFees(CTransaction& tx);
|
||||
/** Connect/disconnect blocks until pindexNew is the new tip of the active block chain */
|
||||
bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew);
|
||||
/** Find a conflicting transcation in a block and disconnect all up to that point **/
|
||||
bool DisconnectBlockAndInputs(CValidationState &state, std::vector<CTxIn> vecInputs);
|
||||
/** Find the best known block, and make it the tip of the block chain */
|
||||
bool ConnectBestBlock(CValidationState &state);
|
||||
/** Create a new block index entry for a given block hash */
|
||||
|
Loading…
Reference in New Issue
Block a user