From 08e4497c6e3b3f434c0bb255c3942648f153fe66 Mon Sep 17 00:00:00 2001 From: Lee Clagett Date: Sun, 24 Jan 2021 07:42:57 +0000 Subject: [PATCH] Improve cryptonote (block and tx) binary read performance --- contrib/epee/include/span.h | 8 +- .../blockchain_blackball.cpp | 4 +- src/cryptonote_basic/cryptonote_basic.h | 20 ++--- .../cryptonote_format_utils.cpp | 60 ++++--------- .../cryptonote_format_utils.h | 4 +- src/cryptonote_basic/tx_extra.h | 9 +- src/device_trezor/trezor/protocol.hpp | 4 +- src/ringct/rctTypes.h | 8 +- src/rpc/rpc_payment.cpp | 5 +- src/serialization/binary_archive.h | 90 ++++++++++--------- src/serialization/binary_utils.h | 3 +- src/serialization/container.h | 10 +-- src/serialization/crypto.h | 6 +- src/serialization/debug_archive.h | 1 + src/serialization/difficulty_type.h | 8 +- src/serialization/json_archive.h | 7 +- src/serialization/pair.h | 12 +-- src/serialization/serialization.h | 36 ++++---- src/serialization/string.h | 2 +- src/serialization/variant.h | 8 +- src/wallet/message_store.cpp | 16 +--- src/wallet/wallet2.cpp | 27 ++---- src/wallet/wallet_rpc_server.cpp | 3 +- tests/core_tests/chaingen.h | 12 +-- tests/fuzz/bulletproof.cpp | 4 +- tests/fuzz/cold-outputs.cpp | 5 +- tests/fuzz/cold-transaction.cpp | 5 +- tests/unit_tests/serialization.cpp | 12 ++- tests/unit_tests/test_tx_utils.cpp | 70 +++++++++++++++ 29 files changed, 229 insertions(+), 230 deletions(-) diff --git a/contrib/epee/include/span.h b/contrib/epee/include/span.h index b355c960a..26861f994 100644 --- a/contrib/epee/include/span.h +++ b/contrib/epee/include/span.h @@ -31,7 +31,6 @@ #include #include #include -#include #include namespace epee @@ -167,10 +166,11 @@ namespace epee } //! make a span from a std::string - template - span strspan(const std::string &s) noexcept + template + span strspan(const U&s) noexcept { - static_assert(std::is_same() || std::is_same() || std::is_same() || std::is_same(), "Unexpected type"); + static_assert(std::is_same(), "unexpected source type"); + static_assert(std::is_same() || std::is_same() || std::is_same() || std::is_same(), "Unexpected destination type"); return {reinterpret_cast(s.data()), s.size()}; } } diff --git a/src/blockchain_utilities/blockchain_blackball.cpp b/src/blockchain_utilities/blockchain_blackball.cpp index 18a37434c..d53251fd3 100644 --- a/src/blockchain_utilities/blockchain_blackball.cpp +++ b/src/blockchain_utilities/blockchain_blackball.cpp @@ -388,9 +388,7 @@ static bool for_all_transactions(const std::string &filename, uint64_t &start_id cryptonote::transaction_prefix tx; blobdata bd; bd.assign(reinterpret_cast(v.mv_data), v.mv_size); - std::stringstream ss; - ss << bd; - binary_archive ba(ss); + binary_archive ba{epee::strspan(bd)}; bool r = do_serialize(ba, tx); CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob"); diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h index c70ae1df1..6394a7071 100644 --- a/src/cryptonote_basic/cryptonote_basic.h +++ b/src/cryptonote_basic/cryptonote_basic.h @@ -152,10 +152,6 @@ namespace cryptonote }; - template static inline unsigned int getpos(T &ar) { return 0; } - template<> inline unsigned int getpos(binary_archive &ar) { return ar.stream().tellp(); } - template<> inline unsigned int getpos(binary_archive &ar) { return ar.stream().tellg(); } - class transaction_prefix { @@ -236,17 +232,17 @@ namespace cryptonote set_blob_size_valid(false); } - const unsigned int start_pos = getpos(ar); + const auto start_pos = ar.getpos(); FIELDS(*static_cast(this)) if (std::is_same, binary_archive>()) - prefix_size = getpos(ar) - start_pos; + prefix_size = ar.getpos() - start_pos; if (version == 1) { if (std::is_same, binary_archive>()) - unprunable_size = getpos(ar) - start_pos; + unprunable_size = ar.getpos() - start_pos; ar.tag("signatures"); ar.begin_array(); @@ -284,11 +280,11 @@ namespace cryptonote { ar.begin_object(); bool r = rct_signatures.serialize_rctsig_base(ar, vin.size(), vout.size()); - if (!r || !ar.stream().good()) return false; + if (!r || !ar.good()) return false; ar.end_object(); if (std::is_same, binary_archive>()) - unprunable_size = getpos(ar) - start_pos; + unprunable_size = ar.getpos() - start_pos; if (!pruned && rct_signatures.type != rct::RCTTypeNull) { @@ -296,7 +292,7 @@ namespace cryptonote ar.begin_object(); r = rct_signatures.p.serialize_rctsig_prunable(ar, rct_signatures.type, vin.size(), vout.size(), vin.size() > 0 && vin[0].type() == typeid(txin_to_key) ? boost::get(vin[0]).key_offsets.size() - 1 : 0); - if (!r || !ar.stream().good()) return false; + if (!r || !ar.good()) return false; ar.end_object(); } } @@ -320,13 +316,13 @@ namespace cryptonote { ar.begin_object(); bool r = rct_signatures.serialize_rctsig_base(ar, vin.size(), vout.size()); - if (!r || !ar.stream().good()) return false; + if (!r || !ar.good()) return false; ar.end_object(); } } if (!typename Archive::is_saving()) pruned = true; - return ar.stream().good(); + return ar.good(); } private: diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index b0c4a25d8..5cd40ce79 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -211,9 +211,7 @@ namespace cryptonote //--------------------------------------------------------------- bool parse_and_validate_tx_from_blob(const blobdata_ref& tx_blob, transaction& tx) { - std::stringstream ss; - ss << tx_blob; - binary_archive ba(ss); + binary_archive ba{epee::strspan(tx_blob)}; bool r = ::serialization::serialize(ba, tx); CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob"); CHECK_AND_ASSERT_MES(expand_transaction_1(tx, false), false, "Failed to expand transaction data"); @@ -224,9 +222,7 @@ namespace cryptonote //--------------------------------------------------------------- bool parse_and_validate_tx_base_from_blob(const blobdata_ref& tx_blob, transaction& tx) { - std::stringstream ss; - ss << tx_blob; - binary_archive ba(ss); + binary_archive ba{epee::strspan(tx_blob)}; bool r = tx.serialize_base(ba); CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob"); CHECK_AND_ASSERT_MES(expand_transaction_1(tx, true), false, "Failed to expand transaction data"); @@ -236,9 +232,7 @@ namespace cryptonote //--------------------------------------------------------------- bool parse_and_validate_tx_prefix_from_blob(const blobdata_ref& tx_blob, transaction_prefix& tx) { - std::stringstream ss; - ss << tx_blob; - binary_archive ba(ss); + binary_archive ba{epee::strspan(tx_blob)}; bool r = ::serialization::serialize_noeof(ba, tx); CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction prefix from blob"); return true; @@ -246,9 +240,7 @@ namespace cryptonote //--------------------------------------------------------------- bool parse_and_validate_tx_from_blob(const blobdata_ref& tx_blob, transaction& tx, crypto::hash& tx_hash) { - std::stringstream ss; - ss << tx_blob; - binary_archive ba(ss); + binary_archive ba{epee::strspan(tx_blob)}; bool r = ::serialization::serialize(ba, tx); CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob"); CHECK_AND_ASSERT_MES(expand_transaction_1(tx, false), false, "Failed to expand transaction data"); @@ -532,22 +524,15 @@ namespace cryptonote if(tx_extra.empty()) return true; - std::string extra_str(reinterpret_cast(tx_extra.data()), tx_extra.size()); - std::istringstream iss(extra_str); - binary_archive ar(iss); + binary_archive ar{epee::to_span(tx_extra)}; - bool eof = false; - while (!eof) + do { tx_extra_field field; bool r = ::do_serialize(ar, field); CHECK_AND_NO_ASSERT_MES_L1(r, false, "failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast(tx_extra.data()), tx_extra.size()))); tx_extra_fields.push_back(field); - - std::ios_base::iostate state = iss.rdstate(); - eof = (EOF == iss.peek()); - iss.clear(state); - } + } while (!ar.eof()); CHECK_AND_NO_ASSERT_MES_L1(::serialization::check_stream_state(ar), false, "failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast(tx_extra.data()), tx_extra.size()))); return true; @@ -578,13 +563,10 @@ namespace cryptonote return true; } - std::string extra_str(reinterpret_cast(tx_extra.data()), tx_extra.size()); - std::istringstream iss(extra_str); - binary_archive ar(iss); + binary_archive ar{epee::to_span(tx_extra)}; - bool eof = false; size_t processed = 0; - while (!eof) + do { tx_extra_field field; bool r = ::do_serialize(ar, field); @@ -596,12 +578,8 @@ namespace cryptonote break; } tx_extra_fields.push_back(field); - processed = iss.tellg(); - - std::ios_base::iostate state = iss.rdstate(); - eof = (EOF == iss.peek()); - iss.clear(state); - } + processed = ar.getpos(); + } while (!ar.eof()); if (!::serialization::check_stream_state(ar)) { MWARNING("failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast(tx_extra.data()), tx_extra.size()))); @@ -752,24 +730,18 @@ namespace cryptonote if (tx_extra.empty()) return true; std::string extra_str(reinterpret_cast(tx_extra.data()), tx_extra.size()); - std::istringstream iss(extra_str); - binary_archive ar(iss); + binary_archive ar{epee::strspan(extra_str)}; std::ostringstream oss; binary_archive newar(oss); - bool eof = false; - while (!eof) + do { tx_extra_field field; bool r = ::do_serialize(ar, field); CHECK_AND_NO_ASSERT_MES_L1(r, false, "failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast(tx_extra.data()), tx_extra.size()))); if (field.type() != type) ::do_serialize(newar, field); - - std::ios_base::iostate state = iss.rdstate(); - eof = (EOF == iss.peek()); - iss.clear(state); - } + } while (!ar.eof()); CHECK_AND_NO_ASSERT_MES_L1(::serialization::check_stream_state(ar), false, "failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast(tx_extra.data()), tx_extra.size()))); tx_extra.clear(); std::string s = oss.str(); @@ -1357,9 +1329,7 @@ namespace cryptonote //--------------------------------------------------------------- bool parse_and_validate_block_from_blob(const blobdata_ref& b_blob, block& b, crypto::hash *block_hash) { - std::stringstream ss; - ss << b_blob; - binary_archive ba(ss); + binary_archive ba{epee::strspan(b_blob)}; bool r = ::serialization::serialize(ba, b); CHECK_AND_ASSERT_MES(r, false, "Failed to parse block from blob"); b.invalidate_hashes(); diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h index b311bd2b2..3fe4c44e7 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.h +++ b/src/cryptonote_basic/cryptonote_format_utils.h @@ -148,9 +148,7 @@ namespace cryptonote template bool t_serializable_object_from_blob(t_object& to, const blobdata& b_blob) { - std::stringstream ss; - ss << b_blob; - binary_archive ba(ss); + binary_archive ba{epee::strspan(b_blob)}; bool r = ::serialization::serialize(ba, to); return r; } diff --git a/src/cryptonote_basic/tx_extra.h b/src/cryptonote_basic/tx_extra.h index 50f2e1438..76efc22d3 100644 --- a/src/cryptonote_basic/tx_extra.h +++ b/src/cryptonote_basic/tx_extra.h @@ -57,11 +57,7 @@ namespace cryptonote // size - 1 - because of variant tag for (size = 1; size <= TX_EXTRA_PADDING_MAX_COUNT; ++size) { - std::ios_base::iostate state = ar.stream().rdstate(); - bool eof = EOF == ar.stream().peek(); - ar.stream().clear(state); - - if (eof) + if (ar.eof()) break; uint8_t zero; @@ -139,8 +135,7 @@ namespace cryptonote if(!::do_serialize(ar, field)) return false; - std::istringstream iss(field); - binary_archive iar(iss); + binary_archive iar{epee::strspan(field)}; serialize_helper helper(*this); return ::serialization::serialize(iar, helper); } diff --git a/src/device_trezor/trezor/protocol.hpp b/src/device_trezor/trezor/protocol.hpp index fa824ec3b..0fdd36a51 100644 --- a/src/device_trezor/trezor/protocol.hpp +++ b/src/device_trezor/trezor/protocol.hpp @@ -66,9 +66,7 @@ namespace protocol{ template bool cn_deserialize(const void * buff, size_t len, T & dst){ - std::stringstream ss; - ss.write(static_cast(buff), len); //ss << tx_blob; - binary_archive ba(ss); + binary_archive ba{{reinterpret_cast(buff), len}}; bool r = ::serialization::serialize(ba, dst); return r; } diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h index 00b72123a..278ff4164 100644 --- a/src/ringct/rctTypes.h +++ b/src/ringct/rctTypes.h @@ -284,7 +284,7 @@ namespace rct { { FIELD(type) if (type == RCTTypeNull) - return ar.stream().good(); + return ar.good(); if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG) return false; VARINT_FIELD(txnFee) @@ -344,7 +344,7 @@ namespace rct { ar.delimit_array(); } ar.end_array(); - return ar.stream().good(); + return ar.good(); } BEGIN_SERIALIZE_OBJECT() @@ -375,7 +375,7 @@ namespace rct { if (mixin >= 0xffffffff) return false; if (type == RCTTypeNull) - return ar.stream().good(); + return ar.good(); if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG) return false; if (type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG) @@ -522,7 +522,7 @@ namespace rct { } ar.end_array(); } - return ar.stream().good(); + return ar.good(); } BEGIN_SERIALIZE_OBJECT() diff --git a/src/rpc/rpc_payment.cpp b/src/rpc/rpc_payment.cpp index bf6584f72..f0c513911 100644 --- a/src/rpc/rpc_payment.cpp +++ b/src/rpc/rpc_payment.cpp @@ -293,12 +293,13 @@ namespace cryptonote MINFO("loading rpc payments data from " << state_file_path); std::ifstream data; data.open(state_file_path, std::ios_base::binary | std::ios_base::in); + std::string bytes(std::istream_iterator{data}, std::istream_iterator{}); if (!data.fail()) { bool loaded = false; try { - binary_archive ar(data); + binary_archive ar{epee::strspan(bytes)}; if (::serialization::serialize(ar, *this)) if (::serialization::check_stream_state(ar)) loaded = true; @@ -306,6 +307,8 @@ namespace cryptonote catch (...) {} if (!loaded) { + bytes.clear(); + bytes.shrink_to_fit(); try { boost::archive::portable_binary_iarchive a(data); diff --git a/src/serialization/binary_archive.h b/src/serialization/binary_archive.h index 49ca8aa57..acda70039 100644 --- a/src/serialization/binary_archive.h +++ b/src/serialization/binary_archive.h @@ -36,9 +36,11 @@ #include #include #include +#include #include #include "common/varint.h" +#include "span.h" #include "warnings.h" /* I have no clue what these lines means */ @@ -55,16 +57,15 @@ DISABLE_VS_WARNINGS(4244) * purpse is to define the functions used for the binary_archive. Its * a header, basically. I think it was declared simply to save typing... */ -template +template struct binary_archive_base { - typedef Stream stream_type; - typedef binary_archive_base base_type; + typedef binary_archive_base base_type; typedef boost::mpl::bool_ is_saving; typedef uint8_t variant_tag_type; - explicit binary_archive_base(stream_type &s) : stream_(s) { } + explicit binary_archive_base() { } /* definition of standard API functions */ void tag(const char *) { } @@ -72,12 +73,6 @@ struct binary_archive_base void end_object() { } void begin_variant() { } void end_variant() { } - /* I just want to leave a comment saying how this line really shows - flaws in the ownership model of many OOP languages, that is all. */ - stream_type &stream() { return stream_; } - -protected: - stream_type &stream_; }; /* \struct binary_archive @@ -95,15 +90,18 @@ struct binary_archive; template <> -struct binary_archive : public binary_archive_base +struct binary_archive : public binary_archive_base { + explicit binary_archive(epee::span s) + : base_type(), bytes_(s), begin_(s.begin()), good_(true), varint_bug_backward_compatibility_(false) + {} - explicit binary_archive(stream_type &s) : base_type(s), varint_bug_backward_compatibility_(false) { - stream_type::pos_type pos = stream_.tellg(); - stream_.seekg(0, std::ios_base::end); - eof_pos_ = stream_.tellg(); - stream_.seekg(pos); - } + bool good() const noexcept { return good_; } + void set_fail() noexcept { good_ = false; } + + //! If implementing as `std::istream`, reset stream error state after `peek()` call. + bool eof() const noexcept { return bytes_.empty(); } + std::size_t getpos() const noexcept { return bytes_.begin() - begin_; } template void serialize_int(T &v) @@ -116,24 +114,24 @@ struct binary_archive : public binary_archive_base * \brief serializes an unsigned integer */ template - void serialize_uint(T &v, size_t width = sizeof(T)) + void serialize_uint(T &v) { - T ret = 0; - unsigned shift = 0; - for (size_t i = 0; i < width; i++) { - //std::cerr << "tell: " << stream_.tellg() << " value: " << ret << std::endl; - char c; - stream_.get(c); - T b = (unsigned char)c; - ret += (b << shift); // can this be changed to OR, i think it can. - shift += 8; + const std::size_t actual = bytes_.remove_prefix(sizeof(T)); + good_ &= (actual == sizeof(T)); + if (actual == sizeof(T)) + { + std::memcpy(std::addressof(v), bytes_.data() - sizeof(T), sizeof(T)); + boost::endian::little_to_native_inplace(v); // epee isn't templated } - v = ret; + else + v = 0; // ensures initialization } void serialize_blob(void *buf, size_t len, const char *delimiter="") { - stream_.read((char *)buf, len); + const std::size_t actual = bytes_.remove_prefix(len); + good_ &= (len == actual); + std::memcpy(buf, bytes_.data() - actual, actual); } template @@ -145,9 +143,11 @@ struct binary_archive : public binary_archive_base template void serialize_uvarint(T &v) { - typedef std::istreambuf_iterator it; - if (tools::read_varint(it(stream_), it(), v) < 0) - stream_.setstate(std::ios_base::failbit); + auto current = bytes_.cbegin(); + auto end = bytes_.cend(); + good_ &= (0 <= tools::read_varint(current, end, v)); + current = std::min(current, bytes_.cend()); + bytes_ = {current, std::size_t(bytes_.cend() - current)}; } void begin_array(size_t &s) @@ -166,26 +166,26 @@ struct binary_archive : public binary_archive_base serialize_int(t); } - size_t remaining_bytes() { - if (!stream_.good()) - return 0; - //std::cerr << "tell: " << stream_.tellg() << std::endl; - assert(stream_.tellg() <= eof_pos_); - return eof_pos_ - stream_.tellg(); - } - + size_t remaining_bytes() const noexcept { return good() ? bytes_.size() : 0; } void enable_varint_bug_backward_compatibility() { varint_bug_backward_compatibility_ = true; } bool varint_bug_backward_compatibility_enabled() const { return varint_bug_backward_compatibility_; } - protected: - std::streamoff eof_pos_; + epee::span bytes_; + std::uint8_t const* const begin_; + bool good_; bool varint_bug_backward_compatibility_; }; template <> -struct binary_archive : public binary_archive_base +struct binary_archive : public binary_archive_base { - explicit binary_archive(stream_type &s) : base_type(s) { } + typedef std::ostream stream_type; + explicit binary_archive(stream_type &s) : base_type(), stream_(s) { } + + bool good() const { return stream_.good(); } + void set_fail() { stream_.setstate(std::ios::failbit); } + + std::streampos getpos() const { return stream_.tellp(); } template void serialize_int(T v) @@ -234,6 +234,8 @@ struct binary_archive : public binary_archive_base } bool varint_bug_backward_compatibility_enabled() const { return false; } +protected: + stream_type& stream_; }; POP_WARNINGS diff --git a/src/serialization/binary_utils.h b/src/serialization/binary_utils.h index 8635585af..8444f220e 100644 --- a/src/serialization/binary_utils.h +++ b/src/serialization/binary_utils.h @@ -39,8 +39,7 @@ namespace serialization { template bool parse_binary(const std::string &blob, T &v) { - std::istringstream istr(blob); - binary_archive iar(istr); + binary_archive iar{epee::strspan(blob)}; return ::serialization::serialize(iar, v); } diff --git a/src/serialization/container.h b/src/serialization/container.h index a4997c8ae..77681ec93 100644 --- a/src/serialization/container.h +++ b/src/serialization/container.h @@ -67,13 +67,13 @@ bool do_serialize_container(Archive &ar, C &v) { size_t cnt; ar.begin_array(cnt); - if (!ar.stream().good()) + if (!ar.good()) return false; v.clear(); // very basic sanity check if (ar.remaining_bytes() < cnt) { - ar.stream().setstate(std::ios::failbit); + ar.set_fail(); return false; } @@ -86,7 +86,7 @@ bool do_serialize_container(Archive &ar, C &v) if (!::serialization::detail::serialize_container_element(ar, e)) return false; ::serialization::detail::do_add(v, std::move(e)); - if (!ar.stream().good()) + if (!ar.good()) return false; } ar.end_array(); @@ -100,13 +100,13 @@ bool do_serialize_container(Archive &ar, C &v) ar.begin_array(cnt); for (auto i = v.begin(); i != v.end(); ++i) { - if (!ar.stream().good()) + if (!ar.good()) return false; if (i != v.begin()) ar.delimit_array(); if(!::serialization::detail::serialize_container_element(ar, (typename C::value_type&)*i)) return false; - if (!ar.stream().good()) + if (!ar.good()) return false; } ar.end_array(); diff --git a/src/serialization/crypto.h b/src/serialization/crypto.h index 42bd06e92..d635a9ee9 100644 --- a/src/serialization/crypto.h +++ b/src/serialization/crypto.h @@ -47,7 +47,7 @@ bool do_serialize(Archive &ar, std::vector &v) // very basic sanity check if (ar.remaining_bytes() < cnt*sizeof(crypto::signature)) { - ar.stream().setstate(std::ios::failbit); + ar.set_fail(); return false; } @@ -55,7 +55,7 @@ bool do_serialize(Archive &ar, std::vector &v) for (size_t i = 0; i < cnt; i++) { v.resize(i+1); ar.serialize_blob(&(v[i]), sizeof(crypto::signature), ""); - if (!ar.stream().good()) + if (!ar.good()) return false; } return true; @@ -70,7 +70,7 @@ bool do_serialize(Archive &ar, std::vector &v) size_t cnt = v.size(); for (size_t i = 0; i < cnt; i++) { ar.serialize_blob(&(v[i]), sizeof(crypto::signature), ""); - if (!ar.stream().good()) + if (!ar.good()) return false; } ar.end_string(); diff --git a/src/serialization/debug_archive.h b/src/serialization/debug_archive.h index b04d6ae19..e8ccb9a58 100644 --- a/src/serialization/debug_archive.h +++ b/src/serialization/debug_archive.h @@ -38,6 +38,7 @@ struct debug_archive : public json_archive { typedef typename json_archive::stream_type stream_type; debug_archive(stream_type &s) : json_archive(s) { } + stream_type& stream() { return this->stream_; } }; template diff --git a/src/serialization/difficulty_type.h b/src/serialization/difficulty_type.h index 56c0312e7..75d1fd13f 100644 --- a/src/serialization/difficulty_type.h +++ b/src/serialization/difficulty_type.h @@ -38,10 +38,10 @@ inline bool do_serialize(Archive& ar, cryptonote::difficulty_type &diff) { uint64_t hi, lo; ar.serialize_varint(hi); - if (!ar.stream().good()) + if (!ar.good()) return false; ar.serialize_varint(lo); - if (!ar.stream().good()) + if (!ar.good()) return false; diff = hi; diff <<= 64; @@ -52,13 +52,13 @@ inline bool do_serialize(Archive& ar, cryptonote::difficulty_type &diff) template