Skip to content

Commit

Permalink
Add native support for serializing char arrays without FLATDATA
Browse files Browse the repository at this point in the history
Support is added to serialize arrays of type char or unsigned char directly,
without any wrappers. All invocations of the FLATDATA wrappers that are
obsoleted by this are removed.

This includes a patch by Russell Yanofsky to make char casting type safe.

The serialization of CSubNet is changed to serialize a bool directly rather
than though FLATDATA. This makes the serialization independent of the size
of the bool type (and will use 1 byte everywhere).
  • Loading branch information
sipa authored and Bashkir committed Mar 2, 2019
1 parent 97221ba commit 865b761
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 26 deletions.
6 changes: 3 additions & 3 deletions src/addrdb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ bool SerializeDB(Stream& stream, const Data& data)
// Write and commit header, data
try {
CHashWriter hasher(SER_DISK, CLIENT_VERSION);
stream << FLATDATA(Params().MessageStart()) << data;
hasher << FLATDATA(Params().MessageStart()) << data;
stream << Params().MessageStart() << data;
hasher << Params().MessageStart() << data;
stream << hasher.GetHash();
} catch (const std::exception& e) {
return error("%s: Serialize or I/O error - %s", __func__, e.what());
Expand Down Expand Up @@ -66,7 +66,7 @@ bool DeserializeDB(Stream& stream, Data& data, bool fCheckSum = true)
CHashVerifier<Stream> verifier(&stream);
// de-serialize file header (network specific magic number) and ..
unsigned char pchMsgTmp[4];
verifier >> FLATDATA(pchMsgTmp);
verifier >> pchMsgTmp;
// ... verify the network matches ours
if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
return error("%s: Invalid network magic number", __func__);
Expand Down
8 changes: 4 additions & 4 deletions src/netaddress.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class CNetAddr

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(FLATDATA(ip));
READWRITE(ip);
}

friend class CSubNet;
Expand Down Expand Up @@ -131,8 +131,8 @@ class CSubNet
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(network);
READWRITE(FLATDATA(netmask));
READWRITE(FLATDATA(valid));
READWRITE(netmask);
READWRITE(valid);
}
};

Expand Down Expand Up @@ -166,7 +166,7 @@ class CService : public CNetAddr

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(FLATDATA(ip));
READWRITE(ip);
unsigned short portN = htons(port);
READWRITE(FLATDATA(portN));
if (ser_action.ForRead())
Expand Down
6 changes: 3 additions & 3 deletions src/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ class CMessageHeader
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(FLATDATA(pchMessageStart));
READWRITE(FLATDATA(pchCommand));
READWRITE(pchMessageStart);
READWRITE(pchCommand);
READWRITE(nMessageSize);
READWRITE(FLATDATA(pchChecksum));
READWRITE(pchChecksum);
}

char pchMessageStart[MESSAGE_START_SIZE];
Expand Down
10 changes: 10 additions & 0 deletions src/serialize.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ inline T* NCONST_PTR(const T* val)
return const_cast<T*>(val);
}

//! Safely convert odd char pointer types to standard ones.
inline char* CharCast(char* c) { return c; }
inline char* CharCast(unsigned char* c) { return (char*)c; }
inline const char* CharCast(const char* c) { return c; }
inline const char* CharCast(const unsigned char* c) { return (const char*)c; }

/*
* Lowest-level serialization and conversion.
* @note Sizes of these types are verified in the tests
Expand Down Expand Up @@ -182,6 +188,8 @@ template<typename Stream> inline void Serialize(Stream& s, int64_t a ) { ser_wri
template<typename Stream> inline void Serialize(Stream& s, uint64_t a) { ser_writedata64(s, a); }
template<typename Stream> inline void Serialize(Stream& s, float a ) { ser_writedata32(s, ser_float_to_uint32(a)); }
template<typename Stream> inline void Serialize(Stream& s, double a ) { ser_writedata64(s, ser_double_to_uint64(a)); }
template<typename Stream, int N> inline void Serialize(Stream& s, const char (&a)[N]) { s.write(a, N); }
template<typename Stream, int N> inline void Serialize(Stream& s, const unsigned char (&a)[N]) { s.write(CharCast(a), N); }

template<typename Stream> inline void Unserialize(Stream& s, char& a ) { a = ser_readdata8(s); } // TODO Get rid of bare char
template<typename Stream> inline void Unserialize(Stream& s, int8_t& a ) { a = ser_readdata8(s); }
Expand All @@ -194,6 +202,8 @@ template<typename Stream> inline void Unserialize(Stream& s, int64_t& a ) { a =
template<typename Stream> inline void Unserialize(Stream& s, uint64_t& a) { a = ser_readdata64(s); }
template<typename Stream> inline void Unserialize(Stream& s, float& a ) { a = ser_uint32_to_float(ser_readdata32(s)); }
template<typename Stream> inline void Unserialize(Stream& s, double& a ) { a = ser_uint64_to_double(ser_readdata64(s)); }
template<typename Stream, int N> inline void Unserialize(Stream& s, char (&a)[N]) { s.read(a, N); }
template<typename Stream, int N> inline void Unserialize(Stream& s, unsigned char (&a)[N]) { s.read(CharCast(a), N); }

template<typename Stream> inline void Serialize(Stream& s, bool a) { char f=a; ser_writedata8(s, f); }
template<typename Stream> inline void Unserialize(Stream& s, bool& a) { char f=ser_readdata8(s); a=f; }
Expand Down
6 changes: 3 additions & 3 deletions src/test/net_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class CAddrManCorrupted : public CAddrManSerializationMock
CDataStream AddrmanToStream(CAddrManSerializationMock& _addrman)
{
CDataStream ssPeersIn(SER_DISK, CLIENT_VERSION);
ssPeersIn << FLATDATA(Params().MessageStart());
ssPeersIn << Params().MessageStart();
ssPeersIn << _addrman;
std::string str = ssPeersIn.str();
std::vector<unsigned char> vchData(str.begin(), str.end());
Expand Down Expand Up @@ -110,7 +110,7 @@ BOOST_AUTO_TEST_CASE(caddrdb_read)
BOOST_CHECK(addrman1.size() == 0);
try {
unsigned char pchMsgTmp[4];
ssPeers1 >> FLATDATA(pchMsgTmp);
ssPeers1 >> pchMsgTmp;
ssPeers1 >> addrman1;
} catch (const std::exception& e) {
exceptionThrown = true;
Expand Down Expand Up @@ -142,7 +142,7 @@ BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
BOOST_CHECK(addrman1.size() == 0);
try {
unsigned char pchMsgTmp[4];
ssPeers1 >> FLATDATA(pchMsgTmp);
ssPeers1 >> pchMsgTmp;
ssPeers1 >> addrman1;
} catch (const std::exception& e) {
exceptionThrown = true;
Expand Down
16 changes: 10 additions & 6 deletions src/test/serialize_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,23 @@ class CSerializeMethodsTestSingle
int intval;
bool boolval;
std::string stringval;
const char* charstrval;
char charstrval[16];
CTransactionRef txval;
public:
CSerializeMethodsTestSingle() = default;
CSerializeMethodsTestSingle(int intvalin, bool boolvalin, std::string stringvalin, const char* charstrvalin, CTransaction txvalin) : intval(intvalin), boolval(boolvalin), stringval(std::move(stringvalin)), charstrval(charstrvalin), txval(MakeTransactionRef(txvalin)){}
CSerializeMethodsTestSingle(int intvalin, bool boolvalin, std::string stringvalin, const char* charstrvalin, CTransaction txvalin) : intval(intvalin), boolval(boolvalin), stringval(std::move(stringvalin)), txval(MakeTransactionRef(txvalin))
{
memcpy(charstrval, charstrvalin, sizeof(charstrval));
}

ADD_SERIALIZE_METHODS;

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(intval);
READWRITE(boolval);
READWRITE(stringval);
READWRITE(FLATDATA(charstrval));
READWRITE(charstrval);
READWRITE(txval);
}

Expand All @@ -53,7 +57,7 @@ class CSerializeMethodsTestMany : public CSerializeMethodsTestSingle

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(intval, boolval, stringval, FLATDATA(charstrval), txval);
READWRITE(intval, boolval, stringval, charstrval, txval);
}
};

Expand Down Expand Up @@ -344,7 +348,7 @@ BOOST_AUTO_TEST_CASE(class_methods)
int intval(100);
bool boolval(true);
std::string stringval("testing");
const char* charstrval("testing charstr");
const char charstrval[16] = "testing charstr";
CMutableTransaction txval;
CSerializeMethodsTestSingle methodtest1(intval, boolval, stringval, charstrval, txval);
CSerializeMethodsTestMany methodtest2(intval, boolval, stringval, charstrval, txval);
Expand All @@ -360,7 +364,7 @@ BOOST_AUTO_TEST_CASE(class_methods)
BOOST_CHECK(methodtest2 == methodtest3);
BOOST_CHECK(methodtest3 == methodtest4);

CDataStream ss2(SER_DISK, PROTOCOL_VERSION, intval, boolval, stringval, FLATDATA(charstrval), txval);
CDataStream ss2(SER_DISK, PROTOCOL_VERSION, intval, boolval, stringval, charstrval, txval);
ss2 >> methodtest3;
BOOST_CHECK(methodtest3 == methodtest4);
}
Expand Down
8 changes: 4 additions & 4 deletions src/test/streams_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,16 @@ BOOST_AUTO_TEST_CASE(streams_vector_writer)
BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));
vch.clear();

CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, FLATDATA(bytes));
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, bytes);
BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, FLATDATA(bytes));
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, bytes);
BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));
vch.clear();

vch.resize(4, 8);
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, FLATDATA(bytes), b);
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, bytes, b);
BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, FLATDATA(bytes), b);
CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, bytes, b);
BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));
vch.clear();
}
Expand Down
6 changes: 3 additions & 3 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1077,7 +1077,7 @@ static bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMes

// Write index header
unsigned int nSize = GetSerializeSize(fileout, block);
fileout << FLATDATA(messageStart) << nSize;
fileout << messageStart << nSize;

// Write block
long fileOutPos = ftell(fileout.Get());
Expand Down Expand Up @@ -1441,7 +1441,7 @@ bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint

// Write index header
unsigned int nSize = GetSerializeSize(fileout, blockundo);
fileout << FLATDATA(messageStart) << nSize;
fileout << messageStart << nSize;

// Write undo data
long fileOutPos = ftell(fileout.Get());
Expand Down Expand Up @@ -4299,7 +4299,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
unsigned char buf[CMessageHeader::MESSAGE_START_SIZE];
blkdat.FindByte(chainparams.MessageStart()[0]);
nRewind = blkdat.GetPos()+1;
blkdat >> FLATDATA(buf);
blkdat >> buf;
if (memcmp(buf, chainparams.MessageStart(), CMessageHeader::MESSAGE_START_SIZE))
continue;
// read size
Expand Down

0 comments on commit 865b761

Please sign in to comment.