aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp24
-rw-r--r--src/common/stack_trace.cpp2
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp12
-rw-r--r--src/p2p/net_node.h14
-rw-r--r--src/p2p/net_node.inl118
-rw-r--r--src/p2p/net_peerlist.h52
-rw-r--r--src/ringct/rctSigs.cpp34
-rw-r--r--src/rpc/core_rpc_server.h2
-rw-r--r--src/simplewallet/simplewallet.cpp18
-rw-r--r--src/wallet/api/wallet.cpp4
-rw-r--r--src/wallet/api/wallet_manager.cpp5
-rw-r--r--src/wallet/wallet2_api.h1
12 files changed, 239 insertions, 47 deletions
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index 343fd1fa4..7d548afed 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -441,7 +441,7 @@ void BlockchainLMDB::do_resize(uint64_t increase_size)
if (result)
throw0(DB_ERROR(lmdb_error("Failed to set new mapsize: ", result).c_str()));
- MINFO("LMDB Mapsize increased." << " Old: " << mei.me_mapsize / (1024 * 1024) << "MiB" << ", New: " << new_mapsize / (1024 * 1024) << "MiB");
+ MGINFO("LMDB Mapsize increased." << " Old: " << mei.me_mapsize / (1024 * 1024) << "MiB" << ", New: " << new_mapsize / (1024 * 1024) << "MiB");
mdb_txn_safe::allow_new_txns();
}
@@ -525,7 +525,7 @@ void BlockchainLMDB::check_and_resize_for_batch(uint64_t batch_num_blocks)
// size-based check
if (need_resize(threshold_size))
{
- LOG_PRINT_L0("[batch] DB resize needed");
+ MGINFO("[batch] DB resize needed");
do_resize(increase_size);
}
}
@@ -1172,7 +1172,7 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags)
{
if (*(const uint32_t*)v.mv_data > VERSION)
{
- MINFO("Existing lmdb database was made by a later version. We don't know how it will change yet.");
+ MWARNING("Existing lmdb database was made by a later version. We don't know how it will change yet.");
compatible = false;
}
#if VERSION > 0
@@ -2301,11 +2301,11 @@ void BlockchainLMDB::batch_commit()
if (! m_batch_transactions)
throw0(DB_ERROR("batch transactions not enabled"));
if (! m_batch_active)
- throw0(DB_ERROR("batch transaction not in progress"));
+ throw1(DB_ERROR("batch transaction not in progress"));
if (m_write_batch_txn == nullptr)
- throw0(DB_ERROR("batch transaction not in progress"));
+ throw1(DB_ERROR("batch transaction not in progress"));
if (m_writer != boost::this_thread::get_id())
- return; // batch txn owned by other thread
+ throw1(DB_ERROR("batch transaction owned by other thread"));
check_open();
@@ -2328,11 +2328,11 @@ void BlockchainLMDB::batch_stop()
if (! m_batch_transactions)
throw0(DB_ERROR("batch transactions not enabled"));
if (! m_batch_active)
- throw0(DB_ERROR("batch transaction not in progress"));
+ throw1(DB_ERROR("batch transaction not in progress"));
if (m_write_batch_txn == nullptr)
- throw0(DB_ERROR("batch transaction not in progress"));
+ throw1(DB_ERROR("batch transaction not in progress"));
if (m_writer != boost::this_thread::get_id())
- return; // batch txn owned by other thread
+ throw1(DB_ERROR("batch transaction owned by other thread"));
check_open();
LOG_PRINT_L3("batch transaction: committing...");
TIME_MEASURE_START(time1);
@@ -2354,9 +2354,11 @@ void BlockchainLMDB::batch_abort()
if (! m_batch_transactions)
throw0(DB_ERROR("batch transactions not enabled"));
if (! m_batch_active)
- throw0(DB_ERROR("batch transaction not in progress"));
+ throw1(DB_ERROR("batch transaction not in progress"));
+ if (m_write_batch_txn == nullptr)
+ throw1(DB_ERROR("batch transaction not in progress"));
if (m_writer != boost::this_thread::get_id())
- return; // batch txn owned by other thread
+ throw1(DB_ERROR("batch transaction owned by other thread"));
check_open();
// for destruction of batch transaction
m_write_txn = nullptr;
diff --git a/src/common/stack_trace.cpp b/src/common/stack_trace.cpp
index ce05b7e04..99e4bda2c 100644
--- a/src/common/stack_trace.cpp
+++ b/src/common/stack_trace.cpp
@@ -38,7 +38,7 @@
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "stacktrace"
-#define ST_LOG(x) CERROR(el::base::Writer,el::base::DispatchAction::FileOnlyLog,MONERO_DEFAULT_LOG_CATEGORY) << x
+#define ST_LOG(x) CINFO(el::base::Writer,el::base::DispatchAction::FileOnlyLog,MONERO_DEFAULT_LOG_CATEGORY) << x
// from http://stackoverflow.com/questions/11665829/how-can-i-print-stack-trace-for-caught-exceptions-in-c-code-injection-in-c
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 055606769..c8103d720 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -496,6 +496,18 @@ namespace cryptonote
return false;
}
+ if(m_mempool.have_tx(tx_hash))
+ {
+ LOG_PRINT_L2("tx " << tx_hash << "already have transaction in tx_pool");
+ return true;
+ }
+
+ if(m_blockchain_storage.have_tx(tx_hash))
+ {
+ LOG_PRINT_L2("tx " << tx_hash << " already have transaction in blockchain");
+ return true;
+ }
+
if(!check_tx_syntax(tx))
{
LOG_PRINT_L1("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " syntax, rejected");
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index cc6a486d3..40598fc0f 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -110,7 +110,12 @@ namespace nodetool
void serialize(Archive &a, const t_version_type ver)
{
a & m_peerlist;
- a & m_config.m_peer_id;
+ if (ver == 0)
+ {
+ // from v1, we do not store the peer id anymore
+ peerid_type peer_id;
+ a & peer_id;
+ }
}
// debug functions
bool log_peerlist();
@@ -162,6 +167,7 @@ namespace nodetool
#endif
int handle_get_support_flags(int command, COMMAND_REQUEST_SUPPORT_FLAGS::request& arg, COMMAND_REQUEST_SUPPORT_FLAGS::response& rsp, p2p_connection_context& context);
bool init_config();
+ bool make_default_peer_id();
bool make_default_config();
bool store_config();
bool check_trust(const proof_of_trust& tr);
@@ -227,6 +233,11 @@ namespace nodetool
bool set_rate_down_limit(const boost::program_options::variables_map& vm, int64_t limit);
bool set_rate_limit(const boost::program_options::variables_map& vm, int64_t limit);
+ bool has_too_many_connections(const uint32_t ip);
+
+ bool check_connection_and_handshake_with_peer(const net_address& na, uint64_t last_seen_stamp);
+ bool gray_peerlist_housekeeping();
+
void kill() { ///< will be called e.g. from deinit()
_info("Killing the net_node");
is_closing = true;
@@ -287,6 +298,7 @@ namespace nodetool
epee::math_helper::once_a_time_seconds<P2P_DEFAULT_HANDSHAKE_INTERVAL> m_peer_handshake_idle_maker_interval;
epee::math_helper::once_a_time_seconds<1> m_connections_maker_interval;
epee::math_helper::once_a_time_seconds<60*30, false> m_peerlist_store_interval;
+ epee::math_helper::once_a_time_seconds<60> m_gray_peerlist_housekeeping_interval;
std::string m_bind_ip;
std::string m_port;
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index 34a3f9363..0e43d9579 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -173,6 +173,9 @@ namespace nodetool
make_default_config();
}
+ // always recreate a new peer id
+ make_default_peer_id();
+
//at this moment we have hardcoded config
m_config.m_net_config.handshake_interval = P2P_DEFAULT_HANDSHAKE_INTERVAL;
m_config.m_net_config.packet_max_size = P2P_DEFAULT_PACKET_MAX_SIZE; //20 MB limit
@@ -205,20 +208,26 @@ namespace nodetool
if(time(nullptr) >= it->second)
{
m_blocked_ips.erase(it);
- MLOG_CYAN(el::Level::Info, "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " unblocked.");
+ MCLOG_CYAN(el::Level::Info, "global", "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " unblocked.");
return true;
}
return false;
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::make_default_config()
+ bool node_server<t_payload_net_handler>::make_default_peer_id()
{
m_config.m_peer_id = crypto::rand<uint64_t>();
return true;
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::make_default_config()
+ {
+ return make_default_peer_id();
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::block_ip(uint32_t addr, time_t seconds)
{
CRITICAL_REGION_LOCAL(m_blocked_ips_lock);
@@ -237,7 +246,7 @@ namespace nodetool
for (const auto &c: conns)
m_net_server.get_config_object().close(c);
- MLOG_CYAN(el::Level::Info, "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " blocked.");
+ MCLOG_CYAN(el::Level::Info, "global", "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " blocked.");
return true;
}
//-----------------------------------------------------------------------------------
@@ -249,7 +258,7 @@ namespace nodetool
if (i == m_blocked_ips.end())
return false;
m_blocked_ips.erase(i);
- MLOG_CYAN(el::Level::Info, "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " unblocked.");
+ MCLOG_CYAN(el::Level::Info, "global", "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " unblocked.");
return true;
}
//-----------------------------------------------------------------------------------
@@ -926,6 +935,50 @@ namespace nodetool
return true;
}
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::check_connection_and_handshake_with_peer(const net_address& na, uint64_t last_seen_stamp)
+ {
+ LOG_PRINT_L1("Connecting to " << epee::string_tools::get_ip_string_from_int32(na.ip) << ":"
+ << epee::string_tools::num_to_string_fast(na.port) << "(last_seen: "
+ << (last_seen_stamp ? epee::misc_utils::get_time_interval_string(time(NULL) - last_seen_stamp):"never")
+ << ")...");
+
+ typename net_server::t_connection_context con = AUTO_VAL_INIT(con);
+ bool res = m_net_server.connect(epee::string_tools::get_ip_string_from_int32(na.ip),
+ epee::string_tools::num_to_string_fast(na.port),
+ m_config.m_net_config.connection_timeout,
+ con);
+
+ if (!res) {
+ bool is_priority = is_priority_node(na);
+
+ LOG_PRINT_CC_PRIORITY_NODE(is_priority, con, "Connect failed to "
+ << epee::string_tools::get_ip_string_from_int32(na.ip)
+ << ":" << epee::string_tools::num_to_string_fast(na.port));
+
+ return false;
+ }
+
+ peerid_type pi = AUTO_VAL_INIT(pi);
+ res = do_handshake_with_peer(pi, con, true);
+
+ if (!res) {
+ bool is_priority = is_priority_node(na);
+
+ LOG_PRINT_CC_PRIORITY_NODE(is_priority, con, "Failed to HANDSHAKE with peer "
+ << epee::string_tools::get_ip_string_from_int32(na.ip)
+ << ":" << epee::string_tools::num_to_string_fast(na.port));
+
+ return false;
+ }
+
+ m_net_server.get_config_object().close(con.m_connection_id);
+
+ LOG_DEBUG_CC(con, "CONNECTION HANDSHAKED OK AND CLOSED.");
+
+ return true;
+ }
+
#undef LOG_PRINT_CC_PRIORITY_NODE
//-----------------------------------------------------------------------------------
@@ -1097,6 +1150,7 @@ namespace nodetool
{
m_peer_handshake_idle_maker_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::peer_sync_idle_maker, this));
m_connections_maker_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::connections_maker, this));
+ m_gray_peerlist_housekeeping_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::gray_peerlist_housekeeping, this));
m_peerlist_store_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::store_config, this));
return true;
}
@@ -1456,6 +1510,14 @@ namespace nodetool
drop_connection(context);
return 1;
}
+
+ if(has_too_many_connections(context.m_remote_ip))
+ {
+ LOG_PRINT_CCONTEXT_L1("CONNECTION FROM " << epee::string_tools::get_ip_string_from_int32(context.m_remote_ip) << " REFUSED, too many connections from the same address");
+ drop_connection(context);
+ return 1;
+ }
+
//associate peer_id with this connection
context.peer_id = arg.node_data.peer_id;
@@ -1674,4 +1736,52 @@ namespace nodetool
return true;
}
+
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::has_too_many_connections(const uint32_t ip)
+ {
+ const uint8_t max_connections = 1;
+ uint8_t count = 0;
+
+ m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
+ {
+ if (cntxt.m_is_income && cntxt.m_remote_ip == ip) {
+ count++;
+
+ if (count > max_connections) {
+ return false;
+ }
+ }
+
+ return true;
+ });
+
+ return count > max_connections;
+ }
+
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::gray_peerlist_housekeeping()
+ {
+ peerlist_entry pe = AUTO_VAL_INIT(pe);
+
+ if (!m_peerlist.get_random_gray_peer(pe)) {
+ return false;
+ }
+
+ bool success = check_connection_and_handshake_with_peer(pe.adr, pe.last_seen);
+
+ if (!success) {
+ m_peerlist.remove_from_peer_gray(pe);
+
+ LOG_PRINT_L2("PEER EVICTED FROM GRAY PEER LIST IP address: " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << " Peer ID: " << std::hex << pe.id);
+
+ return true;
+ }
+
+ m_peerlist.set_peer_just_seen(pe.id, pe.adr);
+
+ LOG_PRINT_L2("PEER PROMOTED TO WHITE PEER LIST IP address: " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << " Peer ID: " << std::hex << pe.id);
+
+ return true;
+ }
}
diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h
index fa69abd6e..4797eb82b 100644
--- a/src/p2p/net_peerlist.h
+++ b/src/p2p/net_peerlist.h
@@ -81,6 +81,8 @@ namespace nodetool
bool set_peer_just_seen(peerid_type peer, const net_address& addr);
bool set_peer_unreachable(const peerlist_entry& pr);
bool is_ip_allowed(uint32_t ip);
+ bool get_random_gray_peer(peerlist_entry& pe);
+ bool remove_from_peer_gray(const peerlist_entry& pe);
private:
@@ -285,9 +287,11 @@ namespace nodetool
{
if(!vl.last_seen)
continue;
- bs_head.push_back(vl);
- if(cnt++ > depth)
+
+ if(cnt++ >= depth)
break;
+
+ bs_head.push_back(vl);
}
return true;
}
@@ -394,6 +398,50 @@ namespace nodetool
return true;
}
//--------------------------------------------------------------------------------------------------
+ inline
+ bool peerlist_manager::get_random_gray_peer(peerlist_entry& pe)
+ {
+ TRY_ENTRY();
+
+ CRITICAL_REGION_LOCAL(m_peerlist_lock);
+
+ if (m_peers_gray.empty()) {
+ return false;
+ }
+
+ size_t x = crypto::rand<size_t>() % (m_peers_gray.size() + 1);
+ size_t res = (x * x * x) / (m_peers_gray.size() * m_peers_gray.size()); //parabola \/
+
+ LOG_PRINT_L3("Random gray peer index=" << res << "(x="<< x << ", max_index=" << m_peers_gray.size() << ")");
+
+ peers_indexed::index<by_time>::type& by_time_index = m_peers_gray.get<by_time>();
+ pe = *epee::misc_utils::move_it_backward(--by_time_index.end(), res);
+
+ return true;
+
+ CATCH_ENTRY_L0("peerlist_manager::get_random_gray_peer()", false);
+ return true;
+ }
+ //--------------------------------------------------------------------------------------------------
+ inline
+ bool peerlist_manager::remove_from_peer_gray(const peerlist_entry& pe)
+ {
+ TRY_ENTRY();
+
+ CRITICAL_REGION_LOCAL(m_peerlist_lock);
+
+ peers_indexed::index_iterator<by_addr>::type iterator = m_peers_gray.get<by_addr>().find(pe.adr);
+
+ if (iterator != m_peers_gray.get<by_addr>().end()) {
+ m_peers_gray.erase(iterator);
+ }
+
+ return true;
+
+ CATCH_ENTRY_L0("peerlist_manager::remove_from_peer_gray()", false);
+ return true;
+ }
+ //--------------------------------------------------------------------------------------------------
}
BOOST_CLASS_VERSION(nodetool::peerlist_manager, CURRENT_PEERLIST_STORAGE_ARCHIVE_VER)
diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp
index 74fed0ede..b8f3596e8 100644
--- a/src/ringct/rctSigs.cpp
+++ b/src/ringct/rctSigs.cpp
@@ -797,23 +797,6 @@ namespace rct {
tools::thread_group threadpool(tools::thread_group::optimal_with_max(threads));
if (semantics) {
- results.clear();
- results.resize(rv.outPk.size());
- tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
- for (size_t i = 0; i < rv.outPk.size(); i++) {
- region.run([&, i] {
- results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
- });
- }
- });
-
- for (size_t i = 0; i < results.size(); ++i) {
- if (!results[i]) {
- LOG_PRINT_L1("Range proof verified failed for output " << i);
- return false;
- }
- }
-
key sumOutpks = identity();
for (size_t i = 0; i < rv.outPk.size(); i++) {
addKeys(sumOutpks, sumOutpks, rv.outPk[i].mask);
@@ -833,6 +816,23 @@ namespace rct {
LOG_PRINT_L1("Sum check failed");
return false;
}
+
+ results.clear();
+ results.resize(rv.outPk.size());
+ tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
+ for (size_t i = 0; i < rv.outPk.size(); i++) {
+ region.run([&, i] {
+ results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
+ });
+ }
+ });
+
+ for (size_t i = 0; i < results.size(); ++i) {
+ if (!results[i]) {
+ LOG_PRINT_L1("Range proof verified failed for output " << i);
+ return false;
+ }
+ }
}
else {
const key message = get_pre_mlsag_hash(rv);
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index 84871e8bb..767bcc715 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -194,3 +194,5 @@ private:
bool m_restricted;
};
}
+
+BOOST_CLASS_VERSION(nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >, 1);
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 68781dd73..50509040c 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -1958,7 +1958,7 @@ bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending
return false;
}
// available for RPC version 1.4 or higher
- if (version < 0x10004)
+ if (version < MAKE_CORE_RPC_VERSION(1, 4))
return true;
std::string err;
uint64_t blockchain_height = get_daemon_blockchain_height(err);
@@ -2317,9 +2317,9 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
LOG_ERROR("RPC error: " << e.to_string());
fail_msg_writer() << tr("RPC error: ") << e.what();
}
- catch (const tools::error::get_random_outs_error&)
+ catch (const tools::error::get_random_outs_error &e)
{
- fail_msg_writer() << tr("failed to get random outputs to mix");
+ fail_msg_writer() << tr("failed to get random outputs to mix: ") << e.what();
}
catch (const tools::error::not_enough_money& e)
{
@@ -2495,9 +2495,9 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
LOG_ERROR("RPC error: " << e.to_string());
fail_msg_writer() << tr("RPC error: ") << e.what();
}
- catch (const tools::error::get_random_outs_error&)
+ catch (const tools::error::get_random_outs_error &e)
{
- fail_msg_writer() << tr("failed to get random outputs to mix");
+ fail_msg_writer() << tr("failed to get random outputs to mix: ") << e.what();
}
catch (const tools::error::not_enough_money& e)
{
@@ -2756,9 +2756,9 @@ bool simple_wallet::sweep_all(const std::vector<std::string> &args_)
LOG_ERROR("RPC error: " << e.to_string());
fail_msg_writer() << tr("RPC error: ") << e.what();
}
- catch (const tools::error::get_random_outs_error&)
+ catch (const tools::error::get_random_outs_error &e)
{
- fail_msg_writer() << tr("failed to get random outputs to mix");
+ fail_msg_writer() << tr("failed to get random outputs to mix: ") << e.what();
}
catch (const tools::error::not_enough_money& e)
{
@@ -3041,9 +3041,9 @@ bool simple_wallet::submit_transfer(const std::vector<std::string> &args_)
LOG_ERROR("Unknown RPC error: " << e.to_string());
fail_msg_writer() << tr("RPC error: ") << e.what();
}
- catch (const tools::error::get_random_outs_error&)
+ catch (const tools::error::get_random_outs_error &e)
{
- fail_msg_writer() << tr("failed to get random outputs to mix");
+ fail_msg_writer() << tr("failed to get random outputs to mix: ") << e.what();
}
catch (const tools::error::not_enough_money& e)
{
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 5f7d8e522..52ecc2e6a 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -834,8 +834,8 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
} catch (const tools::error::wallet_rpc_error& e) {
m_errorString = tr("RPC error: ") + e.to_string();
m_status = Status_Error;
- } catch (const tools::error::get_random_outs_error&) {
- m_errorString = tr("failed to get random outputs to mix");
+ } catch (const tools::error::get_random_outs_error &e) {
+ m_errorString = (boost::format(tr("failed to get random outputs to mix: %s")) % e.what()).str();
m_status = Status_Error;
} catch (const tools::error::not_enough_money& e) {
diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp
index 12bce0285..904338a72 100644
--- a/src/wallet/api/wallet_manager.cpp
+++ b/src/wallet/api/wallet_manager.cpp
@@ -448,6 +448,11 @@ void WalletManagerFactory::setLogLevel(int level)
mlog_set_log_level(level);
}
+void WalletManagerFactory::setLogCategories(const std::string &categories)
+{
+ mlog_set_categories(categories.c_str());
+}
+
}
diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h
index 5a13205c5..78caddc0b 100644
--- a/src/wallet/wallet2_api.h
+++ b/src/wallet/wallet2_api.h
@@ -708,6 +708,7 @@ struct WalletManagerFactory
static WalletManager * getWalletManager();
static void setLogLevel(int level);
+ static void setLogCategories(const std::string &categories);
};