mirror of
https://github.com/dashpay/dash.git
synced 2024-12-27 21:12:48 +01:00
Prepare database format for multi-stage block processing
This commit adds a status field and a transaction counter to the block indexes.
This commit is contained in:
parent
4fea06db25
commit
857c61df0b
10
src/db.cpp
10
src/db.cpp
@ -622,6 +622,9 @@ bool LoadBlockIndex(CChainDB &chaindb)
|
|||||||
{
|
{
|
||||||
CBlockIndex* pindex = item.second;
|
CBlockIndex* pindex = item.second;
|
||||||
pindex->bnChainWork = (pindex->pprev ? pindex->pprev->bnChainWork : 0) + pindex->GetBlockWork();
|
pindex->bnChainWork = (pindex->pprev ? pindex->pprev->bnChainWork : 0) + pindex->GetBlockWork();
|
||||||
|
pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx;
|
||||||
|
if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TRANSACTIONS && !(pindex->nStatus & BLOCK_FAILED_MASK))
|
||||||
|
setBlockIndexValid.insert(pindex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load block file info
|
// Load block file info
|
||||||
@ -727,20 +730,23 @@ bool CChainDB::LoadBlockIndexGuts()
|
|||||||
CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
|
CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
|
||||||
pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
|
pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
|
||||||
pindexNew->nHeight = diskindex.nHeight;
|
pindexNew->nHeight = diskindex.nHeight;
|
||||||
pindexNew->pos = diskindex.pos;
|
pindexNew->nFile = diskindex.nFile;
|
||||||
|
pindexNew->nDataPos = diskindex.nDataPos;
|
||||||
pindexNew->nUndoPos = diskindex.nUndoPos;
|
pindexNew->nUndoPos = diskindex.nUndoPos;
|
||||||
pindexNew->nVersion = diskindex.nVersion;
|
pindexNew->nVersion = diskindex.nVersion;
|
||||||
pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
|
pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
|
||||||
pindexNew->nTime = diskindex.nTime;
|
pindexNew->nTime = diskindex.nTime;
|
||||||
pindexNew->nBits = diskindex.nBits;
|
pindexNew->nBits = diskindex.nBits;
|
||||||
pindexNew->nNonce = diskindex.nNonce;
|
pindexNew->nNonce = diskindex.nNonce;
|
||||||
|
pindexNew->nStatus = diskindex.nStatus;
|
||||||
|
pindexNew->nTx = diskindex.nTx;
|
||||||
|
|
||||||
// Watch for genesis block
|
// Watch for genesis block
|
||||||
if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock)
|
if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock)
|
||||||
pindexGenesisBlock = pindexNew;
|
pindexGenesisBlock = pindexNew;
|
||||||
|
|
||||||
if (!pindexNew->CheckIndex())
|
if (!pindexNew->CheckIndex())
|
||||||
return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight);
|
return error("LoadBlockIndex() : CheckIndex failed: %s", pindexNew->ToString().c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
35
src/init.cpp
35
src/init.cpp
@ -781,38 +781,9 @@ bool AppInit2()
|
|||||||
// ********************************************************* Step 9: import blocks
|
// ********************************************************* Step 9: import blocks
|
||||||
|
|
||||||
// scan for better chains in the block chain database, that are not yet connected in the active best chain
|
// scan for better chains in the block chain database, that are not yet connected in the active best chain
|
||||||
CBlockIndex *pindexFoundBest = pindexBest;
|
uiInterface.InitMessage(_("Importing blocks from block database..."));
|
||||||
for (std::map<uint256,CBlockIndex*>::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); it++) {
|
if (!ConnectBestBlock())
|
||||||
CBlockIndex *pindex = it->second;
|
strErrors << "Failed to connect best block";
|
||||||
if (pindexFoundBest==NULL || pindex->bnChainWork > pindexFoundBest->bnChainWork)
|
|
||||||
pindexFoundBest = pindex;
|
|
||||||
}
|
|
||||||
if (pindexFoundBest != pindexBest) {
|
|
||||||
uiInterface.InitMessage(_("Importing blocks from block database..."));
|
|
||||||
uint64 nTxs = 0;
|
|
||||||
uint64 nBlocks = 0;
|
|
||||||
std::vector<CBlockIndex*> vAttach;
|
|
||||||
vAttach.reserve(pindexFoundBest->nHeight - (pindexBest==NULL ? 0 : pindexBest->nHeight));
|
|
||||||
while (pindexFoundBest && pindexFoundBest->bnChainWork > (pindexBest==NULL ? 0 : pindexBest->bnChainWork)) {
|
|
||||||
vAttach.push_back(pindexFoundBest);
|
|
||||||
pindexFoundBest = pindexFoundBest->pprev;
|
|
||||||
}
|
|
||||||
for (std::vector<CBlockIndex*>::reverse_iterator it = vAttach.rbegin(); it != vAttach.rend(); it++) {
|
|
||||||
CBlockIndex *pindex = *it;
|
|
||||||
CBlock block;
|
|
||||||
if (!block.ReadFromDisk(pindex))
|
|
||||||
break;
|
|
||||||
nTxs += block.vtx.size();
|
|
||||||
nBlocks++;
|
|
||||||
if (pindex->nHeight == 0 || nTxs + nBlocks*3 > 500) {
|
|
||||||
nTxs=0;
|
|
||||||
nBlocks=0;
|
|
||||||
block.SetBestChain(pindex);
|
|
||||||
}
|
|
||||||
if (fRequestShutdown)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<boost::filesystem::path> *vPath = new std::vector<boost::filesystem::path>();
|
std::vector<boost::filesystem::path> *vPath = new std::vector<boost::filesystem::path>();
|
||||||
if (mapArgs.count("-loadblock"))
|
if (mapArgs.count("-loadblock"))
|
||||||
|
112
src/main.cpp
112
src/main.cpp
@ -37,6 +37,7 @@ CBigNum bnBestChainWork = 0;
|
|||||||
CBigNum bnBestInvalidWork = 0;
|
CBigNum bnBestInvalidWork = 0;
|
||||||
uint256 hashBestChain = 0;
|
uint256 hashBestChain = 0;
|
||||||
CBlockIndex* pindexBest = NULL;
|
CBlockIndex* pindexBest = NULL;
|
||||||
|
set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexValid; // may contain all CBlockIndex*'s that have validness >=BLOCK_VALID_TRANSACTIONS, and must contain those who aren't failed
|
||||||
int64 nTimeBestReceived = 0;
|
int64 nTimeBestReceived = 0;
|
||||||
bool fImporting = false;
|
bool fImporting = false;
|
||||||
|
|
||||||
@ -1156,6 +1157,62 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
|
|||||||
printf("InvalidChainFound: Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.\n");
|
printf("InvalidChainFound: Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void static InvalidBlockFound(CBlockIndex *pindex) {
|
||||||
|
pindex->nStatus |= BLOCK_FAILED_VALID;
|
||||||
|
CChainDB().WriteBlockIndex(CDiskBlockIndex(pindex));
|
||||||
|
setBlockIndexValid.erase(pindex);
|
||||||
|
InvalidChainFound(pindex);
|
||||||
|
if (pindex->pnext)
|
||||||
|
ConnectBestBlock(); // reorganise away from the failed block
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConnectBestBlock() {
|
||||||
|
do {
|
||||||
|
CBlockIndex *pindexNewBest;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::set<CBlockIndex*,CBlockIndexWorkComparator>::reverse_iterator it = setBlockIndexValid.rbegin();
|
||||||
|
if (it == setBlockIndexValid.rend())
|
||||||
|
return true;
|
||||||
|
pindexNewBest = *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pindexNewBest == pindexBest)
|
||||||
|
return true; // nothing to do
|
||||||
|
|
||||||
|
// check ancestry
|
||||||
|
CBlockIndex *pindexTest = pindexNewBest;
|
||||||
|
std::vector<CBlockIndex*> vAttach;
|
||||||
|
do {
|
||||||
|
if (pindexTest->nStatus & BLOCK_FAILED_MASK) {
|
||||||
|
// mark descendants failed
|
||||||
|
CChainDB chaindb;
|
||||||
|
CBlockIndex *pindexFailed = pindexNewBest;
|
||||||
|
while (pindexTest != pindexFailed) {
|
||||||
|
pindexFailed->nStatus |= BLOCK_FAILED_CHILD;
|
||||||
|
setBlockIndexValid.erase(pindexFailed);
|
||||||
|
chaindb.WriteBlockIndex(CDiskBlockIndex(pindexFailed));
|
||||||
|
pindexFailed = pindexFailed->pprev;
|
||||||
|
}
|
||||||
|
InvalidChainFound(pindexNewBest);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pindexBest == NULL || pindexTest->bnChainWork > pindexBest->bnChainWork)
|
||||||
|
vAttach.push_back(pindexTest);
|
||||||
|
|
||||||
|
if (pindexTest->pprev == NULL || pindexTest->pnext != NULL) {
|
||||||
|
reverse(vAttach.begin(), vAttach.end());
|
||||||
|
BOOST_FOREACH(CBlockIndex *pindexSwitch, vAttach)
|
||||||
|
if (!SetBestChain(pindexSwitch))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
pindexTest = pindexTest->pprev;
|
||||||
|
} while(true);
|
||||||
|
} while(true);
|
||||||
|
}
|
||||||
|
|
||||||
void CBlock::UpdateTime(const CBlockIndex* pindexPrev)
|
void CBlock::UpdateTime(const CBlockIndex* pindexPrev)
|
||||||
{
|
{
|
||||||
nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
|
nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
|
||||||
@ -1522,17 +1579,24 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Write undo information to disk
|
// Write undo information to disk
|
||||||
if (pindex->GetUndoPos().IsNull())
|
if (pindex->GetUndoPos().IsNull() || (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_SCRIPTS)
|
||||||
{
|
{
|
||||||
CChainDB chaindb;
|
CChainDB chaindb;
|
||||||
CDiskBlockPos pos;
|
|
||||||
if (!FindUndoPos(chaindb, pindex->pos.nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 8))
|
|
||||||
return error("ConnectBlock() : FindUndoPos failed");
|
|
||||||
if (!blockundo.WriteToDisk(pos))
|
|
||||||
return error("ConnectBlock() : CBlockUndo::WriteToDisk failed");
|
|
||||||
|
|
||||||
// update nUndoPos in block index
|
if (pindex->GetUndoPos().IsNull()) {
|
||||||
pindex->nUndoPos = pos.nPos + 1;
|
CDiskBlockPos pos;
|
||||||
|
if (!FindUndoPos(chaindb, pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 8))
|
||||||
|
return error("ConnectBlock() : FindUndoPos failed");
|
||||||
|
if (!blockundo.WriteToDisk(pos))
|
||||||
|
return error("ConnectBlock() : CBlockUndo::WriteToDisk failed");
|
||||||
|
|
||||||
|
// update nUndoPos in block index
|
||||||
|
pindex->nUndoPos = pos.nPos;
|
||||||
|
pindex->nStatus |= BLOCK_HAVE_UNDO;
|
||||||
|
}
|
||||||
|
|
||||||
|
pindex->nStatus = (pindex->nStatus & ~BLOCK_VALID_MASK) | BLOCK_VALID_SCRIPTS;
|
||||||
|
|
||||||
CDiskBlockIndex blockindex(pindex);
|
CDiskBlockIndex blockindex(pindex);
|
||||||
if (!chaindb.WriteBlockIndex(blockindex))
|
if (!chaindb.WriteBlockIndex(blockindex))
|
||||||
return error("ConnectBlock() : WriteBlockIndex failed");
|
return error("ConnectBlock() : WriteBlockIndex failed");
|
||||||
@ -1549,7 +1613,7 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBlock::SetBestChain(CBlockIndex* pindexNew)
|
bool SetBestChain(CBlockIndex* pindexNew)
|
||||||
{
|
{
|
||||||
CCoinsViewCache &view = *pcoinsTip;
|
CCoinsViewCache &view = *pcoinsTip;
|
||||||
|
|
||||||
@ -1620,24 +1684,19 @@ bool CBlock::SetBestChain(CBlockIndex* pindexNew)
|
|||||||
vector<CTransaction> vDelete;
|
vector<CTransaction> vDelete;
|
||||||
BOOST_FOREACH(CBlockIndex *pindex, vConnect) {
|
BOOST_FOREACH(CBlockIndex *pindex, vConnect) {
|
||||||
CBlock block;
|
CBlock block;
|
||||||
CBlock *pblock;
|
if (!block.ReadFromDisk(pindex))
|
||||||
if (pindex == pindexNew) // connecting *this block
|
return error("SetBestBlock() : ReadFromDisk for connect failed");
|
||||||
pblock = this;
|
|
||||||
else { // other block; read it from disk
|
|
||||||
if (!block.ReadFromDisk(pindex))
|
|
||||||
return error("SetBestBlock() : ReadFromDisk for connect failed");
|
|
||||||
pblock = █
|
|
||||||
}
|
|
||||||
CCoinsViewCache viewTemp(view, true);
|
CCoinsViewCache viewTemp(view, true);
|
||||||
if (!pblock->ConnectBlock(pindex, viewTemp)) {
|
if (!block.ConnectBlock(pindex, viewTemp)) {
|
||||||
InvalidChainFound(pindexNew);
|
InvalidChainFound(pindexNew);
|
||||||
|
InvalidBlockFound(pindex);
|
||||||
return error("SetBestBlock() : ConnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str());
|
return error("SetBestBlock() : ConnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str());
|
||||||
}
|
}
|
||||||
if (!viewTemp.Flush())
|
if (!viewTemp.Flush())
|
||||||
return error("SetBestBlock() : Cache flush failed after connect");
|
return error("SetBestBlock() : Cache flush failed after connect");
|
||||||
|
|
||||||
// Queue memory transactions to delete
|
// Queue memory transactions to delete
|
||||||
BOOST_FOREACH(const CTransaction& tx, pblock->vtx)
|
BOOST_FOREACH(const CTransaction& tx, block.vtx)
|
||||||
vDelete.push_back(tx);
|
vDelete.push_back(tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1683,8 +1742,8 @@ bool CBlock::SetBestChain(CBlockIndex* pindexNew)
|
|||||||
bnBestChainWork = pindexNew->bnChainWork;
|
bnBestChainWork = pindexNew->bnChainWork;
|
||||||
nTimeBestReceived = GetTime();
|
nTimeBestReceived = GetTime();
|
||||||
nTransactionsUpdated++;
|
nTransactionsUpdated++;
|
||||||
printf("SetBestChain: new best=%s height=%d work=%s date=%s\n",
|
printf("SetBestChain: new best=%s height=%d work=%s tx=%lu date=%s\n",
|
||||||
hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str(),
|
hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str(), (unsigned long)pindexNew->nChainTx,
|
||||||
DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str());
|
DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str());
|
||||||
|
|
||||||
// Check the version of the last 100 blocks to see if we need to upgrade:
|
// Check the version of the last 100 blocks to see if we need to upgrade:
|
||||||
@ -1736,9 +1795,14 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos)
|
|||||||
pindexNew->pprev = (*miPrev).second;
|
pindexNew->pprev = (*miPrev).second;
|
||||||
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
|
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
|
||||||
}
|
}
|
||||||
|
pindexNew->nTx = vtx.size();
|
||||||
pindexNew->bnChainWork = (pindexNew->pprev ? pindexNew->pprev->bnChainWork : 0) + pindexNew->GetBlockWork();
|
pindexNew->bnChainWork = (pindexNew->pprev ? pindexNew->pprev->bnChainWork : 0) + pindexNew->GetBlockWork();
|
||||||
pindexNew->pos = pos;
|
pindexNew->nChainTx = (pindexNew->pprev ? pindexNew->pprev->nChainTx : 0) + pindexNew->nTx;
|
||||||
|
pindexNew->nFile = pos.nFile;
|
||||||
|
pindexNew->nDataPos = pos.nPos;
|
||||||
pindexNew->nUndoPos = 0;
|
pindexNew->nUndoPos = 0;
|
||||||
|
pindexNew->nStatus = BLOCK_VALID_TRANSACTIONS | BLOCK_HAVE_DATA;
|
||||||
|
setBlockIndexValid.insert(pindexNew);
|
||||||
|
|
||||||
CChainDB chaindb;
|
CChainDB chaindb;
|
||||||
if (!chaindb.TxnBegin())
|
if (!chaindb.TxnBegin())
|
||||||
@ -1747,8 +1811,8 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos)
|
|||||||
if (!chaindb.TxnCommit())
|
if (!chaindb.TxnCommit())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// New best
|
// New best?
|
||||||
if (!SetBestChain(pindexNew))
|
if (!ConnectBestBlock())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (pindexNew == pindexBest)
|
if (pindexNew == pindexBest)
|
||||||
|
111
src/main.h
111
src/main.h
@ -23,6 +23,8 @@ class CInv;
|
|||||||
class CRequestTracker;
|
class CRequestTracker;
|
||||||
class CNode;
|
class CNode;
|
||||||
|
|
||||||
|
class CBlockIndexWorkComparator;
|
||||||
|
|
||||||
static const unsigned int MAX_BLOCK_SIZE = 1000000;
|
static const unsigned int MAX_BLOCK_SIZE = 1000000;
|
||||||
static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2;
|
static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2;
|
||||||
static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
|
static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
|
||||||
@ -55,6 +57,7 @@ extern CScript COINBASE_FLAGS;
|
|||||||
|
|
||||||
extern CCriticalSection cs_main;
|
extern CCriticalSection cs_main;
|
||||||
extern std::map<uint256, CBlockIndex*> mapBlockIndex;
|
extern std::map<uint256, CBlockIndex*> mapBlockIndex;
|
||||||
|
extern std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexValid;
|
||||||
extern uint256 hashGenesisBlock;
|
extern uint256 hashGenesisBlock;
|
||||||
extern CBlockIndex* pindexGenesisBlock;
|
extern CBlockIndex* pindexGenesisBlock;
|
||||||
extern int nBestHeight;
|
extern int nBestHeight;
|
||||||
@ -114,6 +117,9 @@ int GetNumBlocksOfPeers();
|
|||||||
bool IsInitialBlockDownload();
|
bool IsInitialBlockDownload();
|
||||||
std::string GetWarnings(std::string strFor);
|
std::string GetWarnings(std::string strFor);
|
||||||
bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow = false);
|
bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow = false);
|
||||||
|
bool SetBestChain(CBlockIndex* pindexNew);
|
||||||
|
bool ConnectBestBlock();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1234,9 +1240,6 @@ public:
|
|||||||
// Read a block from disk
|
// Read a block from disk
|
||||||
bool ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions=true);
|
bool ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions=true);
|
||||||
|
|
||||||
// Make this block (with given index) the new tip of the active block chain
|
|
||||||
bool SetBestChain(CBlockIndex* pindexNew);
|
|
||||||
|
|
||||||
// Add this block to the block index, and if necessary, switch the active block chain to this
|
// Add this block to the block index, and if necessary, switch the active block chain to this
|
||||||
bool AddToBlockIndex(const CDiskBlockPos &pos);
|
bool AddToBlockIndex(const CDiskBlockPos &pos);
|
||||||
|
|
||||||
@ -1308,6 +1311,24 @@ extern CCriticalSection cs_LastBlockFile;
|
|||||||
extern CBlockFileInfo infoLastBlockFile;
|
extern CBlockFileInfo infoLastBlockFile;
|
||||||
extern int nLastBlockFile;
|
extern int nLastBlockFile;
|
||||||
|
|
||||||
|
enum BlockStatus {
|
||||||
|
BLOCK_VALID_UNKNOWN = 0,
|
||||||
|
BLOCK_VALID_HEADER = 1, // parsed, version ok, hash satisfies claimed PoW, 1 <= vtx count <= max, timestamp not in future
|
||||||
|
BLOCK_VALID_TREE = 2, // parent found, difficulty matches, timestamp >= median previous, checkpoint
|
||||||
|
BLOCK_VALID_TRANSACTIONS = 3, // only first tx is coinbase, 2 <= coinbase input script length <= 100, transactions valid, no duplicate txids, sigops, size, merkle root
|
||||||
|
BLOCK_VALID_CHAIN = 4, // outputs do not overspend inputs, no double spends, coinbase output ok, immature coinbase spends, BIP30
|
||||||
|
BLOCK_VALID_SCRIPTS = 5, // scripts/signatures ok
|
||||||
|
BLOCK_VALID_MASK = 7,
|
||||||
|
|
||||||
|
BLOCK_HAVE_DATA = 8, // full block available in blk*.dat
|
||||||
|
BLOCK_HAVE_UNDO = 16, // undo data available in rev*.dat
|
||||||
|
BLOCK_HAVE_MASK = 24,
|
||||||
|
|
||||||
|
BLOCK_FAILED_VALID = 32, // stage after last reached validness failed
|
||||||
|
BLOCK_FAILED_CHILD = 64, // descends from failed block
|
||||||
|
BLOCK_FAILED_MASK = 96
|
||||||
|
};
|
||||||
|
|
||||||
/** The block chain is a tree shaped structure starting with the
|
/** The block chain is a tree shaped structure starting with the
|
||||||
* genesis block at the root, with each block potentially having multiple
|
* genesis block at the root, with each block potentially having multiple
|
||||||
* candidates to be the next block. pprev and pnext link a path through the
|
* candidates to be the next block. pprev and pnext link a path through the
|
||||||
@ -1318,14 +1339,40 @@ extern int nLastBlockFile;
|
|||||||
class CBlockIndex
|
class CBlockIndex
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
// pointer to the hash of the block, if any. memory is owned by this CBlockIndex
|
||||||
const uint256* phashBlock;
|
const uint256* phashBlock;
|
||||||
|
|
||||||
|
// pointer to the index of the predecessor of this block
|
||||||
CBlockIndex* pprev;
|
CBlockIndex* pprev;
|
||||||
|
|
||||||
|
// (memory only) pointer to the index of the *active* successor of this block
|
||||||
CBlockIndex* pnext;
|
CBlockIndex* pnext;
|
||||||
|
|
||||||
|
// height of the entry in the chain. The genesis block has height 0
|
||||||
int nHeight;
|
int nHeight;
|
||||||
CDiskBlockPos pos;
|
|
||||||
|
// Which # file this block is stored in (blk?????.dat)
|
||||||
|
int nFile;
|
||||||
|
|
||||||
|
// Byte offset within blk?????.dat where this block's data is stored
|
||||||
|
unsigned int nDataPos;
|
||||||
|
|
||||||
|
// Byte offset within rev?????.dat where this block's undo data is stored
|
||||||
unsigned int nUndoPos;
|
unsigned int nUndoPos;
|
||||||
|
|
||||||
|
// (memory only) Total amount of work (expected number of hashes) in the chain up to and including this block
|
||||||
CBigNum bnChainWork;
|
CBigNum bnChainWork;
|
||||||
|
|
||||||
|
// Number of transactions in this block.
|
||||||
|
// Note: in a potential headers-first mode, this number cannot be relied upon
|
||||||
|
unsigned int nTx;
|
||||||
|
|
||||||
|
// (memory only) Number of transactions in the chain up to and including this block
|
||||||
|
unsigned int nChainTx; // change to 64-bit type when necessary; won't happen before 2030
|
||||||
|
|
||||||
|
// Verification status of this block. See enum BlockStatus
|
||||||
|
unsigned int nStatus;
|
||||||
|
|
||||||
// block header
|
// block header
|
||||||
int nVersion;
|
int nVersion;
|
||||||
uint256 hashMerkleRoot;
|
uint256 hashMerkleRoot;
|
||||||
@ -1340,9 +1387,13 @@ public:
|
|||||||
pprev = NULL;
|
pprev = NULL;
|
||||||
pnext = NULL;
|
pnext = NULL;
|
||||||
nHeight = 0;
|
nHeight = 0;
|
||||||
pos.SetNull();
|
nFile = 0;
|
||||||
|
nDataPos = 0;
|
||||||
nUndoPos = 0;
|
nUndoPos = 0;
|
||||||
bnChainWork = 0;
|
bnChainWork = 0;
|
||||||
|
nTx = 0;
|
||||||
|
nChainTx = 0;
|
||||||
|
nStatus = 0;
|
||||||
|
|
||||||
nVersion = 0;
|
nVersion = 0;
|
||||||
hashMerkleRoot = 0;
|
hashMerkleRoot = 0;
|
||||||
@ -1357,9 +1408,13 @@ public:
|
|||||||
pprev = NULL;
|
pprev = NULL;
|
||||||
pnext = NULL;
|
pnext = NULL;
|
||||||
nHeight = 0;
|
nHeight = 0;
|
||||||
pos.SetNull();
|
nFile = 0;
|
||||||
|
nDataPos = 0;
|
||||||
nUndoPos = 0;
|
nUndoPos = 0;
|
||||||
bnChainWork = 0;
|
bnChainWork = 0;
|
||||||
|
nTx = 0;
|
||||||
|
nChainTx = 0;
|
||||||
|
nStatus = 0;
|
||||||
|
|
||||||
nVersion = block.nVersion;
|
nVersion = block.nVersion;
|
||||||
hashMerkleRoot = block.hashMerkleRoot;
|
hashMerkleRoot = block.hashMerkleRoot;
|
||||||
@ -1369,15 +1424,22 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
CDiskBlockPos GetBlockPos() const {
|
CDiskBlockPos GetBlockPos() const {
|
||||||
return pos;
|
CDiskBlockPos ret;
|
||||||
|
if (nStatus & BLOCK_HAVE_DATA) {
|
||||||
|
ret.nFile = nFile;
|
||||||
|
ret.nPos = nDataPos;
|
||||||
|
} else
|
||||||
|
ret.SetNull();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
CDiskBlockPos GetUndoPos() const {
|
CDiskBlockPos GetUndoPos() const {
|
||||||
CDiskBlockPos ret = pos;
|
CDiskBlockPos ret;
|
||||||
if (nUndoPos == 0)
|
if (nStatus & BLOCK_HAVE_UNDO) {
|
||||||
|
ret.nFile = nFile;
|
||||||
|
ret.nPos = nUndoPos;
|
||||||
|
} else
|
||||||
ret.SetNull();
|
ret.SetNull();
|
||||||
else
|
|
||||||
ret.nPos = nUndoPos - 1;
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1472,6 +1534,19 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CBlockIndexWorkComparator
|
||||||
|
{
|
||||||
|
bool operator()(CBlockIndex *pa, CBlockIndex *pb) {
|
||||||
|
if (pa->bnChainWork > pb->bnChainWork) return false;
|
||||||
|
if (pa->bnChainWork < pb->bnChainWork) return true;
|
||||||
|
|
||||||
|
if (pa->GetBlockHash() < pb->GetBlockHash()) return false;
|
||||||
|
if (pa->GetBlockHash() > pb->GetBlockHash()) return true;
|
||||||
|
|
||||||
|
return false; // identical blocks
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Used to marshal pointers into hashes for db storage. */
|
/** Used to marshal pointers into hashes for db storage. */
|
||||||
@ -1491,11 +1566,17 @@ public:
|
|||||||
IMPLEMENT_SERIALIZE
|
IMPLEMENT_SERIALIZE
|
||||||
(
|
(
|
||||||
if (!(nType & SER_GETHASH))
|
if (!(nType & SER_GETHASH))
|
||||||
READWRITE(nVersion);
|
READWRITE(VARINT(nVersion));
|
||||||
|
|
||||||
READWRITE(nHeight);
|
READWRITE(VARINT(nHeight));
|
||||||
READWRITE(pos);
|
READWRITE(VARINT(nStatus));
|
||||||
READWRITE(nUndoPos);
|
READWRITE(VARINT(nTx));
|
||||||
|
if (nStatus & (BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO))
|
||||||
|
READWRITE(VARINT(nFile));
|
||||||
|
if (nStatus & BLOCK_HAVE_DATA)
|
||||||
|
READWRITE(VARINT(nDataPos));
|
||||||
|
if (nStatus & BLOCK_HAVE_UNDO)
|
||||||
|
READWRITE(VARINT(nUndoPos));
|
||||||
|
|
||||||
// block header
|
// block header
|
||||||
READWRITE(this->nVersion);
|
READWRITE(this->nVersion);
|
||||||
|
Loading…
Reference in New Issue
Block a user