aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/build.yml43
-rw-r--r--CMakeLists.txt4
-rw-r--r--contrib/epee/include/byte_stream.h2
-rw-r--r--contrib/epee/include/rolling_median.h1
-rw-r--r--contrib/gitian/README.md1
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp4
-rw-r--r--src/cryptonote_basic/connection_context.h1
-rw-r--r--src/cryptonote_config.h2
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_defs.h2
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.h2
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl54
-rw-r--r--src/cryptonote_protocol/levin_notify.cpp2
-rw-r--r--src/daemon/command_parser_executor.cpp42
-rw-r--r--src/daemon/command_server.cpp4
-rw-r--r--src/p2p/net_node.cpp1
-rw-r--r--src/p2p/net_node.h7
-rw-r--r--src/p2p/net_node.inl74
-rw-r--r--src/p2p/net_node_common.h4
-rw-r--r--src/ringct/bulletproofs.cc2
-rw-r--r--src/rpc/core_rpc_server.cpp1
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h4
-rw-r--r--src/simplewallet/simplewallet.cpp30
-rw-r--r--tests/unit_tests/epee_utils.cpp17
23 files changed, 271 insertions, 33 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index b21c53401..c6ed13e62 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -5,14 +5,24 @@ on: [push, pull_request]
jobs:
build-macos:
runs-on: macOS-latest
+ env:
+ CCACHE_COMPRESS: 1
+ CCACHE_TEMPDIR: /tmp/.ccache-temp
steps:
- uses: actions/checkout@v1
with:
submodules: recursive
+ - uses: actions/cache@v2
+ with:
+ path: ~/.ccache
+ key: ccache-macos-build-${{ github.sha }}
+ restore-keys: ccache-macos-build-
- name: install dependencies
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install boost hidapi zmq libpgm miniupnpc ldns expat libunwind-headers protobuf
+ run: HOMEBREW_NO_AUTO_UPDATE=1 brew install boost hidapi zmq libpgm miniupnpc ldns expat libunwind-headers protobuf ccache
- name: build
- run: make -j3
+ run: |
+ ccache --max-size=150M
+ make -j3
build-windows:
runs-on: windows-latest
@@ -32,10 +42,18 @@ jobs:
build-ubuntu:
runs-on: ubuntu-latest
+ env:
+ CCACHE_COMPRESS: 1
+ CCACHE_TEMPDIR: /tmp/.ccache-temp
steps:
- uses: actions/checkout@v1
with:
submodules: recursive
+ - uses: actions/cache@v2
+ with:
+ path: ~/.ccache
+ key: ccache-ubuntu-build-${{ github.sha }}
+ restore-keys: ccache-ubuntu-build-
- name: remove bundled boost
run: sudo rm -rf /usr/local/share/boost
- name: set apt conf
@@ -46,16 +64,26 @@ jobs:
- name: update apt
run: sudo apt update
- name: install monero dependencies
- run: sudo apt -y install build-essential cmake libboost-all-dev miniupnpc libunbound-dev graphviz doxygen libunwind8-dev pkg-config libssl-dev libzmq3-dev libsodium-dev libhidapi-dev libnorm-dev libusb-1.0-0-dev libpgm-dev libprotobuf-dev protobuf-compiler
+ run: sudo apt -y install build-essential cmake libboost-all-dev miniupnpc libunbound-dev graphviz doxygen libunwind8-dev pkg-config libssl-dev libzmq3-dev libsodium-dev libhidapi-dev libnorm-dev libusb-1.0-0-dev libpgm-dev libprotobuf-dev protobuf-compiler ccache
- name: build
- run: make -j3
+ run: |
+ ccache --max-size=150M
+ make -j3
libwallet-ubuntu:
runs-on: ubuntu-latest
+ env:
+ CCACHE_COMPRESS: 1
+ CCACHE_TEMPDIR: /tmp/.ccache-temp
steps:
- uses: actions/checkout@v1
with:
submodules: recursive
+ - uses: actions/cache@v2
+ with:
+ path: ~/.ccache
+ key: ccache-ubuntu-libwallet-${{ github.sha }}
+ restore-keys: ccache-ubuntu-libwallet-
- name: remove bundled boost
run: sudo rm -rf /usr/local/share/boost
- name: set apt conf
@@ -66,9 +94,12 @@ jobs:
- name: update apt
run: sudo apt update
- name: install monero dependencies
- run: sudo apt -y install build-essential cmake libboost-all-dev miniupnpc libunbound-dev graphviz doxygen libunwind8-dev pkg-config libssl-dev libzmq3-dev libsodium-dev libhidapi-dev libnorm-dev libusb-1.0-0-dev libpgm-dev libprotobuf-dev protobuf-compiler
+ run: sudo apt -y install build-essential cmake libboost-all-dev miniupnpc libunbound-dev graphviz doxygen libunwind8-dev pkg-config libssl-dev libzmq3-dev libsodium-dev libhidapi-dev libnorm-dev libusb-1.0-0-dev libpgm-dev libprotobuf-dev protobuf-compiler ccache
- name: build
- run: cmake -DBUILD_GUI_DEPS=ON && make -j3
+ run: |
+ ccache --max-size=150M
+ cmake -DBUILD_GUI_DEPS=ON
+ make -j3
test-ubuntu:
needs: build-ubuntu
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8a7b783aa..c6d102ba7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -973,10 +973,12 @@ list(APPEND EXTRA_LIBRARIES ${CMAKE_DL_LIBS})
if (HIDAPI_FOUND OR LibUSB_COMPILE_TEST_PASSED)
if (APPLE)
if(DEPENDS)
- list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework IOKit")
+ list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework AppKit -framework IOKit")
else()
find_library(COREFOUNDATION CoreFoundation)
+ find_library(APPKIT AppKit)
find_library(IOKIT IOKit)
+ list(APPEND EXTRA_LIBRARIES ${APPKIT})
list(APPEND EXTRA_LIBRARIES ${IOKIT})
list(APPEND EXTRA_LIBRARIES ${COREFOUNDATION})
endif()
diff --git a/contrib/epee/include/byte_stream.h b/contrib/epee/include/byte_stream.h
index 30abd050d..93f9ac85c 100644
--- a/contrib/epee/include/byte_stream.h
+++ b/contrib/epee/include/byte_stream.h
@@ -175,7 +175,7 @@ namespace epee
void put_n(const std::uint8_t ch, const std::size_t count)
{
check(count);
- std::memset(tellp(), count, ch);
+ std::memset(tellp(), ch, count);
next_write_ += count;
}
diff --git a/contrib/epee/include/rolling_median.h b/contrib/epee/include/rolling_median.h
index 088a71d3e..877814e57 100644
--- a/contrib/epee/include/rolling_median.h
+++ b/contrib/epee/include/rolling_median.h
@@ -141,7 +141,6 @@ public:
rolling_median_t(rolling_median_t &&m)
{
- free(data);
memcpy(this, &m, sizeof(rolling_median_t));
m.data = NULL;
}
diff --git a/contrib/gitian/README.md b/contrib/gitian/README.md
index 1938462aa..e2e1d0b94 100644
--- a/contrib/gitian/README.md
+++ b/contrib/gitian/README.md
@@ -188,6 +188,7 @@ gpg --detach-sign ${VERSION}-linux/${GH_USER}/monero-linux-*-build.assert
gpg --detach-sign ${VERSION}-win/${GH_USER}/monero-win-*-build.assert
gpg --detach-sign ${VERSION}-osx/${GH_USER}/monero-osx-*-build.assert
gpg --detach-sign ${VERSION}-android/${GH_USER}/monero-android-*-build.assert
+gpg --detach-sign ${VERSION}-freebsd/${GH_USER}/monero-freebsd-*-build.assert
```
This will create a `.sig` file for each `.assert` file above (2 files for each platform).
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index 8aa958825..4207bb2de 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -3001,7 +3001,7 @@ bool BlockchainLMDB::tx_exists(const crypto::hash& h) const
if (! tx_found)
{
- LOG_PRINT_L1("transaction with hash " << epee::string_tools::pod_to_hex(h) << " not found in db");
+ LOG_PRINT_L3("transaction with hash " << epee::string_tools::pod_to_hex(h) << " not found in db");
return false;
}
@@ -3032,7 +3032,7 @@ bool BlockchainLMDB::tx_exists(const crypto::hash& h, uint64_t& tx_id) const
bool ret = false;
if (get_result == MDB_NOTFOUND)
{
- LOG_PRINT_L1("transaction with hash " << epee::string_tools::pod_to_hex(h) << " not found in db");
+ LOG_PRINT_L3("transaction with hash " << epee::string_tools::pod_to_hex(h) << " not found in db");
}
else if (get_result)
throw0(DB_ERROR(lmdb_error("DB error attempting to fetch transaction from hash", get_result).c_str()));
diff --git a/src/cryptonote_basic/connection_context.h b/src/cryptonote_basic/connection_context.h
index 8d26e5638..dfc59631f 100644
--- a/src/cryptonote_basic/connection_context.h
+++ b/src/cryptonote_basic/connection_context.h
@@ -69,6 +69,7 @@ namespace cryptonote
bool m_anchor;
int32_t m_score;
int m_expect_response;
+ uint64_t m_expect_height;
};
inline std::string get_protocol_state_string(cryptonote_connection_context::state s)
diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h
index 21f2bf81e..97706f745 100644
--- a/src/cryptonote_config.h
+++ b/src/cryptonote_config.h
@@ -197,6 +197,8 @@
#define RPC_CREDITS_PER_HASH_SCALE ((float)(1<<24))
+#define DNS_BLOCKLIST_LIFETIME (86400 * 8)
+
// New constants are intended to go here
namespace config
{
diff --git a/src/cryptonote_protocol/cryptonote_protocol_defs.h b/src/cryptonote_protocol/cryptonote_protocol_defs.h
index 9687b07a6..8c511e824 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_defs.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_defs.h
@@ -298,6 +298,7 @@ namespace cryptonote
uint64_t cumulative_difficulty_top64;
std::vector<crypto::hash> m_block_ids;
std::vector<uint64_t> m_block_weights;
+ cryptonote::blobdata first_block;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(start_height)
@@ -309,6 +310,7 @@ namespace cryptonote
KV_SERIALIZE_OPT(cumulative_difficulty_top64, (uint64_t)0)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_block_ids)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_block_weights)
+ KV_SERIALIZE(first_block)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h
index 6368f8190..8f867eee6 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h
@@ -117,6 +117,8 @@ namespace cryptonote
std::string get_peers_overview() const;
std::pair<uint32_t, uint32_t> get_next_needed_pruning_stripe() const;
bool needs_new_sync_connections() const;
+ bool is_busy_syncing();
+
private:
//----------------- commands handlers ----------------------------------------------
int handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context);
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 27f8888bb..e2598e382 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -141,6 +141,7 @@ namespace cryptonote
{
NOTIFY_REQUEST_CHAIN::request r = {};
context.m_needed_objects.clear();
+ context.m_expect_height = m_core.get_current_blockchain_height();
m_core.get_short_chain_history(r.block_ids);
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
r.prune = m_sync_pruned_blocks;
@@ -493,6 +494,7 @@ namespace cryptonote
context.m_needed_objects.clear();
context.m_state = cryptonote_connection_context::state_synchronizing;
NOTIFY_REQUEST_CHAIN::request r = {};
+ context.m_expect_height = m_core.get_current_blockchain_height();
m_core.get_short_chain_history(r.block_ids);
r.prune = m_sync_pruned_blocks;
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
@@ -773,6 +775,7 @@ namespace cryptonote
context.m_needed_objects.clear();
context.m_state = cryptonote_connection_context::state_synchronizing;
NOTIFY_REQUEST_CHAIN::request r = {};
+ context.m_expect_height = m_core.get_current_blockchain_height();
m_core.get_short_chain_history(r.block_ids);
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
r.prune = m_sync_pruned_blocks;
@@ -1168,7 +1171,16 @@ namespace cryptonote
return 1;
}
if (start_height == std::numeric_limits<uint64_t>::max())
+ {
start_height = boost::get<txin_gen>(b.miner_tx.vin[0]).height;
+ if (start_height > context.m_expect_height)
+ {
+ LOG_ERROR_CCONTEXT("sent block ahead of expected height, dropping connection");
+ drop_connection(context, false, false);
+ ++m_sync_bad_spans_downloaded;
+ return 1;
+ }
+ }
auto req_it = context.m_requested_objects.find(block_hash);
if(req_it == context.m_requested_objects.end())
@@ -1714,6 +1726,7 @@ skip:
LOG_PRINT_CCONTEXT_L2("requesting callback");
context.m_last_request_time = boost::date_time::not_a_date_time;
context.m_expect_response = 0;
+ context.m_expect_height = 0;
context.m_state = cryptonote_connection_context::state_standby; // we'll go back to adding, then (if we can't), download
++context.m_callback_request_count;
m_p2p->request_callback(context);
@@ -1813,6 +1826,16 @@ skip:
LOG_ERROR_CCONTEXT("Failed to handle NOTIFY_REQUEST_CHAIN.");
return 1;
}
+ if (r.m_block_ids.size() >= 2)
+ {
+ cryptonote::block b;
+ if (!m_core.get_block_by_hash(r.m_block_ids[1], b))
+ {
+ LOG_ERROR_CCONTEXT("Failed to handle NOTIFY_REQUEST_CHAIN: first block not found");
+ return 1;
+ }
+ r.first_block = cryptonote::block_to_blob(b);
+ }
MLOG_P2P_MESSAGE("-->>NOTIFY_RESPONSE_CHAIN_ENTRY: m_start_height=" << r.start_height << ", m_total_height=" << r.total_height << ", m_block_ids.size()=" << r.m_block_ids.size());
post_notify<NOTIFY_RESPONSE_CHAIN_ENTRY>(r, context);
return 1;
@@ -2259,6 +2282,7 @@ skip:
}
}
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
+ context.m_expect_height = span.first;
context.m_expect_response = NOTIFY_RESPONSE_GET_OBJECTS::ID;
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_GET_OBJECTS: blocks.size()=" << req.blocks.size()
<< "requested blocks count=" << count << " / " << count_limit << " from " << span.first << ", first hash " << req.blocks.front());
@@ -2331,6 +2355,7 @@ skip:
{//we have to fetch more objects ids, request blockchain entry
NOTIFY_REQUEST_CHAIN::request r = {};
+ context.m_expect_height = m_core.get_current_blockchain_height();
m_core.get_short_chain_history(r.block_ids);
CHECK_AND_ASSERT_MES(!r.block_ids.empty(), false, "Short chain history is empty");
@@ -2338,7 +2363,10 @@ skip:
{
// we'll want to start off from where we are on that peer, which may not be added yet
if (context.m_last_known_hash != crypto::null_hash && r.block_ids.front() != context.m_last_known_hash)
+ {
+ context.m_expect_height = std::numeric_limits<uint64_t>::max();
r.block_ids.push_front(context.m_last_known_hash);
+ }
}
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
@@ -2480,6 +2508,12 @@ skip:
return 1;
}
context.m_expect_response = 0;
+ if (arg.start_height + 1 > context.m_expect_height) // we expect an overlapping block
+ {
+ LOG_ERROR_CCONTEXT("Got NOTIFY_RESPONSE_CHAIN_ENTRY past expected height, dropping connection");
+ drop_connection(context, true, false);
+ return 1;
+ }
context.m_last_request_time = boost::date_time::not_a_date_time;
@@ -2491,7 +2525,7 @@ skip:
drop_connection(context, true, false);
return 1;
}
- if (arg.total_height < arg.m_block_ids.size() || arg.start_height > arg.total_height - arg.m_block_ids.size() || arg.start_height >= m_core.get_current_blockchain_height())
+ if (arg.total_height < arg.m_block_ids.size() || arg.start_height > arg.total_height - arg.m_block_ids.size())
{
LOG_ERROR_CCONTEXT("sent invalid start/nblocks/height, dropping connection");
drop_connection(context, true, false);
@@ -2527,6 +2561,17 @@ skip:
return 1;
}
+ std::unordered_set<crypto::hash> hashes;
+ for (const auto &h: arg.m_block_ids)
+ {
+ if (!hashes.insert(h).second)
+ {
+ LOG_ERROR_CCONTEXT("sent duplicate block, dropping connection");
+ drop_connection(context, true, false);
+ return 1;
+ }
+ }
+
uint64_t n_use_blocks = m_core.prevalidate_block_hashes(arg.start_height, arg.m_block_ids, arg.m_block_weights);
if (n_use_blocks == 0 || n_use_blocks + HASH_OF_HASHES_STEP <= arg.m_block_ids.size())
{
@@ -2726,6 +2771,13 @@ skip:
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
+ bool t_cryptonote_protocol_handler<t_core>::is_busy_syncing()
+ {
+ const boost::unique_lock<boost::mutex> sync{m_sync_lock, boost::try_to_lock};
+ return !sync.owns_lock();
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
void t_cryptonote_protocol_handler<t_core>::drop_connection_with_score(cryptonote_connection_context &context, unsigned score, bool flush_all_spans)
{
LOG_DEBUG_CC(context, "dropping connection id " << context.m_connection_id << " (pruning seed " <<
diff --git a/src/cryptonote_protocol/levin_notify.cpp b/src/cryptonote_protocol/levin_notify.cpp
index 318bcf4e1..21363972d 100644
--- a/src/cryptonote_protocol/levin_notify.cpp
+++ b/src/cryptonote_protocol/levin_notify.cpp
@@ -287,7 +287,6 @@ namespace levin
connection_count(0),
flush_callbacks(0),
nzone(zone),
- is_public(is_public),
pad_txs(pad_txs),
fluffing(false)
{
@@ -305,7 +304,6 @@ namespace levin
std::atomic<std::size_t> connection_count; //!< Only update in strand, can be read at any time
std::uint32_t flush_callbacks; //!< Number of active fluff flush callbacks queued
const epee::net_utils::zone nzone; //!< Zone is public ipv4/ipv6 connections, or i2p or tor
- const bool is_public; //!< Zone is public ipv4/ipv6 connections
const bool pad_txs; //!< Pad txs to the next boundary for privacy
bool fluffing; //!< Zone is in Dandelion++ fluff epoch
};
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index aac891c4a..767ce7bc6 100644
--- a/src/daemon/command_parser_executor.cpp
+++ b/src/daemon/command_parser_executor.cpp
@@ -28,6 +28,7 @@
#include "common/dns_utils.h"
#include "common/command_line.h"
+#include "net/parse.h"
#include "daemon/command_parser_executor.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
@@ -657,7 +658,6 @@ bool t_command_parser_executor::ban(const std::vector<std::string>& args)
std::cout << "Invalid syntax: Expects one or two parameters. For more details, use the help command." << std::endl;
return true;
}
- std::string ip = args[0];
time_t seconds = P2P_IP_BLOCKTIME;
if (args.size() > 1)
{
@@ -676,7 +676,45 @@ bool t_command_parser_executor::ban(const std::vector<std::string>& args)
return true;
}
}
- return m_executor.ban(ip, seconds);
+ if (boost::starts_with(args[0], "@"))
+ {
+ const std::string ban_list = args[0].substr(1);
+
+ try
+ {
+ const boost::filesystem::path ban_list_path(ban_list);
+ boost::system::error_code ec;
+ if (!boost::filesystem::exists(ban_list_path, ec))
+ {
+ std::cout << "Can't find ban list file " + ban_list + " - " + ec.message() << std::endl;
+ return true;
+ }
+
+ bool ret = true;
+ std::ifstream ifs(ban_list_path.string());
+ for (std::string line; std::getline(ifs, line); )
+ {
+ const expect<epee::net_utils::network_address> parsed_addr = net::get_network_address(line, 0);
+ if (!parsed_addr)
+ {
+ std::cout << "Invalid IP address: " << line << " - " << parsed_addr.error() << std::endl;
+ continue;
+ }
+ ret &= m_executor.ban(parsed_addr->host_str(), seconds);
+ }
+ return ret;
+ }
+ catch (const std::exception &e)
+ {
+ std::cout << "Error loading ban list: " << e.what() << std::endl;
+ return false;
+ }
+ }
+ else
+ {
+ const std::string ip = args[0];
+ return m_executor.ban(ip, seconds);
+ }
}
bool t_command_parser_executor::unban(const std::vector<std::string>& args)
diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp
index dd5f76188..4768bb842 100644
--- a/src/daemon/command_server.cpp
+++ b/src/daemon/command_server.cpp
@@ -234,8 +234,8 @@ t_command_server::t_command_server(
m_command_lookup.set_handler(
"ban"
, std::bind(&t_command_parser_executor::ban, &m_parser, p::_1)
- , "ban <IP> [<seconds>]"
- , "Ban a given <IP> for a given amount of <seconds>."
+ , "ban [<IP>|@<filename>] [<seconds>]"
+ , "Ban a given <IP> or list of IPs from a file for a given amount of <seconds>."
);
m_command_lookup.set_handler(
"unban"
diff --git a/src/p2p/net_node.cpp b/src/p2p/net_node.cpp
index aee1fa593..8dd551d1e 100644
--- a/src/p2p/net_node.cpp
+++ b/src/p2p/net_node.cpp
@@ -149,6 +149,7 @@ namespace nodetool
const command_line::arg_descriptor<std::string> arg_ban_list = {"ban-list", "Specify ban list file, one IP address per line"};
const command_line::arg_descriptor<bool> arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true};
const command_line::arg_descriptor<bool> arg_no_sync = {"no-sync", "Don't synchronize the blockchain with other peers", false};
+ const command_line::arg_descriptor<bool> arg_enable_dns_blocklist = {"enable-dns-blocklist", "Apply realtime blocklist from DNS", false};
const command_line::arg_descriptor<bool> arg_no_igd = {"no-igd", "Disable UPnP port mapping"};
const command_line::arg_descriptor<std::string> arg_igd = {"igd", "UPnP port mapping (disabled, enabled, delayed)", "delayed"};
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index f13b36a82..9fba5d636 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -287,7 +287,7 @@ namespace nodetool
uint32_t get_max_out_public_peers() const;
void change_max_in_public_peers(size_t count);
uint32_t get_max_in_public_peers() const;
- virtual bool block_host(epee::net_utils::network_address address, time_t seconds = P2P_IP_BLOCKTIME);
+ virtual bool block_host(epee::net_utils::network_address address, time_t seconds = P2P_IP_BLOCKTIME, bool add_only = false);
virtual bool unblock_host(const epee::net_utils::network_address &address);
virtual bool block_subnet(const epee::net_utils::ipv4_network_subnet &subnet, time_t seconds = P2P_IP_BLOCKTIME);
virtual bool unblock_subnet(const epee::net_utils::ipv4_network_subnet &subnet);
@@ -369,6 +369,7 @@ namespace nodetool
bool peer_sync_idle_maker();
bool do_handshake_with_peer(peerid_type& pi, p2p_connection_context& context, bool just_take_peerlist = false);
bool do_peer_timed_sync(const epee::net_utils::connection_context_base& context, peerid_type peer_id);
+ bool update_dns_blocklist();
bool make_new_connection_from_anchor_peerlist(const std::vector<anchor_peerlist_entry>& anchor_peerlist);
bool make_new_connection_from_peerlist(network_zone& zone, bool use_white_list);
@@ -474,6 +475,7 @@ namespace nodetool
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;
epee::math_helper::once_a_time_seconds<3600, false> m_incoming_connections_interval;
+ epee::math_helper::once_a_time_seconds<7000> m_dns_blocklist_interval;
std::list<epee::net_utils::network_address> m_priority_peers;
std::vector<epee::net_utils::network_address> m_exclusive_peers;
@@ -512,6 +514,8 @@ namespace nodetool
cryptonote::network_type m_nettype;
epee::net_utils::ssl_support_t m_ssl_support;
+
+ bool m_enable_dns_blocklist;
};
const int64_t default_limit_up = P2P_DEFAULT_LIMIT_RATE_UP; // kB/s
@@ -533,6 +537,7 @@ namespace nodetool
extern const command_line::arg_descriptor<std::string> arg_ban_list;
extern const command_line::arg_descriptor<bool> arg_p2p_hide_my_port;
extern const command_line::arg_descriptor<bool> arg_no_sync;
+ extern const command_line::arg_descriptor<bool> arg_enable_dns_blocklist;
extern const command_line::arg_descriptor<bool> arg_no_igd;
extern const command_line::arg_descriptor<std::string> arg_igd;
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index e32e7c31c..6016b243f 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -37,6 +37,7 @@
#include <boost/optional/optional.hpp>
#include <boost/thread/thread.hpp>
#include <boost/uuid/uuid_io.hpp>
+#include <boost/algorithm/string.hpp>
#include <atomic>
#include <functional>
#include <limits>
@@ -120,6 +121,7 @@ namespace nodetool
command_line::add_arg(desc, arg_ban_list);
command_line::add_arg(desc, arg_p2p_hide_my_port);
command_line::add_arg(desc, arg_no_sync);
+ command_line::add_arg(desc, arg_enable_dns_blocklist);
command_line::add_arg(desc, arg_no_igd);
command_line::add_arg(desc, arg_igd);
command_line::add_arg(desc, arg_out_peers);
@@ -226,7 +228,7 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::block_host(epee::net_utils::network_address addr, time_t seconds)
+ bool node_server<t_payload_net_handler>::block_host(epee::net_utils::network_address addr, time_t seconds, bool add_only)
{
if(!addr.is_blockable())
return false;
@@ -240,7 +242,11 @@ namespace nodetool
else
limit = now + seconds;
const std::string host_str = addr.host_str();
- m_blocked_hosts[host_str] = limit;
+ auto it = m_blocked_hosts.find(host_str);
+ if (it == m_blocked_hosts.end())
+ m_blocked_hosts[host_str] = limit;
+ else if (it->second < limit || !add_only)
+ it->second = limit;
// drop any connection to that address. This should only have to look into
// the zone related to the connection, but really make sure everything is
@@ -499,6 +505,8 @@ namespace nodetool
if (command_line::has_arg(vm, arg_no_sync))
m_payload_handler.set_no_sync(true);
+ m_enable_dns_blocklist = command_line::get_arg(vm, arg_enable_dns_blocklist);
+
if ( !set_max_out_peers(public_zone, command_line::get_arg(vm, arg_out_peers) ) )
return false;
else
@@ -806,6 +814,7 @@ namespace nodetool
"zbjkbsxc5munw3qusl7j2hpcmikhqocdf4pqhnhtpzw5nt5jrmofptid.onion:18083",
};
}
+ return {};
case epee::net_utils::zone::i2p:
if (m_nettype == cryptonote::MAINNET)
{
@@ -813,7 +822,8 @@ namespace nodetool
"s3l6ke4ed3df466khuebb4poienoingwof7oxtbo6j4n56sghe3a.b32.i2p:18080",
"sel36x6fibfzujwvt4hf5gxolz6kd3jpvbjqg6o3ud2xtionyl2q.b32.i2p:18080"
};
- }
+ }
+ return {};
default:
break;
}
@@ -1965,6 +1975,52 @@ namespace nodetool
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));
m_incoming_connections_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::check_incoming_connections, this));
+ m_dns_blocklist_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::update_dns_blocklist, this));
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::update_dns_blocklist()
+ {
+ if (!m_enable_dns_blocklist)
+ return true;
+ if (m_nettype != cryptonote::MAINNET)
+ return true;
+
+ static const std::vector<std::string> dns_urls = {
+ "blocklist.moneropulse.se"
+ , "blocklist.moneropulse.org"
+ , "blocklist.moneropulse.net"
+ , "blocklist.moneropulse.no"
+ , "blocklist.moneropulse.fr"
+ , "blocklist.moneropulse.de"
+ , "blocklist.moneropulse.ch"
+ };
+
+ std::vector<std::string> records;
+ if (!tools::dns_utils::load_txt_records_from_dns(records, dns_urls))
+ return true;
+
+ unsigned good = 0, bad = 0;
+ for (const auto& record : records)
+ {
+ std::vector<std::string> ips;
+ boost::split(ips, record, boost::is_any_of(";"));
+ for (const auto &ip: ips)
+ {
+ const expect<epee::net_utils::network_address> parsed_addr = net::get_network_address(ip, 0);
+ if (!parsed_addr)
+ {
+ MWARNING("Invalid IP address from DNS blocklist: " << ip << " - " << parsed_addr.error());
+ ++bad;
+ continue;
+ }
+ block_host(*parsed_addr, DNS_BLOCKLIST_LIFETIME, true);
+ ++good;
+ }
+ }
+ if (good > 0)
+ MINFO(good << " addresses added to the blocklist");
return true;
}
//-----------------------------------------------------------------------------------
@@ -2087,7 +2143,9 @@ namespace nodetool
LOG_DEBUG_CC(context, "REMOTE PEERLIST: remote peerlist size=" << peerlist_.size());
LOG_TRACE_CC(context, "REMOTE PEERLIST: " << ENDL << print_peerlist_to_string(peerlist_));
- return m_network_zones.at(context.m_remote_address.get_zone()).m_peerlist.merge_peerlist(peerlist_, [this](const peerlist_entry &pe) { return !is_addr_recently_failed(pe.adr); });
+ return m_network_zones.at(context.m_remote_address.get_zone()).m_peerlist.merge_peerlist(peerlist_, [this](const peerlist_entry &pe) {
+ return !is_addr_recently_failed(pe.adr) && is_remote_host_allowed(pe.adr);
+ });
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
@@ -2832,8 +2890,8 @@ namespace nodetool
const uint32_t index = stripe - 1;
CRITICAL_REGION_LOCAL(m_used_stripe_peers_mutex);
MINFO("adding stripe " << stripe << " peer: " << context.m_remote_address.str());
- std::remove_if(m_used_stripe_peers[index].begin(), m_used_stripe_peers[index].end(),
- [&context](const epee::net_utils::network_address &na){ return context.m_remote_address == na; });
+ m_used_stripe_peers[index].erase(std::remove_if(m_used_stripe_peers[index].begin(), m_used_stripe_peers[index].end(),
+ [&context](const epee::net_utils::network_address &na){ return context.m_remote_address == na; }), m_used_stripe_peers[index].end());
m_used_stripe_peers[index].push_back(context.m_remote_address);
}
@@ -2846,8 +2904,8 @@ namespace nodetool
const uint32_t index = stripe - 1;
CRITICAL_REGION_LOCAL(m_used_stripe_peers_mutex);
MINFO("removing stripe " << stripe << " peer: " << context.m_remote_address.str());
- std::remove_if(m_used_stripe_peers[index].begin(), m_used_stripe_peers[index].end(),
- [&context](const epee::net_utils::network_address &na){ return context.m_remote_address == na; });
+ m_used_stripe_peers[index].erase(std::remove_if(m_used_stripe_peers[index].begin(), m_used_stripe_peers[index].end(),
+ [&context](const epee::net_utils::network_address &na){ return context.m_remote_address == na; }), m_used_stripe_peers[index].end());
}
template<class t_payload_net_handler>
diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h
index f1490a0db..0da758ad4 100644
--- a/src/p2p/net_node_common.h
+++ b/src/p2p/net_node_common.h
@@ -58,7 +58,7 @@ namespace nodetool
virtual uint64_t get_public_connections_count()=0;
virtual void for_each_connection(std::function<bool(t_connection_context&, peerid_type, uint32_t)> f)=0;
virtual bool for_connection(const boost::uuids::uuid&, std::function<bool(t_connection_context&, peerid_type, uint32_t)> f)=0;
- virtual bool block_host(epee::net_utils::network_address address, time_t seconds = 0)=0;
+ virtual bool block_host(epee::net_utils::network_address address, time_t seconds = 0, bool add_only = false)=0;
virtual bool unblock_host(const epee::net_utils::network_address &address)=0;
virtual std::map<std::string, time_t> get_blocked_hosts()=0;
virtual std::map<epee::net_utils::ipv4_network_subnet, time_t> get_blocked_subnets()=0;
@@ -108,7 +108,7 @@ namespace nodetool
{
return false;
}
- virtual bool block_host(epee::net_utils::network_address address, time_t seconds)
+ virtual bool block_host(epee::net_utils::network_address address, time_t seconds, bool add_only)
{
return true;
}
diff --git a/src/ringct/bulletproofs.cc b/src/ringct/bulletproofs.cc
index 359dfa879..a6e12c9b3 100644
--- a/src/ringct/bulletproofs.cc
+++ b/src/ringct/bulletproofs.cc
@@ -826,7 +826,7 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
proof_data.reserve(proofs.size());
size_t inv_offset = 0;
std::vector<rct::key> to_invert;
- to_invert.reserve(11 * sizeof(proofs));
+ to_invert.reserve(11 * proofs.size());
size_t max_logM = 0;
for (const Bulletproof *p: proofs)
{
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 144ffe888..01735d62e 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -499,6 +499,7 @@ namespace cryptonote
res.update_available = restricted ? false : m_core.is_update_available();
res.version = restricted ? "" : MONERO_VERSION_FULL;
res.synchronized = check_core_ready();
+ res.busy_syncing = m_p2p.get_payload_object().is_busy_syncing();
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 10f7aac7a..bb9005a5f 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -88,7 +88,7 @@ namespace cryptonote
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define CORE_RPC_VERSION_MAJOR 3
-#define CORE_RPC_VERSION_MINOR 3
+#define CORE_RPC_VERSION_MINOR 4
#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
@@ -684,6 +684,7 @@ namespace cryptonote
bool was_bootstrap_ever_used;
uint64_t database_size;
bool update_available;
+ bool busy_syncing;
std::string version;
bool synchronized;
@@ -724,6 +725,7 @@ namespace cryptonote
KV_SERIALIZE(was_bootstrap_ever_used)
KV_SERIALIZE(database_size)
KV_SERIALIZE(update_available)
+ KV_SERIALIZE(busy_syncing)
KV_SERIALIZE(version)
KV_SERIALIZE(synchronized)
END_KV_SERIALIZE_MAP()
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index a90bd3a39..2260b9c9a 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -143,6 +143,7 @@ typedef cryptonote::simple_wallet sw;
#define CREDITS_TARGET 50000
#define MAX_PAYMENT_DIFF 10000
#define MIN_PAYMENT_RATE 0.01f // per hash
+#define MAX_MNEW_ADDRESSES 1000
enum TransferType {
Transfer,
@@ -203,7 +204,7 @@ namespace
" account tag <tag_name> <account_index_1> [<account_index_2> ...]\n"
" account untag <account_index_1> [<account_index_2> ...]\n"
" account tag_description <tag_name> <description>");
- const char* USAGE_ADDRESS("address [ new <label text with white spaces allowed> | all | <index_min> [<index_max>] | label <index> <label text with white spaces allowed> | device [<index>] | one-off <account> <subaddress>]");
+ const char* USAGE_ADDRESS("address [ new <label text with white spaces allowed> | mnew <amount of new addresses> | all | <index_min> [<index_max>] | label <index> <label text with white spaces allowed> | device [<index>] | one-off <account> <subaddress>]");
const char* USAGE_INTEGRATED_ADDRESS("integrated_address [device] [<payment_id> | <address>]");
const char* USAGE_ADDRESS_BOOK("address_book [(add (<address>|<integrated address>) [<description possibly with whitespaces>])|(delete <index>)]");
const char* USAGE_SET_VARIABLE("set <option> [<value>]");
@@ -3320,7 +3321,7 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("address",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::print_address, _1),
tr(USAGE_ADDRESS),
- tr("If no arguments are specified or <index> is specified, the wallet shows the default or specified address. If \"all\" is specified, the wallet shows all the existing addresses in the currently selected account. If \"new \" is specified, the wallet creates a new address with the provided label text (which can be empty). If \"label\" is specified, the wallet sets the label of the address specified by <index> to the provided label text. If \"one-off\" is specified, the address for the specified index is generated and displayed, and remembered by the wallet"));
+ tr("If no arguments are specified or <index> is specified, the wallet shows the default or specified address. If \"all\" is specified, the wallet shows all the existing addresses in the currently selected account. If \"new \" is specified, the wallet creates a new address with the provided label text (which can be empty). If \"mnew\" is specified, the wallet creates as many new addresses as specified by the argument; the default label is set for the new addresses. If \"label\" is specified, the wallet sets the label of the address specified by <index> to the provided label text. If \"one-off\" is specified, the address for the specified index is generated and displayed, and remembered by the wallet"));
m_cmd_binder.set_handler("integrated_address",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::print_integrated_address, _1),
tr(USAGE_INTEGRATED_ADDRESS),
@@ -9528,6 +9529,31 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
print_address_sub(m_wallet->get_num_subaddresses(m_current_subaddress_account) - 1);
m_wallet->device_show_address(m_current_subaddress_account, m_wallet->get_num_subaddresses(m_current_subaddress_account) - 1, boost::none);
}
+ else if (local_args[0] == "mnew")
+ {
+ local_args.erase(local_args.begin());
+ if (local_args.size() != 1)
+ {
+ fail_msg_writer() << tr("Expected exactly one argument for the amount of new addresses");
+ return true;
+ }
+ uint32_t n;
+ if (!epee::string_tools::get_xtype_from_string(n, local_args[0]))
+ {
+ fail_msg_writer() << tr("failed to parse the amount of new addresses: ") << local_args[0];
+ return true;
+ }
+ if (n > MAX_MNEW_ADDRESSES)
+ {
+ fail_msg_writer() << tr("the amount of new addresses must be lower or equal to ") << MAX_MNEW_ADDRESSES;
+ return true;
+ }
+ for (uint32_t i = 0; i < n; ++i)
+ {
+ m_wallet->add_subaddress(m_current_subaddress_account, tr("(Untitled address)"));
+ print_address_sub(m_wallet->get_num_subaddresses(m_current_subaddress_account) - 1);
+ }
+ }
else if (local_args[0] == "one-off")
{
local_args.erase(local_args.begin());
diff --git a/tests/unit_tests/epee_utils.cpp b/tests/unit_tests/epee_utils.cpp
index 207c4a7dc..256f8c3c2 100644
--- a/tests/unit_tests/epee_utils.cpp
+++ b/tests/unit_tests/epee_utils.cpp
@@ -982,6 +982,23 @@ TEST(ByteStream, Put)
EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()}));
}
+TEST(ByteStream, PutN)
+{
+ using boost::range::equal;
+ using byte_span = epee::span<const std::uint8_t>;
+
+ std::vector<std::uint8_t> bytes;
+ bytes.resize(1000, 'f');
+
+ epee::byte_stream stream;
+ stream.put_n('f', 1000);
+
+ EXPECT_EQ(1000u, stream.size());
+ EXPECT_LE(1000u, stream.capacity());
+ EXPECT_EQ(stream.available(), stream.capacity() - stream.size());
+ EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()}));
+}
+
TEST(ByteStream, Reserve)
{
using boost::range::equal;