Compare commits

...

40 Commits

Author SHA1 Message Date
luigi1111
f690e4984d Merge pull request #6997
752837b build: prepare v0.17.1.3 (selsta)
2020-11-07 13:10:15 -06:00
luigi1111
ebc9197326 Merge pull request #6996
981e0b5 epee: readline_buffer - fix thread safety, fix sync() after stop() (xiphon)
2020-11-07 13:09:18 -06:00
luigi1111
81f9fa947b Merge pull request #6994
6f48a14 Fix i2p/tor seed nodes (vtnerd)
2020-11-07 13:08:00 -06:00
selsta
752837b2c8 build: prepare v0.17.1.3 2020-11-07 18:19:08 +01:00
xiphon
981e0b5cc3 epee: readline_buffer - fix thread safety, fix sync() after stop() 2020-11-07 15:32:02 +00:00
Lee Clagett
6f48a146f8 Fix i2p/tor seed nodes 2020-11-07 00:37:49 -05:00
luigi1111
1a3bef15b9 Merge pull request #6993
44c93bb p2p: fix accessing non existent element of map (moneromooo-monero)
2020-11-06 18:53:22 -06:00
moneromooo-monero
44c93bb47a p2p: fix accessing non existent element of map 2020-11-07 00:17:47 +00:00
luigi1111
c3fc96f0cf Merge pull request #6992
f3dd25c build: prepare v0.17.1.2 (selsta)
2020-11-06 17:34:32 -06:00
luigi1111
07f6ecd227 Merge pull request #6991
4985afd p2p: add a tor seed (moneromooo-monero)
2020-11-06 17:32:28 -06:00
moneromooo-monero
4985afddb3 p2p: add a tor seed 2020-11-06 23:21:10 +00:00
luigi1111
4191dc8981 Merge pull request #6990
263579b Add support for i2p and tor seed nodes (vtnerd)
2020-11-06 17:15:11 -06:00
luigi1111
32581fb223 Merge pull request #6985
91f1be9 net_node: add tor / i2p seed nodes (selsta)
2020-11-06 17:12:42 -06:00
selsta
f3dd25c0e0 build: prepare v0.17.1.2 2020-11-07 00:12:39 +01:00
luigi1111
33dc825d6f Merge pull request #6983
35186b1 p2p: fix endianness when checking IPv6 addresses mapping to IPv4 (moneromooo-monero)
2020-11-05 19:09:43 -06:00
selsta
91f1be9ea2 net_node: add tor / i2p seed nodes 2020-11-05 21:41:11 +01:00
moneromooo-monero
35186b1b84 p2p: fix endianness when checking IPv6 addresses mapping to IPv4 2020-11-05 16:05:54 +00:00
luigi1111
bddd5653e1 Merge pull request #6981
b36c4f3 p2p: make this work with boost <= 1.65 (pffff) (moneromooo-monero)
2020-11-04 20:57:49 -06:00
moneromooo-monero
b36c4f354b p2p: make this work with boost <= 1.65 (pffff) 2020-11-04 23:01:47 +00:00
luigi1111
1ba4c8dbc2 Merge pull request #6979
92d19c4 p2p: rewrite boost's make_address_v4 to cater for < 1.66 (moneromooo-monero)
2020-11-04 16:28:43 -06:00
moneromooo
92d19c48da p2p: rewrite boost's make_address_v4 to cater for < 1.66 2020-11-04 20:26:50 +00:00
luigi1111
01606ee52e Merge pull request #6974
58cde83 Switch to Dandelion++ fluff mode if no out connections for stem mode (vtnerd)
2020-11-04 10:40:49 -06:00
luigi1111
81d2389c24 Merge pull request #6972
8965489 protocol: reject empty incoming block messages (moneromooo-monero)
2020-11-04 10:39:53 -06:00
luigi1111
ef64c4e22f Merge pull request #6967
fa63d4b Fix tx flush callback queueing (vtnerd)
2020-11-04 10:38:08 -06:00
luigi1111
7fa01f342c Merge pull request #6966
42403c7 Fix CLI and unrestricted RPC relay_tx with stempool (vtnerd)
2020-11-04 10:37:18 -06:00
luigi1111
4603ec9765 Merge pull request #6962
1a627e1 p2p: use /16 filtering on IPv4-within-IPv6 addresses (moneromooo-monero)
2020-11-04 10:36:23 -06:00
luigi1111
0be71bcea9 Merge pull request #6961
f55f3fe net_node: add --ban-list option (selsta)
2020-11-04 10:35:07 -06:00
moneromooo-monero
1a627e1f89 p2p: use /16 filtering on IPv4-within-IPv6 addresses
IPv6 addresses include a range that can map IPv4 addresses,
which allowed those mapped addresses to bypass filtering.

This filter should be replaced by AS filtering at some point.
2020-11-03 17:36:25 +00:00
luigi1111
c1229a4432 Merge pull request #6965
d695340 rpc: on_send_raw_tx (bootstrap) - send to bootstrap daemon and P2P (xiphon)
2020-11-03 11:23:17 -06:00
luigi1111
9f68111b69 Merge pull request #6964
5090cdc p2p: remove banned peers from the white list (moneromooo-monero)
2020-11-03 11:22:27 -06:00
luigi1111
d1e79f2086 Merge pull request #6963
df1061c p2p: give all hosts the same chance of being picked for connecting (moneromooo-monero)
2020-11-03 11:21:26 -06:00
moneromooo-monero
8965489acb protocol: reject empty incoming block messages 2020-11-03 13:08:19 +00:00
xiphon
d6953406c9 rpc: on_send_raw_tx (bootstrap) - send to bootstrap daemon and P2P 2020-11-02 19:47:54 +00:00
moneromooo
5090cdc9f5 p2p: remove banned peers from the white list 2020-11-02 19:03:12 +00:00
moneromooo
df1061c87d p2p: give all hosts the same chance of being picked for connecting
even if some run more than one node
2020-11-02 19:01:43 +00:00
selsta
f55f3fe81c net_node: add --ban-list option 2020-11-02 17:26:02 +01:00
Lee Clagett
42403c7acc Fix CLI and unrestricted RPC relay_tx with stempool 2020-10-14 13:02:27 +00:00
Lee Clagett
fa63d4b3f0 Fix tx flush callback queueing 2020-10-14 13:01:34 +00:00
Lee Clagett
263579b217 Add support for i2p and tor seed nodes 2020-10-09 14:07:40 +00:00
Lee Clagett
58cde83fb0 Switch to Dandelion++ fluff mode if no out connections for stem mode 2020-10-06 13:52:01 +00:00
14 changed files with 369 additions and 101 deletions

View File

@@ -134,8 +134,8 @@ Dates are provided in the format YYYY-MM-DD.
| 1788000 | 2019-03-09 | v10 | v0.14.0.0 | v0.14.1.2 | New PoW based on Cryptonight-R, new block weight algorithm, slightly more efficient RingCT format
| 1788720 | 2019-03-10 | v11 | v0.14.0.0 | v0.14.1.2 | forbid old RingCT transaction format
| 1978433 | 2019-11-30* | v12 | v0.15.0.0 | v0.16.0.0 | New PoW based on RandomX, only allow >= 2 outputs, change to the block median used to calculate penalty, v1 coinbases are forbidden, rct sigs in coinbase forbidden, 10 block lock time for incoming outputs
| 2210000 | 2020-10-17 | v13 | v0.17.0.0 | v0.17.1.1 | New CLSAG transaction format
| 2210720 | 2020-10-18 | v14 | v0.17.1.1 | v0.17.1.1 | forbid old MLSAG transaction format
| 2210000 | 2020-10-17 | v13 | v0.17.0.0 | v0.17.1.3 | New CLSAG transaction format
| 2210720 | 2020-10-18 | v14 | v0.17.1.1 | v0.17.1.3 | forbid old MLSAG transaction format
| XXXXXXX | XXX-XX-XX | XXX | vX.XX.X.X | vX.XX.X.X | XXX |
X's indicate that these details have not been determined as of commit date.
@@ -295,7 +295,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (
```bash
git clone https://github.com/monero-project/monero.git
cd monero
git checkout tags/v0.17.1.1
git checkout tags/v0.17.1.3
```
* Build:
@@ -412,10 +412,10 @@ application.
cd monero
```
* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.17.1.1'. If you don't care about the version and just want binaries from master, skip this step:
* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.17.1.3'. If you don't care about the version and just want binaries from master, skip this step:
```bash
git checkout v0.17.1.1
git checkout v0.17.1.3
```
* If you are on a 64-bit system, run:

View File

@@ -51,6 +51,7 @@ rdln::readline_buffer::readline_buffer()
void rdln::readline_buffer::start()
{
boost::lock_guard<boost::mutex> lock(sync_mutex);
if(m_cout_buf != NULL)
return;
m_cout_buf = std::cout.rdbuf();
@@ -60,6 +61,7 @@ void rdln::readline_buffer::start()
void rdln::readline_buffer::stop()
{
boost::lock_guard<boost::mutex> lock(sync_mutex);
if(m_cout_buf == NULL)
return;
std::cout.rdbuf(m_cout_buf);
@@ -88,9 +90,9 @@ rdln::linestatus rdln::readline_buffer::get_line(std::string& line) const
void rdln::readline_buffer::set_prompt(const std::string& prompt)
{
boost::lock_guard<boost::mutex> lock(sync_mutex);
if(m_cout_buf == NULL)
return;
boost::lock_guard<boost::mutex> lock(sync_mutex);
rl_set_prompt(std::string(m_prompt_length, ' ').c_str());
rl_redisplay();
rl_set_prompt(prompt.c_str());
@@ -113,6 +115,12 @@ const std::vector<std::string>& rdln::readline_buffer::get_completions()
int rdln::readline_buffer::sync()
{
boost::lock_guard<boost::mutex> lock(sync_mutex);
if (m_cout_buf == nullptr)
{
return -1;
}
#if RL_READLINE_VERSION < 0x0700
char lbuf[2] = {0,0};
char *line = NULL;

View File

@@ -126,7 +126,7 @@ Setup for LXC:
```bash
GH_USER=fluffypony
VERSION=v0.17.1.1
VERSION=v0.17.1.3
./gitian-build.py --setup $GH_USER $VERSION
```
@@ -182,7 +182,7 @@ If you chose to do detached signing using `--detach-sign` above (recommended), y
```bash
GH_USER=fluffypony
VERSION=v0.17.1.1
VERSION=v0.17.1.3
gpg --detach-sign ${VERSION}-linux/${GH_USER}/monero-linux-*-build.assert
gpg --detach-sign ${VERSION}-win/${GH_USER}/monero-win-*-build.assert

Binary file not shown.

View File

@@ -240,6 +240,7 @@ namespace cryptonote
ADD_CHECKPOINT2(2193000, "6e91b917a40309f89f75f2c8d7be5a6d1a3c425634f07f7d1867bd32d2e602ed", "0xf085140f17389d");
ADD_CHECKPOINT2(2206500, "dd3c8590f33eaa546a4ce69d02f27fd58a2f115cd32d733bd9426f8278f0cb8a", "0xf8725275799f0d");
ADD_CHECKPOINT2(2210500, "ed17259215ac6aabe6e8252b5b5eff613d2e69cc2111173e567109aa78301911", "0xfbcb50a9a6a433");
ADD_CHECKPOINT2(2224000, "e34bc71301600df96d08aaa6b0bde932cba1b06a3dd57076e3f664a078810a80", "0x1052fc256fceb6f");
return true;
}

View File

@@ -5376,7 +5376,7 @@ void Blockchain::cancel()
}
#if defined(PER_BLOCK_CHECKPOINT)
static const char expected_block_hashes_hash[] = "be42dfed51f6b9da134d7dcfd5f4b7e1df8cae93f1b41b846a5818f0aaf09fda";
static const char expected_block_hashes_hash[] = "1d166275537bfbb5841d98da298c65089f3006d751776b2dc8a4f0275ef0ce58";
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
{
if (get_checkpoints == nullptr || !m_fast_sync)

View File

@@ -1091,6 +1091,13 @@ namespace cryptonote
//epee::net_utils::network_throttle_manager::get_global_throttle_inreq().logger_handle_net("log/dr-monero/net/req-all.data", sec, get_avg_block_size());
if(arg.blocks.empty())
{
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_HAVE_OBJECTS: no blocks");
drop_connection(context, true, false);
++m_sync_bad_spans_downloaded;
return 1;
}
if(context.m_last_response_height > arg.current_blockchain_height)
{
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_HAVE_OBJECTS: arg.m_current_blockchain_height=" << arg.current_blockchain_height

View File

@@ -241,8 +241,8 @@ namespace levin
strand(io_service),
map(),
channels(),
flush_time(std::chrono::steady_clock::time_point::max()),
connection_count(0),
flush_callbacks(0),
is_public(is_public),
pad_txs(pad_txs),
fluffing(false)
@@ -258,8 +258,8 @@ namespace levin
boost::asio::io_service::strand strand;
net::dandelionpp::connection_map map;//!< Tracks outgoing uuid's for noise channels or Dandelion++ stems
std::deque<noise_channel> channels; //!< Never touch after init; only update elements on `noise_channel.strand`
std::chrono::steady_clock::time_point flush_time; //!< Next expected Dandelion++ fluff flush
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 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
@@ -305,7 +305,6 @@ namespace levin
struct fluff_flush
{
std::shared_ptr<detail::zone> zone_;
std::chrono::steady_clock::time_point flush_time_;
static void queue(std::shared_ptr<detail::zone> zone, const std::chrono::steady_clock::time_point flush_time)
{
@@ -313,28 +312,21 @@ namespace levin
assert(zone->strand.running_in_this_thread());
detail::zone& this_zone = *zone;
this_zone.flush_time = flush_time;
++this_zone.flush_callbacks;
this_zone.flush_txs.expires_at(flush_time);
this_zone.flush_txs.async_wait(this_zone.strand.wrap(fluff_flush{std::move(zone), flush_time}));
this_zone.flush_txs.async_wait(this_zone.strand.wrap(fluff_flush{std::move(zone)}));
}
void operator()(const boost::system::error_code error)
{
if (!zone_ || !zone_->p2p)
if (!zone_ || !zone_->flush_callbacks || --zone_->flush_callbacks || !zone_->p2p)
return;
assert(zone_->strand.running_in_this_thread());
const bool timer_error = bool(error);
if (timer_error)
{
if (error != boost::system::errc::operation_canceled)
throw boost::system::system_error{error, "fluff_flush timer failed"};
// new timer canceled this one set in future
if (zone_->flush_time < flush_time_)
return;
}
if (timer_error && error != boost::system::errc::operation_canceled)
throw boost::system::system_error{error, "fluff_flush timer failed"};
const auto now = std::chrono::steady_clock::now();
auto next_flush = std::chrono::steady_clock::time_point::max();
@@ -370,8 +362,6 @@ namespace levin
if (next_flush != std::chrono::steady_clock::time_point::max())
fluff_flush::queue(std::move(zone_), next_flush);
else
zone_->flush_time = next_flush; // signal that no timer is set
}
};
@@ -406,13 +396,11 @@ namespace levin
MDEBUG("Queueing " << txs.size() << " transaction(s) for Dandelion++ fluffing");
bool available = false;
zone->p2p->foreach_connection([txs, now, &zone, &source, &in_duration, &out_duration, &next_flush, &available] (detail::p2p_context& context)
zone->p2p->foreach_connection([txs, now, &zone, &source, &in_duration, &out_duration, &next_flush] (detail::p2p_context& context)
{
// When i2p/tor, only fluff to outbound connections
if (source != context.m_connection_id && (zone->is_public || !context.m_is_income))
{
available = true;
if (context.fluff_txs.empty())
context.flush_time = now + (context.m_is_income ? in_duration() : out_duration());
@@ -424,10 +412,9 @@ namespace levin
return true;
});
if (!available)
if (next_flush == std::chrono::steady_clock::time_point::max())
MWARNING("Unable to send transaction(s), no available connections");
if (next_flush < zone->flush_time)
else if (!zone->flush_callbacks || next_flush < zone->flush_txs.expires_at())
fluff_flush::queue(std::move(zone), next_flush);
}
};
@@ -524,12 +511,7 @@ namespace levin
if (!zone_ || !core_ || txs_.empty())
return;
if (zone_->fluffing)
{
core_->on_transactions_relayed(epee::to_span(txs_), relay_method::fluff);
fluff_notify::run(std::move(zone_), epee::to_span(txs_), source_);
}
else // forward tx in stem
if (!zone_->fluffing)
{
core_->on_transactions_relayed(epee::to_span(txs_), relay_method::stem);
for (int tries = 2; 0 < tries; tries--)
@@ -549,6 +531,9 @@ namespace levin
MERROR("Unable to send transaction(s) via Dandelion++ stem");
}
core_->on_transactions_relayed(epee::to_span(txs_), relay_method::fluff);
fluff_notify::run(std::move(zone_), epee::to_span(txs_), source_);
}
};

View File

@@ -146,6 +146,7 @@ namespace nodetool
const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_seed_node = {"seed-node", "Connect to a node to retrieve peer addresses, and disconnect"};
const command_line::arg_descriptor<std::vector<std::string> > arg_tx_proxy = {"tx-proxy", "Send local txes through proxy: <network-type>,<socks-ip:port>[,max_connections][,disable_noise] i.e. \"tor,127.0.0.1:9050,100,disable_noise\""};
const command_line::arg_descriptor<std::vector<std::string> > arg_anonymous_inbound = {"anonymous-inbound", "<hidden-service-address>,<[bind-ip:]port>[,max_connections] i.e. \"x.onion,127.0.0.1:18083,100\""};
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};

View File

@@ -164,6 +164,7 @@ namespace nodetool
network_zone()
: m_connect(nullptr),
m_net_server(epee::net_utils::e_connection_type_P2P),
m_seed_nodes(),
m_bind_ip(),
m_bind_ipv6_address(),
m_port(),
@@ -175,7 +176,9 @@ namespace nodetool
m_proxy_address(),
m_current_number_of_out_peers(0),
m_current_number_of_in_peers(0),
m_can_pingback(false)
m_seed_nodes_lock(),
m_can_pingback(false),
m_seed_nodes_initialized(false)
{
set_config_defaults();
}
@@ -183,6 +186,7 @@ namespace nodetool
network_zone(boost::asio::io_service& public_service)
: m_connect(nullptr),
m_net_server(public_service, epee::net_utils::e_connection_type_P2P),
m_seed_nodes(),
m_bind_ip(),
m_bind_ipv6_address(),
m_port(),
@@ -194,13 +198,16 @@ namespace nodetool
m_proxy_address(),
m_current_number_of_out_peers(0),
m_current_number_of_in_peers(0),
m_can_pingback(false)
m_seed_nodes_lock(),
m_can_pingback(false),
m_seed_nodes_initialized(false)
{
set_config_defaults();
}
connect_func* m_connect;
net_server m_net_server;
std::vector<epee::net_utils::network_address> m_seed_nodes;
std::string m_bind_ip;
std::string m_bind_ipv6_address;
std::string m_port;
@@ -212,7 +219,9 @@ namespace nodetool
boost::asio::ip::tcp::endpoint m_proxy_address;
std::atomic<unsigned int> m_current_number_of_out_peers;
std::atomic<unsigned int> m_current_number_of_in_peers;
boost::shared_mutex m_seed_nodes_lock;
bool m_can_pingback;
bool m_seed_nodes_initialized;
private:
void set_config_defaults() noexcept
@@ -383,9 +392,10 @@ namespace nodetool
void record_addr_failed(const epee::net_utils::network_address& addr);
bool is_addr_recently_failed(const epee::net_utils::network_address& addr);
bool is_priority_node(const epee::net_utils::network_address& na);
std::set<std::string> get_seed_nodes(cryptonote::network_type nettype) const;
std::set<std::string> get_seed_nodes();
bool connect_to_seed();
std::set<std::string> get_ip_seed_nodes() const;
std::set<std::string> get_dns_seed_nodes();
std::set<std::string> get_seed_nodes(epee::net_utils::zone);
bool connect_to_seed(epee::net_utils::zone);
template <class Container>
bool connect_to_peerlist(const Container& peers);
@@ -467,9 +477,6 @@ namespace nodetool
std::list<epee::net_utils::network_address> m_priority_peers;
std::vector<epee::net_utils::network_address> m_exclusive_peers;
std::vector<epee::net_utils::network_address> m_seed_nodes;
bool m_seed_nodes_initialized = false;
boost::shared_mutex m_seed_nodes_lock;
std::atomic_flag m_fallback_seed_nodes_added;
std::vector<nodetool::peerlist_entry> m_command_line_peers;
uint64_t m_peer_livetime;
@@ -523,6 +530,7 @@ namespace nodetool
extern const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_seed_node;
extern const command_line::arg_descriptor<std::vector<std::string> > arg_tx_proxy;
extern const command_line::arg_descriptor<std::vector<std::string> > arg_anonymous_inbound;
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;

View File

@@ -71,6 +71,17 @@
#define MIN_WANTED_SEED_NODES 12
static inline boost::asio::ip::address_v4 make_address_v4_from_v6(const boost::asio::ip::address_v6& a)
{
const auto &bytes = a.to_bytes();
uint32_t v4 = 0;
v4 = (v4 << 8) | bytes[12];
v4 = (v4 << 8) | bytes[13];
v4 = (v4 << 8) | bytes[14];
v4 = (v4 << 8) | bytes[15];
return boost::asio::ip::address_v4(v4);
}
namespace nodetool
{
template<class t_payload_net_handler>
@@ -106,6 +117,7 @@ namespace nodetool
command_line::add_arg(desc, arg_p2p_seed_node);
command_line::add_arg(desc, arg_tx_proxy);
command_line::add_arg(desc, arg_anonymous_inbound);
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_no_igd);
@@ -245,6 +257,10 @@ namespace nodetool
zone.second.m_net_server.get_config_object().close(c);
conns.clear();
peerlist_entry pe{};
pe.adr = addr;
zone.second.m_peerlist.remove_from_peer_white(pe);
}
MCLOG_CYAN(el::Level::Info, "global", "Host " << addr.host_str() << " blocked.");
@@ -435,12 +451,42 @@ namespace nodetool
if (command_line::has_arg(vm, arg_p2p_seed_node))
{
boost::unique_lock<boost::shared_mutex> lock(m_seed_nodes_lock);
boost::unique_lock<boost::shared_mutex> lock(public_zone.m_seed_nodes_lock);
if (!parse_peers_and_add_to_container(vm, arg_p2p_seed_node, m_seed_nodes))
if (!parse_peers_and_add_to_container(vm, arg_p2p_seed_node, public_zone.m_seed_nodes))
return false;
}
if (!command_line::is_arg_defaulted(vm, arg_ban_list))
{
const std::string ban_list = command_line::get_arg(vm, arg_ban_list);
const boost::filesystem::path ban_list_path(ban_list);
boost::system::error_code ec;
if (!boost::filesystem::exists(ban_list_path, ec))
{
throw std::runtime_error("Can't find ban list file " + ban_list + " - " + ec.message());
}
std::string banned_ips;
if (!epee::file_io_utils::load_file_to_string(ban_list_path.string(), banned_ips))
{
throw std::runtime_error("Failed to read ban list file " + ban_list);
}
std::istringstream iss(banned_ips);
for (std::string line; std::getline(iss, line); )
{
const expect<epee::net_utils::network_address> parsed_addr = net::get_network_address(line, 0);
if (!parsed_addr)
{
MERROR("Invalid IP address: " << line << " - " << parsed_addr.error());
continue;
}
block_host(*parsed_addr, std::numeric_limits<time_t>::max());
}
}
if(command_line::has_arg(vm, arg_p2p_hide_my_port))
m_hide_my_port = true;
@@ -598,21 +644,21 @@ namespace nodetool
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
std::set<std::string> node_server<t_payload_net_handler>::get_seed_nodes(cryptonote::network_type nettype) const
std::set<std::string> node_server<t_payload_net_handler>::get_ip_seed_nodes() const
{
std::set<std::string> full_addrs;
if (nettype == cryptonote::TESTNET)
if (m_nettype == cryptonote::TESTNET)
{
full_addrs.insert("212.83.175.67:28080");
full_addrs.insert("212.83.172.165:28080");
full_addrs.insert("192.110.160.146:28080");
}
else if (nettype == cryptonote::STAGENET)
else if (m_nettype == cryptonote::STAGENET)
{
full_addrs.insert("162.210.173.150:38080");
full_addrs.insert("192.110.160.146:38080");
}
else if (nettype == cryptonote::FAKECHAIN)
else if (m_nettype == cryptonote::FAKECHAIN)
{
}
else
@@ -630,7 +676,7 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
std::set<std::string> node_server<t_payload_net_handler>::get_seed_nodes()
std::set<std::string> node_server<t_payload_net_handler>::get_dns_seed_nodes()
{
if (!m_exclusive_peers.empty() || m_offline)
{
@@ -638,11 +684,11 @@ namespace nodetool
}
if (m_nettype == cryptonote::TESTNET)
{
return get_seed_nodes(cryptonote::TESTNET);
return get_ip_seed_nodes();
}
if (m_nettype == cryptonote::STAGENET)
{
return get_seed_nodes(cryptonote::STAGENET);
return get_ip_seed_nodes();
}
std::set<std::string> full_addrs;
@@ -730,7 +776,7 @@ namespace nodetool
else
MINFO("Not enough DNS seed nodes found, using fallback defaults too");
for (const auto &peer: get_seed_nodes(cryptonote::MAINNET))
for (const auto &peer: get_ip_seed_nodes())
full_addrs.insert(peer);
m_fallback_seed_nodes_added.test_and_set();
}
@@ -739,6 +785,38 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
std::set<std::string> node_server<t_payload_net_handler>::get_seed_nodes(epee::net_utils::zone zone)
{
switch (zone)
{
case epee::net_utils::zone::public_:
return get_dns_seed_nodes();
case epee::net_utils::zone::tor:
if (m_nettype == cryptonote::MAINNET)
{
return {
"xwvz3ekocr3dkyxfkmgm2hvbpzx2ysqmaxgter7znnqrhoicygkfswid.onion:18083",
"4pixvbejrvihnkxmduo2agsnmc3rrulrqc7s3cbwwrep6h6hrzsibeqd.onion:18083",
"zbjkbsxc5munw3qusl7j2hpcmikhqocdf4pqhnhtpzw5nt5jrmofptid.onion:18083"
};
}
return {};
case epee::net_utils::zone::i2p:
if (m_nettype == cryptonote::MAINNET)
{
return {
"s3l6ke4ed3df466khuebb4poienoingwof7oxtbo6j4n56sghe3a.b32.i2p:18080",
"sel36x6fibfzujwvt4hf5gxolz6kd3jpvbjqg6o3ud2xtionyl2q.b32.i2p:18080"
};
}
return {};
default:
break;
}
throw std::logic_error{"Bad zone given to get_seed_nodes"};
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
typename node_server<t_payload_net_handler>::network_zone& node_server<t_payload_net_handler>::add_zone(const epee::net_utils::zone zone)
{
const auto zone_ = m_network_zones.lower_bound(zone);
@@ -1232,7 +1310,13 @@ namespace nodetool
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::try_to_connect_and_handshake_with_new_peer(const epee::net_utils::network_address& na, bool just_take_peerlist, uint64_t last_seen_stamp, PeerType peer_type, uint64_t first_seen_stamp)
{
network_zone& zone = m_network_zones.at(na.get_zone());
const auto i = m_network_zones.find(na.get_zone());
if (i == m_network_zones.end())
{
MERROR("Tried connecting to address for disabled network");
return false;
}
network_zone& zone = i->second;
if (zone.m_connect == nullptr) // outgoing connections in zone not possible
return false;
@@ -1432,17 +1516,44 @@ namespace nodetool
const uint32_t actual_ip = na.as<const epee::net_utils::ipv4_network_address>().ip();
classB.insert(actual_ip & 0x0000ffff);
}
else if (cntxt.m_remote_address.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id())
{
const epee::net_utils::network_address na = cntxt.m_remote_address;
const boost::asio::ip::address_v6 &actual_ip = na.as<const epee::net_utils::ipv6_network_address>().ip();
if (actual_ip.is_v4_mapped())
{
boost::asio::ip::address_v4 v4ip = make_address_v4_from_v6(actual_ip);
uint32_t actual_ipv4;
memcpy(&actual_ipv4, v4ip.to_bytes().data(), sizeof(actual_ipv4));
classB.insert(actual_ipv4 & ntohl(0xffff0000));
}
}
return true;
});
}
auto get_host_string = [](const epee::net_utils::network_address &address) {
if (address.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id())
{
boost::asio::ip::address_v6 actual_ip = address.as<const epee::net_utils::ipv6_network_address>().ip();
if (actual_ip.is_v4_mapped())
{
boost::asio::ip::address_v4 v4ip = make_address_v4_from_v6(actual_ip);
uint32_t actual_ipv4;
memcpy(&actual_ipv4, v4ip.to_bytes().data(), sizeof(actual_ipv4));
return epee::net_utils::ipv4_network_address(actual_ipv4, 0).host_str();
}
}
return address.host_str();
};
std::unordered_set<std::string> hosts_added;
std::deque<size_t> filtered;
const size_t limit = use_white_list ? 20 : std::numeric_limits<size_t>::max();
for (int step = 0; step < 2; ++step)
{
bool skip_duplicate_class_B = step == 0;
size_t idx = 0, skipped = 0;
zone.m_peerlist.foreach (use_white_list, [&classB, &filtered, &idx, &skipped, skip_duplicate_class_B, limit, next_needed_pruning_stripe](const peerlist_entry &pe){
zone.m_peerlist.foreach (use_white_list, [&classB, &filtered, &idx, &skipped, skip_duplicate_class_B, limit, next_needed_pruning_stripe, &hosts_added, &get_host_string](const peerlist_entry &pe){
if (filtered.size() >= limit)
return false;
bool skip = false;
@@ -1452,6 +1563,27 @@ namespace nodetool
uint32_t actual_ip = na.as<const epee::net_utils::ipv4_network_address>().ip();
skip = classB.find(actual_ip & 0x0000ffff) != classB.end();
}
else if (skip_duplicate_class_B && pe.adr.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id())
{
const epee::net_utils::network_address na = pe.adr;
const boost::asio::ip::address_v6 &actual_ip = na.as<const epee::net_utils::ipv6_network_address>().ip();
if (actual_ip.is_v4_mapped())
{
boost::asio::ip::address_v4 v4ip = make_address_v4_from_v6(actual_ip);
uint32_t actual_ipv4;
memcpy(&actual_ipv4, v4ip.to_bytes().data(), sizeof(actual_ipv4));
skip = classB.find(actual_ipv4 & ntohl(0xffff0000)) != classB.end();
}
}
// consider each host once, to avoid giving undue inflence to hosts running several nodes
if (!skip)
{
const auto i = hosts_added.find(get_host_string(pe.adr));
if (i != hosts_added.end())
skip = true;
}
if (skip)
++skipped;
else if (next_needed_pruning_stripe == 0 || pe.pruning_seed == 0)
@@ -1459,16 +1591,17 @@ namespace nodetool
else if (next_needed_pruning_stripe == tools::get_pruning_stripe(pe.pruning_seed))
filtered.push_front(idx);
++idx;
hosts_added.insert(get_host_string(pe.adr));
return true;
});
if (skipped == 0 || !filtered.empty())
break;
if (skipped)
MINFO("Skipping " << skipped << " possible peers as they share a class B with existing peers");
MDEBUG("Skipping " << skipped << " possible peers as they share a class B with existing peers");
}
if (filtered.empty())
{
MDEBUG("No available peer in " << (use_white_list ? "white" : "gray") << " list filtered by " << next_needed_pruning_stripe);
MINFO("No available peer in " << (use_white_list ? "white" : "gray") << " list filtered by " << next_needed_pruning_stripe);
return false;
}
if (use_white_list)
@@ -1541,56 +1674,59 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::connect_to_seed()
bool node_server<t_payload_net_handler>::connect_to_seed(epee::net_utils::zone zone)
{
boost::upgrade_lock<boost::shared_mutex> seed_nodes_upgrade_lock(m_seed_nodes_lock);
network_zone& server = m_network_zones.at(zone);
boost::upgrade_lock<boost::shared_mutex> seed_nodes_upgrade_lock(server.m_seed_nodes_lock);
if (!m_seed_nodes_initialized)
if (!server.m_seed_nodes_initialized)
{
const std::uint16_t default_port = cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT;
boost::upgrade_to_unique_lock<boost::shared_mutex> seed_nodes_lock(seed_nodes_upgrade_lock);
m_seed_nodes_initialized = true;
for (const auto& full_addr : get_seed_nodes())
server.m_seed_nodes_initialized = true;
for (const auto& full_addr : get_seed_nodes(zone))
{
// seeds should have hostname converted to IP already
MDEBUG("Seed node: " << full_addr);
append_net_address(m_seed_nodes, full_addr, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT);
server.m_seed_nodes.push_back(MONERO_UNWRAP(net::get_network_address(full_addr, default_port)));
}
MDEBUG("Number of seed nodes: " << m_seed_nodes.size());
MDEBUG("Number of seed nodes: " << server.m_seed_nodes.size());
}
if (m_seed_nodes.empty() || m_offline || !m_exclusive_peers.empty())
if (server.m_seed_nodes.empty() || m_offline || !m_exclusive_peers.empty())
return true;
size_t try_count = 0;
bool is_connected_to_at_least_one_seed_node = false;
size_t current_index = crypto::rand_idx(m_seed_nodes.size());
const net_server& server = m_network_zones.at(epee::net_utils::zone::public_).m_net_server;
size_t current_index = crypto::rand_idx(server.m_seed_nodes.size());
while(true)
{
if(server.is_stop_signal_sent())
if(server.m_net_server.is_stop_signal_sent())
return false;
peerlist_entry pe_seed{};
pe_seed.adr = m_seed_nodes[current_index];
pe_seed.adr = server.m_seed_nodes[current_index];
if (is_peer_used(pe_seed))
is_connected_to_at_least_one_seed_node = true;
else if (try_to_connect_and_handshake_with_new_peer(m_seed_nodes[current_index], true))
else if (try_to_connect_and_handshake_with_new_peer(server.m_seed_nodes[current_index], true))
break;
if(++try_count > m_seed_nodes.size())
if(++try_count > server.m_seed_nodes.size())
{
if (!m_fallback_seed_nodes_added.test_and_set())
// only IP zone has fallback (to direct IP) seeds
if (zone == epee::net_utils::zone::public_ && !m_fallback_seed_nodes_added.test_and_set())
{
MWARNING("Failed to connect to any of seed peers, trying fallback seeds");
current_index = m_seed_nodes.size() - 1;
current_index = server.m_seed_nodes.size() - 1;
{
boost::upgrade_to_unique_lock<boost::shared_mutex> seed_nodes_lock(seed_nodes_upgrade_lock);
for (const auto &peer: get_seed_nodes(m_nettype))
for (const auto &peer: get_ip_seed_nodes())
{
MDEBUG("Fallback seed node: " << peer);
append_net_address(m_seed_nodes, peer, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT);
append_net_address(server.m_seed_nodes, peer, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT);
}
}
if (current_index == m_seed_nodes.size() - 1)
if (current_index == server.m_seed_nodes.size() - 1)
{
MWARNING("No fallback seeds, continuing without seeds");
break;
@@ -1604,7 +1740,7 @@ namespace nodetool
break;
}
}
if(++current_index >= m_seed_nodes.size())
if(++current_index >= server.m_seed_nodes.size())
current_index = 0;
}
return true;
@@ -1620,20 +1756,21 @@ namespace nodetool
if (!m_exclusive_peers.empty()) return true;
// Only have seeds in the public zone right now.
size_t start_conn_count = get_public_outgoing_connections_count();
if(!get_public_white_peers_count() && !connect_to_seed())
{
return false;
}
if (!connect_to_peerlist(m_priority_peers)) return false;
bool one_succeeded = false;
for(auto& zone : m_network_zones)
{
size_t start_conn_count = get_outgoing_connections_count(zone.second);
if(!zone.second.m_peerlist.get_white_peers_count() && !connect_to_seed(zone.first))
{
continue;
}
if (zone.first == zone_type::public_ && !connect_to_peerlist(m_priority_peers)) continue;
size_t base_expected_white_connections = (zone.second.m_config.m_net_config.max_out_connection_count*P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT)/100;
// carefully avoid `continue` in nested loop
size_t conn_count = get_outgoing_connections_count(zone.second);
while(conn_count < zone.second.m_config.m_net_config.max_out_connection_count)
{
@@ -1670,16 +1807,17 @@ namespace nodetool
}
conn_count = new_conn_count;
}
if (start_conn_count == get_outgoing_connections_count(zone.second) && start_conn_count < zone.second.m_config.m_net_config.max_out_connection_count)
{
MINFO("Failed to connect to any, trying seeds");
if (!connect_to_seed(zone.first))
continue;
}
one_succeeded = true;
}
if (start_conn_count == get_public_outgoing_connections_count() && start_conn_count < m_network_zones.at(zone_type::public_).m_config.m_net_config.max_out_connection_count)
{
MINFO("Failed to connect to any, trying seeds");
if (!connect_to_seed())
return false;
}
return true;
return one_succeeded;
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>

View File

@@ -1131,6 +1131,11 @@ namespace cryptonote
{
RPC_TRACKER(send_raw_tx);
{
bool ok;
use_bootstrap_daemon_if_necessary<COMMAND_RPC_SEND_RAW_TX>(invoke_http_mode::JON, "/sendrawtransaction", req, res, ok);
}
const bool restricted = m_restricted && ctx;
bool skip_validation = false;
@@ -2827,6 +2832,8 @@ namespace cryptonote
RPC_TRACKER(relay_tx);
CHECK_PAYMENT_MIN1(req, res, req.txids.size() * COST_PER_TX_RELAY, false);
const bool restricted = m_restricted && ctx;
bool failed = false;
res.status = "";
for (const auto &str: req.txids)
@@ -2840,12 +2847,16 @@ namespace cryptonote
continue;
}
//TODO: The get_pool_transaction could have an optional meta parameter
bool broadcasted = false;
cryptonote::blobdata txblob;
if (m_core.get_pool_transaction(txid, txblob, relay_category::legacy))
if ((broadcasted = m_core.get_pool_transaction(txid, txblob, relay_category::broadcasted)) || (!restricted && m_core.get_pool_transaction(txid, txblob, relay_category::all)))
{
// The settings below always choose i2p/tor if enabled. Otherwise, do fluff iff previously relayed else dandelion++ stem.
NOTIFY_NEW_TRANSACTIONS::request r;
r.txs.push_back(std::move(txblob));
m_core.get_protocol()->relay_transactions(r, boost::uuids::nil_uuid(), epee::net_utils::zone::invalid, relay_method::local);
const auto tx_relay = broadcasted ? relay_method::fluff : relay_method::local;
m_core.get_protocol()->relay_transactions(r, boost::uuids::nil_uuid(), epee::net_utils::zone::invalid, tx_relay);
//TODO: make sure that tx has reached other nodes here, probably wait to receive reflections from other nodes
}
else

View File

@@ -1,5 +1,5 @@
#define DEF_MONERO_VERSION_TAG "@VERSIONTAG@"
#define DEF_MONERO_VERSION "0.17.1.1"
#define DEF_MONERO_VERSION "0.17.1.3"
#define DEF_MONERO_RELEASE_NAME "Oxygen Orion"
#define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG
#define DEF_MONERO_VERSION_IS_RELEASE @VERSION_IS_RELEASE@

View File

@@ -613,6 +613,61 @@ TEST_F(levin_notify, stem_without_padding)
}
}
TEST_F(levin_notify, stem_no_outs_without_padding)
{
cryptonote::levin::notify notifier = make_notifier(0, true, false);
for (unsigned count = 0; count < 10; ++count)
add_connection(true);
{
const auto status = notifier.get_status();
EXPECT_FALSE(status.has_noise);
EXPECT_FALSE(status.connections_filled);
}
notifier.new_out_connection();
io_service_.poll();
std::vector<cryptonote::blobdata> txs(2);
txs[0].resize(100, 'f');
txs[1].resize(200, 'e');
std::vector<cryptonote::blobdata> sorted_txs = txs;
std::sort(sorted_txs.begin(), sorted_txs.end());
ASSERT_EQ(10u, contexts_.size());
auto context = contexts_.begin();
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::stem));
io_service_.reset();
ASSERT_LT(0u, io_service_.poll());
EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff));
if (events_.has_stem_txes())
EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::stem));
notifier.run_fluff();
ASSERT_LT(0u, io_service_.poll());
std::size_t send_count = 0;
EXPECT_EQ(0u, context->process_send_queue());
for (++context; context != contexts_.end(); ++context)
{
send_count += context->process_send_queue();
}
EXPECT_EQ(9u, send_count);
ASSERT_EQ(9u, receiver_.notified_size());
for (unsigned count = 0; count < 9u; ++count)
{
auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
EXPECT_EQ(sorted_txs, notification.txs);
EXPECT_TRUE(notification._.empty());
EXPECT_TRUE(notification.dandelionpp_fluff);
}
}
TEST_F(levin_notify, local_without_padding)
{
cryptonote::levin::notify notifier = make_notifier(0, true, false);
@@ -928,6 +983,60 @@ TEST_F(levin_notify, stem_with_padding)
}
}
TEST_F(levin_notify, stem_no_outs_with_padding)
{
cryptonote::levin::notify notifier = make_notifier(0, true, true);
for (unsigned count = 0; count < 10; ++count)
add_connection(true);
{
const auto status = notifier.get_status();
EXPECT_FALSE(status.has_noise);
EXPECT_FALSE(status.connections_filled);
}
notifier.new_out_connection();
io_service_.poll();
std::vector<cryptonote::blobdata> txs(2);
txs[0].resize(100, 'f');
txs[1].resize(200, 'e');
std::vector<cryptonote::blobdata> sorted_txs = txs;
std::sort(sorted_txs.begin(), sorted_txs.end());
ASSERT_EQ(10u, contexts_.size());
auto context = contexts_.begin();
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::stem));
io_service_.reset();
ASSERT_LT(0u, io_service_.poll());
EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff));
if (events_.has_stem_txes())
EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::stem));
notifier.run_fluff();
ASSERT_LT(0u, io_service_.poll());
std::size_t send_count = 0;
EXPECT_EQ(0u, context->process_send_queue());
for (++context; context != contexts_.end(); ++context)
{
send_count += context->process_send_queue();
}
EXPECT_EQ(9u, send_count);
ASSERT_EQ(9u, receiver_.notified_size());
for (unsigned count = 0; count < 9u; ++count)
{
auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
EXPECT_EQ(sorted_txs, notification.txs);
EXPECT_FALSE(notification._.empty());
EXPECT_TRUE(notification.dandelionpp_fluff);
}
}
TEST_F(levin_notify, local_with_padding)
{
cryptonote::levin::notify notifier = make_notifier(0, true, true);