Browse Source

Add checksums to undo data

This should be compatible with older code that didn't write checksums.
tags/v0.15.1
Pieter Wuille 8 years ago
parent
commit
8539361e66
2 changed files with 52 additions and 16 deletions
  1. 7
    15
      src/main.cpp
  2. 45
    1
      src/main.h

+ 7
- 15
src/main.cpp View File

@@ -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");
@@ -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

+ 45
- 1
src/main.h View File

@@ -746,7 +746,7 @@ public:
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);
@@ -764,6 +764,12 @@ public:
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())
@@ -771,6 +777,44 @@ public:

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

Loading…
Cancel
Save