aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/depends.yml2
-rw-r--r--CMakeLists.txt10
-rw-r--r--contrib/epee/include/serialization/wire/write.h9
-rw-r--r--contrib/epee/src/http_auth.cpp6
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.cpp20
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.h2
-rw-r--r--src/cryptonote_basic/merge_mining.cpp10
-rw-r--r--src/cryptonote_basic/merge_mining.h4
-rw-r--r--src/cryptonote_basic/tx_extra.h10
-rw-r--r--src/rpc/core_rpc_server.cpp34
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h2
-rw-r--r--src/rpc/daemon_messages.cpp201
-rw-r--r--src/rpc/rpc_payment.h8
-rw-r--r--src/rpc/zmq_server.cpp23
-rw-r--r--src/serialization/container.h33
-rw-r--r--src/serialization/containers.h99
-rw-r--r--src/serialization/debug_archive.h10
-rw-r--r--src/serialization/difficulty_type.h2
-rw-r--r--src/serialization/pair.h4
-rw-r--r--src/serialization/serialization.h125
-rw-r--r--src/serialization/tuple.h2
-rw-r--r--src/serialization/variant.h45
-rw-r--r--src/wallet/message_transporter.cpp13
-rw-r--r--src/wallet/wallet2.cpp73
-rw-r--r--src/wallet/wallet2.h60
-rw-r--r--tests/unit_tests/crypto.cpp10
-rw-r--r--tests/unit_tests/json_serialization.cpp7
-rw-r--r--tests/unit_tests/serialization.cpp39
-rw-r--r--utils/gpg_keys/tobtoht.asc51
29 files changed, 573 insertions, 341 deletions
diff --git a/.github/workflows/depends.yml b/.github/workflows/depends.yml
index 4827bb51d..c534965e8 100644
--- a/.github/workflows/depends.yml
+++ b/.github/workflows/depends.yml
@@ -105,7 +105,7 @@ jobs:
${{env.CCACHE_SETTINGS}}
make depends target=${{ matrix.toolchain.host }} -j2
- uses: actions/upload-artifact@v3
- if: ${{ matrix.toolchain.host == 'x86_64-w64-mingw32' || matrix.toolchain.host == 'x86_64-apple-darwin11' || matrix.toolchain.host == 'x86_64-unknown-linux-gnu' }}
+ if: ${{ matrix.toolchain.host == 'x86_64-w64-mingw32' || matrix.toolchain.host == 'x86_64-apple-darwin' || matrix.toolchain.host == 'x86_64-unknown-linux-gnu' }}
with:
name: ${{ matrix.toolchain.name }}
path: |
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 99baba2ba..3c35a225a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -28,6 +28,9 @@
#
# Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+cmake_minimum_required(VERSION 3.5)
+message(STATUS "CMake version ${CMAKE_VERSION}")
+
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
list(INSERT CMAKE_MODULE_PATH 0
@@ -37,15 +40,14 @@ include(CheckCXXCompilerFlag)
include(CheckLinkerFlag)
include(CheckLibraryExists)
include(CheckFunctionExists)
+
+cmake_policy(SET CMP0148 OLD)
include(FindPythonInterp)
if (IOS)
INCLUDE(CmakeLists_IOS.txt)
endif()
-cmake_minimum_required(VERSION 3.5)
-message(STATUS "CMake version ${CMAKE_VERSION}")
-
project(monero)
option (USE_CCACHE "Use ccache if a usable instance is found" ON)
@@ -219,7 +221,7 @@ function(forbid_undefined_symbols)
file(MAKE_DIRECTORY "${TEST_PROJECT}")
file(WRITE "${TEST_PROJECT}/CMakeLists.txt"
[=[
-cmake_minimum_required(VERSION 3.1)
+cmake_minimum_required(VERSION 3.5)
project(test)
option(EXPECT_SUCCESS "" ON)
file(WRITE "${CMAKE_SOURCE_DIR}/incorrect_source.cpp" "void undefined_symbol(); void symbol() { undefined_symbol(); }")
diff --git a/contrib/epee/include/serialization/wire/write.h b/contrib/epee/include/serialization/wire/write.h
index c18f7dbcc..c2359918c 100644
--- a/contrib/epee/include/serialization/wire/write.h
+++ b/contrib/epee/include/serialization/wire/write.h
@@ -30,6 +30,7 @@
#include <boost/utility/string_ref.hpp>
#include <boost/range/size.hpp>
#include <cstdint>
+#include <iterator>
#include <system_error>
#include <type_traits>
@@ -188,7 +189,13 @@ namespace wire_write
template<typename T>
inline std::size_t array_size(std::true_type, const T& source)
- { return boost::size(source); }
+ {
+ static_assert(
+ !std::is_same<typename std::iterator_traits<typename T::const_iterator>::iterator_category, std::input_iterator_tag>{},
+ "Input iterators must use json (or similar) derived classes directly"
+ );
+ return boost::size(source);
+ }
template<typename T>
inline constexpr std::size_t array_size(std::false_type, const T&) noexcept
diff --git a/contrib/epee/src/http_auth.cpp b/contrib/epee/src/http_auth.cpp
index 5071d2685..d6de6a0e1 100644
--- a/contrib/epee/src/http_auth.cpp
+++ b/contrib/epee/src/http_auth.cpp
@@ -217,15 +217,13 @@ namespace
//// Digest Authentication
template<typename Digest>
- typename std::result_of<Digest()>::type generate_a1(
- Digest digest, const http::login& creds, const boost::string_ref realm)
+ auto generate_a1(Digest digest, const http::login& creds, const boost::string_ref realm)
{
return digest(creds.username, u8":", realm, u8":", creds.password);
}
template<typename Digest>
- typename std::result_of<Digest()>::type generate_a1(
- Digest digest, const http::http_client_auth::session& user)
+ auto generate_a1(Digest digest, const http::http_client_auth::session& user)
{
return generate_a1(std::move(digest), user.credentials, user.server.realm);
}
diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp
index 9aeee3d55..c86e7d848 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.cpp
+++ b/src/cryptonote_basic/cryptonote_format_utils.cpp
@@ -739,22 +739,28 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
- bool add_mm_merkle_root_to_tx_extra(std::vector<uint8_t>& tx_extra, const crypto::hash& mm_merkle_root, size_t mm_merkle_tree_depth)
+ bool add_mm_merkle_root_to_tx_extra(std::vector<uint8_t>& tx_extra, const crypto::hash& mm_merkle_root, uint64_t mm_merkle_tree_depth)
{
- CHECK_AND_ASSERT_MES(mm_merkle_tree_depth < 32, false, "merge mining merkle tree depth should be less than 32");
size_t start_pos = tx_extra.size();
- tx_extra.resize(tx_extra.size() + 3 + 32);
+ static const size_t max_varint_size = 16;
+ tx_extra.resize(tx_extra.size() + 2 + 32 + max_varint_size);
//write tag
tx_extra[start_pos] = TX_EXTRA_MERGE_MINING_TAG;
//write data size
++start_pos;
- tx_extra[start_pos] = 33;
- //write depth varint (always one byte here)
+ const off_t len_bytes = start_pos;
+ // one byte placeholder for length since we'll only know the size later after writing a varint
+ tx_extra[start_pos] = 0;
+ //write depth varint
++start_pos;
- tx_extra[start_pos] = mm_merkle_tree_depth;
+ uint8_t *ptr = &tx_extra[start_pos], *start = ptr;
+ tools::write_varint(ptr, mm_merkle_tree_depth);
//write data
- ++start_pos;
+ const size_t varint_size = ptr - start;
+ start_pos += varint_size;
memcpy(&tx_extra[start_pos], &mm_merkle_root, 32);
+ tx_extra.resize(tx_extra.size() - (max_varint_size - varint_size));
+ tx_extra[len_bytes] = 32 + varint_size;
return true;
}
//---------------------------------------------------------------
diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h
index 33fec238e..bd4dcd83d 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.h
+++ b/src/cryptonote_basic/cryptonote_format_utils.h
@@ -83,7 +83,7 @@ namespace cryptonote
std::vector<crypto::public_key> get_additional_tx_pub_keys_from_extra(const transaction_prefix& tx);
bool add_additional_tx_pub_keys_to_extra(std::vector<uint8_t>& tx_extra, const std::vector<crypto::public_key>& additional_pub_keys);
bool add_extra_nonce_to_tx_extra(std::vector<uint8_t>& tx_extra, const blobdata& extra_nonce);
- bool add_mm_merkle_root_to_tx_extra(std::vector<uint8_t>& tx_extra, const crypto::hash& mm_merkle_root, size_t mm_merkle_tree_depth);
+ bool add_mm_merkle_root_to_tx_extra(std::vector<uint8_t>& tx_extra, const crypto::hash& mm_merkle_root, uint64_t mm_merkle_tree_depth);
bool remove_field_from_tx_extra(std::vector<uint8_t>& tx_extra, const std::type_info &type);
void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id);
void set_encrypted_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash8& payment_id);
diff --git a/src/cryptonote_basic/merge_mining.cpp b/src/cryptonote_basic/merge_mining.cpp
index 0e649e095..3e26c00e3 100644
--- a/src/cryptonote_basic/merge_mining.cpp
+++ b/src/cryptonote_basic/merge_mining.cpp
@@ -71,21 +71,21 @@ uint32_t get_path_from_aux_slot(uint32_t slot, uint32_t n_aux_chains)
return path;
}
//---------------------------------------------------------------
-uint32_t encode_mm_depth(uint32_t n_aux_chains, uint32_t nonce)
+uint64_t encode_mm_depth(uint32_t n_aux_chains, uint32_t nonce)
{
CHECK_AND_ASSERT_THROW_MES(n_aux_chains > 0, "n_aux_chains is 0");
+ CHECK_AND_ASSERT_THROW_MES(n_aux_chains <= 256, "n_aux_chains is too large");
// how many bits to we need to representing n_aux_chains - 1
uint32_t n_bits = 1;
- while ((1u << n_bits) < n_aux_chains && n_bits < 16)
+ while ((1u << n_bits) < n_aux_chains)
++n_bits;
- CHECK_AND_ASSERT_THROW_MES(n_bits <= 16, "Way too many bits required");
- const uint32_t depth = (n_bits - 1) | ((n_aux_chains - 1) << 3) | (nonce << (3 + n_bits));
+ const uint64_t depth = (n_bits - 1) | ((n_aux_chains - 1) << 3) | (((uint64_t)nonce) << (3 + n_bits));
return depth;
}
//---------------------------------------------------------------
-bool decode_mm_depth(uint32_t depth, uint32_t &n_aux_chains, uint32_t &nonce)
+bool decode_mm_depth(uint64_t depth, uint32_t &n_aux_chains, uint32_t &nonce)
{
const uint32_t n_bits = 1 + (depth & 7);
n_aux_chains = 1 + (depth >> 3 & ((1 << n_bits) - 1));
diff --git a/src/cryptonote_basic/merge_mining.h b/src/cryptonote_basic/merge_mining.h
index acb70ebf0..ef4c92d67 100644
--- a/src/cryptonote_basic/merge_mining.h
+++ b/src/cryptonote_basic/merge_mining.h
@@ -36,6 +36,6 @@ namespace cryptonote
{
uint32_t get_aux_slot(const crypto::hash &id, uint32_t nonce, uint32_t n_aux_chains);
uint32_t get_path_from_aux_slot(uint32_t slot, uint32_t n_aux_chains);
- uint32_t encode_mm_depth(uint32_t n_aux_chains, uint32_t nonce);
- bool decode_mm_depth(uint32_t depth, uint32_t &n_aux_chains, uint32_t &nonce);
+ uint64_t encode_mm_depth(uint32_t n_aux_chains, uint32_t nonce);
+ bool decode_mm_depth(uint64_t depth, uint32_t &n_aux_chains, uint32_t &nonce);
}
diff --git a/src/cryptonote_basic/tx_extra.h b/src/cryptonote_basic/tx_extra.h
index af6ee5197..cbf942d4c 100644
--- a/src/cryptonote_basic/tx_extra.h
+++ b/src/cryptonote_basic/tx_extra.h
@@ -52,7 +52,7 @@ namespace cryptonote
// load
template <template <bool> class Archive>
- bool do_serialize(Archive<false>& ar)
+ bool member_do_serialize(Archive<false>& ar)
{
// size - 1 - because of variant tag
for (size = 1; size <= TX_EXTRA_PADDING_MAX_COUNT; ++size)
@@ -73,7 +73,7 @@ namespace cryptonote
// store
template <template <bool> class Archive>
- bool do_serialize(Archive<true>& ar)
+ bool member_do_serialize(Archive<true>& ar)
{
if(TX_EXTRA_PADDING_MAX_COUNT < size)
return false;
@@ -124,12 +124,12 @@ namespace cryptonote
END_SERIALIZE()
};
- size_t depth;
+ uint64_t depth;
crypto::hash merkle_root;
// load
template <template <bool> class Archive>
- bool do_serialize(Archive<false>& ar)
+ bool member_do_serialize(Archive<false>& ar)
{
std::string field;
if(!::do_serialize(ar, field))
@@ -142,7 +142,7 @@ namespace cryptonote
// store
template <template <bool> class Archive>
- bool do_serialize(Archive<true>& ar)
+ bool member_do_serialize(Archive<true>& ar)
{
std::ostringstream oss;
binary_archive<true> oar(oss);
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index fbca32f80..9a0b02f70 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -2082,11 +2082,12 @@ namespace cryptonote
}
crypto::hash merkle_root;
- size_t merkle_tree_depth = 0;
std::vector<std::pair<crypto::hash, crypto::hash>> aux_pow;
std::vector<crypto::hash> aux_pow_raw;
+ std::vector<crypto::hash> aux_pow_id_raw;
aux_pow.reserve(req.aux_pow.size());
- aux_pow_raw.reserve(req.aux_pow.size());
+ aux_pow_raw.resize(req.aux_pow.size());
+ aux_pow_id_raw.resize(req.aux_pow.size());
for (const auto &s: req.aux_pow)
{
aux_pow.push_back({});
@@ -2102,7 +2103,6 @@ namespace cryptonote
error_resp.message = "Invalid aux pow hash";
return false;
}
- aux_pow_raw.push_back(aux_pow.back().second);
}
size_t path_domain = 1;
@@ -2111,11 +2111,14 @@ namespace cryptonote
uint32_t nonce;
const uint32_t max_nonce = 65535;
bool collision = true;
+ std::vector<uint32_t> slots(aux_pow.size());
for (nonce = 0; nonce <= max_nonce; ++nonce)
{
- std::vector<bool> slots(aux_pow.size(), false);
+ std::vector<bool> slot_seen(aux_pow.size(), false);
collision = false;
for (size_t idx = 0; idx < aux_pow.size(); ++idx)
+ slots[idx] = 0xffffffff;
+ for (size_t idx = 0; idx < aux_pow.size(); ++idx)
{
const uint32_t slot = cryptonote::get_aux_slot(aux_pow[idx].first, nonce, aux_pow.size());
if (slot >= aux_pow.size())
@@ -2124,12 +2127,13 @@ namespace cryptonote
error_resp.message = "Computed slot is out of range";
return false;
}
- if (slots[slot])
+ if (slot_seen[slot])
{
collision = true;
break;
}
- slots[slot] = true;
+ slot_seen[slot] = true;
+ slots[idx] = slot;
}
if (!collision)
break;
@@ -2141,6 +2145,19 @@ namespace cryptonote
return false;
}
+ // set the order determined above
+ for (size_t i = 0; i < aux_pow.size(); ++i)
+ {
+ if (slots[i] >= aux_pow.size())
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
+ error_resp.message = "Slot value out of range";
+ return false;
+ }
+ aux_pow_raw[slots[i]] = aux_pow[i].second;
+ aux_pow_id_raw[slots[i]] = aux_pow[i].first;
+ }
+
crypto::tree_hash((const char(*)[crypto::HASH_SIZE])aux_pow_raw.data(), aux_pow_raw.size(), merkle_root.data);
res.merkle_root = epee::string_tools::pod_to_hex(merkle_root);
res.merkle_tree_depth = cryptonote::encode_mm_depth(aux_pow.size(), nonce);
@@ -2167,7 +2184,7 @@ namespace cryptonote
error_resp.message = "Error removing existing merkle root";
return false;
}
- if (!add_mm_merkle_root_to_tx_extra(b.miner_tx.extra, merkle_root, merkle_tree_depth))
+ if (!add_mm_merkle_root_to_tx_extra(b.miner_tx.extra, merkle_root, res.merkle_tree_depth))
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
error_resp.message = "Error adding merkle root";
@@ -2181,7 +2198,8 @@ namespace cryptonote
res.blocktemplate_blob = string_tools::buff_to_hex_nodelimer(block_blob);
res.blockhashing_blob = string_tools::buff_to_hex_nodelimer(hashing_blob);
- res.aux_pow = req.aux_pow;
+ for (size_t i = 0; i < aux_pow_raw.size(); ++i)
+ res.aux_pow.push_back({epee::string_tools::pod_to_hex(aux_pow_id_raw[i]), epee::string_tools::pod_to_hex(aux_pow_raw[i])});
res.status = CORE_RPC_STATUS_OK;
return true;
}
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index c0330eed9..2a0a6201d 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -1094,7 +1094,7 @@ namespace cryptonote
blobdata blocktemplate_blob;
blobdata blockhashing_blob;
std::string merkle_root;
- uint32_t merkle_tree_depth;
+ uint64_t merkle_tree_depth;
std::vector<aux_pow_t> aux_pow;
BEGIN_KV_SERIALIZE_MAP()
diff --git a/src/rpc/daemon_messages.cpp b/src/rpc/daemon_messages.cpp
index 0da22f15f..36528fcea 100644
--- a/src/rpc/daemon_messages.cpp
+++ b/src/rpc/daemon_messages.cpp
@@ -48,6 +48,11 @@ void GetHeight::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) c
void GetHeight::Response::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, height, height);
}
@@ -61,6 +66,11 @@ void GetBlocksFast::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest
void GetBlocksFast::Request::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, block_ids, block_ids);
GET_FROM_JSON_OBJECT(val, start_height, start_height);
GET_FROM_JSON_OBJECT(val, prune, prune);
@@ -76,6 +86,11 @@ void GetBlocksFast::Response::doToJson(rapidjson::Writer<epee::byte_stream>& des
void GetBlocksFast::Response::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, blocks, blocks);
GET_FROM_JSON_OBJECT(val, start_height, start_height);
GET_FROM_JSON_OBJECT(val, current_height, current_height);
@@ -91,6 +106,11 @@ void GetHashesFast::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest
void GetHashesFast::Request::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, known_hashes, known_hashes);
GET_FROM_JSON_OBJECT(val, start_height, start_height);
}
@@ -100,10 +120,16 @@ void GetHashesFast::Response::doToJson(rapidjson::Writer<epee::byte_stream>& des
INSERT_INTO_JSON_OBJECT(dest, hashes, hashes);
INSERT_INTO_JSON_OBJECT(dest, start_height, start_height);
INSERT_INTO_JSON_OBJECT(dest, current_height, current_height);
+
}
void GetHashesFast::Response::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, hashes, hashes);
GET_FROM_JSON_OBJECT(val, start_height, start_height);
GET_FROM_JSON_OBJECT(val, current_height, current_height);
@@ -117,6 +143,11 @@ void GetTransactions::Request::doToJson(rapidjson::Writer<epee::byte_stream>& de
void GetTransactions::Request::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, tx_hashes, tx_hashes);
}
@@ -128,6 +159,11 @@ void GetTransactions::Response::doToJson(rapidjson::Writer<epee::byte_stream>& d
void GetTransactions::Response::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, txs, txs);
GET_FROM_JSON_OBJECT(val, missed_hashes, missed_hashes);
}
@@ -140,6 +176,11 @@ void KeyImagesSpent::Request::doToJson(rapidjson::Writer<epee::byte_stream>& des
void KeyImagesSpent::Request::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, key_images, key_images);
}
@@ -150,6 +191,11 @@ void KeyImagesSpent::Response::doToJson(rapidjson::Writer<epee::byte_stream>& de
void KeyImagesSpent::Response::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, spent_status, spent_status);
}
@@ -161,6 +207,11 @@ void GetTxGlobalOutputIndices::Request::doToJson(rapidjson::Writer<epee::byte_st
void GetTxGlobalOutputIndices::Request::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, tx_hash, tx_hash);
}
@@ -171,6 +222,11 @@ void GetTxGlobalOutputIndices::Response::doToJson(rapidjson::Writer<epee::byte_s
void GetTxGlobalOutputIndices::Response::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, output_indices, output_indices);
}
@@ -182,6 +238,11 @@ void SendRawTx::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) co
void SendRawTx::Request::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, tx, tx);
GET_FROM_JSON_OBJECT(val, relay, relay);
}
@@ -194,6 +255,11 @@ void SendRawTx::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) c
void SendRawTx::Response::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, relayed, relayed);
}
@@ -205,6 +271,11 @@ void SendRawTxHex::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest)
void SendRawTxHex::Request::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, tx_as_hex, tx_as_hex);
GET_FROM_JSON_OBJECT(val, relay, relay);
}
@@ -219,6 +290,11 @@ void StartMining::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest)
void StartMining::Request::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, miner_address, miner_address);
GET_FROM_JSON_OBJECT(val, threads_count, threads_count);
GET_FROM_JSON_OBJECT(val, do_background_mining, do_background_mining);
@@ -266,6 +342,11 @@ void MiningStatus::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest
void MiningStatus::Response::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, active, active);
GET_FROM_JSON_OBJECT(val, speed, speed);
GET_FROM_JSON_OBJECT(val, threads_count, threads_count);
@@ -288,6 +369,11 @@ void GetInfo::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) con
void GetInfo::Response::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, info, info);
}
@@ -314,6 +400,11 @@ void GetBlockHash::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest)
void GetBlockHash::Request::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, height, height);
}
@@ -324,6 +415,11 @@ void GetBlockHash::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest
void GetBlockHash::Response::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, hash, hash);
}
@@ -342,6 +438,11 @@ void GetLastBlockHeader::Response::doToJson(rapidjson::Writer<epee::byte_stream>
void GetLastBlockHeader::Response::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, header, header);
}
@@ -353,6 +454,11 @@ void GetBlockHeaderByHash::Request::doToJson(rapidjson::Writer<epee::byte_stream
void GetBlockHeaderByHash::Request::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, hash, hash);
}
@@ -363,6 +469,11 @@ void GetBlockHeaderByHash::Response::doToJson(rapidjson::Writer<epee::byte_strea
void GetBlockHeaderByHash::Response::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, header, header);
}
@@ -374,6 +485,11 @@ void GetBlockHeaderByHeight::Request::doToJson(rapidjson::Writer<epee::byte_stre
void GetBlockHeaderByHeight::Request::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, height, height);
}
@@ -384,6 +500,11 @@ void GetBlockHeaderByHeight::Response::doToJson(rapidjson::Writer<epee::byte_str
void GetBlockHeaderByHeight::Response::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, header, header);
}
@@ -395,6 +516,11 @@ void GetBlockHeadersByHeight::Request::doToJson(rapidjson::Writer<epee::byte_str
void GetBlockHeadersByHeight::Request::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, heights, heights);
}
@@ -405,6 +531,11 @@ void GetBlockHeadersByHeight::Response::doToJson(rapidjson::Writer<epee::byte_st
void GetBlockHeadersByHeight::Response::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, headers, headers);
}
@@ -424,6 +555,11 @@ void GetPeerList::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest)
void GetPeerList::Response::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, white_list, white_list);
GET_FROM_JSON_OBJECT(val, gray_list, gray_list);
}
@@ -436,6 +572,11 @@ void SetLogLevel::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest)
void SetLogLevel::Request::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, level, level);
}
@@ -462,6 +603,11 @@ void GetTransactionPool::Response::doToJson(rapidjson::Writer<epee::byte_stream>
void GetTransactionPool::Response::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, transactions, transactions);
GET_FROM_JSON_OBJECT(val, key_images, key_images);
}
@@ -474,6 +620,11 @@ void HardForkInfo::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest)
void HardForkInfo::Request::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, version, version);
}
@@ -484,6 +635,11 @@ void HardForkInfo::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest
void HardForkInfo::Response::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, info, info);
}
@@ -499,6 +655,11 @@ void GetOutputHistogram::Request::doToJson(rapidjson::Writer<epee::byte_stream>&
void GetOutputHistogram::Request::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, amounts, amounts);
GET_FROM_JSON_OBJECT(val, min_count, min_count);
GET_FROM_JSON_OBJECT(val, max_count, max_count);
@@ -513,6 +674,11 @@ void GetOutputHistogram::Response::doToJson(rapidjson::Writer<epee::byte_stream>
void GetOutputHistogram::Response::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, histogram, histogram);
}
@@ -524,6 +690,11 @@ void GetOutputKeys::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest
void GetOutputKeys::Request::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, outputs, outputs);
}
@@ -534,6 +705,11 @@ void GetOutputKeys::Response::doToJson(rapidjson::Writer<epee::byte_stream>& des
void GetOutputKeys::Response::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, keys, keys);
}
@@ -552,6 +728,11 @@ void GetRPCVersion::Response::doToJson(rapidjson::Writer<epee::byte_stream>& des
void GetRPCVersion::Response::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, version, version);
}
@@ -562,6 +743,11 @@ void GetFeeEstimate::Request::doToJson(rapidjson::Writer<epee::byte_stream>& des
void GetFeeEstimate::Request::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, num_grace_blocks, num_grace_blocks);
}
@@ -575,6 +761,11 @@ void GetFeeEstimate::Response::doToJson(rapidjson::Writer<epee::byte_stream>& de
void GetFeeEstimate::Response::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, estimated_base_fee, estimated_base_fee);
GET_FROM_JSON_OBJECT(val, fee_mask, fee_mask);
GET_FROM_JSON_OBJECT(val, size_scale, size_scale);
@@ -591,6 +782,11 @@ void GetOutputDistribution::Request::doToJson(rapidjson::Writer<epee::byte_strea
void GetOutputDistribution::Request::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, amounts, amounts);
GET_FROM_JSON_OBJECT(val, from_height, from_height);
GET_FROM_JSON_OBJECT(val, to_height, to_height);
@@ -605,6 +801,11 @@ void GetOutputDistribution::Response::doToJson(rapidjson::Writer<epee::byte_stre
void GetOutputDistribution::Response::fromJson(const rapidjson::Value& val)
{
+ if (!val.IsObject())
+ {
+ throw json::WRONG_TYPE("json object");
+ }
+
GET_FROM_JSON_OBJECT(val, status, status);
GET_FROM_JSON_OBJECT(val, distributions, distributions);
}
diff --git a/src/rpc/rpc_payment.h b/src/rpc/rpc_payment.h
index 4ead5a344..a4cc6db57 100644
--- a/src/rpc/rpc_payment.h
+++ b/src/rpc/rpc_payment.h
@@ -148,8 +148,8 @@ namespace cryptonote
template <class t_archive>
inline void serialize(t_archive &a, const unsigned int ver)
{
- a & m_client_info.parent();
- a & m_hashrate.parent();
+ a & m_client_info;
+ a & m_hashrate;
a & m_credits_total;
a & m_credits_used;
a & m_nonces_good;
@@ -177,9 +177,9 @@ namespace cryptonote
cryptonote::account_public_address m_address;
uint64_t m_diff;
uint64_t m_credits_per_hash_found;
- serializable_unordered_map<crypto::public_key, client_info> m_client_info;
+ std::unordered_map<crypto::public_key, client_info> m_client_info;
std::string m_directory;
- serializable_map<uint64_t, uint64_t> m_hashrate;
+ std::map<uint64_t, uint64_t> m_hashrate;
uint64_t m_credits_total;
uint64_t m_credits_used;
uint64_t m_nonces_good;
diff --git a/src/rpc/zmq_server.cpp b/src/rpc/zmq_server.cpp
index cb8a8bea4..d73ea3bc9 100644
--- a/src/rpc/zmq_server.cpp
+++ b/src/rpc/zmq_server.cpp
@@ -158,13 +158,22 @@ void ZmqServer::serve()
if (!pub || sockets[2].revents)
{
- std::string message = MONERO_UNWRAP(net::zmq::receive(rep.get(), read_flags));
- MDEBUG("Received RPC request: \"" << message << "\"");
- epee::byte_slice response = handler.handle(std::move(message));
-
- const boost::string_ref response_view{reinterpret_cast<const char*>(response.data()), response.size()};
- MDEBUG("Sending RPC reply: \"" << response_view << "\"");
- MONERO_UNWRAP(net::zmq::send(std::move(response), rep.get()));
+ expect<std::string> message = net::zmq::receive(rep.get(), read_flags);
+ if (!message)
+ {
+ // EAGAIN can occur when using `zmq_poll`, which doesn't inspect for message validity
+ if (message != net::zmq::make_error_code(EAGAIN))
+ MONERO_THROW(message.error(), "Read failure on ZMQ-RPC");
+ }
+ else // no errors
+ {
+ MDEBUG("Received RPC request: \"" << *message << "\"");
+ epee::byte_slice response = handler.handle(std::move(*message));
+
+ const boost::string_ref response_view{reinterpret_cast<const char*>(response.data()), response.size()};
+ MDEBUG("Sending RPC reply: \"" << response_view << "\"");
+ MONERO_UNWRAP(net::zmq::send(std::move(response), rep.get()));
+ }
}
}
}
diff --git a/src/serialization/container.h b/src/serialization/container.h
index 80e1892f2..6f0c48069 100644
--- a/src/serialization/container.h
+++ b/src/serialization/container.h
@@ -42,7 +42,7 @@ namespace serialization
typename std::enable_if<!use_container_varint<T>(), bool>::type
serialize_container_element(Archive& ar, T& e)
{
- return ::do_serialize(ar, e);
+ return do_serialize(ar, e);
}
template<typename Archive, typename T>
@@ -52,13 +52,33 @@ namespace serialization
static constexpr const bool previously_varint = std::is_same<uint64_t, T>() || std::is_same<uint32_t, T>();
if (!previously_varint && ar.varint_bug_backward_compatibility_enabled() && !typename Archive::is_saving())
- return ::do_serialize(ar, e);
+ return do_serialize(ar, e);
ar.serialize_varint(e);
return true;
}
- template <typename C>
- void do_reserve(C &c, size_t N) {}
+ //! @brief Add an element to a container, inserting at the back if applicable.
+ template <class Container>
+ auto do_add(Container &c, typename Container::value_type &&e) -> decltype(c.emplace_back(e))
+ { return c.emplace_back(e); }
+ template <class Container>
+ auto do_add(Container &c, typename Container::value_type &&e) -> decltype(c.emplace(e))
+ { return c.emplace(e); }
+
+ //! @brief Reserve space for N elements if applicable for container.
+ template<typename... C>
+ void do_reserve(const C&...) {}
+ template<typename C>
+ auto do_reserve(C &c, std::size_t N) -> decltype(c.reserve(N)) { return c.reserve(N); }
+
+ // The value_type of STL map-like containers come in the form std::pair<const K, V>.
+ // Since we can't {de}serialize const types in this lib, we must convert this to std::pair<K, V>
+ template <class Container, typename = void>
+ struct serializable_value_type
+ { using type = typename Container::value_type; };
+ template <class Container>
+ struct serializable_value_type<Container, std::conditional_t<false, typename Container::mapped_type, void>>
+ { using type = std::pair<typename Container::key_type, typename Container::mapped_type>; };
}
}
@@ -82,7 +102,7 @@ bool do_serialize_container(Archive<false> &ar, C &v)
for (size_t i = 0; i < cnt; i++) {
if (i > 0)
ar.delimit_array();
- typename C::value_type e;
+ typename ::serialization::detail::serializable_value_type<C>::type e;
if (!::serialization::detail::serialize_container_element(ar, e))
return false;
::serialization::detail::do_add(v, std::move(e));
@@ -104,7 +124,8 @@ bool do_serialize_container(Archive<true> &ar, C &v)
return false;
if (i != v.begin())
ar.delimit_array();
- if(!::serialization::detail::serialize_container_element(ar, (typename C::value_type&)*i))
+ using serializable_value_type = typename ::serialization::detail::serializable_value_type<C>::type;
+ if(!::serialization::detail::serialize_container_element(ar, (serializable_value_type&)*i))
return false;
if (!ar.good())
return false;
diff --git a/src/serialization/containers.h b/src/serialization/containers.h
index 65e6359b2..28eaa50fb 100644
--- a/src/serialization/containers.h
+++ b/src/serialization/containers.h
@@ -38,91 +38,26 @@
#include <set>
#include "serialization.h"
-template <template <bool> class Archive, class T> bool do_serialize(Archive<false> &ar, std::vector<T> &v);
-template <template <bool> class Archive, class T> bool do_serialize(Archive<true> &ar, std::vector<T> &v);
-
-template <template <bool> class Archive, class T> bool do_serialize(Archive<false> &ar, std::deque<T> &v);
-template <template <bool> class Archive, class T> bool do_serialize(Archive<true> &ar, std::deque<T> &v);
-
-template<typename K, typename V>
-class serializable_unordered_map: public std::unordered_map<K, V>
-{
-public:
- typedef typename std::pair<K, V> value_type;
- typename std::unordered_map<K, V> &parent() { return *this; }
-};
-
-template <template <bool> class Archive, typename K, typename V> bool do_serialize(Archive<false> &ar, serializable_unordered_map<K, V> &v);
-template <template <bool> class Archive, typename K, typename V> bool do_serialize(Archive<true> &ar, serializable_unordered_map<K, V> &v);
-
-template<typename K, typename V>
-class serializable_map: public std::map<K, V>
-{
-public:
- typedef typename std::pair<K, V> value_type;
- typename std::map<K, V> &parent() { return *this; }
-};
-
-template <template <bool> class Archive, typename K, typename V> bool do_serialize(Archive<false> &ar, serializable_map<K, V> &v);
-template <template <bool> class Archive, typename K, typename V> bool do_serialize(Archive<true> &ar, serializable_map<K, V> &v);
-
-template<typename K, typename V>
-class serializable_unordered_multimap: public std::unordered_multimap<K, V>
-{
-public:
- typedef typename std::pair<K, V> value_type;
- typename std::unordered_multimap<K, V> &parent() { return *this; }
-};
-
-template <template <bool> class Archive, typename K, typename V> bool do_serialize(Archive<false> &ar, serializable_unordered_multimap<K, V> &v);
-template <template <bool> class Archive, typename K, typename V> bool do_serialize(Archive<true> &ar, serializable_unordered_multimap<K, V> &v);
-
-template <template <bool> class Archive, class T> bool do_serialize(Archive<false> &ar, std::unordered_set<T> &v);
-template <template <bool> class Archive, class T> bool do_serialize(Archive<true> &ar, std::unordered_set<T> &v);
-
-template <template <bool> class Archive, class T> bool do_serialize(Archive<false> &ar, std::set<T> &v);
-template <template <bool> class Archive, class T> bool do_serialize(Archive<true> &ar, std::set<T> &v);
-
namespace serialization
{
- namespace detail
- {
- template <typename T> void do_reserve(std::vector<T> &c, size_t N) { c.reserve(N); }
- template <typename T> void do_add(std::vector<T> &c, T &&e) { c.emplace_back(std::forward<T>(e)); }
-
- template <typename T> void do_add(std::deque<T> &c, T &&e) { c.emplace_back(std::forward<T>(e)); }
-
- template <typename K, typename V> void do_add(serializable_unordered_map<K, V> &c, std::pair<K, V> &&e) { c.insert(std::forward<std::pair<K, V>>(e)); }
-
- template <typename K, typename V> void do_add(serializable_map<K, V> &c, std::pair<K, V> &&e) { c.insert(std::forward<std::pair<K, V>>(e)); }
-
- template <typename K, typename V> void do_add(serializable_unordered_multimap<K, V> &c, std::pair<K, V> &&e) { c.insert(std::forward<std::pair<K, V>>(e)); }
-
- template <typename T> void do_add(std::unordered_set<T> &c, T &&e) { c.insert(std::forward<T>(e)); }
-
- template <typename T> void do_add(std::set<T> &c, T &&e) { c.insert(std::forward<T>(e)); }
- }
+ //! @brief Is this type a STL-like container?
+ //! To add a new container to be serialized, partially specialize the template is_container like so:
+ template <typename T> struct is_container: std::false_type {};
+ template <typename... TA> struct is_container<std::deque<TA...>>: std::true_type {};
+ template <typename... TA> struct is_container<std::map<TA...>>: std::true_type {};
+ template <typename... TA> struct is_container<std::multimap<TA...>>: std::true_type {};
+ template <typename... TA> struct is_container<std::set<TA...>>: std::true_type {};
+ template <typename... TA> struct is_container<std::unordered_map<TA...>>: std::true_type {};
+ template <typename... TA> struct is_container<std::unordered_multimap<TA...>>: std::true_type {};
+ template <typename... TA> struct is_container<std::unordered_set<TA...>>: std::true_type {};
+ template <typename... TA> struct is_container<std::vector<TA...>>: std::true_type {};
}
#include "container.h"
-template <template <bool> class Archive, class T> bool do_serialize(Archive<false> &ar, std::vector<T> &v) { return do_serialize_container(ar, v); }
-template <template <bool> class Archive, class T> bool do_serialize(Archive<true> &ar, std::vector<T> &v) { return do_serialize_container(ar, v); }
-
-template <template <bool> class Archive, class T> bool do_serialize(Archive<false> &ar, std::deque<T> &v) { return do_serialize_container(ar, v); }
-template <template <bool> class Archive, class T> bool do_serialize(Archive<true> &ar, std::deque<T> &v) { return do_serialize_container(ar, v); }
-
-template <template <bool> class Archive, typename K, typename V> bool do_serialize(Archive<false> &ar, serializable_unordered_map<K, V> &v) { return do_serialize_container(ar, v); }
-template <template <bool> class Archive, typename K, typename V> bool do_serialize(Archive<true> &ar, serializable_unordered_map<K, V> &v) { return do_serialize_container(ar, v); }
-
-template <template <bool> class Archive, typename K, typename V> bool do_serialize(Archive<false> &ar, serializable_map<K, V> &v) { return do_serialize_container(ar, v); }
-template <template <bool> class Archive, typename K, typename V> bool do_serialize(Archive<true> &ar, serializable_map<K, V> &v) { return do_serialize_container(ar, v); }
-
-template <template <bool> class Archive, typename K, typename V> bool do_serialize(Archive<false> &ar, serializable_unordered_multimap<K, V> &v) { return do_serialize_container(ar, v); }
-template <template <bool> class Archive, typename K, typename V> bool do_serialize(Archive<true> &ar, serializable_unordered_multimap<K, V> &v) { return do_serialize_container(ar, v); }
-
-template <template <bool> class Archive, class T> bool do_serialize(Archive<false> &ar, std::unordered_set<T> &v) { return do_serialize_container(ar, v); }
-template <template <bool> class Archive, class T> bool do_serialize(Archive<true> &ar, std::unordered_set<T> &v) { return do_serialize_container(ar, v); }
-
-template <template <bool> class Archive, class T> bool do_serialize(Archive<false> &ar, std::set<T> &v) { return do_serialize_container(ar, v); }
-template <template <bool> class Archive, class T> bool do_serialize(Archive<true> &ar, std::set<T> &v) { return do_serialize_container(ar, v); }
+template <class Archive, class Container>
+std::enable_if_t<::serialization::is_container<Container>::value, bool>
+do_serialize(Archive &ar, Container &c)
+{
+ return ::do_serialize_container(ar, c);
+}
diff --git a/src/serialization/debug_archive.h b/src/serialization/debug_archive.h
index ef3bb4345..f4df963db 100644
--- a/src/serialization/debug_archive.h
+++ b/src/serialization/debug_archive.h
@@ -42,14 +42,12 @@ struct debug_archive : public json_archive<W> {
};
template <class T>
-struct serializer<debug_archive<true>, T>
+static inline bool do_serialize(debug_archive<true> &ar, T &v)
{
- static void serialize(debug_archive<true> &ar, T &v)
- {
ar.begin_object();
ar.tag(variant_serialization_traits<debug_archive<true>, T>::get_tag());
- serializer<json_archive<true>, T>::serialize(ar, v);
+ do_serialize(static_cast<json_archive<true>&>(ar), v);
ar.end_object();
ar.stream() << std::endl;
- }
-};
+ return true;
+}
diff --git a/src/serialization/difficulty_type.h b/src/serialization/difficulty_type.h
index 37761839b..c071f287b 100644
--- a/src/serialization/difficulty_type.h
+++ b/src/serialization/difficulty_type.h
@@ -31,8 +31,6 @@
#include "cryptonote_basic/difficulty.h"
#include "serialization.h"
-template<> struct is_basic_type<cryptonote::difficulty_type> { typedef boost::true_type type; };
-
template <template <bool> class Archive>
inline bool do_serialize(Archive<false>& ar, cryptonote::difficulty_type &diff)
{
diff --git a/src/serialization/pair.h b/src/serialization/pair.h
index f21041fe8..888033fb9 100644
--- a/src/serialization/pair.h
+++ b/src/serialization/pair.h
@@ -47,7 +47,7 @@ namespace serialization
typename std::enable_if<!use_pair_varint<T>(), bool>::type
serialize_pair_element(Archive& ar, T& e)
{
- return ::do_serialize(ar, e);
+ return do_serialize(ar, e);
}
template<typename Archive, typename T>
@@ -57,7 +57,7 @@ namespace serialization
static constexpr const bool previously_varint = std::is_same<uint64_t, T>();
if (!previously_varint && ar.varint_bug_backward_compatibility_enabled() && !typename Archive::is_saving())
- return ::do_serialize(ar, e);
+ return do_serialize(ar, e);
ar.serialize_varint(e);
return true;
}
diff --git a/src/serialization/serialization.h b/src/serialization/serialization.h
index efe1270a4..2911aecb5 100644
--- a/src/serialization/serialization.h
+++ b/src/serialization/serialization.h
@@ -57,73 +57,30 @@
template <class T>
struct is_blob_type { typedef boost::false_type type; };
-/*! \struct has_free_serializer
- *
- * \brief a descriptor for dispatching serialize
- */
-template <class T>
-struct has_free_serializer { typedef boost::true_type type; };
-
-/*! \struct is_basic_type
- *
- * \brief a descriptor for dispatching serialize
- */
-template <class T>
-struct is_basic_type { typedef boost::false_type type; };
-
-template<typename F, typename S>
-struct is_basic_type<std::pair<F,S>> { typedef boost::true_type type; };
-template<>
-struct is_basic_type<std::string> { typedef boost::true_type type; };
-
-/*! \struct serializer
+/*! \fn do_serialize(Archive &ar, T &v)
*
- * \brief ... wouldn't a class be better?
+ * \brief main function for dispatching serialization for a given pair of archive and value types
*
- * \detailed The logic behind serializing data. Places the archive
- * data into the supplied parameter. This dispatches based on the
- * supplied \a T template parameter's traits of is_blob_type or it is
- * an integral (as defined by the is_integral trait). Depends on the
- * \a Archive parameter to have overloaded the serialize_blob(T v,
- * size_t size) and serialize_int(T v) base on which trait it
- * applied. When the class has neither types, it falls to the
- * overloaded method do_serialize(Archive ar) in T to do the work.
+ * Types marked true with is_blob_type<T> will be serialized as a blob, integral types will be
+ * serialized as integers, and types who have a `member_do_serialize` method will be serialized
+ * using that method. Booleans are serialized like blobs.
*/
template <class Archive, class T>
-struct serializer{
- static bool serialize(Archive &ar, T &v) {
- return serialize(ar, v, typename boost::is_integral<T>::type(), typename is_blob_type<T>::type(), typename is_basic_type<T>::type());
- }
- template<typename A>
- static bool serialize(Archive &ar, T &v, boost::false_type, boost::true_type, A a) {
- ar.serialize_blob(&v, sizeof(v));
- return true;
- }
- template<typename A>
- static bool serialize(Archive &ar, T &v, boost::true_type, boost::false_type, A a) {
- ar.serialize_int(v);
- return true;
- }
- static bool serialize(Archive &ar, T &v, boost::false_type, boost::false_type, boost::false_type) {
- //serialize_custom(ar, v, typename has_free_serializer<T>::type());
- return v.do_serialize(ar);
- }
- static bool serialize(Archive &ar, T &v, boost::false_type, boost::false_type, boost::true_type) {
- //serialize_custom(ar, v, typename has_free_serializer<T>::type());
- return do_serialize(ar, v);
- }
- static void serialize_custom(Archive &ar, T &v, boost::true_type) {
- }
-};
-
-/*! \fn do_serialize(Archive &ar, T &v)
- *
- * \brief just calls the serialize function defined for ar and v...
- */
+inline std::enable_if_t<is_blob_type<T>::type::value, bool> do_serialize(Archive &ar, T &v)
+{
+ ar.serialize_blob(&v, sizeof(v));
+ return true;
+}
template <class Archive, class T>
-inline bool do_serialize(Archive &ar, T &v)
+inline std::enable_if_t<boost::is_integral<T>::value, bool> do_serialize(Archive &ar, T &v)
{
- return ::serializer<Archive, T>::serialize(ar, v);
+ ar.serialize_int(v);
+ return true;
+}
+template <class Archive, class T>
+inline auto do_serialize(Archive &ar, T &v) -> decltype(v.member_do_serialize(ar), true)
+{
+ return v.member_do_serialize(ar);
}
template <class Archive>
inline bool do_serialize(Archive &ar, bool &v)
@@ -144,16 +101,6 @@ inline bool do_serialize(Archive &ar, bool &v)
typedef boost::true_type type; \
}
-/*! \macro FREE_SERIALIZER
- *
- * \brief adds the has_free_serializer to the type
- */
-#define FREE_SERIALIZER(T) \
- template<> \
- struct has_free_serializer<T> { \
- typedef boost::true_type type; \
- }
-
/*! \macro VARIANT_TAG
*
* \brief Adds the tag \tag to the \a Archive of \a Type
@@ -174,7 +121,7 @@ inline bool do_serialize(Archive &ar, bool &v)
*/
#define BEGIN_SERIALIZE() \
template <bool W, template <bool> class Archive> \
- bool do_serialize(Archive<W> &ar) {
+ bool member_do_serialize(Archive<W> &ar) {
/*! \macro BEGIN_SERIALIZE_OBJECT
*
@@ -183,7 +130,7 @@ inline bool do_serialize(Archive &ar, bool &v)
*/
#define BEGIN_SERIALIZE_OBJECT() \
template <bool W, template <bool> class Archive> \
- bool do_serialize(Archive<W> &ar) { \
+ bool member_do_serialize(Archive<W> &ar) { \
ar.begin_object(); \
bool r = do_serialize_object(ar); \
ar.end_object(); \
@@ -197,11 +144,6 @@ inline bool do_serialize(Archive &ar, bool &v)
#define PREPARE_CUSTOM_VECTOR_SERIALIZATION(size, vec) \
::serialization::detail::prepare_custom_vector_serialization(size, vec, typename Archive<W>::is_saving())
-/*! \macro PREPARE_CUSTOM_DEQUE_SERIALIZATION
- */
-#define PREPARE_CUSTOM_DEQUE_SERIALIZATION(size, vec) \
- ::serialization::detail::prepare_custom_deque_serialization(size, vec, typename Archive<W>::is_saving())
-
/*! \macro END_SERIALIZE
* \brief self-explanatory
*/
@@ -209,16 +151,6 @@ inline bool do_serialize(Archive &ar, bool &v)
return ar.good(); \
}
-/*! \macro VALUE(f)
- * \brief the same as FIELD(f)
- */
-#define VALUE(f) \
- do { \
- ar.tag(#f); \
- bool r = ::do_serialize(ar, f); \
- if (!r || !ar.good()) return false; \
- } while(0);
-
/*! \macro FIELD_N(t,f)
*
* \brief serializes a field \a f tagged \a t
@@ -226,7 +158,7 @@ inline bool do_serialize(Archive &ar, bool &v)
#define FIELD_N(t, f) \
do { \
ar.tag(t); \
- bool r = ::do_serialize(ar, f); \
+ bool r = do_serialize(ar, f); \
if (!r || !ar.good()) return false; \
} while(0);
@@ -237,7 +169,7 @@ inline bool do_serialize(Archive &ar, bool &v)
#define FIELD(f) \
do { \
ar.tag(#f); \
- bool r = ::do_serialize(ar, f); \
+ bool r = do_serialize(ar, f); \
if (!r || !ar.good()) return false; \
} while(0);
@@ -247,7 +179,7 @@ inline bool do_serialize(Archive &ar, bool &v)
*/
#define FIELDS(f) \
do { \
- bool r = ::do_serialize(ar, f); \
+ bool r = do_serialize(ar, f); \
if (!r || !ar.good()) return false; \
} while(0);
@@ -317,17 +249,6 @@ namespace serialization {
vec.resize(size);
}
- template <typename T>
- void prepare_custom_deque_serialization(size_t size, std::deque<T>& vec, const boost::mpl::bool_<true>& /*is_saving*/)
- {
- }
-
- template <typename T>
- void prepare_custom_deque_serialization(size_t size, std::deque<T>& vec, const boost::mpl::bool_<false>& /*is_saving*/)
- {
- vec.resize(size);
- }
-
/*! \fn do_check_stream_state
*
* \brief self explanatory
diff --git a/src/serialization/tuple.h b/src/serialization/tuple.h
index e76ca0b99..d9592bc96 100644
--- a/src/serialization/tuple.h
+++ b/src/serialization/tuple.h
@@ -39,7 +39,7 @@ namespace serialization
template <typename Archive, class T>
bool serialize_tuple_element(Archive& ar, T& e)
{
- return ::do_serialize(ar, e);
+ return do_serialize(ar, e);
}
template <typename Archive>
diff --git a/src/serialization/variant.h b/src/serialization/variant.h
index 77d767a1c..1cf93c8cf 100644
--- a/src/serialization/variant.h
+++ b/src/serialization/variant.h
@@ -72,7 +72,7 @@ struct variant_reader
{
if(variant_serialization_traits<Archive, current_type>::get_tag() == t) {
current_type x;
- if(!::do_serialize(ar, x))
+ if(!do_serialize(ar, x))
{
ar.set_fail();
return false;
@@ -100,19 +100,13 @@ struct variant_reader<Archive, Variant, TBegin, TBegin>
}
};
-
-template <template <bool> class Archive, BOOST_VARIANT_ENUM_PARAMS(typename T)>
-struct serializer<Archive<false>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>>
-{
- typedef boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> variant_type;
- typedef typename Archive<false>::variant_tag_type variant_tag_type;
- typedef typename variant_type::types types;
-
- static bool serialize(Archive<false> &ar, variant_type &v) {
- variant_tag_type t;
+template <template <bool> class Archive, typename... T>
+static bool do_serialize(Archive<false> &ar, boost::variant<T...> &v) {
+ using types = typename boost::variant<T...>::types;
+ typename Archive<false>::variant_tag_type t;
ar.begin_variant();
ar.read_variant_tag(t);
- if(!variant_reader<Archive<false>, variant_type,
+ if(!variant_reader<Archive<false>, boost::variant<T...>,
typename boost::mpl::begin<types>::type,
typename boost::mpl::end<types>::type>::read(ar, v, t))
{
@@ -121,27 +115,21 @@ struct serializer<Archive<false>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>>
}
ar.end_variant();
return true;
- }
-};
+}
-template <template <bool> class Archive, BOOST_VARIANT_ENUM_PARAMS(typename T)>
-struct serializer<Archive<true>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>>
+template <template <bool> class Archive>
+struct variant_write_visitor : public boost::static_visitor<bool>
{
- typedef boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> variant_type;
- //typedef typename Archive<true>::variant_tag_type variant_tag_type;
-
- struct visitor : public boost::static_visitor<bool>
- {
Archive<true> &ar;
- visitor(Archive<true> &a) : ar(a) { }
+ variant_write_visitor(Archive<true> &a) : ar(a) { }
template <class T>
bool operator ()(T &rv) const
{
ar.begin_variant();
ar.write_variant_tag(variant_serialization_traits<Archive<true>, T>::get_tag());
- if(!::do_serialize(ar, rv))
+ if(!do_serialize(ar, rv))
{
ar.set_fail();
return false;
@@ -149,9 +137,10 @@ struct serializer<Archive<true>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>>
ar.end_variant();
return true;
}
- };
-
- static bool serialize(Archive<true> &ar, variant_type &v) {
- return boost::apply_visitor(visitor(ar), v);
- }
};
+
+template <template <bool> class Archive, typename... T>
+static bool do_serialize(Archive<true> &ar, boost::variant<T...> &v)
+{
+ return boost::apply_visitor(variant_write_visitor<Archive>(ar), v);
+}
diff --git a/src/wallet/message_transporter.cpp b/src/wallet/message_transporter.cpp
index b4f6ce7bd..e6c26cba0 100644
--- a/src/wallet/message_transporter.cpp
+++ b/src/wallet/message_transporter.cpp
@@ -273,16 +273,29 @@ bool message_transporter::post_request(const std::string &request, std::string &
{
if ((string_value.find("API Error 0021") == 0) && (request.find("joinChan") != std::string::npos))
{
+ // "API Error 0021: Unexpected API Failure"
// Error that occurs if one tries to join an already joined chan, which can happen
// if several auto-config participants share one PyBitmessage instance: As a little
// hack simply ignore the error. (A clean solution would be to check for the chan
// with 'listAddresses2', but parsing the returned array is much more complicated.)
}
+ else if ((string_value.find("API Error 0024") == 0) && (request.find("joinChan") != std::string::npos))
+ {
+ // "API Error 0024: Chan address is already present."
+ // Maybe a result of creating the chan in a slightly different way i.e. not with
+ // 'createChan'; everything works by just ignoring this error
+ }
else if ((string_value.find("API Error 0013") == 0) && (request.find("leaveChan") != std::string::npos))
{
+ // "API Error 0013: Could not find your fromAddress in the keys.dat file."
// Error that occurs if one tries to leave an already left / deleted chan, which can happen
// if several auto-config participants share one PyBitmessage instance: Also ignore.
}
+ else if ((string_value.find("API Error 0025") == 0) && (request.find("leaveChan") != std::string::npos))
+ {
+ // "API Error 0025: Specified address is not a chan address. Use deleteAddress API call instead."
+ // Error does not really make sense, but everything works by just ignoring
+ }
else
{
THROW_WALLET_EXCEPTION(tools::error::bitmessage_api_error, string_value);
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index b5392d5f9..336f4e159 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1821,7 +1821,7 @@ void reattach_blockchain(hashchain &blockchain, wallet2::detached_blockchain_dat
}
//----------------------------------------------------------------------------------------------------
bool has_nonrequested_tx_at_height_or_above_requested(uint64_t height, const std::unordered_set<crypto::hash> &requested_txids, const wallet2::transfer_container &transfers,
- const wallet2::payment_container &payments, const serializable_unordered_map<crypto::hash, wallet2::confirmed_transfer_details> &confirmed_txs)
+ const wallet2::payment_container &payments, const std::unordered_map<crypto::hash, wallet2::confirmed_transfer_details> &confirmed_txs)
{
for (const auto &td : transfers)
if (td.m_block_height >= height && requested_txids.find(td.m_txid) == requested_txids.end())
@@ -7304,9 +7304,7 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector<wallet2::pendin
crypto::key_derivation derivation;
std::vector<crypto::key_derivation> additional_derivations;
- // compute public keys from out secret keys
- crypto::public_key tx_pub_key;
- crypto::secret_key_to_public_key(txs[n].tx_key, tx_pub_key);
+ crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx);
std::vector<crypto::public_key> additional_tx_pub_keys;
for (const crypto::secret_key &skey: txs[n].additional_tx_keys)
{
@@ -8685,6 +8683,26 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
COMMAND_RPC_GET_OUTPUTS_BIN::request req = AUTO_VAL_INIT(req);
COMMAND_RPC_GET_OUTPUTS_BIN::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
+ // The secret picking order contains outputs in the order that we selected them.
+ //
+ // We will later sort the output request entries in a pre-determined order so that the daemon
+ // that we're requesting information from doesn't learn any information about the true spend
+ // for each ring. However, internally, we want to prefer to construct our rings using the
+ // outputs that we picked first versus outputs picked later.
+ //
+ // The reason why is because each consecutive output pick within a ring becomes increasing less
+ // statistically independent from other picks, since we pick outputs from a finite set
+ // *without replacement*, due to the protocol not allowing duplicate ring members. This effect
+ // is exacerbated by the fact that we pick 1.5x + 75 as many outputs as we need per RPC
+ // request to account for unusable outputs. This effect is small, but non-neglibile and gets
+ // worse with larger ring sizes.
+ std::vector<get_outputs_out> secret_picking_order;
+
+ // Convenience/safety lambda to make sure that both output lists req.outputs and secret_picking_order are updated together
+ // Each ring section of req.outputs gets sorted later after selecting all outputs for that ring
+ const auto add_output_to_lists = [&req, &secret_picking_order](const get_outputs_out &goo)
+ { req.outputs.push_back(goo); secret_picking_order.push_back(goo); };
+
std::unique_ptr<gamma_picker> gamma;
if (has_rct)
gamma.reset(new gamma_picker(rct_offsets));
@@ -8819,7 +8837,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
if (out < num_outs)
{
MINFO("Using it");
- req.outputs.push_back({amount, out});
+ add_output_to_lists({amount, out});
++num_found;
seen_indices.emplace(out);
if (out == td.m_global_output_index)
@@ -8841,12 +8859,12 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
if (num_outs <= requested_outputs_count)
{
for (uint64_t i = 0; i < num_outs; i++)
- req.outputs.push_back({amount, i});
+ add_output_to_lists({amount, i});
// duplicate to make up shortfall: this will be caught after the RPC call,
// so we can also output the amounts for which we can't reach the required
// mixin after checking the actual unlockedness
for (uint64_t i = num_outs; i < requested_outputs_count; ++i)
- req.outputs.push_back({amount, num_outs - 1});
+ add_output_to_lists({amount, num_outs - 1});
}
else
{
@@ -8855,7 +8873,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
{
num_found = 1;
seen_indices.emplace(td.m_global_output_index);
- req.outputs.push_back({amount, td.m_global_output_index});
+ add_output_to_lists({amount, td.m_global_output_index});
LOG_PRINT_L1("Selecting real output: " << td.m_global_output_index << " for " << print_money(amount));
}
@@ -8963,7 +8981,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
seen_indices.emplace(i);
picks[type].insert(i);
- req.outputs.push_back({amount, i});
+ add_output_to_lists({amount, i});
++num_found;
MDEBUG("picked " << i << ", " << num_found << " now picked");
}
@@ -8977,7 +8995,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
// we'll error out later
while (num_found < requested_outputs_count)
{
- req.outputs.push_back({amount, 0});
+ add_output_to_lists({amount, 0});
++num_found;
}
}
@@ -8987,6 +9005,10 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
[](const get_outputs_out &a, const get_outputs_out &b) { return a.index < b.index; });
}
+ THROW_WALLET_EXCEPTION_IF(req.outputs.size() != secret_picking_order.size(), error::wallet_internal_error,
+ "bug: we did not update req.outputs/secret_picking_order in tandem");
+
+ // List all requested outputs to debug log
if (ELPP->vRegistry()->allowed(el::Level::Debug, MONERO_DEFAULT_LOG_CATEGORY))
{
std::map<uint64_t, std::set<uint64_t>> outs;
@@ -9104,18 +9126,21 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
}
}
- // then pick others in random order till we reach the required number
- // since we use an equiprobable pick here, we don't upset the triangular distribution
- std::vector<size_t> order;
- order.resize(requested_outputs_count);
- for (size_t n = 0; n < order.size(); ++n)
- order[n] = n;
- std::shuffle(order.begin(), order.end(), crypto::random_device{});
-
+ // While we are still lacking outputs in this result ring, in our secret pick order...
LOG_PRINT_L2("Looking for " << (fake_outputs_count+1) << " outputs of size " << print_money(td.is_rct() ? 0 : td.amount()));
- for (size_t o = 0; o < requested_outputs_count && outs.back().size() < fake_outputs_count + 1; ++o)
+ for (size_t ring_pick_idx = base; ring_pick_idx < base + requested_outputs_count && outs.back().size() < fake_outputs_count + 1; ++ring_pick_idx)
{
- size_t i = base + order[o];
+ const get_outputs_out attempted_output = secret_picking_order[ring_pick_idx];
+
+ // Find the index i of our pick in the request/response arrays
+ size_t i;
+ for (i = base; i < base + requested_outputs_count; ++i)
+ if (req.outputs[i].index == attempted_output.index)
+ break;
+ THROW_WALLET_EXCEPTION_IF(i == base + requested_outputs_count, error::wallet_internal_error,
+ "Could not find index of picked output in requested outputs");
+
+ // Try adding this output's information to result ring if output isn't invalid
LOG_PRINT_L2("Index " << i << "/" << requested_outputs_count << ": idx " << req.outputs[i].index << " (real " << td.m_global_output_index << "), unlocked " << daemon_resp.outs[i].unlocked << ", key " << daemon_resp.outs[i].key);
tx_add_fake_output(outs, req.outputs[i].index, daemon_resp.outs[i].key, daemon_resp.outs[i].mask, td.m_global_output_index, daemon_resp.outs[i].unlocked, valid_public_keys_cache);
}
@@ -12008,7 +12033,7 @@ std::string wallet2::get_reserve_proof(const boost::optional<std::pair<uint32_t,
}
// collect all subaddress spend keys that received those outputs and generate their signatures
- serializable_unordered_map<crypto::public_key, crypto::signature> subaddr_spendkeys;
+ std::unordered_map<crypto::public_key, crypto::signature> subaddr_spendkeys;
for (const cryptonote::subaddress_index &index : subaddr_indices)
{
crypto::secret_key subaddr_spend_skey = m_account.get_keys().m_spend_secret_key;
@@ -12053,7 +12078,7 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr
bool loaded = false;
std::vector<reserve_proof_entry> proofs;
- serializable_unordered_map<crypto::public_key, crypto::signature> subaddr_spendkeys;
+ std::unordered_map<crypto::public_key, crypto::signature> subaddr_spendkeys;
try
{
binary_archive<false> ar{epee::strspan<std::uint8_t>(sig_decoded)};
@@ -12067,7 +12092,7 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr
{
std::istringstream iss(sig_decoded);
boost::archive::portable_binary_iarchive ar(iss);
- ar >> proofs >> subaddr_spendkeys.parent();
+ ar >> proofs >> subaddr_spendkeys;
}
THROW_WALLET_EXCEPTION_IF(subaddr_spendkeys.count(address.m_spend_public_key) == 0, error::wallet_internal_error,
@@ -12311,7 +12336,7 @@ std::string wallet2::get_description() const
return "";
}
-const std::pair<serializable_map<std::string, std::string>, std::vector<std::string>>& wallet2::get_account_tags()
+const std::pair<std::map<std::string, std::string>, std::vector<std::string>>& wallet2::get_account_tags()
{
// ensure consistency
if (m_account_tags.second.size() != get_num_subaddress_accounts())
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index d93b9b9fb..21ca48464 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -590,7 +590,7 @@ private:
};
typedef std::vector<transfer_details> transfer_container;
- typedef serializable_unordered_multimap<crypto::hash, payment_details> payment_container;
+ typedef std::unordered_multimap<crypto::hash, payment_details> payment_container;
struct multisig_sig
{
@@ -701,7 +701,7 @@ private:
{
std::vector<pending_tx> ptx;
std::vector<crypto::key_image> key_images;
- serializable_unordered_map<crypto::public_key, crypto::key_image> tx_key_images;
+ std::unordered_map<crypto::public_key, crypto::key_image> tx_key_images;
BEGIN_SERIALIZE_OBJECT()
VERSION_FIELD(0)
@@ -1157,25 +1157,25 @@ private:
}
a & m_transfers;
a & m_account_public_address;
- a & m_key_images.parent();
+ a & m_key_images;
if(ver < 6)
return;
- a & m_unconfirmed_txs.parent();
+ a & m_unconfirmed_txs;
if(ver < 7)
return;
- a & m_payments.parent();
+ a & m_payments;
if(ver < 8)
return;
- a & m_tx_keys.parent();
+ a & m_tx_keys;
if(ver < 9)
return;
- a & m_confirmed_txs.parent();
+ a & m_confirmed_txs;
if(ver < 11)
return;
a & dummy_refresh_height;
if(ver < 12)
return;
- a & m_tx_notes.parent();
+ a & m_tx_notes;
if(ver < 13)
return;
if (ver < 17)
@@ -1200,7 +1200,7 @@ private:
}
return;
}
- a & m_pub_keys.parent();
+ a & m_pub_keys;
if(ver < 16)
return;
a & m_address_book;
@@ -1221,17 +1221,17 @@ private:
a & m_scanned_pool_txs[1];
if (ver < 20)
return;
- a & m_subaddresses.parent();
+ a & m_subaddresses;
std::unordered_map<cryptonote::subaddress_index, crypto::public_key> dummy_subaddresses_inv;
a & dummy_subaddresses_inv;
a & m_subaddress_labels;
- a & m_additional_tx_keys.parent();
+ a & m_additional_tx_keys;
if(ver < 21)
return;
- a & m_attributes.parent();
+ a & m_attributes;
if(ver < 22)
return;
- a & m_unconfirmed_payments.parent();
+ a & m_unconfirmed_payments;
if(ver < 23)
return;
a & (std::pair<std::map<std::string, std::string>, std::vector<std::string>>&)m_account_tags;
@@ -1243,13 +1243,13 @@ private:
a & m_last_block_reward;
if(ver < 26)
return;
- a & m_tx_device.parent();
+ a & m_tx_device;
if(ver < 27)
return;
a & m_device_last_key_image_sync;
if(ver < 28)
return;
- a & m_cold_key_images.parent();
+ a & m_cold_key_images;
if(ver < 29)
return;
crypto::secret_key dummy_rpc_client_secret_key; // Compatibility for old RPC payment system
@@ -1464,7 +1464,7 @@ private:
* \brief Get the list of registered account tags.
* \return first.Key=(tag's name), first.Value=(tag's label), second[i]=(i-th account's tag)
*/
- const std::pair<serializable_map<std::string, std::string>, std::vector<std::string>>& get_account_tags();
+ const std::pair<std::map<std::string, std::string>, std::vector<std::string>>& get_account_tags();
/*!
* \brief Set a tag to the given accounts.
* \param account_indices Indices of accounts.
@@ -1776,28 +1776,28 @@ private:
std::string m_mms_file;
const std::unique_ptr<epee::net_utils::http::abstract_http_client> m_http_client;
hashchain m_blockchain;
- serializable_unordered_map<crypto::hash, unconfirmed_transfer_details> m_unconfirmed_txs;
- serializable_unordered_map<crypto::hash, confirmed_transfer_details> m_confirmed_txs;
- serializable_unordered_multimap<crypto::hash, pool_payment_details> m_unconfirmed_payments;
- serializable_unordered_map<crypto::hash, crypto::secret_key> m_tx_keys;
+ std::unordered_map<crypto::hash, unconfirmed_transfer_details> m_unconfirmed_txs;
+ std::unordered_map<crypto::hash, confirmed_transfer_details> m_confirmed_txs;
+ std::unordered_multimap<crypto::hash, pool_payment_details> m_unconfirmed_payments;
+ std::unordered_map<crypto::hash, crypto::secret_key> m_tx_keys;
cryptonote::checkpoints m_checkpoints;
- serializable_unordered_map<crypto::hash, std::vector<crypto::secret_key>> m_additional_tx_keys;
+ std::unordered_map<crypto::hash, std::vector<crypto::secret_key>> m_additional_tx_keys;
transfer_container m_transfers;
payment_container m_payments;
- serializable_unordered_map<crypto::key_image, size_t> m_key_images;
- serializable_unordered_map<crypto::public_key, size_t> m_pub_keys;
+ std::unordered_map<crypto::key_image, size_t> m_key_images;
+ std::unordered_map<crypto::public_key, size_t> m_pub_keys;
cryptonote::account_public_address m_account_public_address;
- serializable_unordered_map<crypto::public_key, cryptonote::subaddress_index> m_subaddresses;
+ std::unordered_map<crypto::public_key, cryptonote::subaddress_index> m_subaddresses;
std::vector<std::vector<std::string>> m_subaddress_labels;
- serializable_unordered_map<crypto::hash, std::string> m_tx_notes;
- serializable_unordered_map<std::string, std::string> m_attributes;
+ std::unordered_map<crypto::hash, std::string> m_tx_notes;
+ std::unordered_map<std::string, std::string> m_attributes;
std::vector<tools::wallet2::address_book_row> m_address_book;
- std::pair<serializable_map<std::string, std::string>, std::vector<std::string>> m_account_tags;
+ std::pair<std::map<std::string, std::string>, std::vector<std::string>> m_account_tags;
uint64_t m_upper_transaction_weight_limit; //TODO: auto-calc this value or request from daemon, now use some fixed value
const std::vector<std::vector<tools::wallet2::multisig_info>> *m_multisig_rescan_info;
const std::vector<std::vector<rct::key>> *m_multisig_rescan_k;
- serializable_unordered_map<crypto::public_key, crypto::key_image> m_cold_key_images;
+ std::unordered_map<crypto::public_key, crypto::key_image> m_cold_key_images;
std::atomic<bool> m_run;
@@ -1868,7 +1868,7 @@ private:
bool m_allow_mismatched_daemon_version;
// Aux transaction data from device
- serializable_unordered_map<crypto::hash, std::string> m_tx_device;
+ std::unordered_map<crypto::hash, std::string> m_tx_device;
std::string m_ring_database;
bool m_ring_history_saved;
@@ -2313,7 +2313,7 @@ namespace boost
a & x.key_images;
if (ver < 1)
return;
- a & x.tx_key_images.parent();
+ a & x.tx_key_images;
}
template <class Archive>
diff --git a/tests/unit_tests/crypto.cpp b/tests/unit_tests/crypto.cpp
index e41f3955f..88ecb5853 100644
--- a/tests/unit_tests/crypto.cpp
+++ b/tests/unit_tests/crypto.cpp
@@ -307,17 +307,21 @@ TEST(Crypto, tree_branch)
ASSERT_FALSE(crypto::tree_branch((const char(*)[32])inputs, 5, crypto::null_hash.data, (char(*)[32])branch, &depth, &path));
// depth encoding roundtrip
- for (uint32_t n_chains = 1; n_chains <= 65; ++n_chains)
+ for (uint32_t n_chains = 1; n_chains <= 256; ++n_chains)
{
- for (uint32_t nonce = 0; nonce < 1024; ++nonce)
+ for (uint32_t nonce = 0xffffffff - 512; nonce != 1025; ++nonce)
{
- const uint32_t depth = cryptonote::encode_mm_depth(n_chains, nonce);
+ const uint64_t depth = cryptonote::encode_mm_depth(n_chains, nonce);
uint32_t n_chains_2, nonce_2;
ASSERT_TRUE(cryptonote::decode_mm_depth(depth, n_chains_2, nonce_2));
ASSERT_EQ(n_chains, n_chains_2);
ASSERT_EQ(nonce, nonce_2);
}
}
+
+ // 257 chains is too much
+ try { cryptonote::encode_mm_depth(257, 0); ASSERT_TRUE(false); }
+ catch (...) {}
}
TEST(Crypto, generator_consistency)
diff --git a/tests/unit_tests/json_serialization.cpp b/tests/unit_tests/json_serialization.cpp
index 9fa589139..aa46b68dc 100644
--- a/tests/unit_tests/json_serialization.cpp
+++ b/tests/unit_tests/json_serialization.cpp
@@ -13,6 +13,7 @@
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "cryptonote_core/cryptonote_tx_utils.h"
#include "serialization/json_object.h"
+#include "rpc/daemon_messages.h"
namespace test
@@ -240,3 +241,9 @@ TEST(JsonSerialization, BulletproofTransaction)
EXPECT_EQ(tx_bytes, tx_copy_bytes);
}
+TEST(JsonRpcSerialization, HandlerFromJson)
+{
+ cryptonote::rpc::FullMessage req_full("{\"jsonrpc\":\"2.0\",\"method\":\"get_hashes_fast\",\"params\":[1]}", true);
+ cryptonote::rpc::GetHashesFast::Request request{};
+ EXPECT_THROW(request.fromJson(req_full.getMessage()), cryptonote::json::WRONG_TYPE);
+}
diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp
index 49f1dc310..ab81acefc 100644
--- a/tests/unit_tests/serialization.cpp
+++ b/tests/unit_tests/serialization.cpp
@@ -59,9 +59,7 @@ struct Struct
};
template <class Archive>
-struct serializer<Archive, Struct>
-{
- static bool serialize(Archive &ar, Struct &s) {
+static bool do_serialize(Archive &ar, Struct &s) {
ar.begin_object();
ar.tag("a");
ar.serialize_int(s.a);
@@ -71,8 +69,7 @@ struct serializer<Archive, Struct>
ar.serialize_blob(s.blob, sizeof(s.blob));
ar.end_object();
return true;
- }
-};
+}
struct Struct1
{
@@ -122,6 +119,23 @@ bool try_parse(const string &blob)
return serialization::parse_binary(blob, s1);
}
+namespace example_namespace
+{
+ struct ADLExampleStruct
+ {
+ std::string msg;
+ };
+
+ template <class Archive>
+ static bool do_serialize(Archive &ar, ADLExampleStruct &aes)
+ {
+ ar.begin_object();
+ FIELD_N("custom_fieldname", aes.msg);
+ ar.end_object();
+ return ar.good();
+ }
+}
+
TEST(Serialization, BinaryArchiveInts) {
uint64_t x = 0xff00000000, x1;
@@ -1178,3 +1192,18 @@ TEST(Serialization, difficulty_type)
ASSERT_EQ(v_original, v_unserialized);
}
+
+TEST(Serialization, adl_free_function)
+{
+ std::stringstream ss;
+ json_archive<true> ar(ss);
+
+ const std::string msg = "Howdy, World!";
+ example_namespace::ADLExampleStruct aes{msg};
+
+ ASSERT_TRUE(serialization::serialize(ar, aes));
+
+ // VVVVVVVVVVVVVVVVVVVVVVVVVV weird string serialization artifact
+ const std::string expected = "{\"custom_fieldname\": " + std::to_string(msg.size()) + '"' + epee::string_tools::buff_to_hex_nodelimer(msg) + "\"}";
+ EXPECT_EQ(expected, ss.str());
+}
diff --git a/utils/gpg_keys/tobtoht.asc b/utils/gpg_keys/tobtoht.asc
new file mode 100644
index 000000000..16311b2d8
--- /dev/null
+++ b/utils/gpg_keys/tobtoht.asc
@@ -0,0 +1,51 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+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
+=KI4D
+-----END PGP PUBLIC KEY BLOCK-----