mirror of
https://github.com/monero-project/monero.git
synced 2024-12-13 11:56:31 +02:00
protocol: drop origin IP if a block fails to verify in sync mode
It would otherwise be possible for a peer to send bad blocks, then disconnect and reconnect again, escaping bans
This commit is contained in:
parent
316dcaa399
commit
d660f22ed1
@ -52,12 +52,12 @@ namespace std {
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
void block_queue::add_blocks(uint64_t height, std::vector<cryptonote::block_complete_entry> bcel, const boost::uuids::uuid &connection_id, float rate, size_t size)
|
||||
void block_queue::add_blocks(uint64_t height, std::vector<cryptonote::block_complete_entry> bcel, const boost::uuids::uuid &connection_id, const epee::net_utils::network_address &addr, float rate, size_t size)
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> lock(mutex);
|
||||
std::vector<crypto::hash> hashes;
|
||||
bool has_hashes = remove_span(height, &hashes);
|
||||
blocks.insert(span(height, std::move(bcel), connection_id, rate, size));
|
||||
blocks.insert(span(height, std::move(bcel), connection_id, addr, rate, size));
|
||||
if (has_hashes)
|
||||
{
|
||||
for (const crypto::hash &h: hashes)
|
||||
@ -69,11 +69,11 @@ void block_queue::add_blocks(uint64_t height, std::vector<cryptonote::block_comp
|
||||
}
|
||||
}
|
||||
|
||||
void block_queue::add_blocks(uint64_t height, uint64_t nblocks, const boost::uuids::uuid &connection_id, boost::posix_time::ptime time)
|
||||
void block_queue::add_blocks(uint64_t height, uint64_t nblocks, const boost::uuids::uuid &connection_id, const epee::net_utils::network_address &addr, boost::posix_time::ptime time)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(nblocks > 0, "Empty span");
|
||||
boost::unique_lock<boost::recursive_mutex> lock(mutex);
|
||||
blocks.insert(span(height, nblocks, connection_id, time));
|
||||
blocks.insert(span(height, nblocks, connection_id, addr, time));
|
||||
}
|
||||
|
||||
void block_queue::flush_spans(const boost::uuids::uuid &connection_id, bool all)
|
||||
@ -228,7 +228,7 @@ bool block_queue::have(const crypto::hash &hash) const
|
||||
return have_blocks.find(hash) != have_blocks.end();
|
||||
}
|
||||
|
||||
std::pair<uint64_t, uint64_t> block_queue::reserve_span(uint64_t first_block_height, uint64_t last_block_height, uint64_t max_blocks, const boost::uuids::uuid &connection_id, bool sync_pruned_blocks, uint32_t local_pruning_seed, uint32_t pruning_seed, uint64_t blockchain_height, const std::vector<std::pair<crypto::hash, uint64_t>> &block_hashes, boost::posix_time::ptime time)
|
||||
std::pair<uint64_t, uint64_t> block_queue::reserve_span(uint64_t first_block_height, uint64_t last_block_height, uint64_t max_blocks, const boost::uuids::uuid &connection_id, const epee::net_utils::network_address &addr, bool sync_pruned_blocks, uint32_t local_pruning_seed, uint32_t pruning_seed, uint64_t blockchain_height, const std::vector<std::pair<crypto::hash, uint64_t>> &block_hashes, boost::posix_time::ptime time)
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> lock(mutex);
|
||||
|
||||
@ -305,7 +305,7 @@ std::pair<uint64_t, uint64_t> block_queue::reserve_span(uint64_t first_block_hei
|
||||
return std::make_pair(0, 0);
|
||||
}
|
||||
MDEBUG("Reserving span " << span_start_height << " - " << (span_start_height + span_length - 1) << " for " << connection_id);
|
||||
add_blocks(span_start_height, span_length, connection_id, time);
|
||||
add_blocks(span_start_height, span_length, connection_id, addr, time);
|
||||
set_span_hashes(span_start_height, connection_id, hashes);
|
||||
return std::make_pair(span_start_height, span_length);
|
||||
}
|
||||
@ -354,7 +354,7 @@ void block_queue::set_span_hashes(uint64_t start_height, const boost::uuids::uui
|
||||
}
|
||||
}
|
||||
|
||||
bool block_queue::get_next_span(uint64_t &height, std::vector<cryptonote::block_complete_entry> &bcel, boost::uuids::uuid &connection_id, bool filled) const
|
||||
bool block_queue::get_next_span(uint64_t &height, std::vector<cryptonote::block_complete_entry> &bcel, boost::uuids::uuid &connection_id, epee::net_utils::network_address &addr, bool filled) const
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> lock(mutex);
|
||||
if (blocks.empty())
|
||||
@ -367,6 +367,7 @@ bool block_queue::get_next_span(uint64_t &height, std::vector<cryptonote::block_
|
||||
height = i->start_block_height;
|
||||
bcel = i->blocks;
|
||||
connection_id = i->connection_id;
|
||||
addr = i->origin;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <unordered_set>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include "net/net_utils_base.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "cn.block_queue"
|
||||
@ -57,19 +58,20 @@ namespace cryptonote
|
||||
float rate;
|
||||
size_t size;
|
||||
boost::posix_time::ptime time;
|
||||
epee::net_utils::network_address origin{};
|
||||
|
||||
span(uint64_t start_block_height, std::vector<cryptonote::block_complete_entry> blocks, const boost::uuids::uuid &connection_id, float rate, size_t size):
|
||||
start_block_height(start_block_height), blocks(std::move(blocks)), connection_id(connection_id), nblocks(this->blocks.size()), rate(rate), size(size), time() {}
|
||||
span(uint64_t start_block_height, uint64_t nblocks, const boost::uuids::uuid &connection_id, boost::posix_time::ptime time):
|
||||
start_block_height(start_block_height), connection_id(connection_id), nblocks(nblocks), rate(0.0f), size(0), time(time) {}
|
||||
span(uint64_t start_block_height, std::vector<cryptonote::block_complete_entry> blocks, const boost::uuids::uuid &connection_id, const epee::net_utils::network_address &addr, float rate, size_t size):
|
||||
start_block_height(start_block_height), blocks(std::move(blocks)), connection_id(connection_id), nblocks(this->blocks.size()), rate(rate), size(size), time(boost::date_time::min_date_time), origin(addr) {}
|
||||
span(uint64_t start_block_height, uint64_t nblocks, const boost::uuids::uuid &connection_id, const epee::net_utils::network_address &addr, boost::posix_time::ptime time):
|
||||
start_block_height(start_block_height), connection_id(connection_id), nblocks(nblocks), rate(0.0f), size(0), time(time), origin(addr) {}
|
||||
|
||||
bool operator<(const span &s) const { return start_block_height < s.start_block_height; }
|
||||
};
|
||||
typedef std::set<span> block_map;
|
||||
|
||||
public:
|
||||
void add_blocks(uint64_t height, std::vector<cryptonote::block_complete_entry> bcel, const boost::uuids::uuid &connection_id, float rate, size_t size);
|
||||
void add_blocks(uint64_t height, uint64_t nblocks, const boost::uuids::uuid &connection_id, boost::posix_time::ptime time = boost::date_time::min_date_time);
|
||||
void add_blocks(uint64_t height, std::vector<cryptonote::block_complete_entry> bcel, const boost::uuids::uuid &connection_id, const epee::net_utils::network_address &addr, float rate, size_t size);
|
||||
void add_blocks(uint64_t height, uint64_t nblocks, const boost::uuids::uuid &connection_id, const epee::net_utils::network_address &addr, boost::posix_time::ptime time = boost::date_time::min_date_time);
|
||||
void flush_spans(const boost::uuids::uuid &connection_id, bool all = false);
|
||||
void flush_stale_spans(const std::set<boost::uuids::uuid> &live_connections);
|
||||
bool remove_span(uint64_t start_block_height, std::vector<crypto::hash> *hashes = NULL);
|
||||
@ -78,12 +80,12 @@ namespace cryptonote
|
||||
void print() const;
|
||||
std::string get_overview(uint64_t blockchain_height) const;
|
||||
bool has_unpruned_height(uint64_t block_height, uint64_t blockchain_height, uint32_t pruning_seed) const;
|
||||
std::pair<uint64_t, uint64_t> reserve_span(uint64_t first_block_height, uint64_t last_block_height, uint64_t max_blocks, const boost::uuids::uuid &connection_id, bool sync_pruned_blocks, uint32_t local_pruning_seed, uint32_t pruning_seed, uint64_t blockchain_height, const std::vector<std::pair<crypto::hash, uint64_t>> &block_hashes, boost::posix_time::ptime time = boost::posix_time::microsec_clock::universal_time());
|
||||
std::pair<uint64_t, uint64_t> reserve_span(uint64_t first_block_height, uint64_t last_block_height, uint64_t max_blocks, const boost::uuids::uuid &connection_id, const epee::net_utils::network_address &addr, bool sync_pruned_blocks, uint32_t local_pruning_seed, uint32_t pruning_seed, uint64_t blockchain_height, const std::vector<std::pair<crypto::hash, uint64_t>> &block_hashes, boost::posix_time::ptime time = boost::posix_time::microsec_clock::universal_time());
|
||||
uint64_t get_next_needed_height(uint64_t blockchain_height) const;
|
||||
std::pair<uint64_t, uint64_t> get_next_span_if_scheduled(std::vector<crypto::hash> &hashes, boost::uuids::uuid &connection_id, boost::posix_time::ptime &time) const;
|
||||
void reset_next_span_time(boost::posix_time::ptime t = boost::posix_time::microsec_clock::universal_time());
|
||||
void set_span_hashes(uint64_t start_height, const boost::uuids::uuid &connection_id, std::vector<crypto::hash> hashes);
|
||||
bool get_next_span(uint64_t &height, std::vector<cryptonote::block_complete_entry> &bcel, boost::uuids::uuid &connection_id, bool filled = true) const;
|
||||
bool get_next_span(uint64_t &height, std::vector<cryptonote::block_complete_entry> &bcel, boost::uuids::uuid &connection_id, epee::net_utils::network_address &addr, bool filled = true) const;
|
||||
bool has_next_span(const boost::uuids::uuid &connection_id, bool &filled, boost::posix_time::ptime &time) const;
|
||||
bool has_next_span(uint64_t height, bool &filled, boost::posix_time::ptime &time, boost::uuids::uuid &connection_id) const;
|
||||
size_t get_data_size() const;
|
||||
|
@ -141,6 +141,7 @@ namespace cryptonote
|
||||
bool should_ask_for_pruned_data(cryptonote_connection_context& context, uint64_t first_block_height, uint64_t nblocks, bool check_block_weights) const;
|
||||
void drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans);
|
||||
void drop_connection_with_score(cryptonote_connection_context &context, unsigned int score, bool flush_all_spans);
|
||||
void drop_connections(const epee::net_utils::network_address address);
|
||||
bool kick_idle_peers();
|
||||
bool check_standby_peers();
|
||||
bool update_sync_search();
|
||||
|
@ -1257,7 +1257,7 @@ namespace cryptonote
|
||||
const boost::posix_time::time_duration dt = now - request_time;
|
||||
const float rate = size * 1e6 / (dt.total_microseconds() + 1);
|
||||
MDEBUG(context << " adding span: " << arg.blocks.size() << " at height " << start_height << ", " << dt.total_microseconds()/1e6 << " seconds, " << (rate/1024) << " kB/s, size now " << (m_block_queue.get_data_size() + blocks_size) / 1048576.f << " MB");
|
||||
m_block_queue.add_blocks(start_height, arg.blocks, context.m_connection_id, rate, blocks_size);
|
||||
m_block_queue.add_blocks(start_height, arg.blocks, context.m_connection_id, context.m_remote_address, rate, blocks_size);
|
||||
|
||||
const crypto::hash last_block_hash = cryptonote::get_block_hash(b);
|
||||
context.m_last_known_hash = last_block_hash;
|
||||
@ -1358,7 +1358,8 @@ namespace cryptonote
|
||||
uint64_t start_height;
|
||||
std::vector<cryptonote::block_complete_entry> blocks;
|
||||
boost::uuids::uuid span_connection_id;
|
||||
if (!m_block_queue.get_next_span(start_height, blocks, span_connection_id))
|
||||
epee::net_utils::network_address span_origin;
|
||||
if (!m_block_queue.get_next_span(start_height, blocks, span_connection_id, span_origin))
|
||||
{
|
||||
MDEBUG(context << " no next span found, going back to download");
|
||||
break;
|
||||
@ -1456,6 +1457,7 @@ namespace cryptonote
|
||||
if (!m_core.prepare_handle_incoming_blocks(blocks, pblocks))
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("Failure in prepare_handle_incoming_blocks");
|
||||
drop_connections(span_origin);
|
||||
return 1;
|
||||
}
|
||||
if (!pblocks.empty() && pblocks.size() != blocks.size())
|
||||
@ -1495,6 +1497,7 @@ namespace cryptonote
|
||||
{
|
||||
if(tvc[i].m_verifivation_failed)
|
||||
{
|
||||
drop_connections(span_origin);
|
||||
if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
|
||||
cryptonote::transaction tx;
|
||||
crypto::hash txid;
|
||||
@ -1536,6 +1539,7 @@ namespace cryptonote
|
||||
|
||||
if(bvc.m_verifivation_failed)
|
||||
{
|
||||
drop_connections(span_origin);
|
||||
if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
|
||||
LOG_PRINT_CCONTEXT_L1("Block verification failed, dropping connection");
|
||||
drop_connection_with_score(context, bvc.m_bad_pow ? P2P_IP_FAILS_BEFORE_BLOCK : 1, true);
|
||||
@ -1555,6 +1559,7 @@ namespace cryptonote
|
||||
}
|
||||
if(bvc.m_marked_as_orphaned)
|
||||
{
|
||||
drop_connections(span_origin);
|
||||
if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
|
||||
LOG_PRINT_CCONTEXT_L1("Block received at sync phase was marked as orphaned, dropping connection");
|
||||
drop_connection(context, true, true);
|
||||
@ -2173,7 +2178,7 @@ skip:
|
||||
const uint64_t first_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1;
|
||||
static const uint64_t bp_fork_height = m_core.get_earliest_ideal_height_for_version(8);
|
||||
bool sync_pruned_blocks = m_sync_pruned_blocks && first_block_height >= bp_fork_height && m_core.get_blockchain_pruning_seed();
|
||||
span = m_block_queue.reserve_span(first_block_height, context.m_last_response_height, count_limit, context.m_connection_id, sync_pruned_blocks, m_core.get_blockchain_pruning_seed(), context.m_pruning_seed, context.m_remote_blockchain_height, context.m_needed_objects);
|
||||
span = m_block_queue.reserve_span(first_block_height, context.m_last_response_height, count_limit, context.m_connection_id, context.m_remote_address, sync_pruned_blocks, m_core.get_blockchain_pruning_seed(), context.m_pruning_seed, context.m_remote_blockchain_height, context.m_needed_objects);
|
||||
MDEBUG(context << " span from " << first_block_height << ": " << span.first << "/" << span.second);
|
||||
if (span.second > 0)
|
||||
{
|
||||
@ -2309,7 +2314,8 @@ skip:
|
||||
uint64_t start_height;
|
||||
std::vector<cryptonote::block_complete_entry> blocks;
|
||||
boost::uuids::uuid span_connection_id;
|
||||
if (m_block_queue.get_next_span(start_height, blocks, span_connection_id, true))
|
||||
epee::net_utils::network_address span_origin;
|
||||
if (m_block_queue.get_next_span(start_height, blocks, span_connection_id, span_origin, true))
|
||||
{
|
||||
LOG_DEBUG_CC(context, "No other thread is adding blocks, resuming");
|
||||
MLOG_PEER_STATE("will try to add blocks next");
|
||||
@ -2734,6 +2740,29 @@ skip:
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
void t_cryptonote_protocol_handler<t_core>::drop_connections(const epee::net_utils::network_address address)
|
||||
{
|
||||
MWARNING("dropping connections to " << address.str());
|
||||
|
||||
m_p2p->add_host_fail(address, 5);
|
||||
|
||||
std::vector<boost::uuids::uuid> drop;
|
||||
m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags) {
|
||||
if (address.is_same_host(cntxt.m_remote_address))
|
||||
drop.push_back(cntxt.m_connection_id);
|
||||
return true;
|
||||
});
|
||||
for (const boost::uuids::uuid &id: drop)
|
||||
{
|
||||
m_block_queue.flush_spans(id, true);
|
||||
m_p2p->for_connection(id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
|
||||
drop_connection(context, true, false);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
void t_cryptonote_protocol_handler<t_core>::on_connection_close(cryptonote_connection_context &context)
|
||||
{
|
||||
uint64_t target = 0;
|
||||
|
@ -2914,11 +2914,7 @@ namespace cryptonote
|
||||
block_queue.foreach([&](const cryptonote::block_queue::span &span) {
|
||||
const std::string span_connection_id = epee::string_tools::pod_to_hex(span.connection_id);
|
||||
uint32_t speed = (uint32_t)(100.0f * block_queue.get_speed(span.connection_id) + 0.5f);
|
||||
std::string address = "";
|
||||
for (const auto &c: m_p2p.get_payload_object().get_connections())
|
||||
if (c.connection_id == span_connection_id)
|
||||
address = c.address;
|
||||
res.spans.push_back({span.start_block_height, span.nblocks, span_connection_id, (uint32_t)(span.rate + 0.5f), speed, span.size, address});
|
||||
res.spans.push_back({span.start_block_height, span.nblocks, span_connection_id, (uint32_t)(span.rate + 0.5f), speed, span.size, span.origin.str()});
|
||||
return true;
|
||||
});
|
||||
res.overview = block_queue.get_overview(res.height);
|
||||
|
@ -52,36 +52,38 @@ TEST(block_queue, empty)
|
||||
|
||||
TEST(block_queue, add_stepwise)
|
||||
{
|
||||
epee::net_utils::network_address na;
|
||||
cryptonote::block_queue bq;
|
||||
bq.add_blocks(0, 200, uuid1());
|
||||
bq.add_blocks(0, 200, uuid1(), na);
|
||||
ASSERT_EQ(bq.get_max_block_height(), 199);
|
||||
bq.add_blocks(200, 200, uuid1());
|
||||
bq.add_blocks(200, 200, uuid1(), na);
|
||||
ASSERT_EQ(bq.get_max_block_height(), 399);
|
||||
bq.add_blocks(401, 200, uuid1());
|
||||
bq.add_blocks(401, 200, uuid1(), na);
|
||||
ASSERT_EQ(bq.get_max_block_height(), 600);
|
||||
bq.add_blocks(400, 10, uuid1());
|
||||
bq.add_blocks(400, 10, uuid1(), na);
|
||||
ASSERT_EQ(bq.get_max_block_height(), 600);
|
||||
}
|
||||
|
||||
TEST(block_queue, flush_uuid)
|
||||
{
|
||||
cryptonote::block_queue bq;
|
||||
epee::net_utils::network_address na;
|
||||
|
||||
bq.add_blocks(0, 200, uuid1());
|
||||
bq.add_blocks(0, 200, uuid1(), na);
|
||||
ASSERT_EQ(bq.get_max_block_height(), 199);
|
||||
bq.add_blocks(200, 200, uuid2());
|
||||
bq.add_blocks(200, 200, uuid2(), na);
|
||||
ASSERT_EQ(bq.get_max_block_height(), 399);
|
||||
bq.flush_spans(uuid2());
|
||||
ASSERT_EQ(bq.get_max_block_height(), 199);
|
||||
bq.flush_spans(uuid1());
|
||||
ASSERT_EQ(bq.get_max_block_height(), 0);
|
||||
|
||||
bq.add_blocks(0, 200, uuid1());
|
||||
bq.add_blocks(0, 200, uuid1(), na);
|
||||
ASSERT_EQ(bq.get_max_block_height(), 199);
|
||||
bq.add_blocks(200, 200, uuid2());
|
||||
bq.add_blocks(200, 200, uuid2(), na);
|
||||
ASSERT_EQ(bq.get_max_block_height(), 399);
|
||||
bq.flush_spans(uuid1());
|
||||
ASSERT_EQ(bq.get_max_block_height(), 399);
|
||||
bq.add_blocks(0, 200, uuid1());
|
||||
bq.add_blocks(0, 200, uuid1(), na);
|
||||
ASSERT_EQ(bq.get_max_block_height(), 399);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user