Merge pull request #3083 from sipa/chainlocator

CBlockLocator improvements & move to core
This commit is contained in:
Gavin Andresen 2013-10-15 16:31:46 -07:00
commit 9e70bff67a
6 changed files with 95 additions and 153 deletions

View file

@ -661,4 +661,38 @@ public:
void print() const; void print() const;
}; };
/** Describes a place in the block chain to another node such that if the
* other node doesn't have the same branch, it can find a recent common trunk.
* The further back it is, the further before the fork it may be.
*/
struct CBlockLocator
{
std::vector<uint256> vHave;
CBlockLocator() {}
CBlockLocator(const std::vector<uint256>& vHaveIn)
{
vHave = vHaveIn;
}
IMPLEMENT_SERIALIZE
(
if (!(nType & SER_GETHASH))
READWRITE(nVersion);
READWRITE(vHave);
)
void SetNull()
{
vHave.clear();
}
bool IsNull()
{
return vHave.empty();
}
};
#endif #endif

View file

@ -16,7 +16,7 @@
#include <db_cxx.h> #include <db_cxx.h>
class CAddrMan; class CAddrMan;
class CBlockLocator; struct CBlockLocator;
class CDiskBlockIndex; class CDiskBlockIndex;
class CMasterKey; class CMasterKey;
class COutPoint; class COutPoint;

View file

@ -116,7 +116,7 @@ void Shutdown()
{ {
LOCK(cs_main); LOCK(cs_main);
if (pwalletMain) if (pwalletMain)
pwalletMain->SetBestChain(CBlockLocator(chainActive.Tip())); pwalletMain->SetBestChain(chainActive.GetLocator());
if (pblocktree) if (pblocktree)
pblocktree->Flush(); pblocktree->Flush();
if (pcoinsTip) if (pcoinsTip)
@ -912,7 +912,7 @@ bool AppInit2(boost::thread_group& threadGroup)
strErrors << _("Cannot write default address") << "\n"; strErrors << _("Cannot write default address") << "\n";
} }
pwalletMain->SetBestChain(CBlockLocator(chainActive.Tip())); pwalletMain->SetBestChain(chainActive.GetLocator());
} }
LogPrintf("%s", strErrors.str().c_str()); LogPrintf("%s", strErrors.str().c_str());
@ -928,7 +928,7 @@ bool AppInit2(boost::thread_group& threadGroup)
CWalletDB walletdb(strWalletFile); CWalletDB walletdb(strWalletFile);
CBlockLocator locator; CBlockLocator locator;
if (walletdb.ReadBestBlock(locator)) if (walletdb.ReadBestBlock(locator))
pindexRescan = locator.GetBlockIndex(); pindexRescan = chainActive.FindFork(locator);
else else
pindexRescan = chainActive.Genesis(); pindexRescan = chainActive.Genesis();
} }
@ -939,7 +939,7 @@ bool AppInit2(boost::thread_group& threadGroup)
nStart = GetTimeMillis(); nStart = GetTimeMillis();
pwalletMain->ScanForWalletTransactions(pindexRescan, true); pwalletMain->ScanForWalletTransactions(pindexRescan, true);
LogPrintf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart); LogPrintf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart);
pwalletMain->SetBestChain(CBlockLocator(chainActive.Tip())); pwalletMain->SetBestChain(chainActive.GetLocator());
nWalletDBUpdated++; nWalletDBUpdated++;
} }

View file

@ -190,97 +190,12 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals)
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// CBlockLocator implementation // CChain implementation
// //
CBlockLocator::CBlockLocator(uint256 hashBlock)
{
std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
if (mi != mapBlockIndex.end())
Set((*mi).second);
}
void CBlockLocator::Set(const CBlockIndex* pindex)
{
vHave.clear();
int nStep = 1;
while (pindex)
{
vHave.push_back(pindex->GetBlockHash());
// Exponentially larger steps back
for (int i = 0; pindex && i < nStep; i++)
pindex = pindex->pprev;
if (vHave.size() > 10)
nStep *= 2;
}
vHave.push_back(Params().HashGenesisBlock());
}
int CBlockLocator::GetDistanceBack()
{
// Retrace how far back it was in the sender's branch
int nDistance = 0;
int nStep = 1;
BOOST_FOREACH(const uint256& hash, vHave)
{
std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end())
{
CBlockIndex* pindex = (*mi).second;
if (chainActive.Contains(pindex))
return nDistance;
}
nDistance += nStep;
if (nDistance > 10)
nStep *= 2;
}
return nDistance;
}
CBlockIndex *CBlockLocator::GetBlockIndex()
{
// Find the first block the caller has in the main chain
BOOST_FOREACH(const uint256& hash, vHave)
{
std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end())
{
CBlockIndex* pindex = (*mi).second;
if (chainActive.Contains(pindex))
return pindex;
}
}
return chainActive.Genesis();
}
uint256 CBlockLocator::GetBlockHash()
{
// Find the first block the caller has in the main chain
BOOST_FOREACH(const uint256& hash, vHave)
{
std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end())
{
CBlockIndex* pindex = (*mi).second;
if (chainActive.Contains(pindex))
return hash;
}
}
return Params().HashGenesisBlock();
}
int CBlockLocator::GetHeight()
{
CBlockIndex* pindex = GetBlockIndex();
if (!pindex)
return 0;
return pindex->nHeight;
}
CBlockIndex *CChain::SetTip(CBlockIndex *pindex) { CBlockIndex *CChain::SetTip(CBlockIndex *pindex) {
if (pindex == NULL) { if (pindex == NULL) {
std::vector<CBlockIndex*>().swap(vChain); vChain.clear();
return NULL; return NULL;
} }
vChain.resize(pindex->nHeight + 1); vChain.resize(pindex->nHeight + 1);
@ -291,6 +206,47 @@ CBlockIndex *CChain::SetTip(CBlockIndex *pindex) {
return pindex; return pindex;
} }
CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const {
int nStep = 1;
std::vector<uint256> vHave;
vHave.reserve(32);
if (!pindex)
pindex = Tip();
while (pindex) {
vHave.push_back(pindex->GetBlockHash());
// Stop when we have added the genesis block.
if (pindex->nHeight == 0)
break;
// Exponentially larger steps back, plus the genesis block.
int nHeight = std::max(pindex->nHeight - nStep, 0);
// In case pindex is not in this chain, iterate pindex->pprev to find blocks.
while (pindex->nHeight > nHeight && !Contains(pindex))
pindex = pindex->pprev;
// If pindex is in this chain, use direct height-based access.
if (pindex->nHeight > nHeight)
pindex = (*this)[nHeight];
if (vHave.size() > 10)
nStep *= 2;
}
return CBlockLocator(vHave);
}
CBlockIndex *CChain::FindFork(const CBlockLocator &locator) const {
// Find the first block the caller has in the main chain
BOOST_FOREACH(const uint256& hash, locator.vHave) {
std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end())
{
CBlockIndex* pindex = (*mi).second;
if (Contains(pindex))
return pindex;
}
}
return Genesis();
}
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// CCoinsView implementations // CCoinsView implementations
@ -2156,10 +2112,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
// Update best block in wallet (so we can detect restored wallets) // Update best block in wallet (so we can detect restored wallets)
if ((pindexNew->nHeight % 20160) == 0 || (!fIsInitialDownload && (pindexNew->nHeight % 144) == 0)) if ((pindexNew->nHeight % 20160) == 0 || (!fIsInitialDownload && (pindexNew->nHeight % 144) == 0))
{ ::SetBestChain(chainActive.GetLocator(pindexNew));
const CBlockLocator locator(pindexNew);
::SetBestChain(locator);
}
// New best block // New best block
nTimeBestReceived = GetTime(); nTimeBestReceived = GetTime();
@ -2525,7 +2478,7 @@ void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd)
pnode->pindexLastGetBlocksBegin = pindexBegin; pnode->pindexLastGetBlocksBegin = pindexBegin;
pnode->hashLastGetBlocksEnd = hashEnd; pnode->hashLastGetBlocksEnd = hashEnd;
pnode->PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd); pnode->PushMessage("getblocks", chainActive.GetLocator(pindexBegin), hashEnd);
} }
bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp) bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
@ -3653,7 +3606,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
vRecv >> locator >> hashStop; vRecv >> locator >> hashStop;
// Find the last block the caller has in the main chain // Find the last block the caller has in the main chain
CBlockIndex* pindex = locator.GetBlockIndex(); CBlockIndex* pindex = chainActive.FindFork(locator);
// Send the rest of the chain // Send the rest of the chain
if (pindex) if (pindex)
@ -3698,7 +3651,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
else else
{ {
// Find the last block the caller has in the main chain // Find the last block the caller has in the main chain
pindex = locator.GetBlockIndex(); pindex = chainActive.FindFork(locator);
if (pindex) if (pindex)
pindex = chainActive.Next(pindex); pindex = chainActive.Next(pindex);
} }

View file

@ -1033,6 +1033,12 @@ public:
/** Set/initialize a chain with a given tip. Returns the forking point. */ /** Set/initialize a chain with a given tip. Returns the forking point. */
CBlockIndex *SetTip(CBlockIndex *pindex); CBlockIndex *SetTip(CBlockIndex *pindex);
/** Return a CBlockLocator that refers to a block in this chain (by default the tip). */
CBlockLocator GetLocator(const CBlockIndex *pindex = NULL) const;
/** Find the last common block between this chain and a locator. */
CBlockIndex *FindFork(const CBlockLocator &locator) const;
}; };
/** The currently-connected chain of blocks. */ /** The currently-connected chain of blocks. */
@ -1040,59 +1046,6 @@ extern CChain chainActive;
/** Describes a place in the block chain to another node such that if the
* other node doesn't have the same branch, it can find a recent common trunk.
* The further back it is, the further before the fork it may be.
*/
class CBlockLocator
{
protected:
std::vector<uint256> vHave;
public:
CBlockLocator() {}
explicit CBlockLocator(const CBlockIndex* pindex)
{
Set(pindex);
}
explicit CBlockLocator(uint256 hashBlock);
CBlockLocator(const std::vector<uint256>& vHaveIn)
{
vHave = vHaveIn;
}
IMPLEMENT_SERIALIZE
(
if (!(nType & SER_GETHASH))
READWRITE(nVersion);
READWRITE(vHave);
)
void SetNull()
{
vHave.clear();
}
bool IsNull()
{
return vHave.empty();
}
/** Given a block initialises the locator to that point in the chain. */
void Set(const CBlockIndex* pindex);
/** Returns the distance in blocks this locator is from our chain head. */
int GetDistanceBack();
/** Returns the first best-chain block the locator contains. */
CBlockIndex* GetBlockIndex();
/** Returns the hash of the first best chain block the locator contains. */
uint256 GetBlockHash();
/** Returns the height of the first best chain block the locator has. */
int GetHeight();
};

View file

@ -1169,7 +1169,9 @@ Value listsinceblock(const Array& params, bool fHelp)
uint256 blockId = 0; uint256 blockId = 0;
blockId.SetHex(params[0].get_str()); blockId.SetHex(params[0].get_str());
pindex = CBlockLocator(blockId).GetBlockIndex(); std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(blockId);
if (it != mapBlockIndex.end())
pindex = it->second;
} }
if (params.size() > 1) if (params.size() > 1)