Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f7aa91f70d | |||
| f9a70e4260 | |||
| f105a0ef38 | |||
| 1cb3ea0447 | |||
| 43788ffd2a | |||
| 6d35b667cf | |||
| ce26c5b2dd | |||
| 21b3ff2c90 | |||
| 446b3c865b | |||
| 9427b5a6d5 | |||
| fa79148e0c | |||
| 1382b17aa1 | |||
| 7982ef5a73 | |||
| b34d50fa76 | |||
| 0833680c74 | |||
| 93135907dd | |||
| 065bb292df | |||
| 3942a1cd04 | |||
| e4c0cb0ff3 | |||
| 9d7f473af0 | |||
| 41652c9aa1 | |||
| 0a0ceb62f0 | |||
| 8e7b762092 | |||
| 551e6c9168 | |||
| c09d142972 | |||
| efca5b8af9 | |||
| 251c64f195 | |||
| 5bb83ab042 | |||
| af4fb4729e | |||
| 8e829e034f | |||
| 398e64ccbe | |||
| a8cd073fcc | |||
| f690e4984d | |||
| ebc9197326 | |||
| 81f9fa947b | |||
| 752837b2c8 | |||
| 981e0b5cc3 | |||
| 6f48a146f8 | |||
| 9b7ed2fd8b | |||
| e8468c5dcf | |||
| 37bb59485f |
@@ -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.2 | New CLSAG transaction format
|
||||
| 2210720 | 2020-10-18 | v14 | v0.17.1.1 | v0.17.1.2 | forbid old MLSAG transaction format
|
||||
| 2210000 | 2020-10-17 | v13 | v0.17.0.0 | v0.17.1.6 | New CLSAG transaction format
|
||||
| 2210720 | 2020-10-18 | v14 | v0.17.1.1 | v0.17.1.6 | 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.2
|
||||
git checkout tags/v0.17.1.6
|
||||
```
|
||||
|
||||
* 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.2'. 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.6'. If you don't care about the version and just want binaries from master, skip this step:
|
||||
|
||||
```bash
|
||||
git checkout v0.17.1.2
|
||||
git checkout v0.17.1.6
|
||||
```
|
||||
|
||||
* If you are on a 64-bit system, run:
|
||||
|
||||
@@ -6,6 +6,17 @@
|
||||
#include "string_tools.h"
|
||||
#include "net/local_ip.h"
|
||||
|
||||
static inline uint32_t 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 htonl(v4);
|
||||
}
|
||||
|
||||
namespace epee { namespace net_utils
|
||||
{
|
||||
bool ipv4_network_address::equal(const ipv4_network_address& other) const noexcept
|
||||
@@ -83,8 +94,28 @@ namespace epee { namespace net_utils
|
||||
network_address::interface const* const other_self = other.self.get();
|
||||
if (self_ == other_self) return true;
|
||||
if (!self_ || !other_self) return false;
|
||||
if (typeid(*self_) != typeid(*other_self)) return false;
|
||||
return self_->is_same_host(*other_self);
|
||||
if (typeid(*self_) == typeid(*other_self))
|
||||
return self_->is_same_host(*other_self);
|
||||
const auto this_id = get_type_id();
|
||||
if (this_id == ipv4_network_address::get_type_id() && other.get_type_id() == ipv6_network_address::get_type_id())
|
||||
{
|
||||
const boost::asio::ip::address_v6 &actual_ip = other.as<const epee::net_utils::ipv6_network_address>().ip();
|
||||
if (actual_ip.is_v4_mapped())
|
||||
{
|
||||
const uint32_t v4ip = make_address_v4_from_v6(actual_ip);
|
||||
return is_same_host(ipv4_network_address(v4ip, 0));
|
||||
}
|
||||
}
|
||||
else if (this_id == ipv6_network_address::get_type_id() && other.get_type_id() == ipv4_network_address::get_type_id())
|
||||
{
|
||||
const boost::asio::ip::address_v6 &actual_ip = this->as<const epee::net_utils::ipv6_network_address>().ip();
|
||||
if (actual_ip.is_v4_mapped())
|
||||
{
|
||||
const uint32_t v4ip = make_address_v4_from_v6(actual_ip);
|
||||
return other.is_same_host(ipv4_network_address(v4ip, 0));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string print_connection_context(const connection_context_base& ctx)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -126,7 +126,7 @@ Setup for LXC:
|
||||
|
||||
```bash
|
||||
GH_USER=fluffypony
|
||||
VERSION=v0.17.1.2
|
||||
VERSION=v0.17.1.6
|
||||
|
||||
./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.2
|
||||
VERSION=v0.17.1.6
|
||||
|
||||
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.
@@ -241,6 +241,8 @@ namespace cryptonote
|
||||
ADD_CHECKPOINT2(2206500, "dd3c8590f33eaa546a4ce69d02f27fd58a2f115cd32d733bd9426f8278f0cb8a", "0xf8725275799f0d");
|
||||
ADD_CHECKPOINT2(2210500, "ed17259215ac6aabe6e8252b5b5eff613d2e69cc2111173e567109aa78301911", "0xfbcb50a9a6a433");
|
||||
ADD_CHECKPOINT2(2224000, "e34bc71301600df96d08aaa6b0bde932cba1b06a3dd57076e3f664a078810a80", "0x1052fc256fceb6f");
|
||||
ADD_CHECKPOINT2(2235500, "3eac1a1253495733e10d00fd5e8e1639741566d91bae38bc6d3342af6b75da53", "0x10cea232ce71d23");
|
||||
ADD_CHECKPOINT2(2244000, "f06b8a19a75070cd002414d9d3ce59cf6b11ed9db464c6b84d3f22abbff84fae", "0x112b3331539f585");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -123,13 +123,17 @@ namespace crypto {
|
||||
void random32_unbiased(unsigned char *bytes)
|
||||
{
|
||||
// l = 2^252 + 27742317777372353535851937790883648493.
|
||||
// it fits 15 in 32 bytes
|
||||
// l fits 15 times in 32 bytes (iow, 15 l is the highest multiple of l that fits in 32 bytes)
|
||||
static const unsigned char limit[32] = { 0xe3, 0x6a, 0x67, 0x72, 0x8b, 0xce, 0x13, 0x29, 0x8f, 0x30, 0x82, 0x8c, 0x0b, 0xa4, 0x10, 0x39, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0 };
|
||||
do
|
||||
while(1)
|
||||
{
|
||||
generate_random_bytes_thread_safe(32, bytes);
|
||||
} while (!sc_isnonzero(bytes) && !less32(bytes, limit)); // should be good about 15/16 of the time
|
||||
sc_reduce32(bytes);
|
||||
if (!less32(bytes, limit))
|
||||
continue;
|
||||
sc_reduce32(bytes);
|
||||
if (sc_isnonzero(bytes))
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* generate a random 32-byte (256-bit) integer and copy it to res */
|
||||
static inline void random_scalar(ec_scalar &res) {
|
||||
|
||||
@@ -43,7 +43,8 @@ namespace cryptonote
|
||||
{
|
||||
cryptonote_connection_context(): m_state(state_before_handshake), m_remote_blockchain_height(0), m_last_response_height(0),
|
||||
m_last_request_time(boost::date_time::not_a_date_time), m_callback_request_count(0),
|
||||
m_last_known_hash(crypto::null_hash), m_pruning_seed(0), m_rpc_port(0), m_rpc_credits_per_hash(0), m_anchor(false) {}
|
||||
m_last_known_hash(crypto::null_hash), m_pruning_seed(0), m_rpc_port(0), m_rpc_credits_per_hash(0), m_anchor(false), m_score(0),
|
||||
m_expect_response(0) {}
|
||||
|
||||
enum state
|
||||
{
|
||||
@@ -66,7 +67,8 @@ namespace cryptonote
|
||||
uint16_t m_rpc_port;
|
||||
uint32_t m_rpc_credits_per_hash;
|
||||
bool m_anchor;
|
||||
//size_t m_score; TODO: add score calculations
|
||||
int32_t m_score;
|
||||
int m_expect_response;
|
||||
};
|
||||
|
||||
inline std::string get_protocol_state_string(cryptonote_connection_context::state s)
|
||||
|
||||
@@ -102,11 +102,11 @@
|
||||
|
||||
|
||||
#define CRYPTONOTE_DANDELIONPP_STEMS 2 // number of outgoing stem connections per epoch
|
||||
#define CRYPTONOTE_DANDELIONPP_FLUFF_PROBABILITY 10 // out of 100
|
||||
#define CRYPTONOTE_DANDELIONPP_FLUFF_PROBABILITY 20 // out of 100
|
||||
#define CRYPTONOTE_DANDELIONPP_MIN_EPOCH 10 // minutes
|
||||
#define CRYPTONOTE_DANDELIONPP_EPOCH_RANGE 30 // seconds
|
||||
#define CRYPTONOTE_DANDELIONPP_FLUSH_AVERAGE 5 // seconds average for poisson distributed fluff flush
|
||||
#define CRYPTONOTE_DANDELIONPP_EMBARGO_AVERAGE 173 // seconds (see tx_pool.cpp for more info)
|
||||
#define CRYPTONOTE_DANDELIONPP_EMBARGO_AVERAGE 39 // seconds (see tx_pool.cpp for more info)
|
||||
|
||||
// see src/cryptonote_protocol/levin_notify.cpp
|
||||
#define CRYPTONOTE_NOISE_MIN_EPOCH 5 // minutes
|
||||
@@ -132,6 +132,7 @@
|
||||
#define P2P_DEFAULT_HANDSHAKE_INTERVAL 60 //secondes
|
||||
#define P2P_DEFAULT_PACKET_MAX_SIZE 50000000 //50000000 bytes maximum packet size
|
||||
#define P2P_DEFAULT_PEERS_IN_HANDSHAKE 250
|
||||
#define P2P_MAX_PEERS_IN_HANDSHAKE 250
|
||||
#define P2P_DEFAULT_CONNECTION_TIMEOUT 5000 //5 seconds
|
||||
#define P2P_DEFAULT_SOCKS_CONNECT_TIMEOUT 45 // seconds
|
||||
#define P2P_DEFAULT_PING_CONNECTION_TIMEOUT 2000 //2 seconds
|
||||
|
||||
@@ -5376,7 +5376,7 @@ void Blockchain::cancel()
|
||||
}
|
||||
|
||||
#if defined(PER_BLOCK_CHECKPOINT)
|
||||
static const char expected_block_hashes_hash[] = "1d166275537bfbb5841d98da298c65089f3006d751776b2dc8a4f0275ef0ce58";
|
||||
static const char expected_block_hashes_hash[] = "6a6436850ed9df5975ca0c45513647c3d401ed8523ff5a793ad93136fa34fd3b";
|
||||
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
|
||||
{
|
||||
if (get_checkpoints == nullptr || !m_fast_sync)
|
||||
|
||||
@@ -1510,6 +1510,11 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::is_synchronized() const
|
||||
{
|
||||
return m_pprotocol != nullptr && m_pprotocol->is_synchronized();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
void core::on_synchronized()
|
||||
{
|
||||
m_miner.on_synchronized();
|
||||
@@ -1725,7 +1730,7 @@ namespace cryptonote
|
||||
m_starter_message_showed = true;
|
||||
}
|
||||
|
||||
m_txpool_auto_relayer.do_call(boost::bind(&core::relay_txpool_transactions, this));
|
||||
relay_txpool_transactions(); // txpool handles periodic DB checking
|
||||
m_check_updates_interval.do_call(boost::bind(&core::check_updates, this));
|
||||
m_check_disk_space_interval.do_call(boost::bind(&core::check_disk_space, this));
|
||||
m_block_rate_interval.do_call(boost::bind(&core::check_block_rate, this));
|
||||
|
||||
@@ -329,7 +329,7 @@ namespace cryptonote
|
||||
*
|
||||
* @note see Blockchain::get_current_blockchain_height()
|
||||
*/
|
||||
uint64_t get_current_blockchain_height() const;
|
||||
virtual uint64_t get_current_blockchain_height() const final;
|
||||
|
||||
/**
|
||||
* @brief get the hash and height of the most recent block
|
||||
@@ -637,6 +637,13 @@ namespace cryptonote
|
||||
*/
|
||||
std::string print_pool(bool short_format) const;
|
||||
|
||||
/**
|
||||
* @brief gets the core synchronization status
|
||||
*
|
||||
* @return core synchronization status
|
||||
*/
|
||||
virtual bool is_synchronized() const final;
|
||||
|
||||
/**
|
||||
* @copydoc miner::on_synchronized
|
||||
*
|
||||
@@ -663,7 +670,7 @@ namespace cryptonote
|
||||
*
|
||||
* @param target_blockchain_height the target height
|
||||
*/
|
||||
virtual uint64_t get_target_blockchain_height() const override;
|
||||
uint64_t get_target_blockchain_height() const;
|
||||
|
||||
/**
|
||||
* @brief returns the newest hardfork version known to the blockchain
|
||||
@@ -1065,7 +1072,6 @@ namespace cryptonote
|
||||
|
||||
epee::math_helper::once_a_time_seconds<60*60*12, false> m_store_blockchain_interval; //!< interval for manual storing of Blockchain, if enabled
|
||||
epee::math_helper::once_a_time_seconds<60*60*2, true> m_fork_moaner; //!< interval for checking HardFork status
|
||||
epee::math_helper::once_a_time_seconds<60*2, false> m_txpool_auto_relayer; //!< interval for checking re-relaying txpool transactions
|
||||
epee::math_helper::once_a_time_seconds<60*60*12, true> m_check_updates_interval; //!< interval for checking for new versions
|
||||
epee::math_helper::once_a_time_seconds<60*10, true> m_check_disk_space_interval; //!< interval for checking for disk space
|
||||
epee::math_helper::once_a_time_seconds<90, false> m_block_rate_interval; //!< interval for checking block rate
|
||||
|
||||
@@ -39,7 +39,8 @@ namespace cryptonote
|
||||
virtual ~i_core_events() noexcept
|
||||
{}
|
||||
|
||||
virtual uint64_t get_target_blockchain_height() const = 0;
|
||||
virtual uint64_t get_current_blockchain_height() const = 0;
|
||||
virtual bool is_synchronized() const = 0;
|
||||
virtual void on_transactions_relayed(epee::span<const cryptonote::blobdata> tx_blobs, relay_method tx_relay) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -75,11 +75,11 @@ namespace cryptonote
|
||||
not ideal since a blackhole is more likely to reveal earlier nodes in
|
||||
the chain.
|
||||
|
||||
This value was calculated with k=10, ep=0.10, and hop = 175 ms. A
|
||||
This value was calculated with k=5, ep=0.10, and hop = 175 ms. A
|
||||
testrun from a recent Intel laptop took ~80ms to
|
||||
receive+parse+proces+send transaction. At least 50ms will be added to
|
||||
the latency if crossing an ocean. So 175ms is the fudge factor for
|
||||
a single hop with 173s being the embargo timer. */
|
||||
a single hop with 39s being the embargo timer. */
|
||||
constexpr const std::chrono::seconds dandelionpp_embargo_average{CRYPTONOTE_DANDELIONPP_EMBARGO_AVERAGE};
|
||||
|
||||
//TODO: constants such as these should at least be in the header,
|
||||
@@ -91,6 +91,9 @@ namespace cryptonote
|
||||
time_t const MAX_RELAY_TIME = (60 * 60 * 4); // at most that many seconds between resends
|
||||
float const ACCEPT_THRESHOLD = 1.0f;
|
||||
|
||||
//! Max DB check interval for relayable txes
|
||||
constexpr const std::chrono::minutes max_relayable_check{2};
|
||||
|
||||
constexpr const std::chrono::seconds forward_delay_average{CRYPTONOTE_FORWARD_DELAY_AVERAGE};
|
||||
|
||||
// a kind of increasing backoff within min/max bounds
|
||||
@@ -115,12 +118,21 @@ namespace cryptonote
|
||||
else
|
||||
return get_min_block_weight(version) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
|
||||
}
|
||||
|
||||
// external lock must be held for the comparison+set to work properly
|
||||
void set_if_less(std::atomic<time_t>& next_check, const time_t candidate) noexcept
|
||||
{
|
||||
if (candidate < next_check.load(std::memory_order_relaxed))
|
||||
next_check = candidate;
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------------
|
||||
tx_memory_pool::tx_memory_pool(Blockchain& bchs): m_blockchain(bchs), m_cookie(0), m_txpool_max_weight(DEFAULT_TXPOOL_MAX_WEIGHT), m_txpool_weight(0), m_mine_stem_txes(false)
|
||||
tx_memory_pool::tx_memory_pool(Blockchain& bchs): m_blockchain(bchs), m_cookie(0), m_txpool_max_weight(DEFAULT_TXPOOL_MAX_WEIGHT), m_txpool_weight(0), m_mine_stem_txes(false), m_next_check(std::time(nullptr))
|
||||
{
|
||||
|
||||
// class code expects unsigned values throughout
|
||||
if (m_next_check < time_t(0))
|
||||
throw std::runtime_error{"Unexpected time_t (system clock) value"};
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::add_tx(transaction &tx, /*const crypto::hash& tx_prefix_hash,*/ const crypto::hash &id, const cryptonote::blobdata &blob, size_t tx_weight, tx_verification_context& tvc, relay_method tx_relay, bool relayed, uint8_t version)
|
||||
@@ -314,7 +326,10 @@ namespace cryptonote
|
||||
using clock = std::chrono::system_clock;
|
||||
auto last_relayed_time = std::numeric_limits<decltype(meta.last_relayed_time)>::max();
|
||||
if (tx_relay == relay_method::forward)
|
||||
{
|
||||
last_relayed_time = clock::to_time_t(clock::now() + crypto::random_poisson_seconds{forward_delay_average}());
|
||||
set_if_less(m_next_check, time_t(last_relayed_time));
|
||||
}
|
||||
// else the `set_relayed` function will adjust the time accordingly later
|
||||
|
||||
//update transactions container
|
||||
@@ -728,16 +743,22 @@ namespace cryptonote
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
//TODO: investigate whether boolean return is appropriate
|
||||
bool tx_memory_pool::get_relayable_transactions(std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>> &txs) const
|
||||
bool tx_memory_pool::get_relayable_transactions(std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>> &txs)
|
||||
{
|
||||
std::vector<std::pair<crypto::hash, txpool_tx_meta_t>> change_timestamps;
|
||||
using clock = std::chrono::system_clock;
|
||||
|
||||
const uint64_t now = time(NULL);
|
||||
if (uint64_t{std::numeric_limits<time_t>::max()} < now || time_t(now) < m_next_check)
|
||||
return false;
|
||||
|
||||
uint64_t next_check = clock::to_time_t(clock::from_time_t(time_t(now)) + max_relayable_check);
|
||||
std::vector<std::pair<crypto::hash, txpool_tx_meta_t>> change_timestamps;
|
||||
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
LockedTXN lock(m_blockchain.get_db());
|
||||
txs.reserve(m_blockchain.get_txpool_tx_count());
|
||||
m_blockchain.for_all_txpool_txes([this, now, &txs, &change_timestamps](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata_ref *){
|
||||
m_blockchain.for_all_txpool_txes([this, now, &txs, &change_timestamps, &next_check](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata_ref *){
|
||||
// 0 fee transactions are never relayed
|
||||
if(!meta.pruned && meta.fee > 0 && !meta.do_not_relay)
|
||||
{
|
||||
@@ -747,7 +768,10 @@ namespace cryptonote
|
||||
case relay_method::stem:
|
||||
case relay_method::forward:
|
||||
if (meta.last_relayed_time > now)
|
||||
{
|
||||
next_check = std::min(next_check, meta.last_relayed_time);
|
||||
return true; // continue to next tx
|
||||
}
|
||||
change_timestamps.emplace_back(txid, meta);
|
||||
break;
|
||||
default:
|
||||
@@ -792,6 +816,8 @@ namespace cryptonote
|
||||
elem.second.last_relayed_time = now + get_relay_delay(now, elem.second.receive_time);
|
||||
m_blockchain.update_txpool_tx(elem.first, elem.second);
|
||||
}
|
||||
|
||||
m_next_check = time_t(next_check);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
@@ -799,6 +825,7 @@ namespace cryptonote
|
||||
{
|
||||
crypto::random_poisson_seconds embargo_duration{dandelionpp_embargo_average};
|
||||
const auto now = std::chrono::system_clock::now();
|
||||
uint64_t next_relay = uint64_t{std::numeric_limits<time_t>::max()};
|
||||
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
@@ -815,7 +842,10 @@ namespace cryptonote
|
||||
meta.relayed = true;
|
||||
|
||||
if (meta.dandelionpp_stem)
|
||||
{
|
||||
meta.last_relayed_time = std::chrono::system_clock::to_time_t(now + embargo_duration());
|
||||
next_relay = std::min(next_relay, meta.last_relayed_time);
|
||||
}
|
||||
else
|
||||
meta.last_relayed_time = std::chrono::system_clock::to_time_t(now);
|
||||
|
||||
@@ -829,6 +859,7 @@ namespace cryptonote
|
||||
}
|
||||
}
|
||||
lock.commit();
|
||||
set_if_less(m_next_check, time_t(next_relay));
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
size_t tx_memory_pool::get_transactions_count(bool include_sensitive) const
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#pragma once
|
||||
#include "include_base_utils.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <set>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
@@ -329,11 +330,14 @@ namespace cryptonote
|
||||
* isn't old enough that relaying it is considered harmful
|
||||
* Note a transaction can be "relayable" even if do_not_relay is true
|
||||
*
|
||||
* This function will skip all DB checks if an insufficient amount of
|
||||
* time since the last call.
|
||||
*
|
||||
* @param txs return-by-reference the transactions and their hashes
|
||||
*
|
||||
* @return true
|
||||
* @return True if DB was checked, false if DB checks skipped.
|
||||
*/
|
||||
bool get_relayable_transactions(std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>>& txs) const;
|
||||
bool get_relayable_transactions(std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>>& txs);
|
||||
|
||||
/**
|
||||
* @brief tell the pool that certain transactions were just relayed
|
||||
@@ -609,6 +613,9 @@ private:
|
||||
mutable std::unordered_map<crypto::hash, std::tuple<bool, tx_verification_context, uint64_t, crypto::hash>> m_input_cache;
|
||||
|
||||
std::unordered_map<crypto::hash, transaction> m_parsed_tx_cache;
|
||||
|
||||
//! Next timestamp that a DB check for relayable txes is allowed
|
||||
std::atomic<time_t> m_next_check;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace cryptonote
|
||||
bool get_payload_sync_data(CORE_SYNC_DATA& hshd);
|
||||
bool on_callback(cryptonote_connection_context& context);
|
||||
t_core& get_core(){return m_core;}
|
||||
bool is_synchronized(){return m_synchronized;}
|
||||
virtual bool is_synchronized() const final { return !no_sync() && m_synchronized; }
|
||||
void log_connections();
|
||||
std::list<connection_info> get_connections();
|
||||
const block_queue &get_block_queue() const { return m_block_queue; }
|
||||
@@ -148,6 +148,7 @@ namespace cryptonote
|
||||
void notify_new_stripe(cryptonote_connection_context &context, uint32_t stripe);
|
||||
void skip_unneeded_hashes(cryptonote_connection_context& context, bool check_block_queue) const;
|
||||
bool request_txpool_complement(cryptonote_connection_context &context);
|
||||
void hit_score(cryptonote_connection_context &context, int32_t score);
|
||||
|
||||
t_core& m_core;
|
||||
|
||||
@@ -160,9 +161,10 @@ namespace cryptonote
|
||||
std::atomic<bool> m_ask_for_txpool_complement;
|
||||
boost::mutex m_sync_lock;
|
||||
block_queue m_block_queue;
|
||||
epee::math_helper::once_a_time_seconds<30> m_idle_peer_kicker;
|
||||
epee::math_helper::once_a_time_seconds<8> m_idle_peer_kicker;
|
||||
epee::math_helper::once_a_time_milliseconds<100> m_standby_checker;
|
||||
epee::math_helper::once_a_time_seconds<101> m_sync_search_checker;
|
||||
epee::math_helper::once_a_time_seconds<43> m_bad_peer_checker;
|
||||
std::atomic<unsigned int> m_max_out_peers;
|
||||
tools::PerformanceTimer m_sync_timer, m_add_timer;
|
||||
uint64_t m_last_add_end_time;
|
||||
@@ -183,6 +185,8 @@ namespace cryptonote
|
||||
double get_avg_block_size();
|
||||
boost::circular_buffer<size_t> m_avg_buffer = boost::circular_buffer<size_t>(10);
|
||||
|
||||
boost::mutex m_bad_peer_check_lock;
|
||||
|
||||
template<class t_parameter>
|
||||
bool post_notify(typename t_parameter::request& arg, cryptonote_connection_context& context)
|
||||
{
|
||||
|
||||
@@ -68,10 +68,12 @@
|
||||
#define BLOCK_QUEUE_FORCE_DOWNLOAD_NEAR_BLOCKS 1000
|
||||
#define REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD_STANDBY (5 * 1000000) // microseconds
|
||||
#define REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD (30 * 1000000) // microseconds
|
||||
#define IDLE_PEER_KICK_TIME (600 * 1000000) // microseconds
|
||||
#define IDLE_PEER_KICK_TIME (240 * 1000000) // microseconds
|
||||
#define NON_RESPONSIVE_PEER_KICK_TIME (20 * 1000000) // microseconds
|
||||
#define PASSIVE_PEER_KICK_TIME (60 * 1000000) // microseconds
|
||||
#define DROP_ON_SYNC_WEDGE_THRESHOLD (30 * 1000000000ull) // nanoseconds
|
||||
#define LAST_ACTIVITY_STALL_THRESHOLD (2.0f) // seconds
|
||||
#define DROP_PEERS_ON_SCORE -2
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
@@ -142,6 +144,8 @@ namespace cryptonote
|
||||
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;
|
||||
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
|
||||
context.m_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID;
|
||||
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
|
||||
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
|
||||
MLOG_PEER_STATE("requesting chain");
|
||||
@@ -326,6 +330,11 @@ namespace cryptonote
|
||||
}
|
||||
}
|
||||
|
||||
if (hshd.current_height < context.m_remote_blockchain_height)
|
||||
{
|
||||
MINFO(context << "Claims " << hshd.current_height << ", claimed " << context.m_remote_blockchain_height << " before");
|
||||
hit_score(context, 1);
|
||||
}
|
||||
context.m_remote_blockchain_height = hshd.current_height;
|
||||
context.m_pruning_seed = hshd.pruning_seed;
|
||||
#ifdef CRYPTONOTE_PRUNING_DEBUG_SPOOF_SEED
|
||||
@@ -427,10 +436,10 @@ namespace cryptonote
|
||||
template<class t_core>
|
||||
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context)
|
||||
{
|
||||
MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, "Received NOTIFY_NEW_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
|
||||
MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, context << "Received NOTIFY_NEW_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
|
||||
if(context.m_state != cryptonote_connection_context::state_normal)
|
||||
return 1;
|
||||
if(!is_synchronized() || m_no_sync) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks
|
||||
if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks
|
||||
{
|
||||
LOG_DEBUG_CC(context, "Received new block while syncing, ignored");
|
||||
return 1;
|
||||
@@ -487,6 +496,8 @@ namespace cryptonote
|
||||
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(?)
|
||||
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
|
||||
context.m_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID;
|
||||
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
|
||||
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
|
||||
MLOG_PEER_STATE("requesting chain");
|
||||
@@ -498,10 +509,10 @@ namespace cryptonote
|
||||
template<class t_core>
|
||||
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_fluffy_block(int command, NOTIFY_NEW_FLUFFY_BLOCK::request& arg, cryptonote_connection_context& context)
|
||||
{
|
||||
MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, "Received NOTIFY_NEW_FLUFFY_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
|
||||
MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, context << "Received NOTIFY_NEW_FLUFFY_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
|
||||
if(context.m_state != cryptonote_connection_context::state_normal)
|
||||
return 1;
|
||||
if(!is_synchronized() || m_no_sync) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks
|
||||
if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks
|
||||
{
|
||||
LOG_DEBUG_CC(context, "Received new block while syncing, ignored");
|
||||
return 1;
|
||||
@@ -765,6 +776,8 @@ namespace cryptonote
|
||||
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;
|
||||
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
|
||||
context.m_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID;
|
||||
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
|
||||
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
|
||||
MLOG_PEER_STATE("requesting chain");
|
||||
@@ -929,7 +942,7 @@ namespace cryptonote
|
||||
// while syncing, core will lock for a long time, so we ignore
|
||||
// those txes as they aren't really needed anyway, and avoid a
|
||||
// long block before replying
|
||||
if(!is_synchronized() || m_no_sync)
|
||||
if(!is_synchronized())
|
||||
{
|
||||
LOG_DEBUG_CC(context, "Received new tx while syncing, ignored");
|
||||
return 1;
|
||||
@@ -1029,6 +1042,7 @@ namespace cryptonote
|
||||
drop_connection(context, false, false);
|
||||
return 1;
|
||||
}
|
||||
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
|
||||
MLOG_P2P_MESSAGE("-->>NOTIFY_RESPONSE_GET_OBJECTS: blocks.size()="
|
||||
<< rsp.blocks.size() << ", rsp.m_current_blockchain_height=" << rsp.current_blockchain_height
|
||||
<< ", missed_ids.size()=" << rsp.missed_ids.size());
|
||||
@@ -1062,6 +1076,14 @@ namespace cryptonote
|
||||
boost::posix_time::ptime request_time = context.m_last_request_time;
|
||||
context.m_last_request_time = boost::date_time::not_a_date_time;
|
||||
|
||||
if (context.m_expect_response != NOTIFY_RESPONSE_GET_OBJECTS::ID)
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("Got NOTIFY_RESPONSE_GET_OBJECTS out of the blue, dropping connection");
|
||||
drop_connection(context, true, false);
|
||||
return 1;
|
||||
}
|
||||
context.m_expect_response = 0;
|
||||
|
||||
// calculate size of request
|
||||
size_t size = 0;
|
||||
size_t blocks_size = 0;
|
||||
@@ -1107,6 +1129,11 @@ namespace cryptonote
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (arg.current_blockchain_height < context.m_remote_blockchain_height)
|
||||
{
|
||||
MINFO(context << "Claims " << arg.current_blockchain_height << ", claimed " << context.m_remote_blockchain_height << " before");
|
||||
hit_score(context, 1);
|
||||
}
|
||||
context.m_remote_blockchain_height = arg.current_blockchain_height;
|
||||
if (context.m_remote_blockchain_height > m_core.get_target_blockchain_height())
|
||||
m_core.set_target_blockchain_height(context.m_remote_blockchain_height);
|
||||
@@ -1666,24 +1693,45 @@ skip:
|
||||
bool t_cryptonote_protocol_handler<t_core>::kick_idle_peers()
|
||||
{
|
||||
MTRACE("Checking for idle peers...");
|
||||
std::vector<std::pair<boost::uuids::uuid, unsigned>> idle_peers;
|
||||
m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
|
||||
{
|
||||
if (context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time != boost::date_time::not_a_date_time)
|
||||
{
|
||||
const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
|
||||
const boost::posix_time::time_duration dt = now - context.m_last_request_time;
|
||||
if (dt.total_microseconds() > IDLE_PEER_KICK_TIME)
|
||||
const auto ms = dt.total_microseconds();
|
||||
if (ms > IDLE_PEER_KICK_TIME || (context.m_expect_response && ms > NON_RESPONSIVE_PEER_KICK_TIME))
|
||||
{
|
||||
MINFO(context << " kicking idle peer, last update " << (dt.total_microseconds() / 1.e6) << " seconds ago");
|
||||
LOG_PRINT_CCONTEXT_L2("requesting callback");
|
||||
context.m_last_request_time = boost::date_time::not_a_date_time;
|
||||
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);
|
||||
if (context.m_score-- >= 0)
|
||||
{
|
||||
MINFO(context << " kicking idle peer, last update " << (dt.total_microseconds() / 1.e6) << " seconds ago, expecting " << (int)context.m_expect_response);
|
||||
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_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);
|
||||
}
|
||||
else
|
||||
{
|
||||
idle_peers.push_back(std::make_pair(context.m_connection_id, context.m_expect_response == 0 ? 1 : 5));
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
for (const auto &e: idle_peers)
|
||||
{
|
||||
const auto &uuid = e.first;
|
||||
m_p2p->for_connection(uuid, [&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t f)->bool{
|
||||
MINFO(ctx << "dropping idle peer with negative score");
|
||||
drop_connection_with_score(ctx, e.second, false);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -2206,6 +2254,7 @@ skip:
|
||||
}
|
||||
}
|
||||
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
|
||||
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());
|
||||
//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());
|
||||
@@ -2296,6 +2345,7 @@ skip:
|
||||
//LOG_PRINT_CCONTEXT_L1("r = " << 200);
|
||||
|
||||
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
|
||||
context.m_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID;
|
||||
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() << ", start_from_current_chain " << start_from_current_chain);
|
||||
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
|
||||
MLOG_PEER_STATE("requesting chain");
|
||||
@@ -2321,7 +2371,7 @@ skip:
|
||||
}
|
||||
else
|
||||
{
|
||||
MINFO(context << " we've reached this peer's blockchain height");
|
||||
MINFO(context << " we've reached this peer's blockchain height (theirs " << context.m_remote_blockchain_height << ", our target " << m_core.get_target_blockchain_height());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -2418,6 +2468,14 @@ skip:
|
||||
<< ", m_start_height=" << arg.start_height << ", m_total_height=" << arg.total_height);
|
||||
MLOG_PEER_STATE("received chain");
|
||||
|
||||
if (context.m_expect_response != NOTIFY_RESPONSE_CHAIN_ENTRY::ID)
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("Got NOTIFY_RESPONSE_CHAIN_ENTRY out of the blue, dropping connection");
|
||||
drop_connection(context, true, false);
|
||||
return 1;
|
||||
}
|
||||
context.m_expect_response = 0;
|
||||
|
||||
context.m_last_request_time = boost::date_time::not_a_date_time;
|
||||
|
||||
m_sync_download_chain_size += arg.m_block_ids.size() * sizeof(crypto::hash);
|
||||
@@ -2448,6 +2506,11 @@ skip:
|
||||
drop_connection(context, false, false);
|
||||
return 1;
|
||||
}
|
||||
if (arg.total_height < context.m_remote_blockchain_height)
|
||||
{
|
||||
MINFO(context << "Claims " << arg.total_height << ", claimed " << context.m_remote_blockchain_height << " before");
|
||||
hit_score(context, 1);
|
||||
}
|
||||
context.m_remote_blockchain_height = arg.total_height;
|
||||
context.m_last_response_height = arg.start_height + arg.m_block_ids.size()-1;
|
||||
if(context.m_last_response_height > context.m_remote_blockchain_height)
|
||||
@@ -2564,6 +2627,19 @@ skip:
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
void t_cryptonote_protocol_handler<t_core>::hit_score(cryptonote_connection_context &context, int32_t score)
|
||||
{
|
||||
if (score <= 0)
|
||||
{
|
||||
MERROR("Negative score hit");
|
||||
return;
|
||||
}
|
||||
context.m_score -= score;
|
||||
if (context.m_score <= DROP_PEERS_ON_SCORE)
|
||||
drop_connection_with_score(context, 5, false);
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
std::string t_cryptonote_protocol_handler<t_core>::get_peers_overview() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace cryptonote
|
||||
/************************************************************************/
|
||||
struct i_cryptonote_protocol
|
||||
{
|
||||
virtual bool is_synchronized() const = 0;
|
||||
virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context)=0;
|
||||
virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, const boost::uuids::uuid& source, epee::net_utils::zone zone, relay_method tx_relay)=0;
|
||||
//virtual bool request_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote_connection_context& context)=0;
|
||||
@@ -50,6 +51,10 @@ namespace cryptonote
|
||||
/************************************************************************/
|
||||
struct cryptonote_protocol_stub: public i_cryptonote_protocol
|
||||
{
|
||||
virtual bool is_synchronized() const final
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context)
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -105,8 +105,44 @@ namespace levin
|
||||
return std::chrono::steady_clock::duration{crypto::rand_range(rep(0), range.count())};
|
||||
}
|
||||
|
||||
//! \return Outgoing connections supporting fragments in `connections` filtered by remote blockchain height.
|
||||
std::vector<boost::uuids::uuid> get_out_connections(connections& p2p, uint64_t min_blockchain_height)
|
||||
uint64_t get_median_remote_height(connections& p2p)
|
||||
{
|
||||
std::vector<uint64_t> remote_heights;
|
||||
remote_heights.reserve(connection_id_reserve_size);
|
||||
p2p.foreach_connection([&remote_heights] (detail::p2p_context& context) {
|
||||
if (!context.m_is_income)
|
||||
{
|
||||
remote_heights.emplace_back(context.m_remote_blockchain_height);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (remote_heights.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const size_t n = remote_heights.size() / 2;
|
||||
std::sort(remote_heights.begin(), remote_heights.end());
|
||||
if (remote_heights.size() % 2 != 0)
|
||||
{
|
||||
return remote_heights[n];
|
||||
}
|
||||
return remote_heights[n-1];
|
||||
}
|
||||
|
||||
uint64_t get_blockchain_height(connections& p2p, const i_core_events* core)
|
||||
{
|
||||
const uint64_t local_blockchain_height = core->get_current_blockchain_height();
|
||||
if (core->is_synchronized())
|
||||
{
|
||||
return local_blockchain_height;
|
||||
}
|
||||
return std::max(local_blockchain_height, get_median_remote_height(p2p));
|
||||
}
|
||||
|
||||
//! \return Outgoing connections supporting fragments in `connections` filtered by blockchain height.
|
||||
std::vector<boost::uuids::uuid> get_out_connections(connections& p2p, uint64_t blockchain_height)
|
||||
{
|
||||
std::vector<boost::uuids::uuid> outs;
|
||||
outs.reserve(connection_id_reserve_size);
|
||||
@@ -115,15 +151,21 @@ namespace levin
|
||||
the reserve call so a strand is not used. Investigate if there is lots
|
||||
of waiting in here. */
|
||||
|
||||
p2p.foreach_connection([&outs, min_blockchain_height] (detail::p2p_context& context) {
|
||||
if (!context.m_is_income && context.m_remote_blockchain_height >= min_blockchain_height)
|
||||
p2p.foreach_connection([&outs, blockchain_height] (detail::p2p_context& context) {
|
||||
if (!context.m_is_income && context.m_remote_blockchain_height >= blockchain_height)
|
||||
outs.emplace_back(context.m_connection_id);
|
||||
return true;
|
||||
});
|
||||
|
||||
MDEBUG("Found " << outs.size() << " out connections having height >= " << blockchain_height);
|
||||
return outs;
|
||||
}
|
||||
|
||||
std::vector<boost::uuids::uuid> get_out_connections(connections& p2p, const i_core_events* core)
|
||||
{
|
||||
return get_out_connections(p2p, get_blockchain_height(p2p, core));
|
||||
}
|
||||
|
||||
std::string make_tx_payload(std::vector<blobdata>&& txs, const bool pad, const bool fluff)
|
||||
{
|
||||
NOTIFY_NEW_TRANSACTIONS::request request{};
|
||||
@@ -233,7 +275,7 @@ namespace levin
|
||||
{
|
||||
struct zone
|
||||
{
|
||||
explicit zone(boost::asio::io_service& io_service, std::shared_ptr<connections> p2p, epee::byte_slice noise_in, bool is_public, bool pad_txs)
|
||||
explicit zone(boost::asio::io_service& io_service, std::shared_ptr<connections> p2p, epee::byte_slice noise_in, epee::net_utils::zone zone, bool pad_txs)
|
||||
: p2p(std::move(p2p)),
|
||||
noise(std::move(noise_in)),
|
||||
next_epoch(io_service),
|
||||
@@ -243,7 +285,7 @@ namespace levin
|
||||
channels(),
|
||||
connection_count(0),
|
||||
flush_callbacks(0),
|
||||
is_public(is_public),
|
||||
nzone(zone),
|
||||
pad_txs(pad_txs),
|
||||
fluffing(false)
|
||||
{
|
||||
@@ -260,7 +302,7 @@ namespace levin
|
||||
std::deque<noise_channel> channels; //!< Never touch after init; only update elements on `noise_channel.strand`
|
||||
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 epee::net_utils::zone nzone; //!< Zone is public ipv4/ipv6 connections, or i2p or tor
|
||||
const bool pad_txs; //!< Pad txs to the next boundary for privacy
|
||||
bool fluffing; //!< Zone is in Dandelion++ fluff epoch
|
||||
};
|
||||
@@ -297,7 +339,8 @@ namespace levin
|
||||
if (!channel.connection.is_nil())
|
||||
channel.queue.push_back(std::move(message_));
|
||||
else if (destination_ == 0 && zone_->connection_count == 0)
|
||||
MWARNING("Unable to send transaction(s) over anonymity network - no available outbound connections");
|
||||
MWARNING("Unable to send transaction(s) to " << epee::net_utils::zone_to_string(zone_->nzone) <<
|
||||
" - no available outbound connections");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -399,7 +442,7 @@ namespace levin
|
||||
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))
|
||||
if (source != context.m_connection_id && (zone->nzone == epee::net_utils::zone::public_ || !context.m_is_income))
|
||||
{
|
||||
if (context.fluff_txs.empty())
|
||||
context.flush_time = now + (context.m_is_income ? in_duration() : out_duration());
|
||||
@@ -526,7 +569,7 @@ namespace levin
|
||||
}
|
||||
|
||||
// connection list may be outdated, try again
|
||||
update_channels::run(zone_, get_out_connections(*zone_->p2p, core_->get_target_blockchain_height()));
|
||||
update_channels::run(zone_, get_out_connections(*zone_->p2p, core_));
|
||||
}
|
||||
|
||||
MERROR("Unable to send transaction(s) via Dandelion++ stem");
|
||||
@@ -562,7 +605,7 @@ namespace levin
|
||||
|
||||
assert(zone_->strand.running_in_this_thread());
|
||||
|
||||
if (zone_->is_public)
|
||||
if (zone_->nzone == epee::net_utils::zone::public_)
|
||||
MDEBUG("Starting new Dandelion++ epoch: " << (fluffing_ ? "fluff" : "stem"));
|
||||
|
||||
zone_->map = std::move(map_);
|
||||
@@ -630,10 +673,12 @@ namespace levin
|
||||
{
|
||||
channel.active = nullptr;
|
||||
channel.connection = boost::uuids::nil_uuid();
|
||||
auto height = get_blockchain_height(*zone_->p2p, core_);
|
||||
|
||||
auto connections = get_out_connections(*zone_->p2p, core_->get_target_blockchain_height());
|
||||
auto connections = get_out_connections(*zone_->p2p, height);
|
||||
if (connections.empty())
|
||||
MWARNING("Lost all outbound connections to anonymity network - currently unable to send transaction(s)");
|
||||
MWARNING("Unable to send transaction(s) to " << epee::net_utils::zone_to_string(zone_->nzone) <<
|
||||
" - no suitable outbound connections at height " << height);
|
||||
|
||||
zone_->strand.post(update_channels{zone_, std::move(connections)});
|
||||
}
|
||||
@@ -664,7 +709,7 @@ namespace levin
|
||||
|
||||
const bool fluffing = crypto::rand_idx(unsigned(100)) < CRYPTONOTE_DANDELIONPP_FLUFF_PROBABILITY;
|
||||
const auto start = std::chrono::steady_clock::now();
|
||||
auto connections = get_out_connections(*(zone_->p2p), core_->get_target_blockchain_height());
|
||||
auto connections = get_out_connections(*(zone_->p2p), core_);
|
||||
zone_->strand.dispatch(
|
||||
change_channels{zone_, net::dandelionpp::connection_map{std::move(connections), count_}, fluffing}
|
||||
);
|
||||
@@ -676,15 +721,15 @@ namespace levin
|
||||
};
|
||||
} // anonymous
|
||||
|
||||
notify::notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, const bool is_public, const bool pad_txs, i_core_events& core)
|
||||
: zone_(std::make_shared<detail::zone>(service, std::move(p2p), std::move(noise), is_public, pad_txs))
|
||||
notify::notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, epee::net_utils::zone zone, const bool pad_txs, i_core_events& core)
|
||||
: zone_(std::make_shared<detail::zone>(service, std::move(p2p), std::move(noise), zone, pad_txs))
|
||||
, core_(std::addressof(core))
|
||||
{
|
||||
if (!zone_->p2p)
|
||||
throw std::logic_error{"cryptonote::levin::notify cannot have nullptr p2p argument"};
|
||||
|
||||
const bool noise_enabled = !zone_->noise.empty();
|
||||
if (noise_enabled || is_public)
|
||||
if (noise_enabled || zone == epee::net_utils::zone::public_)
|
||||
{
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
const auto min_epoch = noise_enabled ? noise_min_epoch : dandelionpp_min_epoch;
|
||||
@@ -715,7 +760,7 @@ namespace levin
|
||||
return;
|
||||
|
||||
zone_->strand.dispatch(
|
||||
update_channels{zone_, get_out_connections(*(zone_->p2p), core_->get_target_blockchain_height())}
|
||||
update_channels{zone_, get_out_connections(*(zone_->p2p), core_)}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -806,7 +851,7 @@ namespace levin
|
||||
case relay_method::stem:
|
||||
case relay_method::forward:
|
||||
case relay_method::local:
|
||||
if (zone_->is_public)
|
||||
if (zone_->nzone == epee::net_utils::zone::public_)
|
||||
{
|
||||
// this will change a local/forward tx to stem or fluff ...
|
||||
zone_->strand.dispatch(
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace levin
|
||||
{}
|
||||
|
||||
//! Construct an instance with available notification `zones`.
|
||||
explicit notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, bool is_public, bool pad_txs, i_core_events& core);
|
||||
explicit notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, epee::net_utils::zone zone, bool pad_txs, i_core_events& core);
|
||||
|
||||
notify(const notify&) = delete;
|
||||
notify(notify&&) = default;
|
||||
|
||||
+2
-1
@@ -66,10 +66,12 @@ uint16_t parse_public_rpc_port(const po::variables_map &vm)
|
||||
}
|
||||
|
||||
std::string rpc_port_str;
|
||||
std::string rpc_bind_address = command_line::get_arg(vm, cryptonote::rpc_args::descriptors().rpc_bind_ip);
|
||||
const auto &restricted_rpc_port = cryptonote::core_rpc_server::arg_rpc_restricted_bind_port;
|
||||
if (!command_line::is_arg_defaulted(vm, restricted_rpc_port))
|
||||
{
|
||||
rpc_port_str = command_line::get_arg(vm, restricted_rpc_port);
|
||||
rpc_bind_address = command_line::get_arg(vm, cryptonote::rpc_args::descriptors().rpc_restricted_bind_ip);
|
||||
}
|
||||
else if (command_line::get_arg(vm, cryptonote::core_rpc_server::arg_restricted_rpc))
|
||||
{
|
||||
@@ -86,7 +88,6 @@ uint16_t parse_public_rpc_port(const po::variables_map &vm)
|
||||
throw std::runtime_error("invalid RPC port " + rpc_port_str);
|
||||
}
|
||||
|
||||
const auto rpc_bind_address = command_line::get_arg(vm, cryptonote::rpc_args::descriptors().rpc_bind_ip);
|
||||
const auto address = net::get_network_address(rpc_bind_address, rpc_port);
|
||||
if (!address) {
|
||||
throw std::runtime_error("failed to parse RPC bind address");
|
||||
|
||||
+2
-2
@@ -149,7 +149,7 @@ namespace nodetool
|
||||
{
|
||||
config_t()
|
||||
: m_net_config(),
|
||||
m_peer_id(crypto::rand<uint64_t>()),
|
||||
m_peer_id(1),
|
||||
m_support_flags(0)
|
||||
{}
|
||||
|
||||
@@ -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(const epee::net_utils::network_address &adress, time_t seconds = P2P_IP_BLOCKTIME);
|
||||
virtual bool block_host(epee::net_utils::network_address address, time_t seconds = P2P_IP_BLOCKTIME);
|
||||
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);
|
||||
|
||||
+84
-53
@@ -139,7 +139,9 @@ namespace nodetool
|
||||
if (storage)
|
||||
m_peerlist_storage = std::move(*storage);
|
||||
|
||||
m_network_zones[epee::net_utils::zone::public_].m_config.m_support_flags = P2P_SUPPORT_FLAGS;
|
||||
network_zone& public_zone = m_network_zones[epee::net_utils::zone::public_];
|
||||
public_zone.m_config.m_support_flags = P2P_SUPPORT_FLAGS;
|
||||
public_zone.m_config.m_peer_id = crypto::rand<uint64_t>();
|
||||
m_first_connection_maker_call = true;
|
||||
|
||||
CATCH_ENTRY_L0("node_server::init_config", false);
|
||||
@@ -224,7 +226,7 @@ namespace nodetool
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
bool node_server<t_payload_net_handler>::block_host(const 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)
|
||||
{
|
||||
if(!addr.is_blockable())
|
||||
return false;
|
||||
@@ -237,7 +239,8 @@ namespace nodetool
|
||||
limit = std::numeric_limits<time_t>::max();
|
||||
else
|
||||
limit = now + seconds;
|
||||
m_blocked_hosts[addr.host_str()] = limit;
|
||||
const std::string host_str = addr.host_str();
|
||||
m_blocked_hosts[host_str] = 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
|
||||
@@ -253,17 +256,18 @@ namespace nodetool
|
||||
}
|
||||
return true;
|
||||
});
|
||||
for (const auto &c: conns)
|
||||
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);
|
||||
|
||||
for (const auto &c: conns)
|
||||
zone.second.m_net_server.get_config_object().close(c);
|
||||
|
||||
conns.clear();
|
||||
}
|
||||
|
||||
MCLOG_CYAN(el::Level::Info, "global", "Host " << addr.host_str() << " blocked.");
|
||||
MCLOG_CYAN(el::Level::Info, "global", "Host " << host_str << " blocked.");
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
@@ -402,7 +406,7 @@ namespace nodetool
|
||||
m_use_ipv6 = command_line::get_arg(vm, arg_p2p_use_ipv6);
|
||||
m_require_ipv4 = !command_line::get_arg(vm, arg_p2p_ignore_ipv4);
|
||||
public_zone.m_notifier = cryptonote::levin::notify{
|
||||
public_zone.m_net_server.get_io_service(), public_zone.m_net_server.get_config_shared(), nullptr, true, pad_txs, m_payload_handler.get_core()
|
||||
public_zone.m_net_server.get_io_service(), public_zone.m_net_server.get_config_shared(), nullptr, epee::net_utils::zone::public_, pad_txs, m_payload_handler.get_core()
|
||||
};
|
||||
|
||||
if (command_line::has_arg(vm, arg_p2p_add_peer))
|
||||
@@ -545,7 +549,7 @@ namespace nodetool
|
||||
}
|
||||
|
||||
zone.m_notifier = cryptonote::levin::notify{
|
||||
zone.m_net_server.get_io_service(), zone.m_net_server.get_config_shared(), std::move(this_noise), false, pad_txs, m_payload_handler.get_core()
|
||||
zone.m_net_server.get_io_service(), zone.m_net_server.get_config_shared(), std::move(this_noise), proxy.zone, pad_txs, m_payload_handler.get_core()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -671,11 +675,6 @@ namespace nodetool
|
||||
full_addrs.insert("209.250.243.248:18080");
|
||||
full_addrs.insert("104.238.221.81:18080");
|
||||
full_addrs.insert("66.85.74.134:18080");
|
||||
full_addrs.insert("xwvz3ekocr3dkyxfkmgm2hvbpzx2ysqmaxgter7znnqrhoicygkfswid.onion:18083");
|
||||
full_addrs.insert("4pixvbejrvihnkxmduo2agsnmc3rrulrqc7s3cbwwrep6h6hrzsibeqd.onion:18083");
|
||||
full_addrs.insert("s3l6ke4ed3df466khuebb4poienoingwof7oxtbo6j4n56sghe3a.b32.i2p:18080");
|
||||
full_addrs.insert("sel36x6fibfzujwvt4hf5gxolz6kd3jpvbjqg6o3ud2xtionyl2q.b32.i2p:18080");
|
||||
full_addrs.insert("zbjkbsxc5munw3qusl7j2hpcmikhqocdf4pqhnhtpzw5nt5jrmofptid.onion:18083");
|
||||
}
|
||||
return full_addrs;
|
||||
}
|
||||
@@ -797,8 +796,23 @@ namespace nodetool
|
||||
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;
|
||||
@@ -1125,11 +1139,12 @@ namespace nodetool
|
||||
pi = context.peer_id = rsp.node_data.peer_id;
|
||||
context.m_rpc_port = rsp.node_data.rpc_port;
|
||||
context.m_rpc_credits_per_hash = rsp.node_data.rpc_credits_per_hash;
|
||||
network_zone& zone = m_network_zones.at(context.m_remote_address.get_zone());
|
||||
const auto azone = context.m_remote_address.get_zone();
|
||||
network_zone& zone = m_network_zones.at(azone);
|
||||
zone.m_peerlist.set_peer_just_seen(rsp.node_data.peer_id, context.m_remote_address, context.m_pruning_seed, context.m_rpc_port, context.m_rpc_credits_per_hash);
|
||||
|
||||
// move
|
||||
if(rsp.node_data.peer_id == zone.m_config.m_peer_id)
|
||||
if(azone == epee::net_utils::zone::public_ && rsp.node_data.peer_id == zone.m_config.m_peer_id)
|
||||
{
|
||||
LOG_DEBUG_CC(context, "Connection to self detected, dropping connection");
|
||||
hsh_result = false;
|
||||
@@ -1221,50 +1236,51 @@ namespace nodetool
|
||||
template<class t_payload_net_handler>
|
||||
bool node_server<t_payload_net_handler>::is_peer_used(const peerlist_entry& peer)
|
||||
{
|
||||
for(const auto& zone : m_network_zones)
|
||||
if(zone.second.m_config.m_peer_id == peer.id)
|
||||
return true;//dont make connections to ourself
|
||||
const auto zone = peer.adr.get_zone();
|
||||
const auto server = m_network_zones.find(zone);
|
||||
if (server == m_network_zones.end())
|
||||
return false;
|
||||
|
||||
const bool is_public = (zone == epee::net_utils::zone::public_);
|
||||
if(is_public && server->second.m_config.m_peer_id == peer.id)
|
||||
return true;//dont make connections to ourself
|
||||
|
||||
bool used = false;
|
||||
for(auto& zone : m_network_zones)
|
||||
server->second.m_net_server.get_config_object().foreach_connection([&, is_public](const p2p_connection_context& cntxt)
|
||||
{
|
||||
zone.second.m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
|
||||
if((is_public && cntxt.peer_id == peer.id) || (!cntxt.m_is_income && peer.adr == cntxt.m_remote_address))
|
||||
{
|
||||
if(cntxt.peer_id == peer.id || (!cntxt.m_is_income && peer.adr == cntxt.m_remote_address))
|
||||
{
|
||||
used = true;
|
||||
return false;//stop enumerating
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if(used)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
used = true;
|
||||
return false;//stop enumerating
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return used;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
bool node_server<t_payload_net_handler>::is_peer_used(const anchor_peerlist_entry& peer)
|
||||
{
|
||||
for(auto& zone : m_network_zones) {
|
||||
if(zone.second.m_config.m_peer_id == peer.id) {
|
||||
return true;//dont make connections to ourself
|
||||
}
|
||||
bool used = false;
|
||||
zone.second.m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
|
||||
const auto zone = peer.adr.get_zone();
|
||||
const auto server = m_network_zones.find(zone);
|
||||
if (server == m_network_zones.end())
|
||||
return false;
|
||||
|
||||
const bool is_public = (zone == epee::net_utils::zone::public_);
|
||||
if(is_public && server->second.m_config.m_peer_id == peer.id)
|
||||
return true;//dont make connections to ourself
|
||||
|
||||
bool used = false;
|
||||
server->second.m_net_server.get_config_object().foreach_connection([&, is_public](const p2p_connection_context& cntxt)
|
||||
{
|
||||
if((is_public && cntxt.peer_id == peer.id) || (!cntxt.m_is_income && peer.adr == cntxt.m_remote_address))
|
||||
{
|
||||
if(cntxt.peer_id == peer.id || (!cntxt.m_is_income && peer.adr == cntxt.m_remote_address))
|
||||
{
|
||||
used = true;
|
||||
return false;//stop enumerating
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (used)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
used = true;
|
||||
return false;//stop enumerating
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return used;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
@@ -1302,11 +1318,17 @@ namespace nodetool
|
||||
{
|
||||
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;
|
||||
|
||||
if (zone.m_our_address == na)
|
||||
return false;
|
||||
|
||||
if (zone.m_current_number_of_out_peers == zone.m_config.m_net_config.max_out_connection_count) // out peers limit
|
||||
{
|
||||
return false;
|
||||
@@ -1634,6 +1656,9 @@ namespace nodetool
|
||||
peerid_to_string(pe.id) << " " << pe.adr.str() << ", pruning seed " << epee::string_tools::to_string_hex(pe.pruning_seed) <<
|
||||
" (stripe " << next_needed_pruning_stripe << " needed)");
|
||||
|
||||
if(zone.m_our_address == pe.adr)
|
||||
continue;
|
||||
|
||||
if(is_peer_used(pe)) {
|
||||
_note("Peer is used");
|
||||
continue;
|
||||
@@ -2047,6 +2072,11 @@ namespace nodetool
|
||||
template<class t_payload_net_handler>
|
||||
bool node_server<t_payload_net_handler>::handle_remote_peerlist(const std::vector<peerlist_entry>& peerlist, const epee::net_utils::connection_context_base& context)
|
||||
{
|
||||
if (peerlist.size() > P2P_MAX_PEERS_IN_HANDSHAKE)
|
||||
{
|
||||
MWARNING(context << "peer sent " << peerlist.size() << " peers, considered spamming");
|
||||
return false;
|
||||
}
|
||||
std::vector<peerlist_entry> peerlist_ = peerlist;
|
||||
if(!sanitize_peerlist(peerlist_))
|
||||
return false;
|
||||
@@ -2407,11 +2437,12 @@ namespace nodetool
|
||||
return 1;
|
||||
}
|
||||
|
||||
network_zone& zone = m_network_zones.at(context.m_remote_address.get_zone());
|
||||
const auto azone = context.m_remote_address.get_zone();
|
||||
network_zone& zone = m_network_zones.at(azone);
|
||||
|
||||
// test only the remote end's zone, otherwise an attacker could connect to you on clearnet
|
||||
// and pass in a tor connection's peer id, and deduce the two are the same if you reject it
|
||||
if(arg.node_data.peer_id == zone.m_config.m_peer_id)
|
||||
if(azone == epee::net_utils::zone::public_ && arg.node_data.peer_id == zone.m_config.m_peer_id)
|
||||
{
|
||||
LOG_DEBUG_CC(context, "Connection to self detected, dropping connection");
|
||||
drop_connection(context);
|
||||
|
||||
@@ -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(const 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)=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(const epee::net_utils::network_address &address, time_t seconds)
|
||||
virtual bool block_host(epee::net_utils::network_address address, time_t seconds)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -288,6 +288,19 @@ namespace nodetool
|
||||
copy_peers(peers.gray, m_peers_gray.get<by_addr>());
|
||||
copy_peers(peers.anchor, m_peers_anchor.get<by_addr>());
|
||||
}
|
||||
|
||||
void peerlist_manager::evict_host_from_white_peerlist(const peerlist_entry& pr)
|
||||
{
|
||||
peers_indexed::index<by_time>::type& sorted_index=m_peers_white.get<by_time>();
|
||||
auto i = sorted_index.begin();
|
||||
while (i != sorted_index.end())
|
||||
{
|
||||
if (i->adr.is_same_host(pr.adr))
|
||||
i = sorted_index.erase(i);
|
||||
else
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_CLASS_VERSION(nodetool::peerlist_types, nodetool::CURRENT_PEERLIST_STORAGE_ARCHIVE_VER);
|
||||
|
||||
@@ -109,6 +109,7 @@ namespace nodetool
|
||||
bool get_white_peer_by_index(peerlist_entry& p, size_t i);
|
||||
bool get_gray_peer_by_index(peerlist_entry& p, size_t i);
|
||||
template<typename F> bool foreach(bool white, const F &f);
|
||||
void evict_host_from_white_peerlist(const peerlist_entry& pr);
|
||||
bool append_with_peer_white(const peerlist_entry& pr);
|
||||
bool append_with_peer_gray(const peerlist_entry& pr);
|
||||
bool append_with_peer_anchor(const anchor_peerlist_entry& ple);
|
||||
@@ -345,6 +346,7 @@ namespace nodetool
|
||||
if(by_addr_it_wt == m_peers_white.get<by_addr>().end())
|
||||
{
|
||||
//put new record into white list
|
||||
evict_host_from_white_peerlist(ple);
|
||||
m_peers_white.insert(ple);
|
||||
trim_white_peerlist();
|
||||
}else
|
||||
|
||||
@@ -45,12 +45,12 @@ namespace cryptonote
|
||||
return host + ":" + m_http_client.get_port();
|
||||
}
|
||||
|
||||
boost::optional<uint64_t> bootstrap_daemon::get_height()
|
||||
boost::optional<std::pair<uint64_t, uint64_t>> bootstrap_daemon::get_height()
|
||||
{
|
||||
cryptonote::COMMAND_RPC_GET_HEIGHT::request req;
|
||||
cryptonote::COMMAND_RPC_GET_HEIGHT::response res;
|
||||
cryptonote::COMMAND_RPC_GET_INFO::request req;
|
||||
cryptonote::COMMAND_RPC_GET_INFO::response res;
|
||||
|
||||
if (!invoke_http_json("/getheight", req, res))
|
||||
if (!invoke_http_json("/getinfo", req, res))
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
@@ -60,7 +60,7 @@ namespace cryptonote
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
return res.height;
|
||||
return {{res.height, res.target_height}};
|
||||
}
|
||||
|
||||
bool bootstrap_daemon::handle_result(bool success, const std::string &status)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
@@ -27,7 +28,7 @@ namespace cryptonote
|
||||
bool rpc_payment_enabled);
|
||||
|
||||
std::string address() const noexcept;
|
||||
boost::optional<uint64_t> get_height();
|
||||
boost::optional<std::pair<uint64_t, uint64_t>> get_height();
|
||||
bool handle_result(bool success, const std::string &status);
|
||||
|
||||
template <class t_request, class t_response>
|
||||
|
||||
+33
-14
@@ -264,6 +264,18 @@ namespace cryptonote
|
||||
if (!rpc_config)
|
||||
return false;
|
||||
|
||||
std::string bind_ip_str = rpc_config->bind_ip;
|
||||
std::string bind_ipv6_str = rpc_config->bind_ipv6_address;
|
||||
if (restricted)
|
||||
{
|
||||
const auto restricted_rpc_port_arg = cryptonote::core_rpc_server::arg_rpc_restricted_bind_port;
|
||||
const bool has_restricted_rpc_port_arg = !command_line::is_arg_defaulted(vm, restricted_rpc_port_arg);
|
||||
if (has_restricted_rpc_port_arg && port == command_line::get_arg(vm, restricted_rpc_port_arg))
|
||||
{
|
||||
bind_ip_str = rpc_config->restricted_bind_ip;
|
||||
bind_ipv6_str = rpc_config->restricted_bind_ipv6_address;
|
||||
}
|
||||
}
|
||||
disable_rpc_ban = rpc_config->disable_rpc_ban;
|
||||
std::string address = command_line::get_arg(vm, arg_rpc_payment_address);
|
||||
if (!address.empty() && allow_rpc_payment)
|
||||
@@ -300,7 +312,7 @@ namespace cryptonote
|
||||
if (!m_rpc_payment)
|
||||
{
|
||||
uint32_t bind_ip;
|
||||
bool ok = epee::string_tools::get_ip_int32_from_string(bind_ip, rpc_config->bind_ip);
|
||||
bool ok = epee::string_tools::get_ip_int32_from_string(bind_ip, bind_ip_str);
|
||||
if (ok & !epee::net_utils::is_ip_loopback(bind_ip))
|
||||
MWARNING("The RPC server is accessible from the outside, but no RPC payment was setup. RPC access will be free for all.");
|
||||
}
|
||||
@@ -322,8 +334,8 @@ namespace cryptonote
|
||||
|
||||
auto rng = [](size_t len, uint8_t *ptr){ return crypto::rand(len, ptr); };
|
||||
return epee::http_server_impl_base<core_rpc_server, connection_context>::init(
|
||||
rng, std::move(port), std::move(rpc_config->bind_ip),
|
||||
std::move(rpc_config->bind_ipv6_address), std::move(rpc_config->use_ipv6), std::move(rpc_config->require_ipv4),
|
||||
rng, std::move(port), std::move(bind_ip_str),
|
||||
std::move(bind_ipv6_str), std::move(rpc_config->use_ipv6), std::move(rpc_config->require_ipv4),
|
||||
std::move(rpc_config->access_control_origins), std::move(http_login), std::move(rpc_config->ssl_options)
|
||||
);
|
||||
}
|
||||
@@ -1151,6 +1163,10 @@ namespace cryptonote
|
||||
CHECK_CORE_READY();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_CORE_READY();
|
||||
}
|
||||
|
||||
CHECK_PAYMENT_MIN1(req, res, COST_PER_TX_RELAY, false);
|
||||
|
||||
@@ -1987,34 +2003,37 @@ namespace cryptonote
|
||||
}
|
||||
|
||||
auto current_time = std::chrono::system_clock::now();
|
||||
if (!m_p2p.get_payload_object().no_sync() &&
|
||||
current_time - m_bootstrap_height_check_time > std::chrono::seconds(30)) // update every 30s
|
||||
if (current_time - m_bootstrap_height_check_time > std::chrono::seconds(30)) // update every 30s
|
||||
{
|
||||
{
|
||||
boost::upgrade_to_unique_lock<boost::shared_mutex> lock(upgrade_lock);
|
||||
m_bootstrap_height_check_time = current_time;
|
||||
}
|
||||
|
||||
boost::optional<uint64_t> bootstrap_daemon_height = m_bootstrap_daemon->get_height();
|
||||
if (!bootstrap_daemon_height)
|
||||
boost::optional<std::pair<uint64_t, uint64_t>> bootstrap_daemon_height_info = m_bootstrap_daemon->get_height();
|
||||
if (!bootstrap_daemon_height_info)
|
||||
{
|
||||
MERROR("Failed to fetch bootstrap daemon height");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t target_height = m_core.get_target_blockchain_height();
|
||||
if (*bootstrap_daemon_height < target_height)
|
||||
const uint64_t bootstrap_daemon_height = bootstrap_daemon_height_info->first;
|
||||
const uint64_t bootstrap_daemon_target_height = bootstrap_daemon_height_info->second;
|
||||
if (bootstrap_daemon_height < bootstrap_daemon_target_height)
|
||||
{
|
||||
MINFO("Bootstrap daemon is out of sync");
|
||||
return m_bootstrap_daemon->handle_result(false, {});
|
||||
}
|
||||
|
||||
uint64_t top_height = m_core.get_current_blockchain_height();
|
||||
m_should_use_bootstrap_daemon = top_height + 10 < *bootstrap_daemon_height;
|
||||
MINFO((m_should_use_bootstrap_daemon ? "Using" : "Not using") << " the bootstrap daemon (our height: " << top_height << ", bootstrap daemon's height: " << *bootstrap_daemon_height << ")");
|
||||
if (!m_p2p.get_payload_object().no_sync())
|
||||
{
|
||||
uint64_t top_height = m_core.get_current_blockchain_height();
|
||||
m_should_use_bootstrap_daemon = top_height + 10 < bootstrap_daemon_height;
|
||||
MINFO((m_should_use_bootstrap_daemon ? "Using" : "Not using") << " the bootstrap daemon (our height: " << top_height << ", bootstrap daemon's height: " << bootstrap_daemon_height << ")");
|
||||
|
||||
if (!m_should_use_bootstrap_daemon)
|
||||
return false;
|
||||
if (!m_should_use_bootstrap_daemon)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == invoke_http_mode::JON)
|
||||
|
||||
@@ -91,6 +91,8 @@ namespace cryptonote
|
||||
rpc_args::descriptors::descriptors()
|
||||
: rpc_bind_ip({"rpc-bind-ip", rpc_args::tr("Specify IP to bind RPC server"), "127.0.0.1"})
|
||||
, rpc_bind_ipv6_address({"rpc-bind-ipv6-address", rpc_args::tr("Specify IPv6 address to bind RPC server"), "::1"})
|
||||
, rpc_restricted_bind_ip({"rpc-restricted-bind-ip", rpc_args::tr("Specify IP to bind restricted RPC server"), "127.0.0.1"})
|
||||
, rpc_restricted_bind_ipv6_address({"rpc-restricted-bind-ipv6-address", rpc_args::tr("Specify IPv6 address to bind restricted RPC server"), "::1"})
|
||||
, rpc_use_ipv6({"rpc-use-ipv6", rpc_args::tr("Allow IPv6 for RPC"), false})
|
||||
, rpc_ignore_ipv4({"rpc-ignore-ipv4", rpc_args::tr("Ignore unsuccessful IPv4 bind for RPC"), false})
|
||||
, rpc_login({"rpc-login", rpc_args::tr("Specify username[:password] required for RPC server"), "", true})
|
||||
@@ -113,6 +115,8 @@ namespace cryptonote
|
||||
const descriptors arg{};
|
||||
command_line::add_arg(desc, arg.rpc_bind_ip);
|
||||
command_line::add_arg(desc, arg.rpc_bind_ipv6_address);
|
||||
command_line::add_arg(desc, arg.rpc_restricted_bind_ip);
|
||||
command_line::add_arg(desc, arg.rpc_restricted_bind_ipv6_address);
|
||||
command_line::add_arg(desc, arg.rpc_use_ipv6);
|
||||
command_line::add_arg(desc, arg.rpc_ignore_ipv4);
|
||||
command_line::add_arg(desc, arg.rpc_login);
|
||||
@@ -136,6 +140,8 @@ namespace cryptonote
|
||||
|
||||
config.bind_ip = command_line::get_arg(vm, arg.rpc_bind_ip);
|
||||
config.bind_ipv6_address = command_line::get_arg(vm, arg.rpc_bind_ipv6_address);
|
||||
config.restricted_bind_ip = command_line::get_arg(vm, arg.rpc_restricted_bind_ip);
|
||||
config.restricted_bind_ipv6_address = command_line::get_arg(vm, arg.rpc_restricted_bind_ipv6_address);
|
||||
config.use_ipv6 = command_line::get_arg(vm, arg.rpc_use_ipv6);
|
||||
config.require_ipv4 = !command_line::get_arg(vm, arg.rpc_ignore_ipv4);
|
||||
config.disable_rpc_ban = command_line::get_arg(vm, arg.disable_rpc_ban);
|
||||
@@ -188,6 +194,34 @@ namespace cryptonote
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
if (!config.restricted_bind_ip.empty())
|
||||
{
|
||||
// always parse IP here for error consistency
|
||||
boost::system::error_code ec{};
|
||||
boost::asio::ip::address::from_string(config.restricted_bind_ip, ec);
|
||||
if (ec)
|
||||
{
|
||||
LOG_ERROR(tr("Invalid IP address given for --") << arg.rpc_restricted_bind_ip.name);
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
if (!config.restricted_bind_ipv6_address.empty())
|
||||
{
|
||||
// allow square braces, but remove them here if present
|
||||
if (config.restricted_bind_ipv6_address.find('[') != std::string::npos)
|
||||
{
|
||||
config.restricted_bind_ipv6_address = config.restricted_bind_ipv6_address.substr(1, config.restricted_bind_ipv6_address.size() - 2);
|
||||
}
|
||||
|
||||
// always parse IP here for error consistency
|
||||
boost::system::error_code ec{};
|
||||
boost::asio::ip::address::from_string(config.restricted_bind_ipv6_address, ec);
|
||||
if (ec)
|
||||
{
|
||||
LOG_ERROR(tr("Invalid IP address given for --") << arg.rpc_restricted_bind_ipv6_address.name);
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
|
||||
const char *env_rpc_login = nullptr;
|
||||
const bool has_rpc_arg = command_line::has_arg(vm, arg.rpc_login);
|
||||
|
||||
@@ -53,6 +53,8 @@ namespace cryptonote
|
||||
|
||||
const command_line::arg_descriptor<std::string> rpc_bind_ip;
|
||||
const command_line::arg_descriptor<std::string> rpc_bind_ipv6_address;
|
||||
const command_line::arg_descriptor<std::string> rpc_restricted_bind_ip;
|
||||
const command_line::arg_descriptor<std::string> rpc_restricted_bind_ipv6_address;
|
||||
const command_line::arg_descriptor<bool> rpc_use_ipv6;
|
||||
const command_line::arg_descriptor<bool> rpc_ignore_ipv4;
|
||||
const command_line::arg_descriptor<std::string> rpc_login;
|
||||
@@ -81,6 +83,8 @@ namespace cryptonote
|
||||
|
||||
std::string bind_ip;
|
||||
std::string bind_ipv6_address;
|
||||
std::string restricted_bind_ip;
|
||||
std::string restricted_bind_ipv6_address;
|
||||
bool use_ipv6;
|
||||
bool require_ipv4;
|
||||
std::vector<std::string> access_control_origins;
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#define DEF_MONERO_VERSION_TAG "@VERSIONTAG@"
|
||||
#define DEF_MONERO_VERSION "0.17.1.2"
|
||||
#define DEF_MONERO_VERSION "0.17.1.6"
|
||||
#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@
|
||||
|
||||
+16
-1
@@ -2961,7 +2961,8 @@ void wallet2::update_pool_state(std::vector<std::tuple<cryptonote::transaction,
|
||||
MTRACE("update_pool_state got pool");
|
||||
|
||||
// remove any pending tx that's not in the pool
|
||||
constexpr const std::chrono::seconds tx_propagation_timeout{CRYPTONOTE_DANDELIONPP_EMBARGO_AVERAGE * 3 / 2};
|
||||
// TODO: set tx_propagation_timeout to CRYPTONOTE_DANDELIONPP_EMBARGO_AVERAGE * 3 / 2 after v15 hardfork
|
||||
constexpr const std::chrono::seconds tx_propagation_timeout{500};
|
||||
const auto now = std::chrono::system_clock::now();
|
||||
std::unordered_map<crypto::hash, wallet2::unconfirmed_transfer_details>::iterator it = m_unconfirmed_txs.begin();
|
||||
while (it != m_unconfirmed_txs.end())
|
||||
@@ -13381,6 +13382,20 @@ size_t wallet2::import_multisig(std::vector<cryptonote::blobdata> blobs)
|
||||
loaded = true;
|
||||
}
|
||||
CHECK_AND_ASSERT_THROW_MES(loaded, "Failed to load output data");
|
||||
|
||||
for (const auto &e: i)
|
||||
{
|
||||
for (const auto &lr: e.m_LR)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(rct::isInMainSubgroup(lr.m_L), "Multisig value is not in the main subgroup");
|
||||
CHECK_AND_ASSERT_THROW_MES(rct::isInMainSubgroup(lr.m_R), "Multisig value is not in the main subgroup");
|
||||
}
|
||||
for (const auto &ki: e.m_partial_key_images)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(rct::isInMainSubgroup(rct::ki2rct(ki)), "Multisig partial key image is not in the main subgroup");
|
||||
}
|
||||
}
|
||||
|
||||
MINFO(boost::format("%u outputs found") % boost::lexical_cast<std::string>(i.size()));
|
||||
info.push_back(std::move(i));
|
||||
}
|
||||
|
||||
@@ -66,9 +66,10 @@ namespace tests
|
||||
|
||||
|
||||
public:
|
||||
virtual bool is_synchronized() const final { return true; }
|
||||
void on_synchronized(){}
|
||||
void safesyncmode(const bool){}
|
||||
uint64_t get_current_blockchain_height(){return 1;}
|
||||
virtual uint64_t get_current_blockchain_height() const final {return 1;}
|
||||
void set_target_blockchain_height(uint64_t) {}
|
||||
bool init(const boost::program_options::variables_map& vm);
|
||||
bool deinit(){return true;}
|
||||
|
||||
+540
-551
File diff suppressed because one or more lines are too long
@@ -120,7 +120,12 @@ namespace
|
||||
{
|
||||
std::map<cryptonote::relay_method, std::vector<cryptonote::blobdata>> relayed_;
|
||||
|
||||
uint64_t get_target_blockchain_height() const override
|
||||
virtual bool is_synchronized() const final
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual uint64_t get_current_blockchain_height() const final
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -329,7 +334,8 @@ namespace
|
||||
epee::byte_slice noise = nullptr;
|
||||
if (noise_size)
|
||||
noise = epee::levin::make_noise_notify(noise_size);
|
||||
return cryptonote::levin::notify{io_service_, connections_, std::move(noise), is_public, pad_txs, events_};
|
||||
epee::net_utils::zone zone = is_public ? epee::net_utils::zone::public_ : epee::net_utils::zone::i2p;
|
||||
return cryptonote::levin::notify{io_service_, connections_, std::move(noise), zone, pad_txs, events_};
|
||||
}
|
||||
|
||||
boost::uuids::random_generator random_generator_;
|
||||
|
||||
@@ -47,9 +47,10 @@ namespace cryptonote {
|
||||
class test_core : public cryptonote::i_core_events
|
||||
{
|
||||
public:
|
||||
virtual bool is_synchronized() const final { return true; }
|
||||
void on_synchronized(){}
|
||||
void safesyncmode(const bool){}
|
||||
uint64_t get_current_blockchain_height() const {return 1;}
|
||||
virtual uint64_t get_current_blockchain_height() const final {return 1;}
|
||||
void set_target_blockchain_height(uint64_t) {}
|
||||
bool init(const boost::program_options::variables_map& vm) {return true ;}
|
||||
bool deinit(){return true;}
|
||||
|
||||
Reference in New Issue
Block a user