@ -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 , COrphan Block * > : : 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 , COrphan Block * > : : iterator it2 = mapOrphanBlocks . begin ( ) ;
for ( ; it2 ! = mapOrphanBlocks . end ( ) ; it2 + + )
for ( ; it2 ! = mapOrphanBlocks . end ( ) ; it2 + + )
delete ( * it2 ) . second ;
delete ( * it2 ) . second ;
mapOrphanBlocks . clear ( ) ;
mapOrphanBlocks . clear ( ) ;