Merge pull request #3516 from sipa/serorphans-head

Store orphan blocks in serialized form
This commit is contained in:
Gavin Andresen 2014-01-13 08:54:33 -08:00
commit 266921e70f
1 changed files with 41 additions and 17 deletions

View File

@ -56,8 +56,13 @@ int64_t CTransaction::nMinRelayTxFee = 10000;
static CMedianFilter<int> cPeerBlockCounts(8, 0); // Amount of blocks that other nodes claim to have static CMedianFilter<int> cPeerBlockCounts(8, 0); // Amount of blocks that other nodes claim to have
map<uint256, CBlock*> mapOrphanBlocks; struct COrphanBlock {
multimap<uint256, CBlock*> mapOrphanBlocksByPrev; uint256 hashBlock;
uint256 hashPrev;
vector<unsigned char> vchBlock;
};
map<uint256, COrphanBlock*> mapOrphanBlocks;
multimap<uint256, COrphanBlock*> mapOrphanBlocksByPrev;
map<uint256, CTransaction> mapOrphanTransactions; map<uint256, CTransaction> mapOrphanTransactions;
map<uint256, set<uint256> > mapOrphanTransactionsByPrev; map<uint256, set<uint256> > mapOrphanTransactionsByPrev;
@ -985,12 +990,19 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex)
return true; return true;
} }
uint256 static GetOrphanRoot(const CBlockHeader* pblock) uint256 static GetOrphanRoot(const uint256& hash)
{ {
map<uint256, COrphanBlock*>::iterator it = mapOrphanBlocks.find(hash);
if (it == mapOrphanBlocks.end())
return hash;
// Work back to the first block in the orphan chain // Work back to the first block in the orphan chain
while (mapOrphanBlocks.count(pblock->hashPrevBlock)) do {
pblock = mapOrphanBlocks[pblock->hashPrevBlock]; map<uint256, COrphanBlock*>::iterator it2 = mapOrphanBlocks.find(it->second->hashPrev);
return pblock->GetHash(); if (it2 == mapOrphanBlocks.end())
return it->first;
it = it2;
} while(true);
} }
int64_t GetBlockValue(int nHeight, int64_t nFees) int64_t GetBlockValue(int nHeight, int64_t nFees)
@ -2277,12 +2289,19 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
// Accept orphans as long as there is a node to request its parents from // Accept orphans as long as there is a node to request its parents from
if (pfrom) { if (pfrom) {
CBlock* pblock2 = new CBlock(*pblock); COrphanBlock* pblock2 = new COrphanBlock();
{
CDataStream ss(SER_DISK, CLIENT_VERSION);
ss << *pblock;
pblock2->vchBlock = std::vector<unsigned char>(ss.begin(), ss.end());
}
pblock2->hashBlock = hash;
pblock2->hashPrev = pblock->hashPrevBlock;
mapOrphanBlocks.insert(make_pair(hash, pblock2)); mapOrphanBlocks.insert(make_pair(hash, pblock2));
mapOrphanBlocksByPrev.insert(make_pair(pblock2->hashPrevBlock, pblock2)); mapOrphanBlocksByPrev.insert(make_pair(pblock2->hashPrev, pblock2));
// Ask this guy to fill in what we're missing // Ask this guy to fill in what we're missing
PushGetBlocks(pfrom, chainActive.Tip(), GetOrphanRoot(pblock2)); PushGetBlocks(pfrom, chainActive.Tip(), GetOrphanRoot(hash));
} }
return true; return true;
} }
@ -2297,17 +2316,22 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
for (unsigned int i = 0; i < vWorkQueue.size(); i++) for (unsigned int i = 0; i < vWorkQueue.size(); i++)
{ {
uint256 hashPrev = vWorkQueue[i]; uint256 hashPrev = vWorkQueue[i];
for (multimap<uint256, CBlock*>::iterator mi = mapOrphanBlocksByPrev.lower_bound(hashPrev); for (multimap<uint256, COrphanBlock*>::iterator mi = mapOrphanBlocksByPrev.lower_bound(hashPrev);
mi != mapOrphanBlocksByPrev.upper_bound(hashPrev); mi != mapOrphanBlocksByPrev.upper_bound(hashPrev);
++mi) ++mi)
{ {
CBlock* pblockOrphan = (*mi).second; CBlock block;
{
CDataStream ss(mi->second->vchBlock, SER_DISK, CLIENT_VERSION);
ss >> block;
}
block.BuildMerkleTree();
// Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan resolution (that is, feeding people an invalid block based on LegitBlockX in order to get anyone relaying LegitBlockX banned) // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan resolution (that is, feeding people an invalid block based on LegitBlockX in order to get anyone relaying LegitBlockX banned)
CValidationState stateDummy; CValidationState stateDummy;
if (AcceptBlock(*pblockOrphan, stateDummy)) if (AcceptBlock(block, stateDummy))
vWorkQueue.push_back(pblockOrphan->GetHash()); vWorkQueue.push_back(mi->second->hashBlock);
mapOrphanBlocks.erase(pblockOrphan->GetHash()); mapOrphanBlocks.erase(mi->second->hashBlock);
delete pblockOrphan; delete mi->second;
} }
mapOrphanBlocksByPrev.erase(hashPrev); mapOrphanBlocksByPrev.erase(hashPrev);
} }
@ -3331,7 +3355,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (!fImporting && !fReindex) if (!fImporting && !fReindex)
pfrom->AskFor(inv); pfrom->AskFor(inv);
} else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) { } else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) {
PushGetBlocks(pfrom, chainActive.Tip(), GetOrphanRoot(mapOrphanBlocks[inv.hash])); PushGetBlocks(pfrom, chainActive.Tip(), GetOrphanRoot(inv.hash));
} else if (nInv == nLastBlock) { } else if (nInv == nLastBlock) {
// In case we are on a very long side-chain, it is possible that we already have // In case we are on a very long side-chain, it is possible that we already have
// the last block in an inv bundle sent in response to getblocks. Try to detect // the last block in an inv bundle sent in response to getblocks. Try to detect
@ -4119,7 +4143,7 @@ public:
mapBlockIndex.clear(); mapBlockIndex.clear();
// orphan blocks // orphan blocks
std::map<uint256, CBlock*>::iterator it2 = mapOrphanBlocks.begin(); std::map<uint256, COrphanBlock*>::iterator it2 = mapOrphanBlocks.begin();
for (; it2 != mapOrphanBlocks.end(); it2++) for (; it2 != mapOrphanBlocks.end(); it2++)
delete (*it2).second; delete (*it2).second;
mapOrphanBlocks.clear(); mapOrphanBlocks.clear();