aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/device_trezor/device_trezor_base.cpp6
-rw-r--r--src/device_trezor/trezor/transport.cpp120
-rw-r--r--src/device_trezor/trezor/transport.hpp5
-rw-r--r--src/p2p/net_node.inl4
-rw-r--r--src/p2p/net_peerlist.h33
-rw-r--r--src/p2p/p2p_protocol_defs.h5
-rw-r--r--src/rpc/core_rpc_server.cpp13
-rw-r--r--src/rpc/daemon_handler.cpp2
-rw-r--r--src/rpc/rpc_handler.cpp33
-rw-r--r--src/rpc/rpc_handler.h3
-rw-r--r--src/wallet/wallet2.cpp22
-rw-r--r--src/wallet/wallet_rpc_server.cpp15
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;