aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPieter Wuille <[email protected]>2017-04-25 11:29:14 -0700
committerPieter Wuille <[email protected]>2017-05-26 13:24:25 -0700
commite484652fc36ef7135cf08ad380ea7142b6cbadc0 (patch)
tree45085d6af75bc045ae486a226c575fef59fd6b22 /src
parenterror() in disconnect for disk corruption, not inconsistency (diff)
downloaddiscoin-e484652fc36ef7135cf08ad380ea7142b6cbadc0.tar.xz
discoin-e484652fc36ef7135cf08ad380ea7142b6cbadc0.zip
Introduce CHashVerifier to hash read data
This is necessary later, when we drop the nVersion field from the undo data. At that point deserializing and reserializing the data won't roundtrip anymore, and thus that approach can't be used to verify checksums anymore. With this CHashVerifier approach, we can deserialize while hashing the exact serialized form that was used. This is both more efficient and more correct in that case.
Diffstat (limited to 'src')
-rw-r--r--src/hash.h35
-rw-r--r--src/validation.cpp9
2 files changed, 39 insertions, 5 deletions
diff --git a/src/hash.h b/src/hash.h
index eacb8f04f..b8de19c0f 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -160,6 +160,41 @@ public:
}
};
+/** Reads data from an underlying stream, while hashing the read data. */
+template<typename Source>
+class CHashVerifier : public CHashWriter
+{
+private:
+ Source* source;
+
+public:
+ CHashVerifier(Source* source_) : CHashWriter(source_->GetType(), source_->GetVersion()), source(source_) {}
+
+ void read(char* pch, size_t nSize)
+ {
+ source->read(pch, nSize);
+ this->write(pch, nSize);
+ }
+
+ void ignore(size_t nSize)
+ {
+ char data[1024];
+ while (nSize > 0) {
+ size_t now = std::min<size_t>(nSize, 1024);
+ read(data, now);
+ nSize -= now;
+ }
+ }
+
+ template<typename T>
+ CHashVerifier<Source>& operator>>(T& obj)
+ {
+ // Unserialize from this stream
+ ::Unserialize(*this, obj);
+ return (*this);
+ }
+};
+
/** Compute the 256-bit hash of an object's serialization. */
template<typename T>
uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
diff --git a/src/validation.cpp b/src/validation.cpp
index ed94be5c2..fc7e129c0 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -1210,8 +1210,10 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uin
// Read block
uint256 hashChecksum;
+ CHashVerifier<CAutoFile> verifier(&filein); // We need a CHashVerifier as reserializing may lose data
try {
- filein >> blockundo;
+ verifier << hashBlock;
+ verifier >> blockundo;
filein >> hashChecksum;
}
catch (const std::exception& e) {
@@ -1219,10 +1221,7 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uin
}
// Verify checksum
- CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
- hasher << hashBlock;
- hasher << blockundo;
- if (hashChecksum != hasher.GetHash())
+ if (hashChecksum != verifier.GetHash())
return error("%s: Checksum mismatch", __func__);
return true;