Skip to content

Commit

Permalink
Remove descendants of expired block headers.
Browse files Browse the repository at this point in the history
Fix Delayblock
  • Loading branch information
tecnovert committed Mar 7, 2019
1 parent bf24626 commit 4013e6a
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 53 deletions.
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ define(_CLIENT_VERSION_MAJOR, 0)
define(_CLIENT_VERSION_MINOR, 17)
define(_CLIENT_VERSION_REVISION, 1)
define(_CLIENT_VERSION_PARTICL, 4)
define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_BUILD, 1)
define(_CLIENT_VERSION_IS_RELEASE, true)
define(_COPYRIGHT_YEAR, 2018)
define(_COPYRIGHT_HOLDERS,[The %s developers])
Expand Down
3 changes: 1 addition & 2 deletions doc/release-notes-particl.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ Master



0.18.0.5 rc
0.18.0.5 rc1
==============
For Testnet.

0.18.0.3 or above required for testnet fork at 2019-02-16 12:00:00 UTC.

Expand Down
8 changes: 0 additions & 8 deletions src/chain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,6 @@ const CBlockIndex* LastCommonAncestor(const CBlockIndex* pa, const CBlockIndex*
pb = pb->GetAncestor(pa->nHeight);
}

// Step over gaps
while (pa && pa->nHeight > pb->nHeight) {
pa = pa->pprev;
}
while (pb && pb->nHeight > pa->nHeight) {
pb = pb->pprev;
}

while (pa != pb && pa && pb) {
pa = pa->pprev;
pb = pb->pprev;
Expand Down
10 changes: 9 additions & 1 deletion src/net_processing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,14 @@ void DecMisbehaving(NodeId nodeid, int howmuch) EXCLUSIVE_LOCKS_REQUIRED(cs_main
}
}

NodeId GetBlockSource(uint256 hash)
{
const auto it = mapBlockSource.find(hash);
if (it == mapBlockSource.end())
return -1;
return it->second.first;
}

size_t MAX_LOOSE_HEADERS = 1000;
int MAX_DUPLICATE_HEADERS = 2000;
int64_t MAX_LOOSE_HEADER_TIME = 120;
Expand Down Expand Up @@ -2133,7 +2141,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// we now only provide a getheaders response here. When we receive the headers, we will
// then ask for the blocks we need.
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash));
LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader ? pindexBestHeader->nHeight : 0, inv.hash.ToString(), pfrom->GetId());
LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->GetId());
}
}
else
Expand Down
2 changes: 2 additions & 0 deletions src/net_processing.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,6 @@ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats);
/** Decrease a node's misbehavior score. */
void DecMisbehaving(NodeId nodeid, int howmuch) EXCLUSIVE_LOCKS_REQUIRED(cs_main);

NodeId GetBlockSource(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);

#endif // BITCOIN_NET_PROCESSING_H
130 changes: 89 additions & 41 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4602,22 +4602,26 @@ void EraseDelayedBlock(std::list<DelayedBlock>::iterator p) EXCLUSIVE_LOCKS_REQU
Misbehaving(p->m_node_id, 25, "Delayed block");
}

// Remove from block index
RemoveUnreceivedHeader(p->m_pblock->GetHash());

list_delayed_blocks.erase(p);
auto it = mapBlockIndex.find(p->m_pblock->GetHash());
if (it != mapBlockIndex.end()) {
it->second->nFlags &= ~BLOCK_DELAYED;
setDirtyBlockIndex.insert(it->second);
}
}

extern NodeId GetBlockSource(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool DelayBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
LogPrintf("Warning: %s - Previous stake modifier is null for block %s from node %d.\n", __func__, pblock->GetHash().ToString(), state.nodeId);
NodeId nodeId = GetBlockSource(pblock->GetHash());
LogPrintf("Warning: %s - Previous stake modifier is null for block %s from peer %d.\n", __func__, pblock->GetHash().ToString(), nodeId);
while (list_delayed_blocks.size() >= MAX_DELAYED_BLOCKS) {
LogPrint(BCLog::NET, "Removing Delayed block %s, too many delayed.\n", pblock->GetHash().ToString());
EraseDelayedBlock(--list_delayed_blocks.end());
EraseDelayedBlock(list_delayed_blocks.begin());
list_delayed_blocks.erase(list_delayed_blocks.begin());
}
assert(list_delayed_blocks.size() < MAX_DELAYED_BLOCKS);
state.nFlags |= BLOCK_DELAYED; // Mark to prevent further processing
list_delayed_blocks.emplace_back(pblock, state.nodeId);
list_delayed_blocks.emplace_back(pblock, nodeId);
return true;
}

Expand All @@ -4628,50 +4632,87 @@ void CheckDelayedBlocks(const CChainParams& chainparams, const uint256 &block_ha
}

int64_t now = GetTime();
std::list<DelayedBlock>::iterator p = list_delayed_blocks.begin();
while (p != list_delayed_blocks.end()) {
if (p->m_pblock->hashPrevBlock == block_hash) {
LogPrint(BCLog::NET, "Processing delayed block %s prev %s.\n", p->m_pblock->GetHash().ToString(), block_hash.ToString());
ProcessNewBlock(chainparams, p->m_pblock, false, nullptr); // Should update DoS if necessary, finding block through mapBlockSource
list_delayed_blocks.erase(p++);
continue;
}
if (p->m_time + MAX_DELAY_BLOCK_SECONDS < now) {
LogPrint(BCLog::NET, "Removing delayed block %s, timed out.\n", p->m_pblock->GetHash().ToString());
LOCK(cs_main);
EraseDelayedBlock(p++);
continue;
std::vector<std::shared_ptr<const CBlock> > process_blocks;
{
LOCK(cs_main);
std::list<DelayedBlock>::iterator p = list_delayed_blocks.begin();
while (p != list_delayed_blocks.end()) {
if (p->m_pblock->hashPrevBlock == block_hash) {
process_blocks.push_back(p->m_pblock);
p = list_delayed_blocks.erase(p);
continue;
}
if (p->m_time + MAX_DELAY_BLOCK_SECONDS < now) {
LogPrint(BCLog::NET, "Removing delayed block %s, timed out.\n", p->m_pblock->GetHash().ToString());
EraseDelayedBlock(p);
p = list_delayed_blocks.erase(p);
continue;
}
++p;
}
++p;
}

for (auto &p : process_blocks) {
LogPrint(BCLog::NET, "Processing delayed block %s prev %s.\n", p->GetHash().ToString(), block_hash.ToString());
ProcessNewBlock(chainparams, p, false, nullptr); // Should update DoS if necessary, finding block through mapBlockSource
}
}

bool RemoveUnreceivedHeader(const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
BlockMap::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end() && !(mi->second->nFlags & BLOCK_ACCEPTED)) {
LogPrint(BCLog::NET, "Removing loose header %s.\n", hash.ToString());
setDirtyBlockIndex.erase(mi->second);
if (pindexBestHeader == mi->second) {
pindexBestHeader = nullptr;
if (mi != mapBlockIndex.end() && (mi->second->nFlags & BLOCK_ACCEPTED)) {
return false;
}
if (mi == mapBlockIndex.end()) {
return true; // was already removed, peer misbehaving
}

// Remove entire chain
std::vector<BlockMap::iterator> remove_headers;
std::vector<BlockMap::iterator> last_round[2];

size_t n = 0;
last_round[n].push_back(mi);
remove_headers.push_back(mi);
while (last_round[n].size()) {
last_round[!n].clear();

for (BlockMap::iterator& check_header : last_round[n]) {
BlockMap::iterator it = mapBlockIndex.begin();
while (it != mapBlockIndex.end()) {
if (it->second->pprev == check_header->second) {
if ((it->second->nFlags & BLOCK_ACCEPTED)) {
LogPrintf("Can't remove header %s, descendant block %s accepted.\n", hash.ToString(), it->second->GetBlockHash().ToString());
return true; // Can't remove any blocks, peer misbehaving for not sending
}
last_round[!n].push_back(it);
remove_headers.push_back(it);
}
it++;
}
}
if (pindexBestInvalid == mi->second) {
pindexBestInvalid = nullptr;
n = !n;
}

LogPrintf("Removing %d loose headers from %s.\n", remove_headers.size(), hash.ToString());

for (auto &entry : remove_headers) {
LogPrintf("Removing loose header %s.\n", entry->second->GetBlockHash().ToString());
setDirtyBlockIndex.erase(entry->second);

if (pindexBestHeader == entry->second) {
pindexBestHeader = chainActive.Tip();
}
for (auto& entry : mapBlockIndex) {
if (entry.second->pskip == mi->second) {
entry.second->pskip = nullptr;
}
if (entry.second->pprev == mi->second) {
entry.second->pprev = mi->second->pprev;
}
if (pindexBestInvalid == entry->second) {
pindexBestInvalid = nullptr;
}
RemoveNonReceivedHeaderFromNodes(mi);
delete mi->second;
mapBlockIndex.erase(mi);
return true;
RemoveNonReceivedHeaderFromNodes(entry);
delete entry->second;
mapBlockIndex.erase(entry);
}
return false;

return true;
}

size_t CountDelayedBlocks() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Expand Down Expand Up @@ -4737,8 +4778,9 @@ bool CChainState::AcceptBlockHeader(const CBlockHeader& block, CValidationState&
if (!pindexPrev->IsValid(BLOCK_VALID_SCRIPTS)) {
for (const CBlockIndex* failedit : m_failed_blocks) {
if (pindexPrev->GetAncestor(failedit->nHeight) == failedit) {
assert(failedit->nStatus & BLOCK_FAILED_VALID);
//assert(failedit->nStatus & BLOCK_FAILED_VALID);
CBlockIndex* invalid_walk = pindexPrev;
if (failedit->nStatus & BLOCK_FAILED_VALID)
while (invalid_walk != failedit) {
invalid_walk->nStatus |= BLOCK_FAILED_CHILD;
setDirtyBlockIndex.insert(invalid_walk);
Expand Down Expand Up @@ -4994,6 +5036,12 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
smsgModule.ScanBlock(*pblock);
}

{
assert(pindex);
// Check here for blocks not connected to the chain, TODO: move to a timer.
CheckDelayedBlocks(chainparams, pindex->GetBlockHash());
}

return true;
}

Expand Down

0 comments on commit 4013e6a

Please sign in to comment.