diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/device_trezor/device_trezor_base.cpp | 6 | ||||
-rw-r--r-- | src/device_trezor/trezor/transport.cpp | 120 | ||||
-rw-r--r-- | src/device_trezor/trezor/transport.hpp | 5 | ||||
-rw-r--r-- | src/p2p/net_node.inl | 4 | ||||
-rw-r--r-- | src/p2p/net_peerlist.h | 33 | ||||
-rw-r--r-- | src/p2p/p2p_protocol_defs.h | 5 | ||||
-rw-r--r-- | src/rpc/core_rpc_server.cpp | 13 | ||||
-rw-r--r-- | src/rpc/daemon_handler.cpp | 2 | ||||
-rw-r--r-- | src/rpc/rpc_handler.cpp | 33 | ||||
-rw-r--r-- | src/rpc/rpc_handler.h | 3 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 22 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server.cpp | 15 |
12 files changed, 220 insertions, 41 deletions
diff --git a/src/device_trezor/device_trezor_base.cpp b/src/device_trezor/device_trezor_base.cpp index 5adadbfc4..b7adf433d 100644 --- a/src/device_trezor/device_trezor_base.cpp +++ b/src/device_trezor/device_trezor_base.cpp @@ -115,10 +115,14 @@ namespace trezor { MDEBUG("Enumerating Trezor devices..."); enumerate(trans); + sort_transports_by_env(trans); - MDEBUG("Enumeration yielded " << trans.size() << " devices"); + MDEBUG("Enumeration yielded " << trans.size() << " Trezor devices"); for (auto &cur : trans) { MDEBUG(" device: " << *(cur.get())); + } + + for (auto &cur : trans) { std::string cur_path = cur->get_path(); if (boost::starts_with(cur_path, this->name)) { MDEBUG("Device Match: " << cur_path); diff --git a/src/device_trezor/trezor/transport.cpp b/src/device_trezor/trezor/transport.cpp index dd9b0b52f..59b281f13 100644 --- a/src/device_trezor/trezor/transport.cpp +++ b/src/device_trezor/trezor/transport.cpp @@ -31,11 +31,13 @@ #include <libusb.h> #endif +#include <algorithm> #include <boost/endian/conversion.hpp> #include <boost/asio/io_service.hpp> #include <boost/asio/ip/udp.hpp> #include <boost/date_time/posix_time/posix_time_types.hpp> #include <boost/format.hpp> +#include "common/apply_permutation.h" #include "transport.hpp" #include "messages/messages-common.pb.h" @@ -95,6 +97,47 @@ namespace trezor{ return patch | (((uint64_t)minor) << bits_2) | (((uint64_t)major) << (bits_1 + bits_2)); } + typedef struct { + uint16_t trezor_type; + uint16_t id_vendor; + uint16_t id_product; + } trezor_usb_desc_t; + + static trezor_usb_desc_t TREZOR_DESC_T1 = {1, 0x534C, 0x0001}; + static trezor_usb_desc_t TREZOR_DESC_T2 = {2, 0x1209, 0x53C1}; + static trezor_usb_desc_t TREZOR_DESC_T2_BL = {3, 0x1209, 0x53C0}; + + static trezor_usb_desc_t TREZOR_DESCS[] = { + TREZOR_DESC_T1, + TREZOR_DESC_T2, + TREZOR_DESC_T2_BL, + }; + + static size_t TREZOR_DESCS_LEN = sizeof(TREZOR_DESCS)/sizeof(TREZOR_DESCS[0]); + + static ssize_t get_device_idx(uint16_t id_vendor, uint16_t id_product){ + for(size_t i = 0; i < TREZOR_DESCS_LEN; ++i){ + if (TREZOR_DESCS[i].id_vendor == id_vendor && TREZOR_DESCS[i].id_product == id_product){ + return i; + } + } + + return -1; + } + + static bool is_device_supported(ssize_t device_idx){ + CHECK_AND_ASSERT_THROW_MES(device_idx < (ssize_t)TREZOR_DESCS_LEN, "Device desc idx too big"); + if (device_idx < 0){ + return false; + } + +#ifdef TREZOR_1_SUPPORTED + return true; +#else + return TREZOR_DESCS[device_idx].trezor_type != 1; +#endif + } + // // Helpers // @@ -312,6 +355,24 @@ namespace trezor{ for(rapidjson::Value::ConstValueIterator itr = bridge_res.Begin(); itr != bridge_res.End(); ++itr){ auto element = itr->GetObject(); auto t = std::make_shared<BridgeTransport>(boost::make_optional(json_get_string(element["path"]))); + + auto itr_vendor = element.FindMember("vendor"); + auto itr_product = element.FindMember("product"); + if (itr_vendor != element.MemberEnd() && itr_product != element.MemberEnd() + && itr_vendor->value.IsNumber() && itr_product->value.IsNumber()){ + try { + const auto id_vendor = (uint16_t) itr_vendor->value.GetUint64(); + const auto id_product = (uint16_t) itr_product->value.GetUint64(); + const auto device_idx = get_device_idx(id_vendor, id_product); + if (!is_device_supported(device_idx)){ + MDEBUG("Device with idx " << device_idx << " is not supported. Vendor: " << id_vendor << ", product: " << id_product); + continue; + } + } catch(const std::exception &e){ + MERROR("Could not detect vendor & product: " << e.what()); + } + } + t->m_device_info.emplace(); t->m_device_info->CopyFrom(*itr, t->m_device_info->GetAllocator()); res.push_back(t); @@ -710,24 +771,20 @@ namespace trezor{ #ifdef WITH_DEVICE_TREZOR_WEBUSB static bool is_trezor1(libusb_device_descriptor * info){ - return info->idVendor == 0x534C && info->idProduct == 0x0001; + return info->idVendor == TREZOR_DESC_T1.id_vendor && info->idProduct == TREZOR_DESC_T1.id_product; } static bool is_trezor2(libusb_device_descriptor * info){ - return info->idVendor == 0x1209 && info->idProduct == 0x53C1; + return info->idVendor == TREZOR_DESC_T2.id_vendor && info->idProduct == TREZOR_DESC_T2.id_product; } static bool is_trezor2_bl(libusb_device_descriptor * info){ - return info->idVendor == 0x1209 && info->idProduct == 0x53C0; + return info->idVendor == TREZOR_DESC_T2_BL.id_vendor && info->idProduct == TREZOR_DESC_T2_BL.id_product; } - static uint8_t get_trezor_dev_mask(libusb_device_descriptor * info){ - uint8_t mask = 0; + static ssize_t get_trezor_dev_id(libusb_device_descriptor *info){ CHECK_AND_ASSERT_THROW_MES(info, "Empty device descriptor"); - mask |= is_trezor1(info) ? 1 : 0; - mask |= is_trezor2(info) ? 2 : 0; - mask |= is_trezor2_bl(info) ? 4 : 0; - return mask; + return get_device_idx(info->idVendor, info->idProduct); } static void set_libusb_log(libusb_context *ctx){ @@ -844,12 +901,12 @@ namespace trezor{ continue; } - const auto trezor_mask = get_trezor_dev_mask(&desc); - if (!trezor_mask){ + const auto trezor_dev_idx = get_trezor_dev_id(&desc); + if (!is_device_supported(trezor_dev_idx)){ continue; } - MTRACE("Found Trezor device: " << desc.idVendor << ":" << desc.idProduct << " mask " << (int)trezor_mask); + MTRACE("Found Trezor device: " << desc.idVendor << ":" << desc.idProduct << " dev_idx " << (int)trezor_dev_idx); auto t = std::make_shared<WebUsbTransport>(boost::make_optional(&desc)); t->m_bus_id = libusb_get_bus_number(devs[i]); @@ -909,8 +966,8 @@ namespace trezor{ continue; } - const auto trezor_mask = get_trezor_dev_mask(&desc); - if (!trezor_mask) { + const auto trezor_dev_idx = get_trezor_dev_id(&desc); + if (!is_device_supported(trezor_dev_idx)){ continue; } @@ -921,7 +978,7 @@ namespace trezor{ get_libusb_ports(devs[i], path); MTRACE("Found Trezor device: " << desc.idVendor << ":" << desc.idProduct - << ", mask: " << (int)trezor_mask + << ", dev_idx: " << (int)trezor_dev_idx << ". path: " << get_usb_path(bus_id, path)); if (bus_id == m_bus_id && path == m_port_numbers) { @@ -1110,6 +1167,39 @@ namespace trezor{ #endif } + void sort_transports_by_env(t_transport_vect & res){ + const char *env_trezor_path = getenv("TREZOR_PATH"); + if (!env_trezor_path){ + return; + } + + // Sort transports by the longest matching prefix with TREZOR_PATH + std::string trezor_path(env_trezor_path); + std::vector<size_t> match_idx(res.size()); + std::vector<size_t> path_permutation(res.size()); + + for(size_t i = 0; i < res.size(); ++i){ + auto cpath = res[i]->get_path(); + std::string * s1 = &trezor_path; + std::string * s2 = &cpath; + + // first has to be shorter in std::mismatch(). Returns first non-matching iterators. + if (s1->size() >= s2->size()){ + std::swap(s1, s2); + } + + const auto mism = std::mismatch(s1->begin(), s1->end(), s2->begin()); + match_idx[i] = mism.first - s1->begin(); + path_permutation[i] = i; + } + + std::sort(path_permutation.begin(), path_permutation.end(), [&](const size_t i0, const size_t i1) { + return match_idx[i0] > match_idx[i1]; + }); + + tools::apply_permutation(path_permutation, res); + } + std::shared_ptr<Transport> transport(const std::string & path){ if (boost::starts_with(path, BridgeTransport::PATH_PREFIX)){ return std::make_shared<BridgeTransport>(path.substr(strlen(BridgeTransport::PATH_PREFIX))); diff --git a/src/device_trezor/trezor/transport.hpp b/src/device_trezor/trezor/transport.hpp index cde862547..affd91553 100644 --- a/src/device_trezor/trezor/transport.hpp +++ b/src/device_trezor/trezor/transport.hpp @@ -303,6 +303,11 @@ namespace trezor { void enumerate(t_transport_vect & res); /** + * Sorts found transports by TREZOR_PATH environment variable. + */ + void sort_transports_by_env(t_transport_vect & res); + + /** * Transforms path to the transport */ std::shared_ptr<Transport> transport(const std::string & path); diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index be97edbe5..ba29d92c9 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -1955,7 +1955,7 @@ namespace nodetool const epee::net_utils::zone zone_type = context.m_remote_address.get_zone(); network_zone& zone = m_network_zones.at(zone_type); - zone.m_peerlist.get_peerlist_head(rsp.local_peerlist_new); + zone.m_peerlist.get_peerlist_head(rsp.local_peerlist_new, true); m_payload_handler.get_payload_sync_data(rsp.payload_data); /* Tor/I2P nodes receiving connections via forwarding (from tor/i2p daemon) @@ -2058,7 +2058,7 @@ namespace nodetool }); //fill response - zone.m_peerlist.get_peerlist_head(rsp.local_peerlist_new); + zone.m_peerlist.get_peerlist_head(rsp.local_peerlist_new, true); get_local_node_data(rsp.node_data, zone); m_payload_handler.get_payload_sync_data(rsp.payload_data); LOG_DEBUG_CC(context, "COMMAND_HANDSHAKE"); diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h index 52814af94..f4fa921e2 100644 --- a/src/p2p/net_peerlist.h +++ b/src/p2p/net_peerlist.h @@ -102,7 +102,7 @@ namespace nodetool size_t get_white_peers_count(){CRITICAL_REGION_LOCAL(m_peerlist_lock); return m_peers_white.size();} size_t get_gray_peers_count(){CRITICAL_REGION_LOCAL(m_peerlist_lock); return m_peers_gray.size();} bool merge_peerlist(const std::vector<peerlist_entry>& outer_bs); - bool get_peerlist_head(std::vector<peerlist_entry>& bs_head, uint32_t depth = P2P_DEFAULT_PEERS_IN_HANDSHAKE); + bool get_peerlist_head(std::vector<peerlist_entry>& bs_head, bool anonymize, uint32_t depth = P2P_DEFAULT_PEERS_IN_HANDSHAKE); void get_peerlist(std::vector<peerlist_entry>& pl_gray, std::vector<peerlist_entry>& pl_white); void get_peerlist(peerlist_types& peers); bool get_white_peer_by_index(peerlist_entry& p, size_t i); @@ -263,23 +263,40 @@ namespace nodetool } //-------------------------------------------------------------------------------------------------- inline - bool peerlist_manager::get_peerlist_head(std::vector<peerlist_entry>& bs_head, uint32_t depth) + bool peerlist_manager::get_peerlist_head(std::vector<peerlist_entry>& bs_head, bool anonymize, uint32_t depth) { - CRITICAL_REGION_LOCAL(m_peerlist_lock); peers_indexed::index<by_time>::type& by_time_index=m_peers_white.get<by_time>(); uint32_t cnt = 0; - bs_head.reserve(depth); + + // picks a random set of peers within the first 120%, rather than a set of the first 100%. + // The intent is that if someone asks twice, they can't easily tell: + // - this address was not in the first list, but is in the second, so the only way this can be + // is if its last_seen was recently reset, so this means the target node recently had a new + // connection to that address + // - this address was in the first list, and not in the second, which means either the address + // was moved to the gray list (if it's not accessibe, which the attacker can check if + // the address accepts incoming connections) or it was the oldest to still fit in the 250 items, + // so its last_seen is old. + const uint32_t pick_depth = anonymize ? depth + depth / 5 : depth; + bs_head.reserve(pick_depth); for(const peers_indexed::value_type& vl: boost::adaptors::reverse(by_time_index)) { - if(!vl.last_seen) - continue; - - if(cnt++ >= depth) + if(cnt++ >= pick_depth) break; bs_head.push_back(vl); } + + if (anonymize) + { + std::random_shuffle(bs_head.begin(), bs_head.end()); + if (bs_head.size() > depth) + bs_head.resize(depth); + for (auto &e: bs_head) + e.last_seen = 0; + } + return true; } //-------------------------------------------------------------------------------------------------- diff --git a/src/p2p/p2p_protocol_defs.h b/src/p2p/p2p_protocol_defs.h index 59c6099d5..85774fcd5 100644 --- a/src/p2p/p2p_protocol_defs.h +++ b/src/p2p/p2p_protocol_defs.h @@ -81,7 +81,8 @@ namespace nodetool BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(adr) KV_SERIALIZE(id) - KV_SERIALIZE(last_seen) + if (!is_store || this_ref.last_seen != 0) + KV_SERIALIZE_OPT(last_seen, (int64_t)0) KV_SERIALIZE_OPT(pruning_seed, (uint32_t)0) KV_SERIALIZE_OPT(rpc_port, (uint16_t)0) END_KV_SERIALIZE_MAP() @@ -132,7 +133,7 @@ namespace nodetool ss << pe.id << "\t" << pe.adr.str() << " \trpc port " << (pe.rpc_port > 0 ? std::to_string(pe.rpc_port) : "-") << " \tpruning seed " << pe.pruning_seed - << " \tlast_seen: " << epee::misc_utils::get_time_interval_string(now_time - pe.last_seen) + << " \tlast_seen: " << (pe.last_seen == 0 ? std::string("never") : epee::misc_utils::get_time_interval_string(now_time - pe.last_seen)) << std::endl; } return ss.str(); diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index c41fb37d8..468fce9e8 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -28,6 +28,7 @@ // // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers +#include <boost/preprocessor/stringize.hpp> #include "include_base_utils.h" #include "string_tools.h" using namespace epee; @@ -159,6 +160,14 @@ namespace cryptonote const std::vector<std::string> ssl_allowed_fingerprint_strings = command_line::get_arg(vm, arg_rpc_ssl_allowed_fingerprints); std::vector<std::vector<uint8_t>> ssl_allowed_fingerprints{ ssl_allowed_fingerprint_strings.size() }; std::transform(ssl_allowed_fingerprint_strings.begin(), ssl_allowed_fingerprint_strings.end(), ssl_allowed_fingerprints.begin(), epee::from_hex::vector); + for (const auto &fpr: ssl_allowed_fingerprints) + { + if (fpr.size() != SSL_FINGERPRINT_SIZE) + { + MERROR("SHA-256 fingerprint should be " BOOST_PP_STRINGIZE(SSL_FINGERPRINT_SIZE) " bytes long."); + return false; + } + } if (!ssl_ca_path.empty() || !ssl_allowed_fingerprints.empty()) ssl_options = epee::net_utils::ssl_options_t{std::move(ssl_allowed_fingerprints), std::move(ssl_ca_path)}; @@ -2308,7 +2317,7 @@ namespace cryptonote const uint64_t req_to_height = req.to_height ? req.to_height : (m_core.get_current_blockchain_height() - 1); for (uint64_t amount: req.amounts) { - auto data = rpc::RpcHandler::get_output_distribution([this](uint64_t amount, uint64_t from, uint64_t to, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base) { return m_core.get_output_distribution(amount, from, to, start_height, distribution, base); }, amount, req.from_height, req_to_height, req.cumulative); + auto data = rpc::RpcHandler::get_output_distribution([this](uint64_t amount, uint64_t from, uint64_t to, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base) { return m_core.get_output_distribution(amount, from, to, start_height, distribution, base); }, amount, req.from_height, req_to_height, [this](uint64_t height) { return m_core.get_blockchain_storage().get_db().get_block_hash_from_height(height); }, req.cumulative, m_core.get_current_blockchain_height()); if (!data) { error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; @@ -2351,7 +2360,7 @@ namespace cryptonote const uint64_t req_to_height = req.to_height ? req.to_height : (m_core.get_current_blockchain_height() - 1); for (uint64_t amount: req.amounts) { - auto data = rpc::RpcHandler::get_output_distribution([this](uint64_t amount, uint64_t from, uint64_t to, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base) { return m_core.get_output_distribution(amount, from, to, start_height, distribution, base); }, amount, req.from_height, req_to_height, req.cumulative); + auto data = rpc::RpcHandler::get_output_distribution([this](uint64_t amount, uint64_t from, uint64_t to, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base) { return m_core.get_output_distribution(amount, from, to, start_height, distribution, base); }, amount, req.from_height, req_to_height, [this](uint64_t height) { return m_core.get_blockchain_storage().get_db().get_block_hash_from_height(height); }, req.cumulative, m_core.get_current_blockchain_height()); if (!data) { res.status = "Failed to get output distribution"; diff --git a/src/rpc/daemon_handler.cpp b/src/rpc/daemon_handler.cpp index 7c8953930..f27c49ff8 100644 --- a/src/rpc/daemon_handler.cpp +++ b/src/rpc/daemon_handler.cpp @@ -778,7 +778,7 @@ namespace rpc const uint64_t req_to_height = req.to_height ? req.to_height : (m_core.get_current_blockchain_height() - 1); for (std::uint64_t amount : req.amounts) { - auto data = rpc::RpcHandler::get_output_distribution([this](uint64_t amount, uint64_t from, uint64_t to, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base) { return m_core.get_output_distribution(amount, from, to, start_height, distribution, base); }, amount, req.from_height, req_to_height, req.cumulative); + auto data = rpc::RpcHandler::get_output_distribution([this](uint64_t amount, uint64_t from, uint64_t to, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base) { return m_core.get_output_distribution(amount, from, to, start_height, distribution, base); }, amount, req.from_height, req_to_height, [this](uint64_t height) { return m_core.get_blockchain_storage().get_db().get_block_hash_from_height(height); }, req.cumulative, m_core.get_current_blockchain_height()); if (!data) { res.distributions.clear(); diff --git a/src/rpc/rpc_handler.cpp b/src/rpc/rpc_handler.cpp index e0a81c70f..af5cb98a3 100644 --- a/src/rpc/rpc_handler.cpp +++ b/src/rpc/rpc_handler.cpp @@ -26,26 +26,49 @@ namespace rpc } boost::optional<output_distribution_data> - RpcHandler::get_output_distribution(const std::function<bool(uint64_t, uint64_t, uint64_t, uint64_t&, std::vector<uint64_t>&, uint64_t&)> &f, uint64_t amount, uint64_t from_height, uint64_t to_height, bool cumulative) + RpcHandler::get_output_distribution(const std::function<bool(uint64_t, uint64_t, uint64_t, uint64_t&, std::vector<uint64_t>&, uint64_t&)> &f, uint64_t amount, uint64_t from_height, uint64_t to_height, const std::function<crypto::hash(uint64_t)> &get_hash, bool cumulative, uint64_t blockchain_height) { static struct D { boost::mutex mutex; std::vector<std::uint64_t> cached_distribution; std::uint64_t cached_from, cached_to, cached_start_height, cached_base; + crypto::hash cached_m10_hash; + crypto::hash cached_top_hash; bool cached; - D(): cached_from(0), cached_to(0), cached_start_height(0), cached_base(0), cached(false) {} + D(): cached_from(0), cached_to(0), cached_start_height(0), cached_base(0), cached_m10_hash(crypto::null_hash), cached_top_hash(crypto::null_hash), cached(false) {} } d; const boost::unique_lock<boost::mutex> lock(d.mutex); - if (d.cached && amount == 0 && d.cached_from == from_height && d.cached_to == to_height) + crypto::hash top_hash = crypto::null_hash; + if (d.cached_to < blockchain_height) + top_hash = get_hash(d.cached_to); + if (d.cached && amount == 0 && d.cached_from == from_height && d.cached_to == to_height && d.cached_top_hash == top_hash) return process_distribution(cumulative, d.cached_start_height, d.cached_distribution, d.cached_base); std::vector<std::uint64_t> distribution; std::uint64_t start_height, base; // see if we can extend the cache - a common case - if (d.cached && amount == 0 && d.cached_from == from_height && to_height > d.cached_to) + bool can_extend = d.cached && amount == 0 && d.cached_from == from_height && to_height > d.cached_to && top_hash == d.cached_top_hash; + if (!can_extend) + { + // we kept track of the hash 10 blocks below, if it exists, so if it matches, + // we can still pop the last 10 cached slots and try again + if (d.cached && amount == 0 && d.cached_from == from_height && d.cached_to - d.cached_from >= 10 && to_height > d.cached_to - 10) + { + crypto::hash hash10 = get_hash(d.cached_to - 10); + if (hash10 == d.cached_m10_hash) + { + d.cached_to -= 10; + d.cached_top_hash = hash10; + d.cached_m10_hash = crypto::null_hash; + d.cached_distribution.resize(d.cached_distribution.size() - 10); + can_extend = true; + } + } + } + if (can_extend) { std::vector<std::uint64_t> new_distribution; if (!f(amount, d.cached_to + 1, to_height, start_height, new_distribution, base)) @@ -74,6 +97,8 @@ namespace rpc { d.cached_from = from_height; d.cached_to = to_height; + d.cached_top_hash = get_hash(d.cached_to); + d.cached_m10_hash = d.cached_to >= 10 ? get_hash(d.cached_to - 10) : crypto::null_hash; d.cached_distribution = distribution; d.cached_start_height = start_height; d.cached_base = base; diff --git a/src/rpc/rpc_handler.h b/src/rpc/rpc_handler.h index 2439eaa58..b81983d28 100644 --- a/src/rpc/rpc_handler.h +++ b/src/rpc/rpc_handler.h @@ -32,6 +32,7 @@ #include <cstdint> #include <string> #include <vector> +#include "crypto/hash.h" namespace cryptonote { @@ -56,7 +57,7 @@ class RpcHandler virtual std::string handle(const std::string& request) = 0; static boost::optional<output_distribution_data> - get_output_distribution(const std::function<bool(uint64_t, uint64_t, uint64_t, uint64_t&, std::vector<uint64_t>&, uint64_t&)> &f, uint64_t amount, uint64_t from_height, uint64_t to_height, bool cumulative); + get_output_distribution(const std::function<bool(uint64_t, uint64_t, uint64_t, uint64_t&, std::vector<uint64_t>&, uint64_t&)> &f, uint64_t amount, uint64_t from_height, uint64_t to_height, const std::function<crypto::hash(uint64_t)> &get_hash, bool cumulative, uint64_t blockchain_height); }; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 6554ef7d5..f5b492771 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -39,6 +39,7 @@ #include <boost/algorithm/string/join.hpp> #include <boost/asio/ip/address.hpp> #include <boost/range/adaptor/transformed.hpp> +#include <boost/preprocessor/stringize.hpp> #include "include_base_utils.h" using namespace epee; @@ -131,6 +132,9 @@ using namespace cryptonote; #define GAMMA_SHAPE 19.28 #define GAMMA_SCALE (1/1.61) +#define DEFAULT_MIN_OUTPUT_COUNT 5 +#define DEFAULT_MIN_OUTPUT_VALUE (2*COIN) + static const std::string MULTISIG_SIGNATURE_MAGIC = "SigMultisigPkV1"; static const std::string MULTISIG_EXTRA_INFO_MAGIC = "MultisigxV1"; @@ -340,6 +344,11 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl { std::vector<std::vector<uint8_t>> ssl_allowed_fingerprints{ daemon_ssl_allowed_fingerprints.size() }; std::transform(daemon_ssl_allowed_fingerprints.begin(), daemon_ssl_allowed_fingerprints.end(), ssl_allowed_fingerprints.begin(), epee::from_hex::vector); + for (const auto &fpr: daemon_ssl_allowed_fingerprints) + { + THROW_WALLET_EXCEPTION_IF(fpr.size() != SSL_FINGERPRINT_SIZE, tools::error::wallet_internal_error, + "SHA-256 fingerprint should be " BOOST_PP_STRINGIZE(SSL_FINGERPRINT_SIZE) " bytes long."); + } ssl_options = epee::net_utils::ssl_options_t{ std::move(ssl_allowed_fingerprints), std::move(daemon_ssl_ca_file) @@ -9375,9 +9384,16 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp idx = pop_best_value(indices, tx.selected_transfers, true); // we might not want to add it if it's a large output and we don't have many left - if (m_transfers[idx].amount() >= m_min_output_value) { - if (get_count_above(m_transfers, *unused_transfers_indices, m_min_output_value) < m_min_output_count) { - LOG_PRINT_L2("Second output was not strictly needed, and we're running out of outputs above " << print_money(m_min_output_value) << ", not adding"); + uint64_t min_output_value = m_min_output_value; + uint32_t min_output_count = m_min_output_count; + if (min_output_value == 0 && min_output_count == 0) + { + min_output_value = DEFAULT_MIN_OUTPUT_VALUE; + min_output_count = DEFAULT_MIN_OUTPUT_COUNT; + } + if (m_transfers[idx].amount() >= min_output_value) { + if (get_count_above(m_transfers, *unused_transfers_indices, min_output_value) < min_output_count) { + LOG_PRINT_L2("Second output was not strictly needed, and we're running out of outputs above " << print_money(min_output_value) << ", not adding"); break; } } diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 4076ae957..22eaffa6f 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -31,6 +31,7 @@ #include <boost/asio/ip/address.hpp> #include <boost/filesystem/operations.hpp> #include <boost/algorithm/string.hpp> +#include <boost/preprocessor/stringize.hpp> #include <cstdint> #include "include_base_utils.h" using namespace epee; @@ -254,6 +255,14 @@ namespace tools { std::vector<std::vector<uint8_t>> allowed_fingerprints{ rpc_ssl_allowed_fingerprints.size() }; std::transform(rpc_ssl_allowed_fingerprints.begin(), rpc_ssl_allowed_fingerprints.end(), allowed_fingerprints.begin(), epee::from_hex::vector); + for (const auto &fpr: rpc_ssl_allowed_fingerprints) + { + if (fpr.size() != SSL_FINGERPRINT_SIZE) + { + MERROR("SHA-256 fingerprint should be " BOOST_PP_STRINGIZE(SSL_FINGERPRINT_SIZE) " bytes long."); + return false; + } + } rpc_ssl_options = epee::net_utils::ssl_options_t{ std::move(allowed_fingerprints), std::move(rpc_ssl_ca_file) @@ -4069,9 +4078,10 @@ namespace tools { cryptonote::TESTNET, "testnet" }, { cryptonote::STAGENET, "stagenet" }, }; + if (!req.any_net_type && !m_wallet) return not_open(er); for (const auto &net_type: net_types) { - if (!req.any_net_type && net_type.type != m_wallet->nettype()) + if (!req.any_net_type && (!m_wallet || net_type.type != m_wallet->nettype())) continue; if (req.allow_openalias) { @@ -4153,6 +4163,7 @@ namespace tools { er.code = WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION; er.message = "SSL is enabled but no user certificate or fingerprints were provided"; + return false; } if (!m_wallet->set_daemon(req.address, boost::none, req.trusted, std::move(ssl_options))) @@ -4177,7 +4188,7 @@ namespace tools { er.code = WALLET_RPC_ERROR_CODE_INVALID_LOG_LEVEL; er.message = "Error: log level not valid"; - return true; + return false; } mlog_set_log_level(req.level); return true; |