From 630fd8dcb6662ed167e967625f2715f97ddd2db5 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 19 Jun 2012 01:36:43 +0200 Subject: [PATCH] One file per block Refactor of the block storage code, which now stores one file per block. This will allow easier pruning, as blocks can be removed individually. --- src/db.cpp | 15 +---- src/main.cpp | 103 +++++++++++--------------------- src/main.h | 161 +++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 155 insertions(+), 124 deletions(-) diff --git a/src/db.cpp b/src/db.cpp index 9ad67892f..cef395c44 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -637,12 +637,12 @@ bool CTxDB::LoadBlockIndex() nCheckDepth = nBestHeight; printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel); CBlockIndex* pindexFork = NULL; - map, CBlockIndex*> mapBlockPos; for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev) { if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth) break; CBlock block; + CDiskBlockPos blockPos = pindex->GetBlockPos(); if (!block.ReadFromDisk(pindex)) return error("LoadBlockIndex() : block.ReadFromDisk failed"); // check level 1: verify block validity @@ -654,8 +654,6 @@ bool CTxDB::LoadBlockIndex() // check level 2: verify transaction index validity if (nCheckLevel>1) { - pair pos = make_pair(pindex->nFile, pindex->nBlockPos); - mapBlockPos[pos] = pindex; BOOST_FOREACH(const CTransaction &tx, block.vtx) { uint256 hashTx = tx.GetHash(); @@ -663,7 +661,7 @@ bool CTxDB::LoadBlockIndex() if (ReadTxIndex(hashTx, txindex)) { // check level 3: checker transaction hashes - if (nCheckLevel>2 || pindex->nFile != txindex.pos.nFile || pindex->nBlockPos != txindex.pos.nBlockPos) + if (nCheckLevel>2 || blockPos != txindex.pos.blockPos) { // either an error or a duplicate transaction CTransaction txFound; @@ -687,12 +685,6 @@ bool CTxDB::LoadBlockIndex() { if (!txpos.IsNull()) { - pair posFind = make_pair(txpos.nFile, txpos.nBlockPos); - if (!mapBlockPos.count(posFind)) - { - printf("LoadBlockIndex(): *** found bad spend at %d, hashBlock=%s, hashTx=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), hashTx.ToString().c_str()); - pindexFork = pindex->pprev; - } // check level 6: check whether spent txouts were spent by a valid transaction that consume them if (nCheckLevel>5) { @@ -795,9 +787,8 @@ bool CTxDB::LoadBlockIndexGuts() CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash()); pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev); pindexNew->pnext = InsertBlockIndex(diskindex.hashNext); - pindexNew->nFile = diskindex.nFile; - pindexNew->nBlockPos = diskindex.nBlockPos; pindexNew->nHeight = diskindex.nHeight; + pindexNew->nAlternative = diskindex.nAlternative; pindexNew->nVersion = diskindex.nVersion; pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; pindexNew->nTime = diskindex.nTime; diff --git a/src/main.cpp b/src/main.cpp index ed677f31c..fa818bd05 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -389,7 +389,7 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock) CTxIndex txindex; if (!CTxDB("r").ReadTxIndex(GetHash(), txindex)) return 0; - if (!blockTmp.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos)) + if (!blockTmp.ReadFromDisk(txindex.pos.blockPos)) return 0; pblock = &blockTmp; } @@ -646,7 +646,7 @@ bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, bool fCheckInputs, // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. - if (!tx.ConnectInputs(mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, false, false)) + if (!tx.ConnectInputs(mapInputs, mapUnused, CDiskTxPos(true), pindexBest, false, false)) { return error("CTxMemPool::accept() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str()); } @@ -817,7 +817,7 @@ int CTxIndex::GetDepthInMainChain() const { // Read block header CBlock block; - if (!block.ReadFromDisk(pos.nFile, pos.nBlockPos, false)) + if (!block.ReadFromDisk(pos.blockPos, false)) return 0; // Find the block in the index map::iterator mi = mapBlockIndex.find(block.GetHash()); @@ -847,7 +847,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock) if (tx.ReadFromDisk(txdb, COutPoint(hash, 0), txindex)) { CBlock block; - if (block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) + if (block.ReadFromDisk(txindex.pos.blockPos, false)) hashBlock = block.GetHash(); return true; } @@ -892,7 +892,7 @@ bool CBlock::ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions) *this = pindex->GetBlockHeader(); return true; } - if (!ReadFromDisk(pindex->nFile, pindex->nBlockPos, fReadTransactions)) + if (!ReadFromDisk(pindex->GetBlockPos(), fReadTransactions)) return false; if (GetHash() != pindex->GetBlockHash()) return error("CBlock::ReadFromDisk() : GetHash() doesn't match index"); @@ -1156,7 +1156,7 @@ bool CTransaction::FetchInputs(CTxDB& txdb, const map& mapTes // Read txPrev CTransaction& txPrev = inputsRet[prevout.hash].second; - if (!fFound || txindex.pos == CDiskTxPos(1,1,1)) + if (!fFound || txindex.pos.IsMemPool()) { // Get prev tx from single transactions in memory { @@ -1262,7 +1262,7 @@ bool CTransaction::ConnectInputs(MapPrevTx inputs, // If prev is coinbase, check that it's matured if (txPrev.IsCoinBase()) for (const CBlockIndex* pindex = pindexBlock; pindex && pindexBlock->nHeight - pindex->nHeight < COINBASE_MATURITY; pindex = pindex->pprev) - if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile) + if (pindex->GetBlockPos() == txindex.pos.blockPos) return error("ConnectInputs() : tried to spend coinbase at depth %d", pindexBlock->nHeight - pindex->nHeight); // Check for negative or overflow input values @@ -1427,11 +1427,10 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck) //// issue here: it doesn't know the version unsigned int nTxPos; if (fJustCheck) - // FetchInputs treats CDiskTxPos(1,1,1) as a special "refer to memorypool" indicator // Since we're just checking the block and not actually connecting it, it might not (and probably shouldn't) be on the disk to get the transaction from nTxPos = 1; else - nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK, CLIENT_VERSION) - 1 + GetSizeOfCompactSize(vtx.size()); + nTxPos = ::GetSerializeSize(CBlock(), SER_DISK, CLIENT_VERSION) - 1 + GetSizeOfCompactSize(vtx.size()); map mapQueuedChanges; int64 nFees = 0; @@ -1453,9 +1452,11 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck) if (nSigOps > MAX_BLOCK_SIGOPS) return DoS(100, error("ConnectBlock() : too many sigops")); - CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos); + CDiskTxPos posThisTx(pindex->GetBlockPos(), nTxPos); if (!fJustCheck) nTxPos += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); + else + posThisTx = CDiskTxPos(true); MapPrevTx mapInputs; if (!tx.IsCoinBase()) @@ -1750,7 +1751,7 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) } -bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) +bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos) { // Check for duplicate uint256 hash = GetHash(); @@ -1758,7 +1759,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) return error("AddToBlockIndex() : %s already exists", hash.ToString().substr(0,20).c_str()); // Construct new block index object - CBlockIndex* pindexNew = new CBlockIndex(nFile, nBlockPos, *this); + CBlockIndex* pindexNew = new CBlockIndex(*this); if (!pindexNew) return error("AddToBlockIndex() : new CBlockIndex failed"); map::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; @@ -1770,6 +1771,8 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) pindexNew->nHeight = pindexNew->pprev->nHeight + 1; } pindexNew->bnChainWork = (pindexNew->pprev ? pindexNew->pprev->bnChainWork : 0) + pindexNew->GetBlockWork(); + assert(pos.nHeight == pindexNew->nHeight); + pindexNew->nAlternative = pos.nAlternative; CTxDB txdb; if (!txdb.TxnBegin()) @@ -1908,13 +1911,12 @@ bool CBlock::AcceptBlock() } // Write block to history file + CDiskBlockPos blockPos = CDiskBlockPos(nHeight); if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION))) return error("AcceptBlock() : out of disk space"); - unsigned int nFile = -1; - unsigned int nBlockPos = 0; - if (!WriteToDisk(nFile, nBlockPos)) + if (!WriteToDisk(blockPos)) return error("AcceptBlock() : WriteToDisk failed"); - if (!AddToBlockIndex(nFile, nBlockPos)) + if (!AddToBlockIndex(blockPos)) return error("AcceptBlock() : AddToBlockIndex failed"); // Relay inventory, but don't relay old inventory during initial block download @@ -2048,53 +2050,18 @@ bool CheckDiskSpace(uint64 nAdditionalBytes) return true; } -static filesystem::path BlockFilePath(unsigned int nFile) +FILE* OpenBlockFile(const CDiskBlockPos &pos, const char* pszMode) { - string strBlockFn = strprintf("blk%04u.dat", nFile); - return GetDataDir() / strBlockFn; -} - -FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode) -{ - if ((nFile < 1) || (nFile == (unsigned int) -1)) + boost::filesystem::path path = pos.GetFileName(GetDataDir()); + boost::filesystem::create_directories(path.parent_path()); + if (pos.IsNull() || pos.IsMemPool()) return NULL; - FILE* file = fopen(BlockFilePath(nFile).string().c_str(), pszMode); + FILE* file = fopen(path.string().c_str(), pszMode); if (!file) return NULL; - if (nBlockPos != 0 && !strchr(pszMode, 'a') && !strchr(pszMode, 'w')) - { - if (fseek(file, nBlockPos, SEEK_SET) != 0) - { - fclose(file); - return NULL; - } - } return file; } -static unsigned int nCurrentBlockFile = 1; - -FILE* AppendBlockFile(unsigned int& nFileRet) -{ - nFileRet = 0; - loop - { - FILE* file = OpenBlockFile(nCurrentBlockFile, 0, "ab"); - if (!file) - return NULL; - if (fseek(file, 0, SEEK_END) != 0) - return NULL; - // FAT32 file size max 4GB, fseek and ftell max 2GB, so we must stay under 2GB - if (ftell(file) < (long)(0x7F000000 - MAX_SIZE)) - { - nFileRet = nCurrentBlockFile; - return file; - } - fclose(file); - nCurrentBlockFile++; - } -} - bool LoadBlockIndex(bool fAllowNew) { if (fTestNet) @@ -2153,19 +2120,19 @@ bool LoadBlockIndex(bool fAllowNew) } //// debug print - printf("%s\n", block.GetHash().ToString().c_str()); + uint256 hash = block.GetHash(); + printf("%s\n", hash.ToString().c_str()); printf("%s\n", hashGenesisBlock.ToString().c_str()); printf("%s\n", block.hashMerkleRoot.ToString().c_str()); assert(block.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); block.print(); - assert(block.GetHash() == hashGenesisBlock); + assert(hash == hashGenesisBlock); // Start new block file - unsigned int nFile; - unsigned int nBlockPos; - if (!block.WriteToDisk(nFile, nBlockPos)) + CDiskBlockPos blockPos(0); + if (!block.WriteToDisk(blockPos)) return error("LoadBlockIndex() : writing genesis block to disk failed"); - if (!block.AddToBlockIndex(nFile, nBlockPos)) + if (!block.AddToBlockIndex(blockPos)) return error("LoadBlockIndex() : genesis block not accepted"); } @@ -2219,11 +2186,9 @@ void PrintBlockTree() // print item CBlock block; block.ReadFromDisk(pindex); - printf("%d (%u,%u) %s %s tx %"PRIszu"", + printf("%d (%s) %s tx %"PRIszu"", pindex->nHeight, - pindex->nFile, - pindex->nBlockPos, - block.GetHash().ToString().substr(0,20).c_str(), + pindex->GetBlockPos().GetFileName("").string().c_str(), DateTimeStrFormat("%x %H:%M:%S", block.GetBlockTime()).c_str(), block.vtx.size()); @@ -3693,9 +3658,9 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) continue; - if (!tx.ConnectInputs(mapInputs, mapTestPoolTmp, CDiskTxPos(1,1,1), pindexPrev, false, true)) + if (!tx.ConnectInputs(mapInputs, mapTestPoolTmp, CDiskTxPos(true), pindexPrev, false, true)) continue; - mapTestPoolTmp[tx.GetHash()] = CTxIndex(CDiskTxPos(1,1,1), tx.vout.size()); + mapTestPoolTmp[tx.GetHash()] = CTxIndex(CDiskTxPos(true), tx.vout.size()); swap(mapTestPool, mapTestPoolTmp); // Added @@ -3743,7 +3708,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) pblock->nNonce = 0; pblock->vtx[0].vin[0].scriptSig = scriptDummy; - CBlockIndex indexDummy(1, 1, *pblock); + CBlockIndex indexDummy(*pblock); indexDummy.pprev = pindexPrev; indexDummy.nHeight = pindexPrev->nHeight + 1; if (!pblock->ConnectBlock(txdb, &indexDummy, true)) diff --git a/src/main.h b/src/main.h index 0c8528639..a1d633474 100644 --- a/src/main.h +++ b/src/main.h @@ -80,14 +80,14 @@ static const uint64 nMinDiskSpace = 52428800; class CReserveKey; class CTxDB; class CTxIndex; +class CDiskBlockPos; void RegisterWallet(CWallet* pwalletIn); void UnregisterWallet(CWallet* pwalletIn); void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false); bool ProcessBlock(CNode* pfrom, CBlock* pblock); bool CheckDiskSpace(uint64 nAdditionalBytes=0); -FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb"); -FILE* AppendBlockFile(unsigned int& nFileRet); +FILE* OpenBlockFile(const CDiskBlockPos &pos, const char* pszMode="rb"); bool LoadBlockIndex(bool fAllowNew=true); void PrintBlockTree(); CBlockIndex* FindBlockByHeight(int nHeight); @@ -118,34 +118,115 @@ bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock); bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut); +class CDiskBlockPos +{ +public: + int nHeight; + int nAlternative; + + CDiskBlockPos() { + SetNull(); + } + + CDiskBlockPos(int nHeightIn, int nAlternativeIn = 0) { + nHeight = nHeightIn; + nAlternative = nAlternativeIn; + } + + std::string GetAlternative() const { + char c[9]={0,0,0,0,0,0,0,0,0}; + char *cp = &c[8]; + unsigned int n = nAlternative; + while (n > 0 && cp>c) { + n--; + *(--cp) = 'a' + (n % 26); + n /= 26; + } + return std::string(cp); + } + + boost::filesystem::path GetDirectory(const boost::filesystem::path &base) const { + assert(nHeight != -1); + return base / strprintf("era%02u", nHeight / 210000) / + strprintf("cycle%04u", nHeight / 2016); + } + + boost::filesystem::path GetFileName(const boost::filesystem::path &base) const { + return GetDirectory(base) / strprintf("%08u%s.blk", nHeight, GetAlternative().c_str()); + } + + // TODO: make thread-safe (lockfile, atomic file creation, ...?) + void MakeUnique(const boost::filesystem::path &base) { + while (boost::filesystem::exists(GetFileName(base))) + nAlternative++; + } + + IMPLEMENT_SERIALIZE(({ + CDiskBlockPos *me = const_cast(this); + if (!fRead) { + unsigned int nCode = (nHeight + 1) * 2 + (nAlternative > 0); + READWRITE(VARINT(nCode)); + if (nAlternative > 0) { + unsigned int nAlt = nAlternative - 1; + READWRITE(VARINT(nAlt)); + } + } else { + unsigned int nCode = 0; + READWRITE(VARINT(nCode)); + me->nHeight = (nCode / 2) - 1; + if (nCode & 1) { + unsigned int nAlt = 0; + READWRITE(VARINT(nAlt)); + me->nAlternative = 1 + nAlt; + } else { + me->nAlternative = 0; + } + } + });) + + friend bool operator==(const CDiskBlockPos &a, const CDiskBlockPos &b) { + return ((a.nHeight == b.nHeight) && (a.nAlternative == b.nAlternative)); + } + + friend bool operator!=(const CDiskBlockPos &a, const CDiskBlockPos &b) { + return !(a == b); + } + + void SetNull() { nHeight = -1; nAlternative = 0; } + bool IsNull() const { return ((nHeight == -1) && (nAlternative == 0)); } + + void SetMemPool() { nHeight = -1; nAlternative = -1; } + bool IsMemPool() const { return ((nHeight == -1) && (nAlternative == -1)); } +}; + /** Position on disk for a particular transaction. */ class CDiskTxPos { public: - unsigned int nFile; - unsigned int nBlockPos; + CDiskBlockPos blockPos; unsigned int nTxPos; - CDiskTxPos() + CDiskTxPos(bool fInMemPool = false) { SetNull(); + if (fInMemPool) + blockPos.SetMemPool(); } - CDiskTxPos(unsigned int nFileIn, unsigned int nBlockPosIn, unsigned int nTxPosIn) - { - nFile = nFileIn; - nBlockPos = nBlockPosIn; - nTxPos = nTxPosIn; - } + CDiskTxPos(const CDiskBlockPos &block, unsigned int nTxPosIn) : blockPos(block), nTxPos(nTxPosIn) { } - IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); ) - void SetNull() { nFile = (unsigned int) -1; nBlockPos = 0; nTxPos = 0; } - bool IsNull() const { return (nFile == (unsigned int) -1); } + IMPLEMENT_SERIALIZE( + READWRITE(blockPos); + READWRITE(VARINT(nTxPos)); + ) + + void SetNull() { blockPos.SetNull(); nTxPos = 0; } + bool IsNull() const { return blockPos.IsNull(); } + bool IsMemPool() const { return blockPos.IsMemPool(); } friend bool operator==(const CDiskTxPos& a, const CDiskTxPos& b) { - return (a.nFile == b.nFile && - a.nBlockPos == b.nBlockPos && + return (a.blockPos == b.blockPos && a.nTxPos == b.nTxPos); } @@ -158,8 +239,10 @@ public: { if (IsNull()) return "null"; + else if (blockPos.IsMemPool()) + return "mempool"; else - return strprintf("(nFile=%u, nBlockPos=%u, nTxPos=%u)", nFile, nBlockPos, nTxPos); + return strprintf("(%s, nTxPos=%u)", blockPos.GetFileName("").string().c_str(), nTxPos); } void print() const @@ -545,7 +628,7 @@ public: bool ReadFromDisk(CDiskTxPos pos, FILE** pfileRet=NULL) { - CAutoFile filein = CAutoFile(OpenBlockFile(pos.nFile, 0, pfileRet ? "rb+" : "rb"), SER_DISK, CLIENT_VERSION); + CAutoFile filein = CAutoFile(OpenBlockFile(pos.blockPos, pfileRet ? "rb+" : "rb"), SER_DISK, CLIENT_VERSION); if (!filein) return error("CTransaction::ReadFromDisk() : OpenBlockFile failed"); @@ -1215,22 +1298,15 @@ public: } - bool WriteToDisk(unsigned int& nFileRet, unsigned int& nBlockPosRet) + bool WriteToDisk(CDiskBlockPos &pos) { // Open history file to append - CAutoFile fileout = CAutoFile(AppendBlockFile(nFileRet), SER_DISK, CLIENT_VERSION); + pos.MakeUnique(GetDataDir()); + CAutoFile fileout = CAutoFile(OpenBlockFile(pos, "ab"), SER_DISK, CLIENT_VERSION); if (!fileout) return error("CBlock::WriteToDisk() : AppendBlockFile failed"); - // Write index header - unsigned int nSize = fileout.GetSerializeSize(*this); - fileout << FLATDATA(pchMessageStart) << nSize; - // Write block - long fileOutPos = ftell(fileout); - if (fileOutPos < 0) - return error("CBlock::WriteToDisk() : ftell failed"); - nBlockPosRet = fileOutPos; fileout << *this; // Flush stdio buffers and commit to disk before returning @@ -1241,12 +1317,12 @@ public: return true; } - bool ReadFromDisk(unsigned int nFile, unsigned int nBlockPos, bool fReadTransactions=true) + bool ReadFromDisk(const CDiskBlockPos &pos, bool fReadTransactions = true) { SetNull(); // Open history file to read - CAutoFile filein = CAutoFile(OpenBlockFile(nFile, nBlockPos, "rb"), SER_DISK, CLIENT_VERSION); + CAutoFile filein = CAutoFile(OpenBlockFile(pos, "rb"), SER_DISK, CLIENT_VERSION); if (!filein) return error("CBlock::ReadFromDisk() : OpenBlockFile failed"); if (!fReadTransactions) @@ -1294,7 +1370,7 @@ public: bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck=false); bool ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions=true); bool SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew); - bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos); + bool AddToBlockIndex(const CDiskBlockPos &pos); bool CheckBlock(bool fCheckPOW=true, bool fCheckMerkleRoot=true) const; bool AcceptBlock(); @@ -1320,9 +1396,8 @@ public: const uint256* phashBlock; CBlockIndex* pprev; CBlockIndex* pnext; - unsigned int nFile; - unsigned int nBlockPos; int nHeight; + unsigned int nAlternative; CBigNum bnChainWork; // block header @@ -1338,10 +1413,9 @@ public: phashBlock = NULL; pprev = NULL; pnext = NULL; - nFile = 0; - nBlockPos = 0; nHeight = 0; bnChainWork = 0; + nAlternative = 0; nVersion = 0; hashMerkleRoot = 0; @@ -1350,15 +1424,14 @@ public: nNonce = 0; } - CBlockIndex(unsigned int nFileIn, unsigned int nBlockPosIn, CBlock& block) + CBlockIndex(CBlock& block) { phashBlock = NULL; pprev = NULL; pnext = NULL; - nFile = nFileIn; - nBlockPos = nBlockPosIn; nHeight = 0; bnChainWork = 0; + nAlternative = 0; nVersion = block.nVersion; hashMerkleRoot = block.hashMerkleRoot; @@ -1367,6 +1440,10 @@ public: nNonce = block.nNonce; } + CDiskBlockPos GetBlockPos() const { + return CDiskBlockPos(nHeight, nAlternative); + } + CBlock GetBlockHeader() const { CBlock block; @@ -1444,11 +1521,10 @@ public: static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired, unsigned int nToCheck); - std::string ToString() const { - return strprintf("CBlockIndex(pprev=%p, pnext=%p, nFile=%u, nBlockPos=%-6u nHeight=%d, merkle=%s, hashBlock=%s)", - pprev, pnext, nFile, nBlockPos, nHeight, + return strprintf("CBlockIndex(pprev=%p, pnext=%p, nHeight=%d, merkle=%s, hashBlock=%s)", + pprev, pnext, nHeight, hashMerkleRoot.ToString().substr(0,10).c_str(), GetBlockHash().ToString().substr(0,20).c_str()); } @@ -1486,9 +1562,8 @@ public: READWRITE(nVersion); READWRITE(hashNext); - READWRITE(nFile); - READWRITE(nBlockPos); READWRITE(nHeight); + READWRITE(nAlternative); // block header READWRITE(this->nVersion);