diff --git a/src/addrdb.cpp b/src/addrdb.cpp index 7f85c1658..12d7af251 100644 --- a/src/addrdb.cpp +++ b/src/addrdb.cpp @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2018 The BitZeny Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -23,8 +24,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()); @@ -67,7 +68,7 @@ bool DeserializeDB(Stream& stream, Data& data, bool fCheckSum = true) CHashVerifier 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__); diff --git a/src/compressor.h b/src/compressor.h index 015911484..7e690b4e6 100644 --- a/src/compressor.h +++ b/src/compressor.h @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2018 The BitZeny Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,6 +10,7 @@ #include "primitives/transaction.h" #include "script/script.h" #include "serialize.h" +#include "span.h" class CKeyID; class CPubKey; @@ -59,12 +61,12 @@ class CScriptCompressor void Serialize(Stream &s) const { std::vector compr; if (Compress(compr)) { - s << CFlatData(compr); + s << MakeSpan(compr); return; } unsigned int nSize = script.size() + nSpecialScripts; s << VARINT(nSize); - s << CFlatData(script); + s << MakeSpan(script); } template @@ -73,7 +75,7 @@ class CScriptCompressor s >> VARINT(nSize); if (nSize < nSpecialScripts) { std::vector vch(GetSpecialSize(nSize), 0x00); - s >> REF(CFlatData(vch)); + s >> REF(MakeSpan(vch)); Decompress(nSize, vch); return; } @@ -84,7 +86,7 @@ class CScriptCompressor s.ignore(nSize); } else { script.resize(nSize); - s >> REF(CFlatData(script)); + s >> REF(MakeSpan(script)); } } }; diff --git a/src/netaddress.h b/src/netaddress.h index 57ce897db..dd080f957 100644 --- a/src/netaddress.h +++ b/src/netaddress.h @@ -1,4 +1,5 @@ // Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2018 The BitZeny Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -11,6 +12,7 @@ #include "compat.h" #include "serialize.h" +#include "span.h" #include #include @@ -93,7 +95,7 @@ class CNetAddr template inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(FLATDATA(ip)); + READWRITE(ip); } friend class CSubNet; @@ -131,8 +133,8 @@ class CSubNet template inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(network); - READWRITE(FLATDATA(netmask)); - READWRITE(FLATDATA(valid)); + READWRITE(netmask); + READWRITE(valid); } }; @@ -166,11 +168,14 @@ class CService : public CNetAddr template inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(FLATDATA(ip)); + READWRITE(ip); + + // TODO: introduce native support for BE serialization in serialize.h unsigned short portN = htons(port); - READWRITE(FLATDATA(portN)); - if (ser_action.ForRead()) + READWRITE(Span((unsigned char*)&portN, 2)); + if (ser_action.ForRead()) { port = ntohs(portN); + } } }; diff --git a/src/protocol.h b/src/protocol.h index 7890bb627..d37e5f1e6 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2018 The BitZeny Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -50,10 +51,10 @@ class CMessageHeader template 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]; diff --git a/src/serialize.h b/src/serialize.h index 8b86a07a7..aaba4aad2 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2018 The BitZeny Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -22,6 +23,7 @@ #include #include "prevector.h" +#include "span.h" static const unsigned int MAX_SIZE = 0x02000000; @@ -41,7 +43,7 @@ constexpr deserialize_type deserialize {}; /** * Used to bypass the rule against non-const reference to temporary - * where it makes sense with wrappers such as CFlatData or CTxDB + * where it makes sense with wrappers. */ template inline T& REF(const T& val) @@ -59,6 +61,12 @@ inline T* NCONST_PTR(const T* val) return const_cast(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 @@ -178,6 +186,10 @@ template inline void Serialize(Stream& s, int64_t a ) { ser_wri template inline void Serialize(Stream& s, uint64_t a) { ser_writedata64(s, a); } template inline void Serialize(Stream& s, float a ) { ser_writedata32(s, ser_float_to_uint32(a)); } template inline void Serialize(Stream& s, double a ) { ser_writedata64(s, ser_double_to_uint64(a)); } +template inline void Serialize(Stream& s, const char (&a)[N]) { s.write(a, N); } +template inline void Serialize(Stream& s, const unsigned char (&a)[N]) { s.write(CharCast(a), N); } +template inline void Serialize(Stream& s, const Span& span) { s.write(CharCast(span.data()), span.size()); } +template inline void Serialize(Stream& s, const Span& span) { s.write(CharCast(span.data()), span.size()); } template inline void Unserialize(Stream& s, char& a ) { a = ser_readdata8(s); } // TODO Get rid of bare char template inline void Unserialize(Stream& s, int8_t& a ) { a = ser_readdata8(s); } @@ -190,6 +202,9 @@ template inline void Unserialize(Stream& s, int64_t& a ) { a = template inline void Unserialize(Stream& s, uint64_t& a) { a = ser_readdata64(s); } template inline void Unserialize(Stream& s, float& a ) { a = ser_uint32_to_float(ser_readdata32(s)); } template inline void Unserialize(Stream& s, double& a ) { a = ser_uint64_to_double(ser_readdata64(s)); } +template inline void Unserialize(Stream& s, char (&a)[N]) { s.read(a, N); } +template inline void Unserialize(Stream& s, unsigned char (&a)[N]) { s.read(CharCast(a), N); } +template inline void Unserialize(Stream& s, Span& span) { s.read(CharCast(span.data()), span.size()); } template inline void Serialize(Stream& s, bool a) { char f=a; ser_writedata8(s, f); } template inline void Unserialize(Stream& s, bool& a) { char f=ser_readdata8(s); a=f; } @@ -351,51 +366,10 @@ I ReadVarInt(Stream& is) } } -#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj))) #define VARINT(obj) REF(WrapVarInt(REF(obj))) #define COMPACTSIZE(obj) REF(CCompactSize(REF(obj))) #define LIMITED_STRING(obj,n) REF(LimitedString< n >(REF(obj))) -/** - * Wrapper for serializing arrays and POD. - */ -class CFlatData -{ -protected: - char* pbegin; - char* pend; -public: - CFlatData(void* pbeginIn, void* pendIn) : pbegin((char*)pbeginIn), pend((char*)pendIn) { } - template - explicit CFlatData(std::vector &v) - { - pbegin = (char*)v.data(); - pend = (char*)(v.data() + v.size()); - } - template - explicit CFlatData(prevector &v) - { - pbegin = (char*)v.data(); - pend = (char*)(v.data() + v.size()); - } - char* begin() { return pbegin; } - const char* begin() const { return pbegin; } - char* end() { return pend; } - const char* end() const { return pend; } - - template - void Serialize(Stream& s) const - { - s.write(pbegin, pend - pbegin); - } - - template - void Unserialize(Stream& s) - { - s.read(pbegin, pend - pbegin); - } -}; - template class CVarInt { diff --git a/src/span.h b/src/span.h new file mode 100644 index 000000000..63b963e28 --- /dev/null +++ b/src/span.h @@ -0,0 +1,62 @@ +// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018 The BitZeny Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_SPAN_H +#define BITCOIN_SPAN_H + +#include +#include +#include + +/** A Span is an object that can refer to a contiguous sequence of objects. + * + * It implements a subset of C++20's std::span. + */ +template +class Span +{ + C* m_data; + std::ptrdiff_t m_size; + +public: + constexpr Span() noexcept : m_data(nullptr), m_size(0) {} + constexpr Span(C* data, std::ptrdiff_t size) noexcept : m_data(data), m_size(size) {} + constexpr Span(C* data, C* end) noexcept : m_data(data), m_size(end - data) {} + + constexpr C* data() const noexcept { return m_data; } + constexpr C* begin() const noexcept { return m_data; } + constexpr C* end() const noexcept { return m_data + m_size; } + constexpr std::ptrdiff_t size() const noexcept { return m_size; } + constexpr C& operator[](std::ptrdiff_t pos) const noexcept { return m_data[pos]; } + + constexpr Span subspan(std::ptrdiff_t offset) const noexcept { return Span(m_data + offset, m_size - offset); } + constexpr Span subspan(std::ptrdiff_t offset, std::ptrdiff_t count) const noexcept { return Span(m_data + offset, count); } + constexpr Span first(std::ptrdiff_t count) const noexcept { return Span(m_data, count); } + constexpr Span last(std::ptrdiff_t count) const noexcept { return Span(m_data + m_size - count, count); } + + friend constexpr bool operator==(const Span& a, const Span& b) noexcept { return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin()); } + friend constexpr bool operator!=(const Span& a, const Span& b) noexcept { return !(a == b); } + friend constexpr bool operator<(const Span& a, const Span& b) noexcept { return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); } + friend constexpr bool operator<=(const Span& a, const Span& b) noexcept { return !(b < a); } + friend constexpr bool operator>(const Span& a, const Span& b) noexcept { return (b < a); } + friend constexpr bool operator>=(const Span& a, const Span& b) noexcept { return !(a < b); } +}; + +/** Create a span to a container exposing data() and size(). + * + * This correctly deals with constness: the returned Span's element type will be + * whatever data() returns a pointer to. If either the passed container is const, + * or its element type is const, the resulting span will have a const element type. + * + * std::span will have a constructor that implements this functionality directly. + */ +template +constexpr Span MakeSpan(A (&a)[N]) { return Span(a, N); } + +template +constexpr Span().data())>::type> MakeSpan(V& v) { return Span().data())>::type>(v.data(), v.size()); } + +#endif + diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index 31b05d868..f638a16d7 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -1,4 +1,5 @@ // Copyright (c) 2012-2016 The Bitcoin Core developers +// Copyright (c) 2018 The BitZeny Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "addrman.h" @@ -64,7 +65,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 vchData(str.begin(), str.end()); @@ -110,7 +111,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; @@ -142,7 +143,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; diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp index 9661a6651..fa42a0071 100644 --- a/src/test/serialize_tests.cpp +++ b/src/test/serialize_tests.cpp @@ -1,4 +1,5 @@ // Copyright (c) 2012-2016 The Bitcoin Core developers +// Copyright (c) 2018 The BitZeny Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -19,11 +20,15 @@ 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 @@ -31,7 +36,7 @@ class CSerializeMethodsTestSingle READWRITE(intval); READWRITE(boolval); READWRITE(stringval); - READWRITE(FLATDATA(charstrval)); + READWRITE(charstrval); READWRITE(txval); } @@ -53,7 +58,7 @@ class CSerializeMethodsTestMany : public CSerializeMethodsTestSingle template inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITEMANY(intval, boolval, stringval, FLATDATA(charstrval), txval); + READWRITEMANY(intval, boolval, stringval, charstrval, txval); } }; @@ -344,7 +349,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); @@ -360,7 +365,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); } diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp index af2a152aa..3e337e30d 100644 --- a/src/test/streams_tests.cpp +++ b/src/test/streams_tests.cpp @@ -1,4 +1,5 @@ // Copyright (c) 2012-2016 The Bitcoin Core developers +// Copyright (c) 2018 The BitZeny Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -57,16 +58,16 @@ BOOST_AUTO_TEST_CASE(streams_vector_writer) BOOST_CHECK((vch == std::vector{{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{{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{{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{{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{{8, 8, 1, 3, 4, 5, 6, 2}})); vch.clear(); } diff --git a/src/validation.cpp b/src/validation.cpp index 337fecb37..959513adf 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2018 The BitZeny Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -993,7 +994,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()); @@ -1356,7 +1357,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()); @@ -4023,7 +4024,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