Skip to content

Commit

Permalink
Add checksums to undo data
Browse files Browse the repository at this point in the history
This should be compatible with older code that didn't write checksums.
  • Loading branch information
sipa committed Jan 3, 2013
1 parent 2cbd71d commit 8539361
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 16 deletions.
22 changes: 7 additions & 15 deletions src/main.cpp
Expand Up @@ -1474,19 +1474,11 @@ bool CBlock::DisconnectBlock(CBlockIndex *pindex, CCoinsViewCache &view, bool *p
bool fClean = true;

CBlockUndo blockUndo;
{
CDiskBlockPos pos = pindex->GetUndoPos();
if (pos.IsNull())
return error("DisconnectBlock() : no undo data available");
CAutoFile fileUndo(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION);
if (!fileUndo)
return error("DisconnectBlock() : cannot open undo file");
try {
fileUndo >> blockUndo;
} catch(std::exception &e) {
return error("DisconnectBlock() : deserialize or I/O error reading udno data");
}
}
CDiskBlockPos pos = pindex->GetUndoPos();
if (pos.IsNull())
return error("DisconnectBlock() : no undo data available");
if (!blockUndo.ReadFromDisk(pos, pindex->pprev->GetBlockHash()))
return error("DisconnectBlock() : failure reading undo data");

if (blockUndo.vtxundo.size() + 1 != vtx.size())
return error("DisconnectBlock() : block and undo data inconsistent");
Expand Down Expand Up @@ -1670,9 +1662,9 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
{
if (pindex->GetUndoPos().IsNull()) {
CDiskBlockPos pos;
if (!FindUndoPos(pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 8))
if (!FindUndoPos(pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40))
return error("ConnectBlock() : FindUndoPos failed");
if (!blockundo.WriteToDisk(pos))
if (!blockundo.WriteToDisk(pos, pindex->pprev->GetBlockHash()))
return error("ConnectBlock() : CBlockUndo::WriteToDisk failed");

// update nUndoPos in block index
Expand Down
46 changes: 45 additions & 1 deletion src/main.h
Expand Up @@ -746,7 +746,7 @@ class CBlockUndo
READWRITE(vtxundo);
)

bool WriteToDisk(CDiskBlockPos &pos)
bool WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock)
{
// Open history file to append
CAutoFile fileout = CAutoFile(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
Expand All @@ -764,13 +764,57 @@ class CBlockUndo
pos.nPos = (unsigned int)fileOutPos;
fileout << *this;

// calculate & write checksum
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
hasher << hashBlock;
hasher << *this;
fileout << hasher.GetHash();

// Flush stdio buffers and commit to disk before returning
fflush(fileout);
if (!IsInitialBlockDownload())
FileCommit(fileout);

return true;
}

bool ReadFromDisk(const CDiskBlockPos &pos, const uint256 &hashBlock)
{
// Open history file to read
CAutoFile filein = CAutoFile(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION);
if (!filein)
return error("CBlockUndo::ReadFromDisk() : OpenBlockFile failed");

// Read block
uint256 hashChecksum;
try {
filein >> *this;
}
catch (std::exception &e) {
return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__);
}

// for compatibility with pre-release code that didn't write checksums to undo data
// TODO: replace by a simply 'filein >> hashChecksum' in the above try block
try {
filein >> hashChecksum;
} catch (std::exception &e) {
hashChecksum = 0;
}
uint32_t hashInit = hashChecksum.Get64(0) & 0xFFFFFFFFUL;
if (hashChecksum == 0 || memcmp(&hashInit, pchMessageStart, 4) == 0)
return true;

// Verify checksum
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
hasher << hashBlock;
hasher << *this;
if (hashChecksum != hasher.GetHash())
return error("CBlockUndo::ReadFromDisk() : checksum mismatch");

return true;
}

};

/** pruned version of CTransaction: only retains metadata and unspent transaction outputs
Expand Down

0 comments on commit 8539361

Please sign in to comment.