Merge pull request #2758 from CodeShark/CBlock-to-core

Finish moving core data structures into core.h.
This commit is contained in:
Jeff Garzik 2013-06-24 06:53:34 -07:00
commit 64225f7ce9
7 changed files with 275 additions and 273 deletions

View File

@ -733,4 +733,127 @@ public:
} }
}; };
class CBlock : public CBlockHeader
{
public:
// network and disk
std::vector<CTransaction> vtx;
// memory only
mutable std::vector<uint256> 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<uint256> GetMerkleBranch(int nIndex) const
{
if (vMerkleTree.empty())
BuildMerkleTree();
std::vector<uint256> 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<uint256>& 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 #endif

View File

@ -820,7 +820,7 @@ bool AppInit2(boost::thread_group& threadGroup)
{ {
CBlockIndex* pindex = (*mi).second; CBlockIndex* pindex = (*mi).second;
CBlock block; CBlock block;
block.ReadFromDisk(pindex); ReadBlockFromDisk(block, pindex);
block.BuildMerkleTree(); block.BuildMerkleTree();
block.print(); block.print();
printf("\n"); printf("\n");

View File

@ -627,7 +627,7 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
if (pcoinsTip->GetCoins(GetHash(), coins)) { if (pcoinsTip->GetCoins(GetHash(), coins)) {
CBlockIndex *pindex = FindBlockByHeight(coins.nHeight); CBlockIndex *pindex = FindBlockByHeight(coins.nHeight);
if (pindex) { if (pindex) {
if (!blockTmp.ReadFromDisk(pindex)) if (!ReadBlockFromDisk(blockTmp, pindex))
return 0; return 0;
pblock = &blockTmp; pblock = &blockTmp;
} }
@ -1114,7 +1114,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
if (pindexSlow) { if (pindexSlow) {
CBlock block; CBlock block;
if (block.ReadFromDisk(pindexSlow)) { if (ReadBlockFromDisk(block, pindexSlow)) {
BOOST_FOREACH(const CTransaction &tx, block.vtx) { BOOST_FOREACH(const CTransaction &tx, block.vtx) {
if (tx.GetHash() == hash) { if (tx.GetHash() == hash) {
txOut = tx; txOut = tx;
@ -1146,12 +1146,62 @@ CBlockIndex* FindBlockByHeight(int nHeight)
return vBlockIndexByHeight[nHeight]; return vBlockIndexByHeight[nHeight];
} }
bool CBlock::ReadFromDisk(const CBlockIndex* pindex) bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos)
{ {
if (!ReadFromDisk(pindex->GetBlockPos())) // 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 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()))
return false; return false;
if (GetHash() != pindex->GetBlockHash()) if (block.GetHash() != pindex->GetBlockHash())
return error("CBlock::ReadFromDisk() : GetHash() doesn't match index"); return error("ReadBlockFromDisk(CBlock&, CBlockIndex*) : GetHash() doesn't match index");
return true; return true;
} }
@ -1553,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()); assert(pindex == view.GetBestBlock());
@ -1569,12 +1619,12 @@ bool CBlock::DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoin
if (!blockUndo.ReadFromDisk(pos, pindex->pprev->GetBlockHash())) if (!blockUndo.ReadFromDisk(pos, pindex->pprev->GetBlockHash()))
return error("DisconnectBlock() : failure reading undo data"); 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"); return error("DisconnectBlock() : block and undo data inconsistent");
// undo transactions in reverse order // undo transactions in reverse order
for (int i = vtx.size() - 1; i >= 0; i--) { for (int i = block.vtx.size() - 1; i >= 0; i--) {
const CTransaction &tx = vtx[i]; const CTransaction &tx = block.vtx[i];
uint256 hash = tx.GetHash(); uint256 hash = tx.GetHash();
// check that all outputs are available // check that all outputs are available
@ -1667,10 +1717,10 @@ void ThreadScriptCheck() {
scriptcheckqueue.Thread(); 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 // Check it again in case a previous version let a bad block in
if (!CheckBlock(state, !fJustCheck, !fJustCheck)) if (!CheckBlock(block, state, !fJustCheck, !fJustCheck))
return false; return false;
// verify that the view's current state corresponds to the previous block // verify that the view's current state corresponds to the previous block
@ -1678,7 +1728,7 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
// Special case for the genesis block, skipping connection of its transactions // Special case for the genesis block, skipping connection of its transactions
// (its coinbase is unspendable) // (its coinbase is unspendable)
if (GetHash() == Params().HashGenesisBlock()) { if (block.GetHash() == Params().HashGenesisBlock()) {
view.SetBestBlock(pindex); view.SetBestBlock(pindex);
pindexGenesisBlock = pindex; pindexGenesisBlock = pindex;
return true; return true;
@ -1702,8 +1752,8 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
!((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) || !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) ||
(pindex->nHeight==91880 && pindex->GetBlockHash() == uint256("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721"))); (pindex->nHeight==91880 && pindex->GetBlockHash() == uint256("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721")));
if (fEnforceBIP30) { if (fEnforceBIP30) {
for (unsigned int i=0; i<vtx.size(); i++) { for (unsigned int i = 0; i < block.vtx.size(); i++) {
uint256 hash = GetTxHash(i); uint256 hash = block.GetTxHash(i);
if (view.HaveCoins(hash) && !view.GetCoins(hash).IsPruned()) if (view.HaveCoins(hash) && !view.GetCoins(hash).IsPruned())
return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction")); return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"));
} }
@ -1724,12 +1774,12 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
int64 nFees = 0; int64 nFees = 0;
int nInputs = 0; int nInputs = 0;
unsigned int nSigOps = 0; unsigned int nSigOps = 0;
CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(vtx.size())); CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
std::vector<std::pair<uint256, CDiskTxPos> > vPos; std::vector<std::pair<uint256, CDiskTxPos> > vPos;
vPos.reserve(vtx.size()); vPos.reserve(block.vtx.size());
for (unsigned int i=0; i<vtx.size(); i++) for (unsigned int i = 0; i < block.vtx.size(); i++)
{ {
const CTransaction &tx = vtx[i]; const CTransaction &tx = block.vtx[i];
nInputs += tx.vin.size(); nInputs += tx.vin.size();
nSigOps += GetLegacySigOpCount(tx); nSigOps += GetLegacySigOpCount(tx);
@ -1760,19 +1810,19 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
} }
CTxUndo txundo; CTxUndo txundo;
UpdateCoins(tx, state, view, txundo, pindex->nHeight, GetTxHash(i)); UpdateCoins(tx, state, view, txundo, pindex->nHeight, block.GetTxHash(i));
if (!tx.IsCoinBase()) if (!tx.IsCoinBase())
blockundo.vtxundo.push_back(txundo); 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); pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
} }
int64 nTime = GetTimeMicros() - nStart; int64 nTime = GetTimeMicros() - nStart;
if (fBenchmark) 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)) 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(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()) if (!control.Wait())
return state.DoS(100, false); return state.DoS(100, false);
@ -1813,8 +1863,8 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
assert(view.SetBestBlock(pindex)); assert(view.SetBestBlock(pindex));
// Watch for transactions paying to me // Watch for transactions paying to me
for (unsigned int i=0; i<vtx.size(); i++) for (unsigned int i = 0; i < block.vtx.size(); i++)
SyncWithWallets(GetTxHash(i), vtx[i], this, true); SyncWithWallets(block.GetTxHash(i), block.vtx[i], &block, true);
return true; return true;
} }
@ -1860,10 +1910,10 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
vector<CTransaction> vResurrect; vector<CTransaction> vResurrect;
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) { BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) {
CBlock block; CBlock block;
if (!block.ReadFromDisk(pindex)) if (!ReadBlockFromDisk(block, pindex))
return state.Abort(_("Failed to read block")); return state.Abort(_("Failed to read block"));
int64 nStart = GetTimeMicros(); 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()); return error("SetBestBlock() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().c_str());
if (fBenchmark) if (fBenchmark)
printf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001); printf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
@ -1880,10 +1930,10 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
vector<CTransaction> vDelete; vector<CTransaction> vDelete;
BOOST_FOREACH(CBlockIndex *pindex, vConnect) { BOOST_FOREACH(CBlockIndex *pindex, vConnect) {
CBlock block; CBlock block;
if (!block.ReadFromDisk(pindex)) if (!ReadBlockFromDisk(block, pindex))
return state.Abort(_("Failed to read block")); return state.Abort(_("Failed to read block"));
int64 nStart = GetTimeMicros(); int64 nStart = GetTimeMicros();
if (!block.ConnectBlock(state, pindex, view)) { if (!ConnectBlock(block, state, pindex, view)) {
if (state.IsInvalid()) { if (state.IsInvalid()) {
InvalidChainFound(pindexNew); InvalidChainFound(pindexNew);
InvalidBlockFound(pindex); InvalidBlockFound(pindex);
@ -1993,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 // Check for duplicate
uint256 hash = GetHash(); uint256 hash = block.GetHash();
if (mapBlockIndex.count(hash)) if (mapBlockIndex.count(hash))
return state.Invalid(error("AddToBlockIndex() : %s already exists", hash.ToString().c_str())); return state.Invalid(error("AddToBlockIndex() : %s already exists", hash.ToString().c_str()));
// Construct new block index object // Construct new block index object
CBlockIndex* pindexNew = new CBlockIndex(*this); CBlockIndex* pindexNew = new CBlockIndex(block);
assert(pindexNew); assert(pindexNew);
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
pindexNew->phashBlock = &((*mi).first); pindexNew->phashBlock = &((*mi).first);
map<uint256, CBlockIndex*>::iterator miPrev = mapBlockIndex.find(hashPrevBlock); map<uint256, CBlockIndex*>::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock);
if (miPrev != mapBlockIndex.end()) if (miPrev != mapBlockIndex.end())
{ {
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->nTx = block.vtx.size();
pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + pindexNew->GetBlockWork().getuint256(); pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + pindexNew->GetBlockWork().getuint256();
pindexNew->nChainTx = (pindexNew->pprev ? pindexNew->pprev->nChainTx : 0) + pindexNew->nTx; pindexNew->nChainTx = (pindexNew->pprev ? pindexNew->pprev->nChainTx : 0) + pindexNew->nTx;
pindexNew->nFile = pos.nFile; pindexNew->nFile = pos.nFile;
@ -2032,7 +2082,7 @@ bool CBlock::AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos)
// Notify UI to display prev block's coinbase if it was ours // Notify UI to display prev block's coinbase if it was ours
static uint256 hashPrevBestCoinBase; static uint256 hashPrevBestCoinBase;
UpdatedTransaction(hashPrevBestCoinBase); UpdatedTransaction(hashPrevBestCoinBase);
hashPrevBestCoinBase = GetTxHash(0); hashPrevBestCoinBase = block.GetTxHash(0);
} }
if (!pblocktree->Flush()) if (!pblocktree->Flush())
@ -2138,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 // These are checks that are independent of context
// that can be verified before saving an orphan block. // that can be verified before saving an orphan block.
// Size limits // 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")); return state.DoS(100, error("CheckBlock() : size limits failed"));
// Check proof of work matches claimed amount // 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")); return state.DoS(50, error("CheckBlock() : proof of work failed"));
// Check timestamp // 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")); return state.Invalid(error("CheckBlock() : block timestamp too far in the future"));
// First transaction must be coinbase, the rest must not be // 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")); return state.DoS(100, error("CheckBlock() : first tx is not coinbase"));
for (unsigned int i = 1; i < vtx.size(); i++) for (unsigned int i = 1; i < block.vtx.size(); i++)
if (vtx[i].IsCoinBase()) if (block.vtx[i].IsCoinBase())
return state.DoS(100, error("CheckBlock() : more than one coinbase")); return state.DoS(100, error("CheckBlock() : more than one coinbase"));
// Check transactions // Check transactions
BOOST_FOREACH(const CTransaction& tx, vtx) BOOST_FOREACH(const CTransaction& tx, block.vtx)
if (!CheckTransaction(tx, state)) if (!CheckTransaction(tx, state))
return error("CheckBlock() : CheckTransaction failed"); return error("CheckBlock() : CheckTransaction failed");
// Build the merkle tree already. We need it anyway later, and it makes the // 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 // block cache the transaction hashes, which means they don't need to be
// recalculated many times during this block's validation. // recalculated many times during this block's validation.
BuildMerkleTree(); block.BuildMerkleTree();
// Check for duplicate txids. This is caught by ConnectInputs(), // Check for duplicate txids. This is caught by ConnectInputs(),
// but catching it earlier avoids a potential DoS attack: // but catching it earlier avoids a potential DoS attack:
set<uint256> uniqueTx; set<uint256> uniqueTx;
for (unsigned int i=0; i<vtx.size(); i++) { for (unsigned int i = 0; i < block.vtx.size(); i++) {
uniqueTx.insert(GetTxHash(i)); uniqueTx.insert(block.GetTxHash(i));
} }
if (uniqueTx.size() != vtx.size()) if (uniqueTx.size() != block.vtx.size())
return state.DoS(100, error("CheckBlock() : duplicate transaction")); return state.DoS(100, error("CheckBlock() : duplicate transaction"));
unsigned int nSigOps = 0; unsigned int nSigOps = 0;
BOOST_FOREACH(const CTransaction& tx, vtx) BOOST_FOREACH(const CTransaction& tx, block.vtx)
{ {
nSigOps += GetLegacySigOpCount(tx); nSigOps += GetLegacySigOpCount(tx);
} }
@ -2190,16 +2240,16 @@ bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerk
return state.DoS(100, error("CheckBlock() : out-of-bounds SigOpCount")); return state.DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"));
// Check merkle root // Check merkle root
if (fCheckMerkleRoot && hashMerkleRoot != BuildMerkleTree()) if (fCheckMerkleRoot && block.hashMerkleRoot != block.BuildMerkleTree())
return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch")); return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"));
return true; return true;
} }
bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp) bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
{ {
// Check for duplicate // Check for duplicate
uint256 hash = GetHash(); uint256 hash = block.GetHash();
if (mapBlockIndex.count(hash)) if (mapBlockIndex.count(hash))
return state.Invalid(error("AcceptBlock() : block already in mapBlockIndex")); return state.Invalid(error("AcceptBlock() : block already in mapBlockIndex"));
@ -2207,23 +2257,23 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
CBlockIndex* pindexPrev = NULL; CBlockIndex* pindexPrev = NULL;
int nHeight = 0; int nHeight = 0;
if (hash != Params().HashGenesisBlock()) { if (hash != Params().HashGenesisBlock()) {
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashPrevBlock); map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
if (mi == mapBlockIndex.end()) if (mi == mapBlockIndex.end())
return state.DoS(10, error("AcceptBlock() : prev block not found")); return state.DoS(10, error("AcceptBlock() : prev block not found"));
pindexPrev = (*mi).second; pindexPrev = (*mi).second;
nHeight = pindexPrev->nHeight+1; nHeight = pindexPrev->nHeight+1;
// Check proof of work // 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")); return state.DoS(100, error("AcceptBlock() : incorrect proof of work"));
// Check timestamp against prev // Check timestamp against prev
if (GetBlockTime() <= pindexPrev->GetMedianTimePast()) if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
return state.Invalid(error("AcceptBlock() : block's timestamp is too early")); return state.Invalid(error("AcceptBlock() : block's timestamp is too early"));
// Check that all transactions are finalized // Check that all transactions are finalized
BOOST_FOREACH(const CTransaction& tx, vtx) BOOST_FOREACH(const CTransaction& tx, block.vtx)
if (!IsFinalTx(tx, nHeight, GetBlockTime())) if (!IsFinalTx(tx, nHeight, block.GetBlockTime()))
return state.DoS(10, error("AcceptBlock() : contains a non-final transaction")); 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 // Check that the block chain matches the known block chain up to a checkpoint
@ -2231,7 +2281,7 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
return state.DoS(100, error("AcceptBlock() : rejected by checkpoint lock-in at %d", nHeight)); 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: // 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)) || if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 950, 1000)) ||
(TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100))) (TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100)))
@ -2240,14 +2290,14 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
} }
} }
// Enforce block.nVersion=2 rule that the coinbase starts with serialized block height // 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 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet):
if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 750, 1000)) || if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 750, 1000)) ||
(TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100))) (TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100)))
{ {
CScript expect = CScript() << nHeight; 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")); return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase"));
} }
} }
@ -2255,16 +2305,16 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
// Write block to history file // Write block to history file
try { try {
unsigned int nBlockSize = ::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION); unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
CDiskBlockPos blockPos; CDiskBlockPos blockPos;
if (dbp != NULL) if (dbp != NULL)
blockPos = *dbp; 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"); return error("AcceptBlock() : FindBlockPos failed");
if (dbp == NULL) if (dbp == NULL)
if (!WriteToDisk(blockPos)) if (!WriteBlockToDisk(block, blockPos))
return state.Abort(_("Failed to write block")); return state.Abort(_("Failed to write block"));
if (!AddToBlockIndex(state, blockPos)) if (!AddToBlockIndex(block, state, blockPos))
return error("AcceptBlock() : AddToBlockIndex failed"); return error("AcceptBlock() : AddToBlockIndex failed");
} catch(std::runtime_error &e) { } catch(std::runtime_error &e) {
return state.Abort(_("System error: ") + e.what()); return state.Abort(_("System error: ") + e.what());
@ -2316,7 +2366,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
return state.Invalid(error("ProcessBlock() : already have block (orphan) %s", hash.ToString().c_str())); return state.Invalid(error("ProcessBlock() : already have block (orphan) %s", hash.ToString().c_str()));
// Preliminary checks // Preliminary checks
if (!pblock->CheckBlock(state)) if (!CheckBlock(*pblock, state))
return error("ProcessBlock() : CheckBlock FAILED"); return error("ProcessBlock() : CheckBlock FAILED");
CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex); CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex);
@ -2357,7 +2407,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
} }
// Store to disk // Store to disk
if (!pblock->AcceptBlock(state, dbp)) if (!AcceptBlock(*pblock, state, dbp))
return error("ProcessBlock() : AcceptBlock FAILED"); return error("ProcessBlock() : AcceptBlock FAILED");
// Recursively process any orphan blocks that depended on this one // Recursively process any orphan blocks that depended on this one
@ -2373,7 +2423,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
CBlock* pblockOrphan = (*mi).second; 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) // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan resolution (that is, feeding people an invalid block based on LegitBlockX in order to get anyone relaying LegitBlockX banned)
CValidationState stateDummy; CValidationState stateDummy;
if (pblockOrphan->AcceptBlock(stateDummy)) if (AcceptBlock(*pblockOrphan, stateDummy))
vWorkQueue.push_back(pblockOrphan->GetHash()); vWorkQueue.push_back(pblockOrphan->GetHash());
mapOrphanBlocks.erase(pblockOrphan->GetHash()); mapOrphanBlocks.erase(pblockOrphan->GetHash());
delete pblockOrphan; delete pblockOrphan;
@ -2710,10 +2760,10 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth)
break; break;
CBlock block; CBlock block;
// check level 0: read from disk // check level 0: read from disk
if (!block.ReadFromDisk(pindex)) if (!ReadBlockFromDisk(block, pindex))
return error("VerifyDB() : *** block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
// check level 1: verify block validity // 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()); return error("VerifyDB() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
// check level 2: verify undo validity // check level 2: verify undo validity
if (nCheckLevel >= 2 && pindex) { if (nCheckLevel >= 2 && pindex) {
@ -2727,7 +2777,7 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth)
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks // 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) { if (nCheckLevel >= 3 && pindex == pindexState && (coins.GetCacheSize() + pcoinsTip->GetCacheSize()) <= 2*nCoinCacheSize + 32000) {
bool fClean = true; 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()); return error("VerifyDB() : *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
pindexState = pindex->pprev; pindexState = pindex->pprev;
if (!fClean) { if (!fClean) {
@ -2747,9 +2797,9 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth)
boost::this_thread::interruption_point(); boost::this_thread::interruption_point();
pindex = pindex->GetNextInMainChain(); pindex = pindex->GetNextInMainChain();
CBlock block; CBlock block;
if (!block.ReadFromDisk(pindex)) if (!ReadBlockFromDisk(block, pindex))
return error("VerifyDB() : *** block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, 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()); return error("VerifyDB() : *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
} }
} }
@ -2800,9 +2850,9 @@ bool InitBlockIndex() {
CValidationState state; CValidationState state;
if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.nTime)) if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.nTime))
return error("LoadBlockIndex() : FindBlockPos failed"); return error("LoadBlockIndex() : FindBlockPos failed");
if (!block.WriteToDisk(blockPos)) if (!WriteBlockToDisk(block, blockPos))
return error("LoadBlockIndex() : writing genesis block to disk failed"); 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"); return error("LoadBlockIndex() : genesis block not accepted");
} catch(std::runtime_error &e) { } catch(std::runtime_error &e) {
return error("LoadBlockIndex() : failed to initialize block database: %s", e.what()); return error("LoadBlockIndex() : failed to initialize block database: %s", e.what());
@ -2858,7 +2908,7 @@ void PrintBlockTree()
// print item // print item
CBlock block; CBlock block;
block.ReadFromDisk(pindex); ReadBlockFromDisk(block, pindex);
printf("%d (blk%05u.dat:0x%x) %s tx %"PRIszu"", printf("%d (blk%05u.dat:0x%x) %s tx %"PRIszu"",
pindex->nHeight, pindex->nHeight,
pindex->GetBlockPos().nFile, pindex->GetBlockPos().nPos, pindex->GetBlockPos().nFile, pindex->GetBlockPos().nPos,
@ -3082,7 +3132,7 @@ void static ProcessGetData(CNode* pfrom)
if (mi != mapBlockIndex.end()) if (mi != mapBlockIndex.end())
{ {
CBlock block; CBlock block;
block.ReadFromDisk((*mi).second); ReadBlockFromDisk(block, (*mi).second);
if (inv.type == MSG_BLOCK) if (inv.type == MSG_BLOCK)
pfrom->PushMessage("block", block); pfrom->PushMessage("block", block);
else // MSG_FILTERED_BLOCK) else // MSG_FILTERED_BLOCK)
@ -4404,7 +4454,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
indexDummy.nHeight = pindexPrev->nHeight + 1; indexDummy.nHeight = pindexPrev->nHeight + 1;
CCoinsViewCache viewNew(*pcoinsTip, true); CCoinsViewCache viewNew(*pcoinsTip, true);
CValidationState state; CValidationState state;
if (!pblock->ConnectBlock(state, &indexDummy, viewNew, true)) if (!ConnectBlock(*pblock, state, &indexDummy, viewNew, true))
throw std::runtime_error("CreateNewBlock() : ConnectBlock failed"); throw std::runtime_error("CreateNewBlock() : ConnectBlock failed");
} }

View File

@ -581,204 +581,33 @@ public:
}; };
class CBlock : public CBlockHeader
{
public:
// network and disk
std::vector<CTransaction> vtx;
// memory only /** Functions for disk access for blocks */
mutable std::vector<uint256> vMerkleTree; bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos);
bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos);
CBlock() bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex);
{
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<uint256> GetMerkleBranch(int nIndex) const
{
if (vMerkleTree.empty())
BuildMerkleTree();
std::vector<uint256> 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<uint256>& 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;
}
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)
{
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;
}
/** Functions for validating blocks and updating the block tree */
void print() const /** 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
printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu")\n", * will be true if no problems were found. Otherwise, the return value will be false in case
GetHash().ToString().c_str(), * of problems. Note that in any case, coins may be modified. */
nVersion, bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL);
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");
}
// 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);
/** Undo the effects of this block (with given index) on the UTXO set represented by coins. // Add this block to the block index, and if necessary, switch the active block chain to this
* In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos);
* 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);
// 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);
// 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);
};
// 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);

View File

@ -163,7 +163,7 @@ Value getblock(const Array& params, bool fHelp)
CBlock block; CBlock block;
CBlockIndex* pblockindex = mapBlockIndex[hash]; CBlockIndex* pblockindex = mapBlockIndex[hash];
block.ReadFromDisk(pblockindex); ReadBlockFromDisk(block, pblockindex);
if (!fVerbose) if (!fVerbose)
{ {

View File

@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(May15)
// After May 15'th, big blocks are OK: // After May 15'th, big blocks are OK:
forkingBlock.nTime = tMay15; // Invalidates PoW forkingBlock.nTime = tMay15; // Invalidates PoW
BOOST_CHECK(forkingBlock.CheckBlock(state, false, false)); BOOST_CHECK(CheckBlock(forkingBlock, state, false, false));
} }
SetMockTime(0); SetMockTime(0);

View File

@ -804,7 +804,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
} }
CBlock block; CBlock block;
block.ReadFromDisk(pindex); ReadBlockFromDisk(block, pindex);
BOOST_FOREACH(CTransaction& tx, block.vtx) BOOST_FOREACH(CTransaction& tx, block.vtx)
{ {
if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate)) if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate))