From a6dba0fdb281ee99e6814ad64c1c4d3032347816 Mon Sep 17 00:00:00 2001 From: Eric Lombrozo Date: Sun, 23 Jun 2013 17:35:01 -0700 Subject: [PATCH 01/10] Moved CBlock::WriteToDisk out of CBlock to inline function WriteBlockToDisk in main.h --- src/main.cpp | 4 ++-- src/main.h | 51 ++++++++++++++++++++++++++------------------------- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 5c9aa3202..bde9d6603 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2262,7 +2262,7 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp) if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, nTime, dbp != NULL)) return error("AcceptBlock() : FindBlockPos failed"); if (dbp == NULL) - if (!WriteToDisk(blockPos)) + if (!WriteBlockToDisk(*this, blockPos)) return state.Abort(_("Failed to write block")); if (!AddToBlockIndex(state, blockPos)) return error("AcceptBlock() : AddToBlockIndex failed"); @@ -2800,7 +2800,7 @@ bool InitBlockIndex() { CValidationState state; if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.nTime)) return error("LoadBlockIndex() : FindBlockPos failed"); - if (!block.WriteToDisk(blockPos)) + if (!WriteBlockToDisk(block, blockPos)) return error("LoadBlockIndex() : writing genesis block to disk failed"); if (!block.AddToBlockIndex(state, blockPos)) return error("LoadBlockIndex() : genesis block not accepted"); diff --git a/src/main.h b/src/main.h index c5e5f2bfe..bda775e84 100644 --- a/src/main.h +++ b/src/main.h @@ -682,31 +682,6 @@ public: return hash; } - bool WriteToDisk(CDiskBlockPos &pos) - { - // Open history file to append - CAutoFile fileout = CAutoFile(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION); - if (!fileout) - return error("CBlock::WriteToDisk() : OpenBlockFile failed"); - - // Write index header - unsigned int nSize = fileout.GetSerializeSize(*this); - fileout << FLATDATA(Params().MessageStart()) << nSize; - - // Write block - long fileOutPos = ftell(fileout); - if (fileOutPos < 0) - return error("CBlock::WriteToDisk() : ftell failed"); - pos.nPos = (unsigned int)fileOutPos; - fileout << *this; - - // Flush stdio buffers and commit to disk before returning - fflush(fileout); - if (!IsInitialBlockDownload()) - FileCommit(fileout); - - return true; - } bool ReadFromDisk(const CDiskBlockPos &pos) { @@ -779,6 +754,32 @@ public: }; +/** Functions for disk access for blocks */ +inline bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos) +{ + // Open history file to append + CAutoFile fileout = CAutoFile(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION); + if (!fileout) + return error("WriteBlockToDisk() : OpenBlockFile failed"); + + // Write index header + unsigned int nSize = fileout.GetSerializeSize(block); + fileout << FLATDATA(Params().MessageStart()) << nSize; + + // Write block + long fileOutPos = ftell(fileout); + if (fileOutPos < 0) + return error("WriteBlockToDisk() : ftell failed"); + pos.nPos = (unsigned int)fileOutPos; + fileout << block; + + // Flush stdio buffers and commit to disk before returning + fflush(fileout); + if (!IsInitialBlockDownload()) + FileCommit(fileout); + + return true; +} From 226f8219422e9252cece036cf61d87738782d674 Mon Sep 17 00:00:00 2001 From: Eric Lombrozo Date: Sun, 23 Jun 2013 17:47:47 -0700 Subject: [PATCH 02/10] Moved WriteBlockToDisk implementation from main.h to main.cpp --- src/main.cpp | 26 ++++++++++++++++++++++++++ src/main.h | 26 +------------------------- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index bde9d6603..87f5256f5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1146,6 +1146,32 @@ CBlockIndex* FindBlockByHeight(int nHeight) return vBlockIndexByHeight[nHeight]; } +bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos) +{ + // Open history file to append + CAutoFile fileout = CAutoFile(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION); + if (!fileout) + return error("WriteBlockToDisk() : OpenBlockFile failed"); + + // Write index header + unsigned int nSize = fileout.GetSerializeSize(block); + fileout << FLATDATA(Params().MessageStart()) << nSize; + + // Write block + long fileOutPos = ftell(fileout); + if (fileOutPos < 0) + return error("WriteBlockToDisk() : ftell failed"); + pos.nPos = (unsigned int)fileOutPos; + fileout << block; + + // Flush stdio buffers and commit to disk before returning + fflush(fileout); + if (!IsInitialBlockDownload()) + FileCommit(fileout); + + return true; +} + bool CBlock::ReadFromDisk(const CBlockIndex* pindex) { if (!ReadFromDisk(pindex->GetBlockPos())) diff --git a/src/main.h b/src/main.h index bda775e84..a613613e5 100644 --- a/src/main.h +++ b/src/main.h @@ -755,31 +755,7 @@ public: /** Functions for disk access for blocks */ -inline bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos) -{ - // Open history file to append - CAutoFile fileout = CAutoFile(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION); - if (!fileout) - return error("WriteBlockToDisk() : OpenBlockFile failed"); - - // Write index header - unsigned int nSize = fileout.GetSerializeSize(block); - fileout << FLATDATA(Params().MessageStart()) << nSize; - - // Write block - long fileOutPos = ftell(fileout); - if (fileOutPos < 0) - return error("WriteBlockToDisk() : ftell failed"); - pos.nPos = (unsigned int)fileOutPos; - fileout << block; - - // Flush stdio buffers and commit to disk before returning - fflush(fileout); - if (!IsInitialBlockDownload()) - FileCommit(fileout); - - return true; -} +bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos); From 7db120d5314578f7360c868bb937e779c33f113a Mon Sep 17 00:00:00 2001 From: Eric Lombrozo Date: Sun, 23 Jun 2013 18:10:02 -0700 Subject: [PATCH 03/10] Moved CBlock::ReadFromDisk out of CBlock to functions ReadBlockFromDisk in main.h --- src/init.cpp | 2 +- src/main.cpp | 28 +++++++++++----------- src/main.h | 54 +++++++++++++++++++------------------------ src/rpcblockchain.cpp | 2 +- src/wallet.cpp | 2 +- 5 files changed, 41 insertions(+), 47 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 449ee906b..e88055bde 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -820,7 +820,7 @@ bool AppInit2(boost::thread_group& threadGroup) { CBlockIndex* pindex = (*mi).second; CBlock block; - block.ReadFromDisk(pindex); + ReadBlockFromDisk(block, pindex); block.BuildMerkleTree(); block.print(); printf("\n"); diff --git a/src/main.cpp b/src/main.cpp index 87f5256f5..67a989559 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -627,7 +627,7 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock) if (pcoinsTip->GetCoins(GetHash(), coins)) { CBlockIndex *pindex = FindBlockByHeight(coins.nHeight); if (pindex) { - if (!blockTmp.ReadFromDisk(pindex)) + if (!ReadBlockFromDisk(blockTmp, pindex)) return 0; pblock = &blockTmp; } @@ -1114,7 +1114,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock if (pindexSlow) { CBlock block; - if (block.ReadFromDisk(pindexSlow)) { + if (ReadBlockFromDisk(block, pindexSlow)) { BOOST_FOREACH(const CTransaction &tx, block.vtx) { if (tx.GetHash() == hash) { txOut = tx; @@ -1172,12 +1172,12 @@ bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos) return true; } -bool CBlock::ReadFromDisk(const CBlockIndex* pindex) +bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex) { - if (!ReadFromDisk(pindex->GetBlockPos())) + if (!ReadBlockFromDisk(block, pindex->GetBlockPos())) return false; - if (GetHash() != pindex->GetBlockHash()) - return error("CBlock::ReadFromDisk() : GetHash() doesn't match index"); + if (block.GetHash() != pindex->GetBlockHash()) + return error("ReadBlockFromDisk(CBlock&, CBlockIndex*) : GetHash() doesn't match index"); return true; } @@ -1886,7 +1886,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) vector vResurrect; BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) { CBlock block; - if (!block.ReadFromDisk(pindex)) + if (!ReadBlockFromDisk(block, pindex)) return state.Abort(_("Failed to read block")); int64 nStart = GetTimeMicros(); if (!block.DisconnectBlock(state, pindex, view)) @@ -1906,7 +1906,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) vector vDelete; BOOST_FOREACH(CBlockIndex *pindex, vConnect) { CBlock block; - if (!block.ReadFromDisk(pindex)) + if (!ReadBlockFromDisk(block, pindex)) return state.Abort(_("Failed to read block")); int64 nStart = GetTimeMicros(); if (!block.ConnectBlock(state, pindex, view)) { @@ -2736,8 +2736,8 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth) break; CBlock block; // check level 0: read from disk - if (!block.ReadFromDisk(pindex)) - return error("VerifyDB() : *** block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); + if (!ReadBlockFromDisk(block, pindex)) + return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); // check level 1: verify block validity if (nCheckLevel >= 1 && !block.CheckBlock(state)) return error("VerifyDB() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); @@ -2773,8 +2773,8 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth) boost::this_thread::interruption_point(); pindex = pindex->GetNextInMainChain(); CBlock block; - if (!block.ReadFromDisk(pindex)) - return error("VerifyDB() : *** block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); + if (!ReadBlockFromDisk(block, pindex)) + return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); if (!block.ConnectBlock(state, pindex, coins)) return error("VerifyDB() : *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); } @@ -2884,7 +2884,7 @@ void PrintBlockTree() // print item CBlock block; - block.ReadFromDisk(pindex); + ReadBlockFromDisk(block, pindex); printf("%d (blk%05u.dat:0x%x) %s tx %"PRIszu"", pindex->nHeight, pindex->GetBlockPos().nFile, pindex->GetBlockPos().nPos, @@ -3108,7 +3108,7 @@ void static ProcessGetData(CNode* pfrom) if (mi != mapBlockIndex.end()) { CBlock block; - block.ReadFromDisk((*mi).second); + ReadBlockFromDisk(block, (*mi).second); if (inv.type == MSG_BLOCK) pfrom->PushMessage("block", block); else // MSG_FILTERED_BLOCK) diff --git a/src/main.h b/src/main.h index a613613e5..3cd0143c6 100644 --- a/src/main.h +++ b/src/main.h @@ -682,33 +682,6 @@ public: return hash; } - - bool ReadFromDisk(const CDiskBlockPos &pos) - { - SetNull(); - - // Open history file to read - CAutoFile filein = CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION); - if (!filein) - return error("CBlock::ReadFromDisk() : OpenBlockFile failed"); - - // Read block - try { - filein >> *this; - } - catch (std::exception &e) { - return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__); - } - - // Check the header - if (!CheckProofOfWork(GetHash(), nBits)) - return error("CBlock::ReadFromDisk() : errors in block header"); - - return true; - } - - - void print() const { printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu")\n", @@ -739,9 +712,6 @@ public: // Apply the effects of this block (with given index) on the UTXO set represented by coins bool ConnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &coins, bool fJustCheck=false); - // Read a block from disk - bool ReadFromDisk(const CBlockIndex* pindex); - // Add this block to the block index, and if necessary, switch the active block chain to this bool AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos); @@ -756,7 +726,31 @@ public: /** Functions for disk access for blocks */ bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos); +inline bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos) +{ + block.SetNull(); + // Open history file to read + CAutoFile filein = CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION); + if (!filein) + return error("ReadBlockFromDisk(CBlock&, CDiskBlockPos&) : OpenBlockFile failed"); + + // Read block + try { + filein >> block; + } + catch (std::exception &e) { + return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__); + } + + // Check the header + if (!CheckProofOfWork(block.GetHash(), block.nBits)) + return error("ReadBlockFromDisk(CBlock&, CDiskBlockPos&) : errors in block header"); + + return true; +} + +bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex); class CBlockFileInfo diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 6b2ef8315..3c24016fe 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -163,7 +163,7 @@ Value getblock(const Array& params, bool fHelp) CBlock block; CBlockIndex* pblockindex = mapBlockIndex[hash]; - block.ReadFromDisk(pblockindex); + ReadBlockFromDisk(block, pblockindex); if (!fVerbose) { diff --git a/src/wallet.cpp b/src/wallet.cpp index b09f94980..488787f96 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -804,7 +804,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) } CBlock block; - block.ReadFromDisk(pindex); + ReadBlockFromDisk(block, pindex); BOOST_FOREACH(CTransaction& tx, block.vtx) { if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate)) From 8031399494cc4cdf47fcaa9763282a930444033f Mon Sep 17 00:00:00 2001 From: Eric Lombrozo Date: Sun, 23 Jun 2013 18:21:33 -0700 Subject: [PATCH 04/10] Moved ReadBlockFromDisk implementation to main.cpp --- src/main.cpp | 24 ++++++++++++++++++++++++ src/main.h | 25 +------------------------ 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 67a989559..7be5c5a79 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1172,6 +1172,30 @@ bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos) return true; } +bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos) +{ + block.SetNull(); + + // Open history file to read + CAutoFile filein = CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION); + if (!filein) + return error("ReadBlockFromDisk(CBlock&, CDiskBlockPos&) : OpenBlockFile failed"); + + // Read block + try { + filein >> block; + } + catch (std::exception &e) { + return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__); + } + + // Check the header + if (!CheckProofOfWork(block.GetHash(), block.nBits)) + return error("ReadBlockFromDisk(CBlock&, CDiskBlockPos&) : errors in block header"); + + return true; +} + bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex) { if (!ReadBlockFromDisk(block, pindex->GetBlockPos())) diff --git a/src/main.h b/src/main.h index 3cd0143c6..47a9fb338 100644 --- a/src/main.h +++ b/src/main.h @@ -726,30 +726,7 @@ public: /** Functions for disk access for blocks */ bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos); -inline bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos) -{ - block.SetNull(); - - // Open history file to read - CAutoFile filein = CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION); - if (!filein) - return error("ReadBlockFromDisk(CBlock&, CDiskBlockPos&) : OpenBlockFile failed"); - - // Read block - try { - filein >> block; - } - catch (std::exception &e) { - return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__); - } - - // Check the header - if (!CheckProofOfWork(block.GetHash(), block.nBits)) - return error("ReadBlockFromDisk(CBlock&, CDiskBlockPos&) : errors in block header"); - - return true; -} - +bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos); bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex); From 5c363ed622ef8e060a3e6f6918a8b5e05798f21e Mon Sep 17 00:00:00 2001 From: Eric Lombrozo Date: Sun, 23 Jun 2013 18:32:58 -0700 Subject: [PATCH 05/10] Pulled DisconnectBlock out of CBlock. --- src/main.cpp | 12 ++++++------ src/main.h | 16 ++++++++++------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 7be5c5a79..f5ea6b5da 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1603,7 +1603,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach -bool CBlock::DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &view, bool *pfClean) +bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean) { assert(pindex == view.GetBestBlock()); @@ -1619,12 +1619,12 @@ bool CBlock::DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoin if (!blockUndo.ReadFromDisk(pos, pindex->pprev->GetBlockHash())) return error("DisconnectBlock() : failure reading undo data"); - if (blockUndo.vtxundo.size() + 1 != vtx.size()) + if (blockUndo.vtxundo.size() + 1 != block.vtx.size()) return error("DisconnectBlock() : block and undo data inconsistent"); // undo transactions in reverse order - for (int i = vtx.size() - 1; i >= 0; i--) { - const CTransaction &tx = vtx[i]; + for (int i = block.vtx.size() - 1; i >= 0; i--) { + const CTransaction &tx = block.vtx[i]; uint256 hash = tx.GetHash(); // check that all outputs are available @@ -1913,7 +1913,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) if (!ReadBlockFromDisk(block, pindex)) return state.Abort(_("Failed to read block")); int64 nStart = GetTimeMicros(); - if (!block.DisconnectBlock(state, pindex, view)) + if (!DisconnectBlock(block, state, pindex, view)) return error("SetBestBlock() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().c_str()); if (fBenchmark) printf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001); @@ -2777,7 +2777,7 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth) // check level 3: check for inconsistencies during memory-only disconnect of tip blocks if (nCheckLevel >= 3 && pindex == pindexState && (coins.GetCacheSize() + pcoinsTip->GetCacheSize()) <= 2*nCoinCacheSize + 32000) { bool fClean = true; - if (!block.DisconnectBlock(state, pindex, coins, &fClean)) + if (!DisconnectBlock(block, state, pindex, coins, &fClean)) return error("VerifyDB() : *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); pindexState = pindex->pprev; if (!fClean) { diff --git a/src/main.h b/src/main.h index 47a9fb338..1822becde 100644 --- a/src/main.h +++ b/src/main.h @@ -703,12 +703,6 @@ public: } - /** Undo the effects of this block (with given index) on the UTXO set represented by coins. - * In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean - * will be true if no problems were found. Otherwise, the return value will be false in case - * of problems. Note that in any case, coins may be modified. */ - bool DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &coins, bool *pfClean = NULL); - // Apply the effects of this block (with given index) on the UTXO set represented by coins bool ConnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &coins, bool fJustCheck=false); @@ -730,6 +724,16 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos); bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex); +/** Functions for validating blocks and updating the block tree */ + +/** Undo the effects of this block (with given index) on the UTXO set represented by coins. + * In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean + * will be true if no problems were found. Otherwise, the return value will be false in case + * of problems. Note that in any case, coins may be modified. */ +bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL); + + + class CBlockFileInfo { public: From f3ae51dcced8a16175426051ce888130cc2493af Mon Sep 17 00:00:00 2001 From: Eric Lombrozo Date: Sun, 23 Jun 2013 18:50:06 -0700 Subject: [PATCH 06/10] Pulled ConnectBlock out of CBlock. --- src/main.cpp | 38 +++++++++++++++++++------------------- src/main.h | 7 ++++--- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index f5ea6b5da..a3355bd10 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1717,10 +1717,10 @@ void ThreadScriptCheck() { scriptcheckqueue.Thread(); } -bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsViewCache &view, bool fJustCheck) +bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck) { // Check it again in case a previous version let a bad block in - if (!CheckBlock(state, !fJustCheck, !fJustCheck)) + if (!block.CheckBlock(state, !fJustCheck, !fJustCheck)) return false; // verify that the view's current state corresponds to the previous block @@ -1728,7 +1728,7 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi // Special case for the genesis block, skipping connection of its transactions // (its coinbase is unspendable) - if (GetHash() == Params().HashGenesisBlock()) { + if (block.GetHash() == Params().HashGenesisBlock()) { view.SetBestBlock(pindex); pindexGenesisBlock = pindex; return true; @@ -1752,8 +1752,8 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) || (pindex->nHeight==91880 && pindex->GetBlockHash() == uint256("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721"))); if (fEnforceBIP30) { - for (unsigned int i=0; iGetBlockPos(), GetSizeOfCompactSize(vtx.size())); + CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size())); std::vector > vPos; - vPos.reserve(vtx.size()); - for (unsigned int i=0; inHeight, GetTxHash(i)); + UpdateCoins(tx, state, view, txundo, pindex->nHeight, block.GetTxHash(i)); if (!tx.IsCoinBase()) blockundo.vtxundo.push_back(txundo); - vPos.push_back(std::make_pair(GetTxHash(i), pos)); + vPos.push_back(std::make_pair(block.GetTxHash(i), pos)); pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); } int64 nTime = GetTimeMicros() - nStart; if (fBenchmark) - printf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)vtx.size(), 0.001 * nTime, 0.001 * nTime / vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1)); + printf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)block.vtx.size(), 0.001 * nTime, 0.001 * nTime / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1)); - if (GetValueOut(vtx[0]) > GetBlockValue(pindex->nHeight, nFees)) - return state.DoS(100, error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", GetValueOut(vtx[0]), GetBlockValue(pindex->nHeight, nFees))); + if (GetValueOut(block.vtx[0]) > GetBlockValue(pindex->nHeight, nFees)) + return state.DoS(100, error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", GetValueOut(block.vtx[0]), GetBlockValue(pindex->nHeight, nFees))); if (!control.Wait()) return state.DoS(100, false); @@ -1863,8 +1863,8 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi assert(view.SetBestBlock(pindex)); // Watch for transactions paying to me - for (unsigned int i=0; inHeight, pindex->GetBlockHash().ToString().c_str()); - if (!block.ConnectBlock(state, pindex, coins)) + if (!ConnectBlock(block, state, pindex, coins)) return error("VerifyDB() : *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); } } @@ -4454,7 +4454,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) indexDummy.nHeight = pindexPrev->nHeight + 1; CCoinsViewCache viewNew(*pcoinsTip, true); CValidationState state; - if (!pblock->ConnectBlock(state, &indexDummy, viewNew, true)) + if (!ConnectBlock(*pblock, state, &indexDummy, viewNew, true)) throw std::runtime_error("CreateNewBlock() : ConnectBlock failed"); } diff --git a/src/main.h b/src/main.h index 1822becde..2c5964455 100644 --- a/src/main.h +++ b/src/main.h @@ -703,9 +703,6 @@ public: } - // Apply the effects of this block (with given index) on the UTXO set represented by coins - bool ConnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &coins, bool fJustCheck=false); - // Add this block to the block index, and if necessary, switch the active block chain to this bool AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos); @@ -732,6 +729,10 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex); * of problems. Note that in any case, coins may be modified. */ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL); +// Apply the effects of this block (with given index) on the UTXO set represented by coins +bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false); + + class CBlockFileInfo From 1959997afb0c710f238ae33fc8c656ab9b5470c8 Mon Sep 17 00:00:00 2001 From: Eric Lombrozo Date: Sun, 23 Jun 2013 19:00:18 -0700 Subject: [PATCH 07/10] Pulled AddToBlockIndex out of CBlock. --- src/main.cpp | 16 ++++++++-------- src/main.h | 5 ++--- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index a3355bd10..d7388077e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2043,25 +2043,25 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) } -bool CBlock::AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos) +bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos) { // Check for duplicate - uint256 hash = GetHash(); + uint256 hash = block.GetHash(); if (mapBlockIndex.count(hash)) return state.Invalid(error("AddToBlockIndex() : %s already exists", hash.ToString().c_str())); // Construct new block index object - CBlockIndex* pindexNew = new CBlockIndex(*this); + CBlockIndex* pindexNew = new CBlockIndex(block); assert(pindexNew); map::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; pindexNew->phashBlock = &((*mi).first); - map::iterator miPrev = mapBlockIndex.find(hashPrevBlock); + map::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock); if (miPrev != mapBlockIndex.end()) { pindexNew->pprev = (*miPrev).second; pindexNew->nHeight = pindexNew->pprev->nHeight + 1; } - pindexNew->nTx = vtx.size(); + pindexNew->nTx = block.vtx.size(); pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + pindexNew->GetBlockWork().getuint256(); pindexNew->nChainTx = (pindexNew->pprev ? pindexNew->pprev->nChainTx : 0) + pindexNew->nTx; pindexNew->nFile = pos.nFile; @@ -2082,7 +2082,7 @@ bool CBlock::AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos) // Notify UI to display prev block's coinbase if it was ours static uint256 hashPrevBestCoinBase; UpdatedTransaction(hashPrevBestCoinBase); - hashPrevBestCoinBase = GetTxHash(0); + hashPrevBestCoinBase = block.GetTxHash(0); } if (!pblocktree->Flush()) @@ -2314,7 +2314,7 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp) if (dbp == NULL) if (!WriteBlockToDisk(*this, blockPos)) return state.Abort(_("Failed to write block")); - if (!AddToBlockIndex(state, blockPos)) + if (!AddToBlockIndex(*this, state, blockPos)) return error("AcceptBlock() : AddToBlockIndex failed"); } catch(std::runtime_error &e) { return state.Abort(_("System error: ") + e.what()); @@ -2852,7 +2852,7 @@ bool InitBlockIndex() { return error("LoadBlockIndex() : FindBlockPos failed"); if (!WriteBlockToDisk(block, blockPos)) return error("LoadBlockIndex() : writing genesis block to disk failed"); - if (!block.AddToBlockIndex(state, blockPos)) + if (!AddToBlockIndex(block, state, blockPos)) return error("LoadBlockIndex() : genesis block not accepted"); } catch(std::runtime_error &e) { return error("LoadBlockIndex() : failed to initialize block database: %s", e.what()); diff --git a/src/main.h b/src/main.h index 2c5964455..e44844a79 100644 --- a/src/main.h +++ b/src/main.h @@ -703,9 +703,6 @@ public: } - // Add this block to the block index, and if necessary, switch the active block chain to this - bool AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos); - // Context-independent validity checks bool CheckBlock(CValidationState &state, bool fCheckPOW=true, bool fCheckMerkleRoot=true) const; @@ -732,6 +729,8 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex // Apply the effects of this block (with given index) on the UTXO set represented by coins bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false); +// Add this block to the block index, and if necessary, switch the active block chain to this +bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos); From 38991ffa8ae627613fadaca8bbc14fcd820e0861 Mon Sep 17 00:00:00 2001 From: Eric Lombrozo Date: Sun, 23 Jun 2013 19:14:11 -0700 Subject: [PATCH 08/10] Pulled CheckBlock out of CBlock. --- src/main.cpp | 34 +++++++++++++++++----------------- src/main.h | 6 +++--- src/test/checkblock_tests.cpp | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index d7388077e..f14d2e51c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1720,7 +1720,7 @@ void ThreadScriptCheck() { bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck) { // Check it again in case a previous version let a bad block in - if (!block.CheckBlock(state, !fJustCheck, !fJustCheck)) + if (!CheckBlock(block, state, !fJustCheck, !fJustCheck)) return false; // verify that the view's current state corresponds to the previous block @@ -2188,51 +2188,51 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne } -bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerkleRoot) const +bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bool fCheckMerkleRoot) { // These are checks that are independent of context // that can be verified before saving an orphan block. // Size limits - if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) + if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) return state.DoS(100, error("CheckBlock() : size limits failed")); // Check proof of work matches claimed amount - if (fCheckPOW && !CheckProofOfWork(GetHash(), nBits)) + if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits)) return state.DoS(50, error("CheckBlock() : proof of work failed")); // Check timestamp - if (GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60) + if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60) return state.Invalid(error("CheckBlock() : block timestamp too far in the future")); // First transaction must be coinbase, the rest must not be - if (vtx.empty() || !vtx[0].IsCoinBase()) + if (block.vtx.empty() || !block.vtx[0].IsCoinBase()) return state.DoS(100, error("CheckBlock() : first tx is not coinbase")); - for (unsigned int i = 1; i < vtx.size(); i++) - if (vtx[i].IsCoinBase()) + for (unsigned int i = 1; i < block.vtx.size(); i++) + if (block.vtx[i].IsCoinBase()) return state.DoS(100, error("CheckBlock() : more than one coinbase")); // Check transactions - BOOST_FOREACH(const CTransaction& tx, vtx) + BOOST_FOREACH(const CTransaction& tx, block.vtx) if (!CheckTransaction(tx, state)) return error("CheckBlock() : CheckTransaction failed"); // Build the merkle tree already. We need it anyway later, and it makes the // block cache the transaction hashes, which means they don't need to be // recalculated many times during this block's validation. - BuildMerkleTree(); + block.BuildMerkleTree(); // Check for duplicate txids. This is caught by ConnectInputs(), // but catching it earlier avoids a potential DoS attack: set uniqueTx; - for (unsigned int i=0; iCheckBlock(state)) + if (!CheckBlock(*pblock, state)) return error("ProcessBlock() : CheckBlock FAILED"); CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex); @@ -2763,7 +2763,7 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth) if (!ReadBlockFromDisk(block, pindex)) return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); // check level 1: verify block validity - if (nCheckLevel >= 1 && !block.CheckBlock(state)) + if (nCheckLevel >= 1 && !CheckBlock(block, state)) return error("VerifyDB() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); // check level 2: verify undo validity if (nCheckLevel >= 2 && pindex) { diff --git a/src/main.h b/src/main.h index e44844a79..022c6ad07 100644 --- a/src/main.h +++ b/src/main.h @@ -703,9 +703,6 @@ public: } - // Context-independent validity checks - bool CheckBlock(CValidationState &state, bool fCheckPOW=true, bool fCheckMerkleRoot=true) const; - // Store block on disk // if dbp is provided, the file is known to already reside on disk bool AcceptBlock(CValidationState &state, CDiskBlockPos *dbp = NULL); @@ -732,6 +729,9 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C // Add this block to the block index, and if necessary, switch the active block chain to this bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos); +// Context-independent validity checks +bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true); + class CBlockFileInfo diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp index d626f9a6f..5675c40e7 100644 --- a/src/test/checkblock_tests.cpp +++ b/src/test/checkblock_tests.cpp @@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(May15) // After May 15'th, big blocks are OK: forkingBlock.nTime = tMay15; // Invalidates PoW - BOOST_CHECK(forkingBlock.CheckBlock(state, false, false)); + BOOST_CHECK(CheckBlock(forkingBlock, state, false, false)); } SetMockTime(0); From 2a4d3464fd5e61a3c89a46d12f6729aeeac919f1 Mon Sep 17 00:00:00 2001 From: Eric Lombrozo Date: Sun, 23 Jun 2013 19:27:02 -0700 Subject: [PATCH 09/10] Pulled AcceptBlock out of CBlock. --- src/main.cpp | 32 ++++++++++++++++---------------- src/main.h | 9 ++++----- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index f14d2e51c..da928a4b9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2246,10 +2246,10 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo return true; } -bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp) +bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp) { // Check for duplicate - uint256 hash = GetHash(); + uint256 hash = block.GetHash(); if (mapBlockIndex.count(hash)) return state.Invalid(error("AcceptBlock() : block already in mapBlockIndex")); @@ -2257,23 +2257,23 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp) CBlockIndex* pindexPrev = NULL; int nHeight = 0; if (hash != Params().HashGenesisBlock()) { - map::iterator mi = mapBlockIndex.find(hashPrevBlock); + map::iterator mi = mapBlockIndex.find(block.hashPrevBlock); if (mi == mapBlockIndex.end()) return state.DoS(10, error("AcceptBlock() : prev block not found")); pindexPrev = (*mi).second; nHeight = pindexPrev->nHeight+1; // Check proof of work - if (nBits != GetNextWorkRequired(pindexPrev, this)) + if (block.nBits != GetNextWorkRequired(pindexPrev, &block)) return state.DoS(100, error("AcceptBlock() : incorrect proof of work")); // Check timestamp against prev - if (GetBlockTime() <= pindexPrev->GetMedianTimePast()) + if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) return state.Invalid(error("AcceptBlock() : block's timestamp is too early")); // Check that all transactions are finalized - BOOST_FOREACH(const CTransaction& tx, vtx) - if (!IsFinalTx(tx, nHeight, GetBlockTime())) + BOOST_FOREACH(const CTransaction& tx, block.vtx) + if (!IsFinalTx(tx, nHeight, block.GetBlockTime())) return state.DoS(10, error("AcceptBlock() : contains a non-final transaction")); // Check that the block chain matches the known block chain up to a checkpoint @@ -2281,7 +2281,7 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp) return state.DoS(100, error("AcceptBlock() : rejected by checkpoint lock-in at %d", nHeight)); // Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded: - if (nVersion < 2) + if (block.nVersion < 2) { if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 950, 1000)) || (TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100))) @@ -2290,14 +2290,14 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp) } } // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height - if (nVersion >= 2) + if (block.nVersion >= 2) { // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet): if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 750, 1000)) || (TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100))) { CScript expect = CScript() << nHeight; - if (!std::equal(expect.begin(), expect.end(), vtx[0].vin[0].scriptSig.begin())) + if (!std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase")); } } @@ -2305,16 +2305,16 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp) // Write block to history file try { - unsigned int nBlockSize = ::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION); + unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); CDiskBlockPos blockPos; if (dbp != NULL) blockPos = *dbp; - if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, nTime, dbp != NULL)) + if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, block.nTime, dbp != NULL)) return error("AcceptBlock() : FindBlockPos failed"); if (dbp == NULL) - if (!WriteBlockToDisk(*this, blockPos)) + if (!WriteBlockToDisk(block, blockPos)) return state.Abort(_("Failed to write block")); - if (!AddToBlockIndex(*this, state, blockPos)) + if (!AddToBlockIndex(block, state, blockPos)) return error("AcceptBlock() : AddToBlockIndex failed"); } catch(std::runtime_error &e) { return state.Abort(_("System error: ") + e.what()); @@ -2407,7 +2407,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl } // Store to disk - if (!pblock->AcceptBlock(state, dbp)) + if (!AcceptBlock(*pblock, state, dbp)) return error("ProcessBlock() : AcceptBlock FAILED"); // Recursively process any orphan blocks that depended on this one @@ -2423,7 +2423,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl CBlock* pblockOrphan = (*mi).second; // 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; - if (pblockOrphan->AcceptBlock(stateDummy)) + if (AcceptBlock(*pblockOrphan, stateDummy)) vWorkQueue.push_back(pblockOrphan->GetHash()); mapOrphanBlocks.erase(pblockOrphan->GetHash()); delete pblockOrphan; diff --git a/src/main.h b/src/main.h index 022c6ad07..f85953c4f 100644 --- a/src/main.h +++ b/src/main.h @@ -701,11 +701,6 @@ public: printf("%s ", vMerkleTree[i].ToString().c_str()); printf("\n"); } - - - // Store block on disk - // if dbp is provided, the file is known to already reside on disk - bool AcceptBlock(CValidationState &state, CDiskBlockPos *dbp = NULL); }; @@ -732,6 +727,10 @@ bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos // Context-independent validity checks bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true); +// Store block on disk +// if dbp is provided, the file is known to already reside on disk +bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp = NULL); + class CBlockFileInfo From 33944573ca0c6b9be59b56e754de8f7238fa95f7 Mon Sep 17 00:00:00 2001 From: Eric Lombrozo Date: Sun, 23 Jun 2013 19:37:03 -0700 Subject: [PATCH 10/10] Moved CBlock from main.h to core.h --- src/core.h | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.h | 122 ---------------------------------------------------- 2 files changed, 123 insertions(+), 122 deletions(-) diff --git a/src/core.h b/src/core.h index c568fd2ef..fce9ccc16 100644 --- a/src/core.h +++ b/src/core.h @@ -733,4 +733,127 @@ public: } }; + +class CBlock : public CBlockHeader +{ +public: + // network and disk + std::vector vtx; + + // memory only + mutable std::vector vMerkleTree; + + CBlock() + { + SetNull(); + } + + CBlock(const CBlockHeader &header) + { + SetNull(); + *((CBlockHeader*)this) = header; + } + + IMPLEMENT_SERIALIZE + ( + READWRITE(*(CBlockHeader*)this); + READWRITE(vtx); + ) + + void SetNull() + { + CBlockHeader::SetNull(); + vtx.clear(); + vMerkleTree.clear(); + } + + CBlockHeader GetBlockHeader() const + { + CBlockHeader block; + block.nVersion = nVersion; + block.hashPrevBlock = hashPrevBlock; + block.hashMerkleRoot = hashMerkleRoot; + block.nTime = nTime; + block.nBits = nBits; + block.nNonce = nNonce; + return block; + } + + uint256 BuildMerkleTree() const + { + vMerkleTree.clear(); + BOOST_FOREACH(const CTransaction& tx, vtx) + vMerkleTree.push_back(tx.GetHash()); + int j = 0; + for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) + { + for (int i = 0; i < nSize; i += 2) + { + int i2 = std::min(i+1, nSize-1); + vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]), + BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2]))); + } + j += nSize; + } + return (vMerkleTree.empty() ? 0 : vMerkleTree.back()); + } + + const uint256 &GetTxHash(unsigned int nIndex) const { + assert(vMerkleTree.size() > 0); // BuildMerkleTree must have been called first + assert(nIndex < vtx.size()); + return vMerkleTree[nIndex]; + } + + std::vector GetMerkleBranch(int nIndex) const + { + if (vMerkleTree.empty()) + BuildMerkleTree(); + std::vector vMerkleBranch; + int j = 0; + for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) + { + int i = std::min(nIndex^1, nSize-1); + vMerkleBranch.push_back(vMerkleTree[j+i]); + nIndex >>= 1; + j += nSize; + } + return vMerkleBranch; + } + + static uint256 CheckMerkleBranch(uint256 hash, const std::vector& vMerkleBranch, int nIndex) + { + if (nIndex == -1) + return 0; + BOOST_FOREACH(const uint256& otherside, vMerkleBranch) + { + if (nIndex & 1) + hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash)); + else + hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside)); + nIndex >>= 1; + } + return hash; + } + + void print() const + { + printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu")\n", + GetHash().ToString().c_str(), + nVersion, + hashPrevBlock.ToString().c_str(), + hashMerkleRoot.ToString().c_str(), + nTime, nBits, nNonce, + vtx.size()); + for (unsigned int i = 0; i < vtx.size(); i++) + { + printf(" "); + vtx[i].print(); + } + printf(" vMerkleTree: "); + for (unsigned int i = 0; i < vMerkleTree.size(); i++) + printf("%s ", vMerkleTree[i].ToString().c_str()); + printf("\n"); + } +}; + #endif diff --git a/src/main.h b/src/main.h index f85953c4f..9e0235fa5 100644 --- a/src/main.h +++ b/src/main.h @@ -581,128 +581,6 @@ public: }; -class CBlock : public CBlockHeader -{ -public: - // network and disk - std::vector vtx; - - // memory only - mutable std::vector vMerkleTree; - - CBlock() - { - SetNull(); - } - - CBlock(const CBlockHeader &header) - { - SetNull(); - *((CBlockHeader*)this) = header; - } - - IMPLEMENT_SERIALIZE - ( - READWRITE(*(CBlockHeader*)this); - READWRITE(vtx); - ) - - void SetNull() - { - CBlockHeader::SetNull(); - vtx.clear(); - vMerkleTree.clear(); - } - - CBlockHeader GetBlockHeader() const - { - CBlockHeader block; - block.nVersion = nVersion; - block.hashPrevBlock = hashPrevBlock; - block.hashMerkleRoot = hashMerkleRoot; - block.nTime = nTime; - block.nBits = nBits; - block.nNonce = nNonce; - return block; - } - - uint256 BuildMerkleTree() const - { - vMerkleTree.clear(); - BOOST_FOREACH(const CTransaction& tx, vtx) - vMerkleTree.push_back(tx.GetHash()); - int j = 0; - for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) - { - for (int i = 0; i < nSize; i += 2) - { - int i2 = std::min(i+1, nSize-1); - vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]), - BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2]))); - } - j += nSize; - } - return (vMerkleTree.empty() ? 0 : vMerkleTree.back()); - } - - const uint256 &GetTxHash(unsigned int nIndex) const { - assert(vMerkleTree.size() > 0); // BuildMerkleTree must have been called first - assert(nIndex < vtx.size()); - return vMerkleTree[nIndex]; - } - - std::vector GetMerkleBranch(int nIndex) const - { - if (vMerkleTree.empty()) - BuildMerkleTree(); - std::vector vMerkleBranch; - int j = 0; - for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) - { - int i = std::min(nIndex^1, nSize-1); - vMerkleBranch.push_back(vMerkleTree[j+i]); - nIndex >>= 1; - j += nSize; - } - return vMerkleBranch; - } - - static uint256 CheckMerkleBranch(uint256 hash, const std::vector& vMerkleBranch, int nIndex) - { - if (nIndex == -1) - return 0; - BOOST_FOREACH(const uint256& otherside, vMerkleBranch) - { - if (nIndex & 1) - hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash)); - else - hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside)); - nIndex >>= 1; - } - return hash; - } - - void print() const - { - printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu")\n", - GetHash().ToString().c_str(), - nVersion, - hashPrevBlock.ToString().c_str(), - hashMerkleRoot.ToString().c_str(), - nTime, nBits, nNonce, - vtx.size()); - for (unsigned int i = 0; i < vtx.size(); i++) - { - printf(" "); - vtx[i].print(); - } - printf(" vMerkleTree: "); - for (unsigned int i = 0; i < vMerkleTree.size(); i++) - printf("%s ", vMerkleTree[i].ToString().c_str()); - printf("\n"); - } -}; - /** Functions for disk access for blocks */ bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos);