diff options
Diffstat (limited to 'src')
31 files changed, 366 insertions, 255 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9904c5de7..aaaae3a09 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -77,30 +77,7 @@ function (monero_add_executable name) enable_stack_trace("${name}") monero_set_target_no_relink("${name}") -endfunction () - -function (monero_add_library name) - monero_add_library_with_deps(NAME "${name}" SOURCES ${ARGN}) -endfunction() - -function (monero_add_library_with_deps) - cmake_parse_arguments(MONERO_ADD_LIBRARY "" "NAME" "DEPENDS;SOURCES" ${ARGN}) - source_group("${MONERO_ADD_LIBRARY_NAME}" FILES ${MONERO_ADD_LIBRARY_SOURCES}) - - # Define a ("virtual") object library and an actual library that links those - # objects together. The virtual libraries can be arbitrarily combined to link - # any subset of objects into one library archive. This is used for releasing - # libwallet, which combines multiple components. - set(objlib obj_${MONERO_ADD_LIBRARY_NAME}) - add_library(${objlib} OBJECT ${MONERO_ADD_LIBRARY_SOURCES}) - add_library("${MONERO_ADD_LIBRARY_NAME}" $<TARGET_OBJECTS:${objlib}>) - monero_set_target_no_relink("${MONERO_ADD_LIBRARY_NAME}") - if (MONERO_ADD_LIBRARY_DEPENDS) - add_dependencies(${objlib} ${MONERO_ADD_LIBRARY_DEPENDS}) - endif() - set_property(TARGET "${MONERO_ADD_LIBRARY_NAME}" PROPERTY FOLDER "libs") - target_compile_definitions(${objlib} - PRIVATE $<TARGET_PROPERTY:${MONERO_ADD_LIBRARY_NAME},INTERFACE_COMPILE_DEFINITIONS>) + monero_set_target_strip ("${name}") endfunction () include(Version) 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<char*>(v.mv_data), v.mv_size); - std::stringstream ss; - ss << bd; - binary_archive<false> ba(ss); + binary_archive<false> ba{epee::strspan<std::uint8_t>(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<typename T> static inline unsigned int getpos(T &ar) { return 0; } - template<> inline unsigned int getpos(binary_archive<true> &ar) { return ar.stream().tellp(); } - template<> inline unsigned int getpos(binary_archive<false> &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<transaction_prefix *>(this)) if (std::is_same<Archive<W>, binary_archive<W>>()) - prefix_size = getpos(ar) - start_pos; + prefix_size = ar.getpos() - start_pos; if (version == 1) { if (std::is_same<Archive<W>, binary_archive<W>>()) - 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<Archive<W>, binary_archive<W>>()) - 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<txin_to_key>(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<W>::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<false> ba(ss); + binary_archive<false> ba{epee::strspan<std::uint8_t>(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<false> ba(ss); + binary_archive<false> ba{epee::strspan<std::uint8_t>(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<false> ba(ss); + binary_archive<false> ba{epee::strspan<std::uint8_t>(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<false> ba(ss); + binary_archive<false> ba{epee::strspan<std::uint8_t>(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<const char*>(tx_extra.data()), tx_extra.size()); - std::istringstream iss(extra_str); - binary_archive<false> ar(iss); + binary_archive<false> 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<const char*>(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<const char*>(tx_extra.data()), tx_extra.size()))); return true; @@ -578,13 +563,10 @@ namespace cryptonote return true; } - std::string extra_str(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size()); - std::istringstream iss(extra_str); - binary_archive<false> ar(iss); + binary_archive<false> 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<const char*>(tx_extra.data()), tx_extra.size()))); @@ -752,24 +730,18 @@ namespace cryptonote if (tx_extra.empty()) return true; std::string extra_str(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size()); - std::istringstream iss(extra_str); - binary_archive<false> ar(iss); + binary_archive<false> ar{epee::strspan<std::uint8_t>(extra_str)}; std::ostringstream oss; binary_archive<true> 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<const char*>(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<const char*>(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<false> ba(ss); + binary_archive<false> ba{epee::strspan<std::uint8_t>(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<class t_object> bool t_serializable_object_from_blob(t_object& to, const blobdata& b_blob) { - std::stringstream ss; - ss << b_blob; - binary_archive<false> ba(ss); + binary_archive<false> ba{epee::strspan<std::uint8_t>(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<false> iar(iss); + binary_archive<false> iar{epee::strspan<std::uint8_t>(field)}; serialize_helper helper(*this); return ::serialization::serialize(iar, helper); } diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index a3d695b85..db707bb65 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -566,6 +566,8 @@ void Blockchain::pop_blocks(uint64_t nblocks) return; } + CHECK_AND_ASSERT_THROW_MES(update_next_cumulative_weight_limit(), "Error updating next cumulative weight limit"); + if (stop_batch) m_db->batch_stop(); } @@ -643,7 +645,6 @@ block Blockchain::pop_block_from_blockchain() m_scan_table.clear(); m_blocks_txs_check.clear(); - CHECK_AND_ASSERT_THROW_MES(update_next_cumulative_weight_limit(), "Error updating next cumulative weight limit"); uint64_t top_block_height; crypto::hash top_block_hash = get_tail_id(top_block_height); m_tx_pool.on_blockchain_dec(top_block_height, top_block_hash); @@ -1110,6 +1111,7 @@ bool Blockchain::rollback_blockchain_switching(std::list<block>& original_chain, { pop_block_from_blockchain(); } + CHECK_AND_ASSERT_THROW_MES(update_next_cumulative_weight_limit(), "Error updating next cumulative weight limit"); // make sure the hard fork object updates its current version m_hardfork->reorganize_from_chain_height(rollback_height); @@ -1160,6 +1162,7 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<block_extended_info> block b = pop_block_from_blockchain(); disconnected_chain.push_front(b); } + CHECK_AND_ASSERT_THROW_MES(update_next_cumulative_weight_limit(), "Error updating next cumulative weight limit"); auto split_height = m_db->height(); @@ -5150,7 +5153,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete if (m_cancel) return false; - for (const auto &tx_blob : entry.txs) + for (size_t i = 0; i < entry.txs.size(); ++i) { if (tx_index >= txes.size()) SCAN_TABLE_QUIT("tx_index is out of sync"); diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index 7400c4328..f41c63a4b 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -622,8 +622,10 @@ namespace cryptonote if (need_additional_txkeys) { additional_tx_keys.clear(); - for (const auto &d: destinations) + for (size_t i = 0; i < destinations.size(); ++i) + { additional_tx_keys.push_back(keypair::generate(sender_account_keys.get_device()).sec); + } } bool r = construct_tx_with_tx_key(sender_account_keys, subaddresses, sources, destinations, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, rct_config, msout); 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<typename T> bool cn_deserialize(const void * buff, size_t len, T & dst){ - std::stringstream ss; - ss.write(static_cast<const char *>(buff), len); //ss << tx_blob; - binary_archive<false> ba(ss); + binary_archive<false> ba{{reinterpret_cast<const std::uint8_t*>(buff), len}}; bool r = ::serialization::serialize(ba, dst); return r; } diff --git a/src/device_trezor/trezor/transport.cpp b/src/device_trezor/trezor/transport.cpp index be95868d0..194176413 100644 --- a/src/device_trezor/trezor/transport.cpp +++ b/src/device_trezor/trezor/transport.cpp @@ -157,7 +157,7 @@ namespace trezor{ #define PROTO_HEADER_SIZE 6 static size_t message_size(const google::protobuf::Message &req){ - return static_cast<size_t>(req.ByteSize()); + return req.ByteSizeLong(); } static size_t serialize_message_buffer_size(size_t msg_size) { 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/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index ded545efa..8d8a68efb 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -1044,6 +1044,7 @@ namespace cryptonote if (e.in_pool) { e.block_height = e.block_timestamp = std::numeric_limits<uint64_t>::max(); + e.confirmations = 0; auto it = per_tx_pool_tx_info.find(tx_hash); if (it != per_tx_pool_tx_info.end()) { @@ -1062,6 +1063,7 @@ namespace cryptonote else { e.block_height = m_core.get_blockchain_storage().get_db().get_tx_block_height(tx_hash); + e.confirmations = m_core.get_current_blockchain_height() - e.block_height; e.block_timestamp = m_core.get_blockchain_storage().get_db().get_block_timestamp(e.block_height); e.received_timestamp = 0; e.double_spend_seen = false; diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 5ebe4f654..ff8c98b98 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -88,7 +88,7 @@ namespace cryptonote // advance which version they will stop working with // Don't go over 32767 for any of these #define CORE_RPC_VERSION_MAJOR 3 -#define CORE_RPC_VERSION_MINOR 6 +#define CORE_RPC_VERSION_MINOR 7 #define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor)) #define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR) @@ -350,6 +350,7 @@ namespace cryptonote bool in_pool; bool double_spend_seen; uint64_t block_height; + uint64_t confirmations; uint64_t block_timestamp; uint64_t received_timestamp; std::vector<uint64_t> output_indices; @@ -367,6 +368,7 @@ namespace cryptonote if (!this_ref.in_pool) { KV_SERIALIZE(block_height) + KV_SERIALIZE(confirmations) KV_SERIALIZE(block_timestamp) KV_SERIALIZE(output_indices) } 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<char>{data}, std::istream_iterator<char>{}); if (!data.fail()) { bool loaded = false; try { - binary_archive<false> ar(data); + binary_archive<false> ar{epee::strspan<std::uint8_t>(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 <cassert> #include <iostream> #include <iterator> +#include <boost/endian/conversion.hpp> #include <boost/type_traits/make_unsigned.hpp> #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 <class Stream, bool IsSaving> +template <bool IsSaving> struct binary_archive_base { - typedef Stream stream_type; - typedef binary_archive_base<Stream, IsSaving> base_type; + typedef binary_archive_base<IsSaving> base_type; typedef boost::mpl::bool_<IsSaving> 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<false> : public binary_archive_base<std::istream, false> +struct binary_archive<false> : public binary_archive_base<false> { + explicit binary_archive(epee::span<const std::uint8_t> 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 <class T> void serialize_int(T &v) @@ -116,24 +114,24 @@ struct binary_archive<false> : public binary_archive_base<std::istream, false> * \brief serializes an unsigned integer */ template <class T> - 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 <class T> @@ -145,9 +143,11 @@ struct binary_archive<false> : public binary_archive_base<std::istream, false> template <class T> void serialize_uvarint(T &v) { - typedef std::istreambuf_iterator<char> 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<false> : public binary_archive_base<std::istream, false> 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<const std::uint8_t> bytes_; + std::uint8_t const* const begin_; + bool good_; bool varint_bug_backward_compatibility_; }; template <> -struct binary_archive<true> : public binary_archive_base<std::ostream, true> +struct binary_archive<true> : public binary_archive_base<true> { - 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 <class T> void serialize_int(T v) @@ -234,6 +234,8 @@ struct binary_archive<true> : public binary_archive_base<std::ostream, true> } 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 <class T> bool parse_binary(const std::string &blob, T &v) { - std::istringstream istr(blob); - binary_archive<false> iar(istr); + binary_archive<false> iar{epee::strspan<std::uint8_t>(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<false> &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<false> &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<true> &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<false> &ar, std::vector<crypto::signature> &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<false> &ar, std::vector<crypto::signature> &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<true> &ar, std::vector<crypto::signature> &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<W> { typedef typename json_archive<W>::stream_type stream_type; debug_archive(stream_type &s) : json_archive<W>(s) { } + stream_type& stream() { return this->stream_; } }; template <class T> 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<false>& 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<false>& ar, cryptonote::difficulty_type &diff) template <template <bool> class Archive> inline bool do_serialize(Archive<true>& ar, cryptonote::difficulty_type &diff) { - if (!ar.stream().good()) + if (!ar.good()) return false; const uint64_t hi = ((diff >> 64) & 0xffffffffffffffff).convert_to<uint64_t>(); const uint64_t lo = (diff & 0xffffffffffffffff).convert_to<uint64_t>(); ar.serialize_varint(hi); ar.serialize_varint(lo); - if (!ar.stream().good()) + if (!ar.good()) return false; return true; } diff --git a/src/serialization/json_archive.h b/src/serialization/json_archive.h index 3f98b5101..bab6dfa94 100644 --- a/src/serialization/json_archive.h +++ b/src/serialization/json_archive.h @@ -58,6 +58,10 @@ struct json_archive_base json_archive_base(stream_type &s, bool indent = false) : stream_(s), indent_(indent), object_begin(false), depth_(0) { } + bool good() const { return stream_.good(); } + void set_fail() { stream_.setstate(std::ios::failbit); } + void clear_fail() { stream_.clear(); } + void tag(const char *tag) { if (!object_begin) stream_ << ", "; @@ -82,7 +86,6 @@ struct json_archive_base void begin_variant() { begin_object(); } void end_variant() { end_object(); } - Stream &stream() { return stream_; } bool varint_bug_backward_compatibility_enabled() const { return false; } @@ -117,6 +120,8 @@ struct json_archive<true> : public json_archive_base<std::ostream, true> { json_archive(stream_type &s, bool indent = false) : base_type(s, indent), inner_array_size_(0) { } + std::streampos getpos() const { return stream_.tellp(); } + template<typename T> static auto promote_to_printable_integer_type(T v) -> decltype(+v) { diff --git a/src/serialization/pair.h b/src/serialization/pair.h index 44aafa04d..2d9a89242 100644 --- a/src/serialization/pair.h +++ b/src/serialization/pair.h @@ -69,19 +69,19 @@ inline bool do_serialize(Archive<false>& ar, std::pair<F,S>& p) { size_t cnt; ar.begin_array(cnt); - if (!ar.stream().good()) + if (!ar.good()) return false; if (cnt != 2) return false; if (!::serialization::detail::serialize_pair_element(ar, p.first)) return false; - if (!ar.stream().good()) + if (!ar.good()) return false; ar.delimit_array(); if (!::serialization::detail::serialize_pair_element(ar, p.second)) return false; - if (!ar.stream().good()) + if (!ar.good()) return false; ar.end_array(); @@ -92,16 +92,16 @@ template <template <bool> class Archive, class F, class S> inline bool do_serialize(Archive<true>& ar, std::pair<F,S>& p) { ar.begin_array(2); - if (!ar.stream().good()) + if (!ar.good()) return false; if(!::serialization::detail::serialize_pair_element(ar, p.first)) return false; - if (!ar.stream().good()) + if (!ar.good()) return false; ar.delimit_array(); if(!::serialization::detail::serialize_pair_element(ar, p.second)) return false; - if (!ar.stream().good()) + if (!ar.good()) return false; ar.end_array(); return true; diff --git a/src/serialization/serialization.h b/src/serialization/serialization.h index 3ebeed171..4acadeab3 100644 --- a/src/serialization/serialization.h +++ b/src/serialization/serialization.h @@ -213,7 +213,7 @@ inline bool do_serialize(Archive &ar, bool &v) * \brief self-explanatory */ #define END_SERIALIZE() \ - return ar.stream().good(); \ + return ar.good(); \ } /*! \macro VALUE(f) @@ -223,7 +223,7 @@ inline bool do_serialize(Archive &ar, bool &v) do { \ ar.tag(#f); \ bool r = ::do_serialize(ar, f); \ - if (!r || !ar.stream().good()) return false; \ + if (!r || !ar.good()) return false; \ } while(0); /*! \macro FIELD_N(t,f) @@ -234,7 +234,7 @@ inline bool do_serialize(Archive &ar, bool &v) do { \ ar.tag(t); \ bool r = ::do_serialize(ar, f); \ - if (!r || !ar.stream().good()) return false; \ + if (!r || !ar.good()) return false; \ } while(0); /*! \macro FIELD(f) @@ -245,7 +245,7 @@ inline bool do_serialize(Archive &ar, bool &v) do { \ ar.tag(#f); \ bool r = ::do_serialize(ar, f); \ - if (!r || !ar.stream().good()) return false; \ + if (!r || !ar.good()) return false; \ } while(0); /*! \macro FIELDS(f) @@ -255,7 +255,7 @@ inline bool do_serialize(Archive &ar, bool &v) #define FIELDS(f) \ do { \ bool r = ::do_serialize(ar, f); \ - if (!r || !ar.stream().good()) return false; \ + if (!r || !ar.good()) return false; \ } while(0); /*! \macro VARINT_FIELD(f) @@ -265,7 +265,7 @@ inline bool do_serialize(Archive &ar, bool &v) do { \ ar.tag(#f); \ ar.serialize_varint(f); \ - if (!ar.stream().good()) return false; \ + if (!ar.good()) return false; \ } while(0); /*! \macro VARINT_FIELD_N(t, f) @@ -276,7 +276,7 @@ inline bool do_serialize(Archive &ar, bool &v) do { \ ar.tag(t); \ ar.serialize_varint(f); \ - if (!ar.stream().good()) return false; \ + if (!ar.good()) return false; \ } while(0); /*! \macro MAGIC_FIELD(m) @@ -286,7 +286,7 @@ inline bool do_serialize(Archive &ar, bool &v) do { \ ar.tag("magic"); \ ar.serialize_blob((void*)magic.data(), magic.size()); \ - if (!ar.stream().good()) return false; \ + if (!ar.good()) return false; \ if (magic != m) return false; \ } while(0); @@ -297,7 +297,7 @@ inline bool do_serialize(Archive &ar, bool &v) do { \ ar.tag("version"); \ ar.serialize_varint(version); \ - if (!ar.stream().good()) return false; \ + if (!ar.good()) return false; \ } while(0); @@ -339,10 +339,10 @@ namespace serialization { * * \brief self explanatory */ - template<class Stream> - bool do_check_stream_state(Stream& s, boost::mpl::bool_<true>, bool noeof) + template<class Archive> + bool do_check_stream_state(Archive& ar, boost::mpl::bool_<true>, bool noeof) { - return s.good(); + return ar.good(); } /*! \fn do_check_stream_state * @@ -350,15 +350,13 @@ namespace serialization { * * \detailed Also checks to make sure that the stream is not at EOF */ - template<class Stream> - bool do_check_stream_state(Stream& s, boost::mpl::bool_<false>, bool noeof) + template<class Archive> + bool do_check_stream_state(Archive& ar, boost::mpl::bool_<false>, bool noeof) { bool result = false; - if (s.good()) + if (ar.good()) { - std::ios_base::iostate state = s.rdstate(); - result = noeof || EOF == s.peek(); - s.clear(state); + result = noeof || ar.eof(); } return result; } @@ -371,7 +369,7 @@ namespace serialization { template<class Archive> bool check_stream_state(Archive& ar, bool noeof = false) { - return detail::do_check_stream_state(ar.stream(), typename Archive::is_saving(), noeof); + return detail::do_check_stream_state(ar, typename Archive::is_saving(), noeof); } /*! \fn serialize diff --git a/src/serialization/string.h b/src/serialization/string.h index f5f69833a..f1f8f4ab0 100644 --- a/src/serialization/string.h +++ b/src/serialization/string.h @@ -39,7 +39,7 @@ inline bool do_serialize(Archive<false>& ar, std::string& str) ar.serialize_varint(size); if (ar.remaining_bytes() < size) { - ar.stream().setstate(std::ios::failbit); + ar.set_fail(); return false; } diff --git a/src/serialization/variant.h b/src/serialization/variant.h index b08cf6bf0..6debb63d1 100644 --- a/src/serialization/variant.h +++ b/src/serialization/variant.h @@ -74,7 +74,7 @@ struct variant_reader current_type x; if(!::do_serialize(ar, x)) { - ar.stream().setstate(std::ios::failbit); + ar.set_fail(); return false; } v = x; @@ -95,7 +95,7 @@ struct variant_reader<Archive, Variant, TBegin, TBegin> static inline bool read(Archive &ar, Variant &v, variant_tag_type t) { - ar.stream().setstate(std::ios::failbit); + ar.set_fail(); return false; } }; @@ -116,7 +116,7 @@ struct serializer<Archive<false>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>> typename boost::mpl::begin<types>::type, typename boost::mpl::end<types>::type>::read(ar, v, t)) { - ar.stream().setstate(std::ios::failbit); + ar.set_fail(); return false; } ar.end_variant(); @@ -143,7 +143,7 @@ struct serializer<Archive<true>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>> ar.write_variant_tag(variant_serialization_traits<Archive<true>, T>::get_tag()); if(!::do_serialize(ar, rv)) { - ar.stream().setstate(std::ios::failbit); + ar.set_fail(); return false; } ar.end_variant(); diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt index 47555d9c8..2dd64a38f 100644 --- a/src/wallet/CMakeLists.txt +++ b/src/wallet/CMakeLists.txt @@ -40,18 +40,7 @@ set(wallet_sources wallet_rpc_payments.cpp ) -set(wallet_private_headers - wallet2.h - wallet_args.h - wallet_errors.h - wallet_rpc_server.h - wallet_rpc_server_commands_defs.h - wallet_rpc_server_error_codes.h - ringdb.h - node_rpc_proxy.h - message_store.h - message_transporter.h - wallet_rpc_helpers.h) +monero_find_all_headers(wallet_private_headers "${CMAKE_CURRENT_SOURCE_DIR}") monero_private_headers(wallet ${wallet_private_headers}) diff --git a/src/wallet/message_store.cpp b/src/wallet/message_store.cpp index b7b29420b..34b4f440b 100644 --- a/src/wallet/message_store.cpp +++ b/src/wallet/message_store.cpp @@ -193,9 +193,7 @@ void message_store::unpack_signer_config(const multisig_wallet_state &state, con { try { - std::stringstream iss; - iss << signer_config; - binary_archive<false> ar(iss); + binary_archive<false> ar{epee::strspan<std::uint8_t>(signer_config)}; THROW_WALLET_EXCEPTION_IF(!::serialization::serialize(ar, signers), tools::error::wallet_internal_error, "Failed to serialize signer config"); } catch (...) @@ -383,9 +381,7 @@ void message_store::process_auto_config_data_message(uint32_t id) auto_config_data data; try { - std::stringstream iss; - iss << m.content; - binary_archive<false> ar(iss); + binary_archive<false> ar{epee::strspan<std::uint8_t>(m.content)}; THROW_WALLET_EXCEPTION_IF(!::serialization::serialize(ar, data), tools::error::wallet_internal_error, "Failed to serialize auto config data"); } catch (...) @@ -790,9 +786,7 @@ void message_store::read_from_file(const multisig_wallet_state &state, const std file_data read_file_data; try { - std::stringstream iss; - iss << buf; - binary_archive<false> ar(iss); + binary_archive<false> ar{epee::strspan<std::uint8_t>(buf)}; if (::serialization::serialize(ar, read_file_data)) if (::serialization::check_stream_state(ar)) loaded = true; @@ -829,9 +823,7 @@ void message_store::read_from_file(const multisig_wallet_state &state, const std loaded = false; try { - std::stringstream iss; - iss << decrypted_data; - binary_archive<false> ar(iss); + binary_archive<false> ar{epee::strspan<std::uint8_t>(decrypted_data)}; if (::serialization::serialize(ar, *this)) if (::serialization::check_stream_state(ar)) loaded = true; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 0b310111e..05fe0a1ad 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -5701,17 +5701,13 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass try { - std::stringstream iss; - iss << cache_data; - binary_archive<false> ar(iss); + binary_archive<false> ar{epee::strspan<std::uint8_t>(cache_data)}; if (::serialization::serialize(ar, *this)) if (::serialization::check_stream_state(ar)) loaded = true; if (!loaded) { - std::stringstream iss; - iss << cache_data; - binary_archive<false> ar(iss); + binary_archive<false> ar{epee::strspan<std::uint8_t>(cache_data)}; ar.enable_varint_bug_backward_compatibility(); if (::serialization::serialize(ar, *this)) if (::serialization::check_stream_state(ar)) @@ -6786,8 +6782,7 @@ bool wallet2::parse_unsigned_tx_from_str(const std::string &unsigned_tx_st, unsi catch(const std::exception &e) { LOG_PRINT_L0("Failed to decrypt unsigned tx: " << e.what()); return false; } try { - std::istringstream iss(s); - binary_archive<false> ar(iss); + binary_archive<false> ar{epee::strspan<std::uint8_t>(s)}; if (!::serialization::serialize(ar, exported_txs)) { LOG_PRINT_L0("Failed to parse data from unsigned tx"); @@ -7101,8 +7096,7 @@ bool wallet2::parse_tx_from_str(const std::string &signed_tx_st, std::vector<too catch (const std::exception &e) { LOG_PRINT_L0("Failed to decrypt signed transaction: " << e.what()); return false; } try { - std::istringstream iss(s); - binary_archive<false> ar(iss); + binary_archive<false> ar{epee::strspan<std::uint8_t>(s)}; if (!::serialization::serialize(ar, signed_txs)) { LOG_PRINT_L0("Failed to deserialize signed transaction"); @@ -7237,8 +7231,7 @@ bool wallet2::parse_multisig_tx_from_str(std::string multisig_tx_st, multisig_tx bool loaded = false; try { - std::istringstream iss(multisig_tx_st); - binary_archive<false> ar(iss); + binary_archive<false> ar{epee::strspan<std::uint8_t>(multisig_tx_st)}; if (::serialization::serialize(ar, exported_txs)) if (::serialization::check_stream_state(ar)) loaded = true; @@ -11516,6 +11509,9 @@ void wallet2::check_tx_key_helper(const cryptonote::transaction &tx, const crypt void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_derivation &derivation, const std::vector<crypto::key_derivation> &additional_derivations, const cryptonote::account_public_address &address, uint64_t &received, bool &in_pool, uint64_t &confirmations) { + uint32_t rpc_version; + THROW_WALLET_EXCEPTION_IF(!check_connection(&rpc_version), error::wallet_internal_error, "Failed to connect to daemon: " + get_daemon_address()); + COMMAND_RPC_GET_TRANSACTIONS::request req; COMMAND_RPC_GET_TRANSACTIONS::response res; req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid)); @@ -11561,10 +11557,17 @@ void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_de confirmations = 0; if (!in_pool) { - std::string err; - uint64_t bc_height = get_daemon_blockchain_height(err); - if (err.empty()) - confirmations = bc_height - res.txs.front().block_height; + if (rpc_version < MAKE_CORE_RPC_VERSION(3, 7)) + { + std::string err; + uint64_t bc_height = get_daemon_blockchain_height(err); + if (err.empty() && bc_height > res.txs.front().block_height) + confirmations = bc_height - res.txs.front().block_height; + } + else + { + confirmations = res.txs.front().confirmations; + } } } @@ -12027,8 +12030,7 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr serializable_unordered_map<crypto::public_key, crypto::signature> subaddr_spendkeys; try { - std::istringstream iss(sig_decoded); - binary_archive<false> ar(iss); + binary_archive<false> ar{epee::strspan<std::uint8_t>(sig_decoded)}; if (::serialization::serialize_noeof(ar, proofs)) if (::serialization::serialize_noeof(ar, subaddr_spendkeys)) if (::serialization::check_stream_state(ar)) @@ -13212,9 +13214,7 @@ size_t wallet2::import_outputs_from_str(const std::string &outputs_st) std::pair<uint64_t, std::vector<tools::wallet2::transfer_details>> outputs; try { - std::stringstream iss; - iss << body; - binary_archive<false> ar(iss); + binary_archive<false> ar{epee::strspan<std::uint8_t>(body)}; if (::serialization::serialize(ar, outputs)) if (::serialization::check_stream_state(ar)) loaded = true; @@ -13466,8 +13466,7 @@ size_t wallet2::import_multisig(std::vector<cryptonote::blobdata> blobs) bool loaded = false; try { - std::istringstream iss(body); - binary_archive<false> ar(iss); + binary_archive<false> ar{epee::strspan<std::uint8_t>(body)}; if (::serialization::serialize(ar, i)) if (::serialization::check_stream_state(ar)) loaded = true; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 0b200ae60..b72817ba0 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -762,6 +762,90 @@ namespace tools return true; } //------------------------------------------------------------------------------------------------------------------------------ + bool wallet_rpc_server::on_freeze(const wallet_rpc::COMMAND_RPC_FREEZE::request& req, wallet_rpc::COMMAND_RPC_FREEZE::response& res, epee::json_rpc::error& er, const connection_context *ctx) + { + if (!m_wallet) return not_open(er); + try + { + if (req.key_image.empty()) + { + er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; + er.message = std::string("Must specify key image to freeze"); + return false; + } + crypto::key_image ki; + if (!epee::string_tools::hex_to_pod(req.key_image, ki)) + { + er.code = WALLET_RPC_ERROR_CODE_WRONG_KEY_IMAGE; + er.message = "failed to parse key image"; + return false; + } + m_wallet->freeze(ki); + } + catch (const std::exception& e) + { + handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR); + return false; + } + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool wallet_rpc_server::on_thaw(const wallet_rpc::COMMAND_RPC_THAW::request& req, wallet_rpc::COMMAND_RPC_THAW::response& res, epee::json_rpc::error& er, const connection_context *ctx) + { + if (!m_wallet) return not_open(er); + try + { + if (req.key_image.empty()) + { + er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; + er.message = std::string("Must specify key image to thaw"); + return false; + } + crypto::key_image ki; + if (!epee::string_tools::hex_to_pod(req.key_image, ki)) + { + er.code = WALLET_RPC_ERROR_CODE_WRONG_KEY_IMAGE; + er.message = "failed to parse key image"; + return false; + } + m_wallet->thaw(ki); + } + catch (const std::exception& e) + { + handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR); + return false; + } + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool wallet_rpc_server::on_frozen(const wallet_rpc::COMMAND_RPC_FROZEN::request& req, wallet_rpc::COMMAND_RPC_FROZEN::response& res, epee::json_rpc::error& er, const connection_context *ctx) + { + if (!m_wallet) return not_open(er); + try + { + if (req.key_image.empty()) + { + er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; + er.message = std::string("Must specify key image to check if frozen"); + return false; + } + crypto::key_image ki; + if (!epee::string_tools::hex_to_pod(req.key_image, ki)) + { + er.code = WALLET_RPC_ERROR_CODE_WRONG_KEY_IMAGE; + er.message = "failed to parse key image"; + return false; + } + res.frozen = m_wallet->frozen(ki); + } + catch (const std::exception& e) + { + handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR); + return false; + } + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::validate_transfer(const std::list<wallet_rpc::transfer_destination>& destinations, const std::string& payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, bool at_least_one_destination, epee::json_rpc::error& er) { crypto::hash8 integrated_payment_id = crypto::null_hash8; @@ -877,10 +961,10 @@ namespace tools return amount; } //------------------------------------------------------------------------------------------------------------------------------ - template<typename Ts, typename Tu> + template<typename Ts, typename Tu, typename Tk> bool wallet_rpc_server::fill_response(std::vector<tools::wallet2::pending_tx> &ptx_vector, bool get_tx_key, Ts& tx_key, Tu &amount, Tu &fee, Tu &weight, std::string &multisig_txset, std::string &unsigned_txset, bool do_not_relay, - Ts &tx_hash, bool get_tx_hex, Ts &tx_blob, bool get_tx_metadata, Ts &tx_metadata, epee::json_rpc::error &er) + Ts &tx_hash, bool get_tx_hex, Ts &tx_blob, bool get_tx_metadata, Ts &tx_metadata, Tk &spent_key_images, epee::json_rpc::error &er) { for (const auto & ptx : ptx_vector) { @@ -895,6 +979,17 @@ namespace tools fill(amount, total_amount(ptx)); fill(fee, ptx.fee); fill(weight, cryptonote::get_transaction_weight(ptx.tx)); + + // add spent key images + tools::wallet_rpc::key_image_list key_image_list; + bool all_are_txin_to_key = std::all_of(ptx.tx.vin.begin(), ptx.tx.vin.end(), [&](const cryptonote::txin_v& s_e) -> bool + { + CHECKED_GET_SPECIFIC_VARIANT(s_e, const cryptonote::txin_to_key, in, false); + key_image_list.key_images.push_back(epee::string_tools::pod_to_hex(in.k_image)); + return true; + }); + THROW_WALLET_EXCEPTION_IF(!all_are_txin_to_key, error::unexpected_txin_type, ptx.tx); + fill(spent_key_images, key_image_list); } if (m_wallet->multisig()) @@ -981,7 +1076,7 @@ namespace tools } return fill_response(ptx_vector, req.get_tx_key, res.tx_key, res.amount, res.fee, res.weight, res.multisig_txset, res.unsigned_txset, req.do_not_relay, - res.tx_hash, req.get_tx_hex, res.tx_blob, req.get_tx_metadata, res.tx_metadata, er); + res.tx_hash, req.get_tx_hex, res.tx_blob, req.get_tx_metadata, res.tx_metadata, res.spent_key_images, er); } catch (const std::exception& e) { @@ -1027,7 +1122,7 @@ namespace tools } return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.weight_list, res.multisig_txset, res.unsigned_txset, req.do_not_relay, - res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, er); + res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, res.spent_key_images_list, er); } catch (const std::exception& e) { @@ -1389,7 +1484,7 @@ namespace tools std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_unmixable_sweep_transactions(); return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.weight_list, res.multisig_txset, res.unsigned_txset, req.do_not_relay, - res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, er); + res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, res.spent_key_images_list, er); } catch (const std::exception& e) { @@ -1447,7 +1542,7 @@ namespace tools std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_all(req.below_amount, dsts[0].addr, dsts[0].is_subaddress, req.outputs, mixin, req.unlock_time, priority, extra, req.account_index, subaddr_indices); return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.weight_list, res.multisig_txset, res.unsigned_txset, req.do_not_relay, - res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, er); + res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, res.spent_key_images_list, er); } catch (const std::exception& e) { @@ -1522,7 +1617,7 @@ namespace tools } return fill_response(ptx_vector, req.get_tx_key, res.tx_key, res.amount, res.fee, res.weight, res.multisig_txset, res.unsigned_txset, req.do_not_relay, - res.tx_hash, req.get_tx_hex, res.tx_blob, req.get_tx_metadata, res.tx_metadata, er); + res.tx_hash, req.get_tx_hex, res.tx_blob, req.get_tx_metadata, res.tx_metadata, res.spent_key_images, er); } catch (const std::exception& e) { @@ -1555,8 +1650,7 @@ namespace tools try { - std::istringstream iss(blob); - binary_archive<false> ar(iss); + binary_archive<false> ar{epee::strspan<std::uint8_t>(blob)}; if (::serialization::serialize(ar, ptx)) loaded = true; } diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h index 9f9e3c134..7169c9136 100644 --- a/src/wallet/wallet_rpc_server.h +++ b/src/wallet/wallet_rpc_server.h @@ -84,6 +84,9 @@ namespace tools MAP_JON_RPC_WE("set_account_tag_description", on_set_account_tag_description, wallet_rpc::COMMAND_RPC_SET_ACCOUNT_TAG_DESCRIPTION) MAP_JON_RPC_WE("get_height", on_getheight, wallet_rpc::COMMAND_RPC_GET_HEIGHT) MAP_JON_RPC_WE("getheight", on_getheight, wallet_rpc::COMMAND_RPC_GET_HEIGHT) + MAP_JON_RPC_WE("freeze", on_freeze, wallet_rpc::COMMAND_RPC_FREEZE) + MAP_JON_RPC_WE("thaw", on_thaw, wallet_rpc::COMMAND_RPC_THAW) + MAP_JON_RPC_WE("frozen", on_frozen, wallet_rpc::COMMAND_RPC_FROZEN) MAP_JON_RPC_WE("transfer", on_transfer, wallet_rpc::COMMAND_RPC_TRANSFER) MAP_JON_RPC_WE("transfer_split", on_transfer_split, wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT) MAP_JON_RPC_WE("sign_transfer", on_sign_transfer, wallet_rpc::COMMAND_RPC_SIGN_TRANSFER) @@ -174,6 +177,9 @@ namespace tools bool on_untag_accounts(const wallet_rpc::COMMAND_RPC_UNTAG_ACCOUNTS::request& req, wallet_rpc::COMMAND_RPC_UNTAG_ACCOUNTS::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL); bool on_set_account_tag_description(const wallet_rpc::COMMAND_RPC_SET_ACCOUNT_TAG_DESCRIPTION::request& req, wallet_rpc::COMMAND_RPC_SET_ACCOUNT_TAG_DESCRIPTION::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL); bool on_getheight(const wallet_rpc::COMMAND_RPC_GET_HEIGHT::request& req, wallet_rpc::COMMAND_RPC_GET_HEIGHT::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL); + bool on_freeze(const wallet_rpc::COMMAND_RPC_FREEZE::request& req, wallet_rpc::COMMAND_RPC_FREEZE::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL); + bool on_thaw(const wallet_rpc::COMMAND_RPC_THAW::request& req, wallet_rpc::COMMAND_RPC_THAW::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL); + bool on_frozen(const wallet_rpc::COMMAND_RPC_FROZEN::request& req, wallet_rpc::COMMAND_RPC_FROZEN::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL); bool on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL); bool on_transfer_split(const wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::request& req, wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL); bool on_sign_transfer(const wallet_rpc::COMMAND_RPC_SIGN_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_SIGN_TRANSFER::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL); @@ -257,10 +263,10 @@ namespace tools bool not_open(epee::json_rpc::error& er); void handle_rpc_exception(const std::exception_ptr& e, epee::json_rpc::error& er, int default_error_code); - template<typename Ts, typename Tu> + template<typename Ts, typename Tu, typename Tk> bool fill_response(std::vector<tools::wallet2::pending_tx> &ptx_vector, bool get_tx_key, Ts& tx_key, Tu &amount, Tu &fee, Tu &weight, std::string &multisig_txset, std::string &unsigned_txset, bool do_not_relay, - Ts &tx_hash, bool get_tx_hex, Ts &tx_blob, bool get_tx_metadata, Ts &tx_metadata, epee::json_rpc::error &er); + Ts &tx_hash, bool get_tx_hex, Ts &tx_blob, bool get_tx_metadata, Ts &tx_metadata, Tk &spent_key_images, epee::json_rpc::error &er); bool validate_transfer(const std::list<wallet_rpc::transfer_destination>& destinations, const std::string& payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, bool at_least_one_destination, epee::json_rpc::error& er); diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index 0002508a2..6640441ed 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -47,7 +47,7 @@ // advance which version they will stop working with // Don't go over 32767 for any of these #define WALLET_RPC_VERSION_MAJOR 1 -#define WALLET_RPC_VERSION_MINOR 21 +#define WALLET_RPC_VERSION_MINOR 22 #define MAKE_WALLET_RPC_VERSION(major,minor) (((major)<<16)|(minor)) #define WALLET_RPC_VERSION MAKE_WALLET_RPC_VERSION(WALLET_RPC_VERSION_MAJOR, WALLET_RPC_VERSION_MINOR) namespace tools @@ -456,6 +456,78 @@ namespace wallet_rpc END_KV_SERIALIZE_MAP() }; + struct COMMAND_RPC_FREEZE + { + struct request_t + { + std::string key_image; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(key_image) + END_KV_SERIALIZE_MAP() + }; + typedef epee::misc_utils::struct_init<request_t> request; + + struct response_t + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + typedef epee::misc_utils::struct_init<response_t> response; + }; + + struct COMMAND_RPC_THAW + { + struct request_t + { + std::string key_image; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(key_image) + END_KV_SERIALIZE_MAP() + }; + typedef epee::misc_utils::struct_init<request_t> request; + + struct response_t + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + typedef epee::misc_utils::struct_init<response_t> response; + }; + + struct COMMAND_RPC_FROZEN + { + struct request_t + { + std::string key_image; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(key_image) + END_KV_SERIALIZE_MAP() + }; + typedef epee::misc_utils::struct_init<request_t> request; + + struct response_t + { + bool frozen; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(frozen) + END_KV_SERIALIZE_MAP() + }; + typedef epee::misc_utils::struct_init<response_t> response; + }; + + struct key_image_list + { + std::list<std::string> key_images; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(key_images) + END_KV_SERIALIZE_MAP() + }; + struct COMMAND_RPC_TRANSFER { struct request_t @@ -499,6 +571,7 @@ namespace wallet_rpc std::string tx_metadata; std::string multisig_txset; std::string unsigned_txset; + key_image_list spent_key_images; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(tx_hash) @@ -510,6 +583,7 @@ namespace wallet_rpc KV_SERIALIZE(tx_metadata) KV_SERIALIZE(multisig_txset) KV_SERIALIZE(unsigned_txset) + KV_SERIALIZE(spent_key_images) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<response_t> response; @@ -567,6 +641,7 @@ namespace wallet_rpc std::list<std::string> tx_metadata_list; std::string multisig_txset; std::string unsigned_txset; + std::list<key_image_list> spent_key_images_list; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(tx_hash_list) @@ -578,6 +653,7 @@ namespace wallet_rpc KV_SERIALIZE(tx_metadata_list) KV_SERIALIZE(multisig_txset) KV_SERIALIZE(unsigned_txset) + KV_SERIALIZE(spent_key_images_list) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<response_t> response; @@ -742,6 +818,7 @@ namespace wallet_rpc std::list<std::string> tx_metadata_list; std::string multisig_txset; std::string unsigned_txset; + std::list<key_image_list> spent_key_images_list; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(tx_hash_list) @@ -753,6 +830,7 @@ namespace wallet_rpc KV_SERIALIZE(tx_metadata_list) KV_SERIALIZE(multisig_txset) KV_SERIALIZE(unsigned_txset) + KV_SERIALIZE(spent_key_images_list) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<response_t> response; @@ -816,6 +894,7 @@ namespace wallet_rpc std::list<std::string> tx_metadata_list; std::string multisig_txset; std::string unsigned_txset; + std::list<key_image_list> spent_key_images_list; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(tx_hash_list) @@ -827,6 +906,7 @@ namespace wallet_rpc KV_SERIALIZE(tx_metadata_list) KV_SERIALIZE(multisig_txset) KV_SERIALIZE(unsigned_txset) + KV_SERIALIZE(spent_key_images_list) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<response_t> response; @@ -875,6 +955,7 @@ namespace wallet_rpc std::string tx_metadata; std::string multisig_txset; std::string unsigned_txset; + key_image_list spent_key_images; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(tx_hash) @@ -886,6 +967,7 @@ namespace wallet_rpc KV_SERIALIZE(tx_metadata) KV_SERIALIZE(multisig_txset) KV_SERIALIZE(unsigned_txset) + KV_SERIALIZE(spent_key_images) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<response_t> response; |