Skip to content

Commit fbb2b51

Browse files
committed
merge bitcoin#26909: prevent peers.dat corruptions by only serializing once
1 parent 4a52099 commit fbb2b51

File tree

4 files changed

+42
-6
lines changed

4 files changed

+42
-6
lines changed

src/addrdb.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,9 @@ bool SerializeDB(Stream& stream, const Data& data)
3333
{
3434
// Write and commit header, data
3535
try {
36-
CHashWriter hasher(stream.GetType(), stream.GetVersion());
37-
stream << Params().MessageStart() << data;
38-
hasher << Params().MessageStart() << data;
39-
stream << hasher.GetHash();
36+
HashedSourceWriter hashwriter{stream};
37+
hashwriter << Params().MessageStart() << data;
38+
stream << hashwriter.GetHash();
4039
} catch (const std::exception& e) {
4140
return error("%s: Serialize or I/O error - %s", __func__, e.what());
4241
}

src/addrman.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,8 +1168,7 @@ void AddrMan::Unserialize(Stream& s_)
11681168
}
11691169

11701170
// explicit instantiation
1171-
template void AddrMan::Serialize(CHashWriter& s) const;
1172-
template void AddrMan::Serialize(CAutoFile& s) const;
1171+
template void AddrMan::Serialize(HashedSourceWriter<CAutoFile>& s) const;
11731172
template void AddrMan::Serialize(CDataStream& s) const;
11741173
template void AddrMan::Unserialize(CAutoFile& s);
11751174
template void AddrMan::Unserialize(CHashVerifier<CAutoFile>& s);

src/hash.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,30 @@ class CHashVerifier : public CHashWriter
201201
}
202202
};
203203

204+
/** Writes data to an underlying source stream, while hashing the written data. */
205+
template <typename Source>
206+
class HashedSourceWriter : public CHashWriter
207+
{
208+
private:
209+
Source& m_source;
210+
211+
public:
212+
explicit HashedSourceWriter(Source& source LIFETIMEBOUND) : CHashWriter{source.GetType(), source.GetVersion()}, m_source{source} {}
213+
214+
void write(Span<const std::byte> src)
215+
{
216+
m_source.write(src);
217+
CHashWriter::write(src);
218+
}
219+
220+
template <typename T>
221+
HashedSourceWriter& operator<<(const T& obj)
222+
{
223+
::Serialize(*this, obj);
224+
return *this;
225+
}
226+
};
227+
204228
/** Compute the 256-bit hash of an object's serialization. */
205229
template<typename T>
206230
uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)

src/test/streams_tests.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,4 +437,18 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand)
437437
fs::remove("streams_test_tmp");
438438
}
439439

440+
BOOST_AUTO_TEST_CASE(streams_hashed)
441+
{
442+
CDataStream stream(SER_NETWORK, INIT_PROTO_VERSION);
443+
HashedSourceWriter hash_writer{stream};
444+
const std::string data{"bitcoin"};
445+
hash_writer << data;
446+
447+
CHashVerifier hash_verifier{&stream};
448+
std::string result;
449+
hash_verifier >> result;
450+
BOOST_CHECK_EQUAL(data, result);
451+
BOOST_CHECK_EQUAL(hash_writer.GetHash(), hash_verifier.GetHash());
452+
}
453+
440454
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)