Compare commits

...

56 Commits

Author SHA1 Message Date
luigi1111 3942a1cd04 Merge pull request #7044
efca5b8 wallet2: check imported multisig curve points are in main subgroup (moneromooo-monero)
2020-11-25 09:31:25 -06:00
luigi1111 e4c0cb0ff3 Merge pull request #7039
9d7f473 cryptonote_core: dandelion - use local height or median height if syncing (xiphon)
2020-11-25 09:14:26 -06:00
xiphon 9d7f473af0 cryptonote_core: dandelion - use local height or median height if syncing 2020-11-25 01:26:03 +00:00
Alexander Blair 41652c9aa1 Merge pull request #7040
af4fb4729 rpc: skip non-synced bootstrap daemons in --no-sync mode too (xiphon)
2020-11-24 11:21:40 -08:00
Alexander Blair 0a0ceb62f0 Merge pull request #7038
5bb83ab04 build: prepare v0.17.1.5 (selsta)
2020-11-24 11:20:33 -08:00
Alexander Blair 8e7b762092 Merge pull request #7037
8e829e034 rpc: on_send_raw_tx - add missing CHECK_CORE_READY (xiphon)
2020-11-24 11:19:32 -08:00
Alexander Blair 551e6c9168 Merge pull request #7028
9b7ed2fd8 Change Dandelion++ fluff probability to 20%, and embargo timeout to 39s (Lee Clagett)
2020-11-24 11:19:07 -08:00
Alexander Blair c09d142972 Merge pull request #7026
e8468c5dc Fix timeout checks for forwarded and Dandelion++ stem txes (Lee Clagett)
2020-11-24 11:17:59 -08:00
Crypto City efca5b8af9 wallet2: check imported multisig curve points are in main subgroup 2020-11-24 16:24:03 +00:00
luigi1111 251c64f195 Merge pull request #7011
398e64c Better log message for unusable anon networks (hyc)
2020-11-23 16:15:50 -06:00
selsta 5bb83ab042 build: prepare v0.17.1.5 2020-11-23 15:22:35 +01:00
xiphon af4fb4729e rpc: skip non-synced bootstrap daemons in --no-sync mode too 2020-11-23 12:24:01 +00:00
xiphon 8e829e034f rpc: on_send_raw_tx - add missing CHECK_CORE_READY 2020-11-22 16:11:19 +00:00
Howard Chu 398e64ccbe Better log message for unusable anon networks 2020-11-16 12:37:40 +00:00
luigi1111 f690e4984d Merge pull request #6997
752837b build: prepare v0.17.1.3 (selsta)
2020-11-07 13:10:15 -06:00
luigi1111 ebc9197326 Merge pull request #6996
981e0b5 epee: readline_buffer - fix thread safety, fix sync() after stop() (xiphon)
2020-11-07 13:09:18 -06:00
luigi1111 81f9fa947b Merge pull request #6994
6f48a14 Fix i2p/tor seed nodes (vtnerd)
2020-11-07 13:08:00 -06:00
selsta 752837b2c8 build: prepare v0.17.1.3 2020-11-07 18:19:08 +01:00
xiphon 981e0b5cc3 epee: readline_buffer - fix thread safety, fix sync() after stop() 2020-11-07 15:32:02 +00:00
Lee Clagett 6f48a146f8 Fix i2p/tor seed nodes 2020-11-07 00:37:49 -05:00
luigi1111 1a3bef15b9 Merge pull request #6993
44c93bb p2p: fix accessing non existent element of map (moneromooo-monero)
2020-11-06 18:53:22 -06:00
moneromooo-monero 44c93bb47a p2p: fix accessing non existent element of map 2020-11-07 00:17:47 +00:00
luigi1111 c3fc96f0cf Merge pull request #6992
f3dd25c build: prepare v0.17.1.2 (selsta)
2020-11-06 17:34:32 -06:00
luigi1111 07f6ecd227 Merge pull request #6991
4985afd p2p: add a tor seed (moneromooo-monero)
2020-11-06 17:32:28 -06:00
moneromooo-monero 4985afddb3 p2p: add a tor seed 2020-11-06 23:21:10 +00:00
luigi1111 4191dc8981 Merge pull request #6990
263579b Add support for i2p and tor seed nodes (vtnerd)
2020-11-06 17:15:11 -06:00
luigi1111 32581fb223 Merge pull request #6985
91f1be9 net_node: add tor / i2p seed nodes (selsta)
2020-11-06 17:12:42 -06:00
selsta f3dd25c0e0 build: prepare v0.17.1.2 2020-11-07 00:12:39 +01:00
luigi1111 33dc825d6f Merge pull request #6983
35186b1 p2p: fix endianness when checking IPv6 addresses mapping to IPv4 (moneromooo-monero)
2020-11-05 19:09:43 -06:00
selsta 91f1be9ea2 net_node: add tor / i2p seed nodes 2020-11-05 21:41:11 +01:00
moneromooo-monero 35186b1b84 p2p: fix endianness when checking IPv6 addresses mapping to IPv4 2020-11-05 16:05:54 +00:00
luigi1111 bddd5653e1 Merge pull request #6981
b36c4f3 p2p: make this work with boost <= 1.65 (pffff) (moneromooo-monero)
2020-11-04 20:57:49 -06:00
moneromooo-monero b36c4f354b p2p: make this work with boost <= 1.65 (pffff) 2020-11-04 23:01:47 +00:00
luigi1111 1ba4c8dbc2 Merge pull request #6979
92d19c4 p2p: rewrite boost's make_address_v4 to cater for < 1.66 (moneromooo-monero)
2020-11-04 16:28:43 -06:00
moneromooo 92d19c48da p2p: rewrite boost's make_address_v4 to cater for < 1.66 2020-11-04 20:26:50 +00:00
luigi1111 01606ee52e Merge pull request #6974
58cde83 Switch to Dandelion++ fluff mode if no out connections for stem mode (vtnerd)
2020-11-04 10:40:49 -06:00
luigi1111 81d2389c24 Merge pull request #6972
8965489 protocol: reject empty incoming block messages (moneromooo-monero)
2020-11-04 10:39:53 -06:00
luigi1111 ef64c4e22f Merge pull request #6967
fa63d4b Fix tx flush callback queueing (vtnerd)
2020-11-04 10:38:08 -06:00
luigi1111 7fa01f342c Merge pull request #6966
42403c7 Fix CLI and unrestricted RPC relay_tx with stempool (vtnerd)
2020-11-04 10:37:18 -06:00
luigi1111 4603ec9765 Merge pull request #6962
1a627e1 p2p: use /16 filtering on IPv4-within-IPv6 addresses (moneromooo-monero)
2020-11-04 10:36:23 -06:00
luigi1111 0be71bcea9 Merge pull request #6961
f55f3fe net_node: add --ban-list option (selsta)
2020-11-04 10:35:07 -06:00
moneromooo-monero 1a627e1f89 p2p: use /16 filtering on IPv4-within-IPv6 addresses
IPv6 addresses include a range that can map IPv4 addresses,
which allowed those mapped addresses to bypass filtering.

This filter should be replaced by AS filtering at some point.
2020-11-03 17:36:25 +00:00
luigi1111 c1229a4432 Merge pull request #6965
d695340 rpc: on_send_raw_tx (bootstrap) - send to bootstrap daemon and P2P (xiphon)
2020-11-03 11:23:17 -06:00
luigi1111 9f68111b69 Merge pull request #6964
5090cdc p2p: remove banned peers from the white list (moneromooo-monero)
2020-11-03 11:22:27 -06:00
luigi1111 d1e79f2086 Merge pull request #6963
df1061c p2p: give all hosts the same chance of being picked for connecting (moneromooo-monero)
2020-11-03 11:21:26 -06:00
moneromooo-monero 8965489acb protocol: reject empty incoming block messages 2020-11-03 13:08:19 +00:00
xiphon d6953406c9 rpc: on_send_raw_tx (bootstrap) - send to bootstrap daemon and P2P 2020-11-02 19:47:54 +00:00
moneromooo 5090cdc9f5 p2p: remove banned peers from the white list 2020-11-02 19:03:12 +00:00
moneromooo df1061c87d p2p: give all hosts the same chance of being picked for connecting
even if some run more than one node
2020-11-02 19:01:43 +00:00
selsta f55f3fe81c net_node: add --ban-list option 2020-11-02 17:26:02 +01:00
Lee Clagett 9b7ed2fd8b Change Dandelion++ fluff probability to 20%, and embargo timeout to 39s
A 20% fluff probability increases the precision of a spy connected to
every node by 10% on average, compared to a network using 0% fluff
probability. The current value (10% fluff) should increase precision by
~5% compared to baseline.

This decreases the expected stem length from 10 to 5. The embargo
timeout was therefore lowered to 39s; the fifth node in a stem is
expected to have a 90% chance of being the first to timeout, which is
the same probability we currently have with an expected stem length of
10 nodes.
2020-10-21 13:11:07 +00:00
Lee Clagett e8468c5dcf Fix timeout checks for forwarded and Dandelion++ stem txes 2020-10-21 00:02:11 +00:00
Lee Clagett 42403c7acc Fix CLI and unrestricted RPC relay_tx with stempool 2020-10-14 13:02:27 +00:00
Lee Clagett fa63d4b3f0 Fix tx flush callback queueing 2020-10-14 13:01:34 +00:00
Lee Clagett 263579b217 Add support for i2p and tor seed nodes 2020-10-09 14:07:40 +00:00
Lee Clagett 58cde83fb0 Switch to Dandelion++ fluff mode if no out connections for stem mode 2020-10-06 13:52:01 +00:00
28 changed files with 563 additions and 164 deletions
+5 -5
View File
@@ -134,8 +134,8 @@ Dates are provided in the format YYYY-MM-DD.
| 1788000 | 2019-03-09 | v10 | v0.14.0.0 | v0.14.1.2 | New PoW based on Cryptonight-R, new block weight algorithm, slightly more efficient RingCT format
| 1788720 | 2019-03-10 | v11 | v0.14.0.0 | v0.14.1.2 | forbid old RingCT transaction format
| 1978433 | 2019-11-30* | v12 | v0.15.0.0 | v0.16.0.0 | New PoW based on RandomX, only allow >= 2 outputs, change to the block median used to calculate penalty, v1 coinbases are forbidden, rct sigs in coinbase forbidden, 10 block lock time for incoming outputs
| 2210000 | 2020-10-17 | v13 | v0.17.0.0 | v0.17.1.1 | New CLSAG transaction format
| 2210720 | 2020-10-18 | v14 | v0.17.1.1 | v0.17.1.1 | forbid old MLSAG transaction format
| 2210000 | 2020-10-17 | v13 | v0.17.0.0 | v0.17.1.5 | New CLSAG transaction format
| 2210720 | 2020-10-18 | v14 | v0.17.1.1 | v0.17.1.5 | forbid old MLSAG transaction format
| XXXXXXX | XXX-XX-XX | XXX | vX.XX.X.X | vX.XX.X.X | XXX |
X's indicate that these details have not been determined as of commit date.
@@ -295,7 +295,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (
```bash
git clone https://github.com/monero-project/monero.git
cd monero
git checkout tags/v0.17.1.1
git checkout tags/v0.17.1.5
```
* Build:
@@ -412,10 +412,10 @@ application.
cd monero
```
* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.17.1.1'. If you don't care about the version and just want binaries from master, skip this step:
* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.17.1.5'. If you don't care about the version and just want binaries from master, skip this step:
```bash
git checkout v0.17.1.1
git checkout v0.17.1.5
```
* If you are on a 64-bit system, run:
+9 -1
View File
@@ -51,6 +51,7 @@ rdln::readline_buffer::readline_buffer()
void rdln::readline_buffer::start()
{
boost::lock_guard<boost::mutex> lock(sync_mutex);
if(m_cout_buf != NULL)
return;
m_cout_buf = std::cout.rdbuf();
@@ -60,6 +61,7 @@ void rdln::readline_buffer::start()
void rdln::readline_buffer::stop()
{
boost::lock_guard<boost::mutex> lock(sync_mutex);
if(m_cout_buf == NULL)
return;
std::cout.rdbuf(m_cout_buf);
@@ -88,9 +90,9 @@ rdln::linestatus rdln::readline_buffer::get_line(std::string& line) const
void rdln::readline_buffer::set_prompt(const std::string& prompt)
{
boost::lock_guard<boost::mutex> lock(sync_mutex);
if(m_cout_buf == NULL)
return;
boost::lock_guard<boost::mutex> lock(sync_mutex);
rl_set_prompt(std::string(m_prompt_length, ' ').c_str());
rl_redisplay();
rl_set_prompt(prompt.c_str());
@@ -113,6 +115,12 @@ const std::vector<std::string>& rdln::readline_buffer::get_completions()
int rdln::readline_buffer::sync()
{
boost::lock_guard<boost::mutex> lock(sync_mutex);
if (m_cout_buf == nullptr)
{
return -1;
}
#if RL_READLINE_VERSION < 0x0700
char lbuf[2] = {0,0};
char *line = NULL;
+2 -2
View File
@@ -126,7 +126,7 @@ Setup for LXC:
```bash
GH_USER=fluffypony
VERSION=v0.17.1.1
VERSION=v0.17.1.5
./gitian-build.py --setup $GH_USER $VERSION
```
@@ -182,7 +182,7 @@ If you chose to do detached signing using `--detach-sign` above (recommended), y
```bash
GH_USER=fluffypony
VERSION=v0.17.1.1
VERSION=v0.17.1.5
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.
+2
View File
@@ -240,6 +240,8 @@ namespace cryptonote
ADD_CHECKPOINT2(2193000, "6e91b917a40309f89f75f2c8d7be5a6d1a3c425634f07f7d1867bd32d2e602ed", "0xf085140f17389d");
ADD_CHECKPOINT2(2206500, "dd3c8590f33eaa546a4ce69d02f27fd58a2f115cd32d733bd9426f8278f0cb8a", "0xf8725275799f0d");
ADD_CHECKPOINT2(2210500, "ed17259215ac6aabe6e8252b5b5eff613d2e69cc2111173e567109aa78301911", "0xfbcb50a9a6a433");
ADD_CHECKPOINT2(2224000, "e34bc71301600df96d08aaa6b0bde932cba1b06a3dd57076e3f664a078810a80", "0x1052fc256fceb6f");
ADD_CHECKPOINT2(2235500, "3eac1a1253495733e10d00fd5e8e1639741566d91bae38bc6d3342af6b75da53", "0x10cea232ce71d23");
return true;
}
+2 -2
View File
@@ -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
+1 -1
View File
@@ -5376,7 +5376,7 @@ void Blockchain::cancel()
}
#if defined(PER_BLOCK_CHECKPOINT)
static const char expected_block_hashes_hash[] = "be42dfed51f6b9da134d7dcfd5f4b7e1df8cae93f1b41b846a5818f0aaf09fda";
static const char expected_block_hashes_hash[] = "3a2a0720f7ed3573d2b632f7ba127e2f97edac3af34bf924df57c13a88bf2460";
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
{
if (get_checkpoints == nullptr || !m_fast_sync)
+6 -1
View File
@@ -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));
+9 -3
View File
@@ -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
+2 -1
View File
@@ -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;
};
}
+38 -7
View File
@@ -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
+9 -2
View File
@@ -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; }
@@ -430,7 +430,7 @@ namespace cryptonote
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)");
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;
@@ -501,7 +501,7 @@ namespace cryptonote
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)");
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;
@@ -929,7 +929,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;
@@ -1091,6 +1091,13 @@ namespace cryptonote
//epee::net_utils::network_throttle_manager::get_global_throttle_inreq().logger_handle_net("log/dr-monero/net/req-all.data", sec, get_avg_block_size());
if(arg.blocks.empty())
{
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_HAVE_OBJECTS: no blocks");
drop_connection(context, true, false);
++m_sync_bad_spans_downloaded;
return 1;
}
if(context.m_last_response_height > arg.current_blockchain_height)
{
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_HAVE_OBJECTS: arg.m_current_blockchain_height=" << arg.current_blockchain_height
@@ -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;
+78 -48
View File
@@ -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),
@@ -241,9 +283,9 @@ namespace levin
strand(io_service),
map(),
channels(),
flush_time(std::chrono::steady_clock::time_point::max()),
connection_count(0),
is_public(is_public),
flush_callbacks(0),
nzone(zone),
pad_txs(pad_txs),
fluffing(false)
{
@@ -258,9 +300,9 @@ namespace levin
boost::asio::io_service::strand strand;
net::dandelionpp::connection_map map;//!< Tracks outgoing uuid's for noise channels or Dandelion++ stems
std::deque<noise_channel> channels; //!< Never touch after init; only update elements on `noise_channel.strand`
std::chrono::steady_clock::time_point flush_time; //!< Next expected Dandelion++ fluff flush
std::atomic<std::size_t> connection_count; //!< Only update in strand, can be read at any time
const bool is_public; //!< Zone is public ipv4/ipv6 connections
std::uint32_t flush_callbacks; //!< Number of active fluff flush callbacks queued
const epee::net_utils::zone nzone; //!< Zone is public ipv4/ipv6 connections, or i2p or tor
const bool 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");
}
};
@@ -305,7 +348,6 @@ namespace levin
struct fluff_flush
{
std::shared_ptr<detail::zone> zone_;
std::chrono::steady_clock::time_point flush_time_;
static void queue(std::shared_ptr<detail::zone> zone, const std::chrono::steady_clock::time_point flush_time)
{
@@ -313,28 +355,21 @@ namespace levin
assert(zone->strand.running_in_this_thread());
detail::zone& this_zone = *zone;
this_zone.flush_time = flush_time;
++this_zone.flush_callbacks;
this_zone.flush_txs.expires_at(flush_time);
this_zone.flush_txs.async_wait(this_zone.strand.wrap(fluff_flush{std::move(zone), flush_time}));
this_zone.flush_txs.async_wait(this_zone.strand.wrap(fluff_flush{std::move(zone)}));
}
void operator()(const boost::system::error_code error)
{
if (!zone_ || !zone_->p2p)
if (!zone_ || !zone_->flush_callbacks || --zone_->flush_callbacks || !zone_->p2p)
return;
assert(zone_->strand.running_in_this_thread());
const bool timer_error = bool(error);
if (timer_error)
{
if (error != boost::system::errc::operation_canceled)
throw boost::system::system_error{error, "fluff_flush timer failed"};
// new timer canceled this one set in future
if (zone_->flush_time < flush_time_)
return;
}
if (timer_error && error != boost::system::errc::operation_canceled)
throw boost::system::system_error{error, "fluff_flush timer failed"};
const auto now = std::chrono::steady_clock::now();
auto next_flush = std::chrono::steady_clock::time_point::max();
@@ -370,8 +405,6 @@ namespace levin
if (next_flush != std::chrono::steady_clock::time_point::max())
fluff_flush::queue(std::move(zone_), next_flush);
else
zone_->flush_time = next_flush; // signal that no timer is set
}
};
@@ -406,13 +439,11 @@ namespace levin
MDEBUG("Queueing " << txs.size() << " transaction(s) for Dandelion++ fluffing");
bool available = false;
zone->p2p->foreach_connection([txs, now, &zone, &source, &in_duration, &out_duration, &next_flush, &available] (detail::p2p_context& context)
zone->p2p->foreach_connection([txs, now, &zone, &source, &in_duration, &out_duration, &next_flush] (detail::p2p_context& context)
{
// When i2p/tor, only fluff to outbound connections
if (source != context.m_connection_id && (zone->is_public || !context.m_is_income))
if (source != context.m_connection_id && (zone->nzone == epee::net_utils::zone::public_ || !context.m_is_income))
{
available = true;
if (context.fluff_txs.empty())
context.flush_time = now + (context.m_is_income ? in_duration() : out_duration());
@@ -424,10 +455,9 @@ namespace levin
return true;
});
if (!available)
if (next_flush == std::chrono::steady_clock::time_point::max())
MWARNING("Unable to send transaction(s), no available connections");
if (next_flush < zone->flush_time)
else if (!zone->flush_callbacks || next_flush < zone->flush_txs.expires_at())
fluff_flush::queue(std::move(zone), next_flush);
}
};
@@ -524,12 +554,7 @@ namespace levin
if (!zone_ || !core_ || txs_.empty())
return;
if (zone_->fluffing)
{
core_->on_transactions_relayed(epee::to_span(txs_), relay_method::fluff);
fluff_notify::run(std::move(zone_), epee::to_span(txs_), source_);
}
else // forward tx in stem
if (!zone_->fluffing)
{
core_->on_transactions_relayed(epee::to_span(txs_), relay_method::stem);
for (int tries = 2; 0 < tries; tries--)
@@ -544,11 +569,14 @@ 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");
}
core_->on_transactions_relayed(epee::to_span(txs_), relay_method::fluff);
fluff_notify::run(std::move(zone_), epee::to_span(txs_), source_);
}
};
@@ -577,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_);
@@ -645,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)});
}
@@ -679,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}
);
@@ -691,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;
@@ -730,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_)}
);
}
@@ -821,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(
+1 -1
View File
@@ -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;
+1
View File
@@ -146,6 +146,7 @@ namespace nodetool
const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_seed_node = {"seed-node", "Connect to a node to retrieve peer addresses, and disconnect"};
const command_line::arg_descriptor<std::vector<std::string> > arg_tx_proxy = {"tx-proxy", "Send local txes through proxy: <network-type>,<socks-ip:port>[,max_connections][,disable_noise] i.e. \"tor,127.0.0.1:9050,100,disable_noise\""};
const command_line::arg_descriptor<std::vector<std::string> > arg_anonymous_inbound = {"anonymous-inbound", "<hidden-service-address>,<[bind-ip:]port>[,max_connections] i.e. \"x.onion,127.0.0.1:18083,100\""};
const command_line::arg_descriptor<std::string> arg_ban_list = {"ban-list", "Specify ban list file, one IP address per line"};
const command_line::arg_descriptor<bool> arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true};
const command_line::arg_descriptor<bool> arg_no_sync = {"no-sync", "Don't synchronize the blockchain with other peers", false};
+16 -8
View File
@@ -164,6 +164,7 @@ namespace nodetool
network_zone()
: m_connect(nullptr),
m_net_server(epee::net_utils::e_connection_type_P2P),
m_seed_nodes(),
m_bind_ip(),
m_bind_ipv6_address(),
m_port(),
@@ -175,7 +176,9 @@ namespace nodetool
m_proxy_address(),
m_current_number_of_out_peers(0),
m_current_number_of_in_peers(0),
m_can_pingback(false)
m_seed_nodes_lock(),
m_can_pingback(false),
m_seed_nodes_initialized(false)
{
set_config_defaults();
}
@@ -183,6 +186,7 @@ namespace nodetool
network_zone(boost::asio::io_service& public_service)
: m_connect(nullptr),
m_net_server(public_service, epee::net_utils::e_connection_type_P2P),
m_seed_nodes(),
m_bind_ip(),
m_bind_ipv6_address(),
m_port(),
@@ -194,13 +198,16 @@ namespace nodetool
m_proxy_address(),
m_current_number_of_out_peers(0),
m_current_number_of_in_peers(0),
m_can_pingback(false)
m_seed_nodes_lock(),
m_can_pingback(false),
m_seed_nodes_initialized(false)
{
set_config_defaults();
}
connect_func* m_connect;
net_server m_net_server;
std::vector<epee::net_utils::network_address> m_seed_nodes;
std::string m_bind_ip;
std::string m_bind_ipv6_address;
std::string m_port;
@@ -212,7 +219,9 @@ namespace nodetool
boost::asio::ip::tcp::endpoint m_proxy_address;
std::atomic<unsigned int> m_current_number_of_out_peers;
std::atomic<unsigned int> m_current_number_of_in_peers;
boost::shared_mutex m_seed_nodes_lock;
bool m_can_pingback;
bool m_seed_nodes_initialized;
private:
void set_config_defaults() noexcept
@@ -383,9 +392,10 @@ namespace nodetool
void record_addr_failed(const epee::net_utils::network_address& addr);
bool is_addr_recently_failed(const epee::net_utils::network_address& addr);
bool is_priority_node(const epee::net_utils::network_address& na);
std::set<std::string> get_seed_nodes(cryptonote::network_type nettype) const;
std::set<std::string> get_seed_nodes();
bool connect_to_seed();
std::set<std::string> get_ip_seed_nodes() const;
std::set<std::string> get_dns_seed_nodes();
std::set<std::string> get_seed_nodes(epee::net_utils::zone);
bool connect_to_seed(epee::net_utils::zone);
template <class Container>
bool connect_to_peerlist(const Container& peers);
@@ -467,9 +477,6 @@ namespace nodetool
std::list<epee::net_utils::network_address> m_priority_peers;
std::vector<epee::net_utils::network_address> m_exclusive_peers;
std::vector<epee::net_utils::network_address> m_seed_nodes;
bool m_seed_nodes_initialized = false;
boost::shared_mutex m_seed_nodes_lock;
std::atomic_flag m_fallback_seed_nodes_added;
std::vector<nodetool::peerlist_entry> m_command_line_peers;
uint64_t m_peer_livetime;
@@ -523,6 +530,7 @@ namespace nodetool
extern const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_seed_node;
extern const command_line::arg_descriptor<std::vector<std::string> > arg_tx_proxy;
extern const command_line::arg_descriptor<std::vector<std::string> > arg_anonymous_inbound;
extern const command_line::arg_descriptor<std::string> arg_ban_list;
extern const command_line::arg_descriptor<bool> arg_p2p_hide_my_port;
extern const command_line::arg_descriptor<bool> arg_no_sync;
+192 -54
View File
@@ -71,6 +71,17 @@
#define MIN_WANTED_SEED_NODES 12
static inline boost::asio::ip::address_v4 make_address_v4_from_v6(const boost::asio::ip::address_v6& a)
{
const auto &bytes = a.to_bytes();
uint32_t v4 = 0;
v4 = (v4 << 8) | bytes[12];
v4 = (v4 << 8) | bytes[13];
v4 = (v4 << 8) | bytes[14];
v4 = (v4 << 8) | bytes[15];
return boost::asio::ip::address_v4(v4);
}
namespace nodetool
{
template<class t_payload_net_handler>
@@ -106,6 +117,7 @@ namespace nodetool
command_line::add_arg(desc, arg_p2p_seed_node);
command_line::add_arg(desc, arg_tx_proxy);
command_line::add_arg(desc, arg_anonymous_inbound);
command_line::add_arg(desc, arg_ban_list);
command_line::add_arg(desc, arg_p2p_hide_my_port);
command_line::add_arg(desc, arg_no_sync);
command_line::add_arg(desc, arg_no_igd);
@@ -245,6 +257,10 @@ namespace nodetool
zone.second.m_net_server.get_config_object().close(c);
conns.clear();
peerlist_entry pe{};
pe.adr = addr;
zone.second.m_peerlist.remove_from_peer_white(pe);
}
MCLOG_CYAN(el::Level::Info, "global", "Host " << addr.host_str() << " blocked.");
@@ -386,7 +402,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))
@@ -435,12 +451,42 @@ namespace nodetool
if (command_line::has_arg(vm, arg_p2p_seed_node))
{
boost::unique_lock<boost::shared_mutex> lock(m_seed_nodes_lock);
boost::unique_lock<boost::shared_mutex> lock(public_zone.m_seed_nodes_lock);
if (!parse_peers_and_add_to_container(vm, arg_p2p_seed_node, m_seed_nodes))
if (!parse_peers_and_add_to_container(vm, arg_p2p_seed_node, public_zone.m_seed_nodes))
return false;
}
if (!command_line::is_arg_defaulted(vm, arg_ban_list))
{
const std::string ban_list = command_line::get_arg(vm, arg_ban_list);
const boost::filesystem::path ban_list_path(ban_list);
boost::system::error_code ec;
if (!boost::filesystem::exists(ban_list_path, ec))
{
throw std::runtime_error("Can't find ban list file " + ban_list + " - " + ec.message());
}
std::string banned_ips;
if (!epee::file_io_utils::load_file_to_string(ban_list_path.string(), banned_ips))
{
throw std::runtime_error("Failed to read ban list file " + ban_list);
}
std::istringstream iss(banned_ips);
for (std::string line; std::getline(iss, line); )
{
const expect<epee::net_utils::network_address> parsed_addr = net::get_network_address(line, 0);
if (!parsed_addr)
{
MERROR("Invalid IP address: " << line << " - " << parsed_addr.error());
continue;
}
block_host(*parsed_addr, std::numeric_limits<time_t>::max());
}
}
if(command_line::has_arg(vm, arg_p2p_hide_my_port))
m_hide_my_port = true;
@@ -499,7 +545,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()
};
}
@@ -598,21 +644,21 @@ namespace nodetool
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
std::set<std::string> node_server<t_payload_net_handler>::get_seed_nodes(cryptonote::network_type nettype) const
std::set<std::string> node_server<t_payload_net_handler>::get_ip_seed_nodes() const
{
std::set<std::string> full_addrs;
if (nettype == cryptonote::TESTNET)
if (m_nettype == cryptonote::TESTNET)
{
full_addrs.insert("212.83.175.67:28080");
full_addrs.insert("212.83.172.165:28080");
full_addrs.insert("192.110.160.146:28080");
}
else if (nettype == cryptonote::STAGENET)
else if (m_nettype == cryptonote::STAGENET)
{
full_addrs.insert("162.210.173.150:38080");
full_addrs.insert("192.110.160.146:38080");
}
else if (nettype == cryptonote::FAKECHAIN)
else if (m_nettype == cryptonote::FAKECHAIN)
{
}
else
@@ -630,7 +676,7 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
std::set<std::string> node_server<t_payload_net_handler>::get_seed_nodes()
std::set<std::string> node_server<t_payload_net_handler>::get_dns_seed_nodes()
{
if (!m_exclusive_peers.empty() || m_offline)
{
@@ -638,11 +684,11 @@ namespace nodetool
}
if (m_nettype == cryptonote::TESTNET)
{
return get_seed_nodes(cryptonote::TESTNET);
return get_ip_seed_nodes();
}
if (m_nettype == cryptonote::STAGENET)
{
return get_seed_nodes(cryptonote::STAGENET);
return get_ip_seed_nodes();
}
std::set<std::string> full_addrs;
@@ -730,7 +776,7 @@ namespace nodetool
else
MINFO("Not enough DNS seed nodes found, using fallback defaults too");
for (const auto &peer: get_seed_nodes(cryptonote::MAINNET))
for (const auto &peer: get_ip_seed_nodes())
full_addrs.insert(peer);
m_fallback_seed_nodes_added.test_and_set();
}
@@ -739,6 +785,38 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
std::set<std::string> node_server<t_payload_net_handler>::get_seed_nodes(epee::net_utils::zone zone)
{
switch (zone)
{
case epee::net_utils::zone::public_:
return get_dns_seed_nodes();
case epee::net_utils::zone::tor:
if (m_nettype == cryptonote::MAINNET)
{
return {
"xwvz3ekocr3dkyxfkmgm2hvbpzx2ysqmaxgter7znnqrhoicygkfswid.onion:18083",
"4pixvbejrvihnkxmduo2agsnmc3rrulrqc7s3cbwwrep6h6hrzsibeqd.onion:18083",
"zbjkbsxc5munw3qusl7j2hpcmikhqocdf4pqhnhtpzw5nt5jrmofptid.onion:18083"
};
}
return {};
case epee::net_utils::zone::i2p:
if (m_nettype == cryptonote::MAINNET)
{
return {
"s3l6ke4ed3df466khuebb4poienoingwof7oxtbo6j4n56sghe3a.b32.i2p:18080",
"sel36x6fibfzujwvt4hf5gxolz6kd3jpvbjqg6o3ud2xtionyl2q.b32.i2p:18080"
};
}
return {};
default:
break;
}
throw std::logic_error{"Bad zone given to get_seed_nodes"};
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
typename node_server<t_payload_net_handler>::network_zone& node_server<t_payload_net_handler>::add_zone(const epee::net_utils::zone zone)
{
const auto zone_ = m_network_zones.lower_bound(zone);
@@ -1232,7 +1310,13 @@ namespace nodetool
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::try_to_connect_and_handshake_with_new_peer(const epee::net_utils::network_address& na, bool just_take_peerlist, uint64_t last_seen_stamp, PeerType peer_type, uint64_t first_seen_stamp)
{
network_zone& zone = m_network_zones.at(na.get_zone());
const auto i = m_network_zones.find(na.get_zone());
if (i == m_network_zones.end())
{
MERROR("Tried connecting to address for disabled network");
return false;
}
network_zone& zone = i->second;
if (zone.m_connect == nullptr) // outgoing connections in zone not possible
return false;
@@ -1432,17 +1516,44 @@ namespace nodetool
const uint32_t actual_ip = na.as<const epee::net_utils::ipv4_network_address>().ip();
classB.insert(actual_ip & 0x0000ffff);
}
else if (cntxt.m_remote_address.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id())
{
const epee::net_utils::network_address na = cntxt.m_remote_address;
const boost::asio::ip::address_v6 &actual_ip = na.as<const epee::net_utils::ipv6_network_address>().ip();
if (actual_ip.is_v4_mapped())
{
boost::asio::ip::address_v4 v4ip = make_address_v4_from_v6(actual_ip);
uint32_t actual_ipv4;
memcpy(&actual_ipv4, v4ip.to_bytes().data(), sizeof(actual_ipv4));
classB.insert(actual_ipv4 & ntohl(0xffff0000));
}
}
return true;
});
}
auto get_host_string = [](const epee::net_utils::network_address &address) {
if (address.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id())
{
boost::asio::ip::address_v6 actual_ip = address.as<const epee::net_utils::ipv6_network_address>().ip();
if (actual_ip.is_v4_mapped())
{
boost::asio::ip::address_v4 v4ip = make_address_v4_from_v6(actual_ip);
uint32_t actual_ipv4;
memcpy(&actual_ipv4, v4ip.to_bytes().data(), sizeof(actual_ipv4));
return epee::net_utils::ipv4_network_address(actual_ipv4, 0).host_str();
}
}
return address.host_str();
};
std::unordered_set<std::string> hosts_added;
std::deque<size_t> filtered;
const size_t limit = use_white_list ? 20 : std::numeric_limits<size_t>::max();
for (int step = 0; step < 2; ++step)
{
bool skip_duplicate_class_B = step == 0;
size_t idx = 0, skipped = 0;
zone.m_peerlist.foreach (use_white_list, [&classB, &filtered, &idx, &skipped, skip_duplicate_class_B, limit, next_needed_pruning_stripe](const peerlist_entry &pe){
zone.m_peerlist.foreach (use_white_list, [&classB, &filtered, &idx, &skipped, skip_duplicate_class_B, limit, next_needed_pruning_stripe, &hosts_added, &get_host_string](const peerlist_entry &pe){
if (filtered.size() >= limit)
return false;
bool skip = false;
@@ -1452,6 +1563,27 @@ namespace nodetool
uint32_t actual_ip = na.as<const epee::net_utils::ipv4_network_address>().ip();
skip = classB.find(actual_ip & 0x0000ffff) != classB.end();
}
else if (skip_duplicate_class_B && pe.adr.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id())
{
const epee::net_utils::network_address na = pe.adr;
const boost::asio::ip::address_v6 &actual_ip = na.as<const epee::net_utils::ipv6_network_address>().ip();
if (actual_ip.is_v4_mapped())
{
boost::asio::ip::address_v4 v4ip = make_address_v4_from_v6(actual_ip);
uint32_t actual_ipv4;
memcpy(&actual_ipv4, v4ip.to_bytes().data(), sizeof(actual_ipv4));
skip = classB.find(actual_ipv4 & ntohl(0xffff0000)) != classB.end();
}
}
// consider each host once, to avoid giving undue inflence to hosts running several nodes
if (!skip)
{
const auto i = hosts_added.find(get_host_string(pe.adr));
if (i != hosts_added.end())
skip = true;
}
if (skip)
++skipped;
else if (next_needed_pruning_stripe == 0 || pe.pruning_seed == 0)
@@ -1459,16 +1591,17 @@ namespace nodetool
else if (next_needed_pruning_stripe == tools::get_pruning_stripe(pe.pruning_seed))
filtered.push_front(idx);
++idx;
hosts_added.insert(get_host_string(pe.adr));
return true;
});
if (skipped == 0 || !filtered.empty())
break;
if (skipped)
MINFO("Skipping " << skipped << " possible peers as they share a class B with existing peers");
MDEBUG("Skipping " << skipped << " possible peers as they share a class B with existing peers");
}
if (filtered.empty())
{
MDEBUG("No available peer in " << (use_white_list ? "white" : "gray") << " list filtered by " << next_needed_pruning_stripe);
MINFO("No available peer in " << (use_white_list ? "white" : "gray") << " list filtered by " << next_needed_pruning_stripe);
return false;
}
if (use_white_list)
@@ -1541,56 +1674,59 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::connect_to_seed()
bool node_server<t_payload_net_handler>::connect_to_seed(epee::net_utils::zone zone)
{
boost::upgrade_lock<boost::shared_mutex> seed_nodes_upgrade_lock(m_seed_nodes_lock);
network_zone& server = m_network_zones.at(zone);
boost::upgrade_lock<boost::shared_mutex> seed_nodes_upgrade_lock(server.m_seed_nodes_lock);
if (!m_seed_nodes_initialized)
if (!server.m_seed_nodes_initialized)
{
const std::uint16_t default_port = cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT;
boost::upgrade_to_unique_lock<boost::shared_mutex> seed_nodes_lock(seed_nodes_upgrade_lock);
m_seed_nodes_initialized = true;
for (const auto& full_addr : get_seed_nodes())
server.m_seed_nodes_initialized = true;
for (const auto& full_addr : get_seed_nodes(zone))
{
// seeds should have hostname converted to IP already
MDEBUG("Seed node: " << full_addr);
append_net_address(m_seed_nodes, full_addr, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT);
server.m_seed_nodes.push_back(MONERO_UNWRAP(net::get_network_address(full_addr, default_port)));
}
MDEBUG("Number of seed nodes: " << m_seed_nodes.size());
MDEBUG("Number of seed nodes: " << server.m_seed_nodes.size());
}
if (m_seed_nodes.empty() || m_offline || !m_exclusive_peers.empty())
if (server.m_seed_nodes.empty() || m_offline || !m_exclusive_peers.empty())
return true;
size_t try_count = 0;
bool is_connected_to_at_least_one_seed_node = false;
size_t current_index = crypto::rand_idx(m_seed_nodes.size());
const net_server& server = m_network_zones.at(epee::net_utils::zone::public_).m_net_server;
size_t current_index = crypto::rand_idx(server.m_seed_nodes.size());
while(true)
{
if(server.is_stop_signal_sent())
if(server.m_net_server.is_stop_signal_sent())
return false;
peerlist_entry pe_seed{};
pe_seed.adr = m_seed_nodes[current_index];
pe_seed.adr = server.m_seed_nodes[current_index];
if (is_peer_used(pe_seed))
is_connected_to_at_least_one_seed_node = true;
else if (try_to_connect_and_handshake_with_new_peer(m_seed_nodes[current_index], true))
else if (try_to_connect_and_handshake_with_new_peer(server.m_seed_nodes[current_index], true))
break;
if(++try_count > m_seed_nodes.size())
if(++try_count > server.m_seed_nodes.size())
{
if (!m_fallback_seed_nodes_added.test_and_set())
// only IP zone has fallback (to direct IP) seeds
if (zone == epee::net_utils::zone::public_ && !m_fallback_seed_nodes_added.test_and_set())
{
MWARNING("Failed to connect to any of seed peers, trying fallback seeds");
current_index = m_seed_nodes.size() - 1;
current_index = server.m_seed_nodes.size() - 1;
{
boost::upgrade_to_unique_lock<boost::shared_mutex> seed_nodes_lock(seed_nodes_upgrade_lock);
for (const auto &peer: get_seed_nodes(m_nettype))
for (const auto &peer: get_ip_seed_nodes())
{
MDEBUG("Fallback seed node: " << peer);
append_net_address(m_seed_nodes, peer, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT);
append_net_address(server.m_seed_nodes, peer, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT);
}
}
if (current_index == m_seed_nodes.size() - 1)
if (current_index == server.m_seed_nodes.size() - 1)
{
MWARNING("No fallback seeds, continuing without seeds");
break;
@@ -1604,7 +1740,7 @@ namespace nodetool
break;
}
}
if(++current_index >= m_seed_nodes.size())
if(++current_index >= server.m_seed_nodes.size())
current_index = 0;
}
return true;
@@ -1620,20 +1756,21 @@ namespace nodetool
if (!m_exclusive_peers.empty()) return true;
// Only have seeds in the public zone right now.
size_t start_conn_count = get_public_outgoing_connections_count();
if(!get_public_white_peers_count() && !connect_to_seed())
{
return false;
}
if (!connect_to_peerlist(m_priority_peers)) return false;
bool one_succeeded = false;
for(auto& zone : m_network_zones)
{
size_t start_conn_count = get_outgoing_connections_count(zone.second);
if(!zone.second.m_peerlist.get_white_peers_count() && !connect_to_seed(zone.first))
{
continue;
}
if (zone.first == zone_type::public_ && !connect_to_peerlist(m_priority_peers)) continue;
size_t base_expected_white_connections = (zone.second.m_config.m_net_config.max_out_connection_count*P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT)/100;
// carefully avoid `continue` in nested loop
size_t conn_count = get_outgoing_connections_count(zone.second);
while(conn_count < zone.second.m_config.m_net_config.max_out_connection_count)
{
@@ -1670,16 +1807,17 @@ namespace nodetool
}
conn_count = new_conn_count;
}
if (start_conn_count == get_outgoing_connections_count(zone.second) && start_conn_count < zone.second.m_config.m_net_config.max_out_connection_count)
{
MINFO("Failed to connect to any, trying seeds");
if (!connect_to_seed(zone.first))
continue;
}
one_succeeded = true;
}
if (start_conn_count == get_public_outgoing_connections_count() && start_conn_count < m_network_zones.at(zone_type::public_).m_config.m_net_config.max_out_connection_count)
{
MINFO("Failed to connect to any, trying seeds");
if (!connect_to_seed())
return false;
}
return true;
return one_succeeded;
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
+5 -5
View File
@@ -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 -1
View File
@@ -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>
+31 -13
View File
@@ -1131,6 +1131,11 @@ namespace cryptonote
{
RPC_TRACKER(send_raw_tx);
{
bool ok;
use_bootstrap_daemon_if_necessary<COMMAND_RPC_SEND_RAW_TX>(invoke_http_mode::JON, "/sendrawtransaction", req, res, ok);
}
const bool restricted = m_restricted && ctx;
bool skip_validation = false;
@@ -1146,6 +1151,10 @@ namespace cryptonote
CHECK_CORE_READY();
}
}
else
{
CHECK_CORE_READY();
}
CHECK_PAYMENT_MIN1(req, res, COST_PER_TX_RELAY, false);
@@ -1982,34 +1991,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)
@@ -2827,6 +2839,8 @@ namespace cryptonote
RPC_TRACKER(relay_tx);
CHECK_PAYMENT_MIN1(req, res, req.txids.size() * COST_PER_TX_RELAY, false);
const bool restricted = m_restricted && ctx;
bool failed = false;
res.status = "";
for (const auto &str: req.txids)
@@ -2840,12 +2854,16 @@ namespace cryptonote
continue;
}
//TODO: The get_pool_transaction could have an optional meta parameter
bool broadcasted = false;
cryptonote::blobdata txblob;
if (m_core.get_pool_transaction(txid, txblob, relay_category::legacy))
if ((broadcasted = m_core.get_pool_transaction(txid, txblob, relay_category::broadcasted)) || (!restricted && m_core.get_pool_transaction(txid, txblob, relay_category::all)))
{
// The settings below always choose i2p/tor if enabled. Otherwise, do fluff iff previously relayed else dandelion++ stem.
NOTIFY_NEW_TRANSACTIONS::request r;
r.txs.push_back(std::move(txblob));
m_core.get_protocol()->relay_transactions(r, boost::uuids::nil_uuid(), epee::net_utils::zone::invalid, relay_method::local);
const auto tx_relay = broadcasted ? relay_method::fluff : relay_method::local;
m_core.get_protocol()->relay_transactions(r, boost::uuids::nil_uuid(), epee::net_utils::zone::invalid, tx_relay);
//TODO: make sure that tx has reached other nodes here, probably wait to receive reflections from other nodes
}
else
+1 -1
View File
@@ -1,5 +1,5 @@
#define DEF_MONERO_VERSION_TAG "@VERSIONTAG@"
#define DEF_MONERO_VERSION "0.17.1.1"
#define DEF_MONERO_VERSION "0.17.1.5"
#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@
+14
View File
@@ -13381,6 +13381,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));
}
+2 -1
View File
@@ -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;}
+117 -2
View File
@@ -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_;
@@ -613,6 +619,61 @@ TEST_F(levin_notify, stem_without_padding)
}
}
TEST_F(levin_notify, stem_no_outs_without_padding)
{
cryptonote::levin::notify notifier = make_notifier(0, true, false);
for (unsigned count = 0; count < 10; ++count)
add_connection(true);
{
const auto status = notifier.get_status();
EXPECT_FALSE(status.has_noise);
EXPECT_FALSE(status.connections_filled);
}
notifier.new_out_connection();
io_service_.poll();
std::vector<cryptonote::blobdata> txs(2);
txs[0].resize(100, 'f');
txs[1].resize(200, 'e');
std::vector<cryptonote::blobdata> sorted_txs = txs;
std::sort(sorted_txs.begin(), sorted_txs.end());
ASSERT_EQ(10u, contexts_.size());
auto context = contexts_.begin();
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::stem));
io_service_.reset();
ASSERT_LT(0u, io_service_.poll());
EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff));
if (events_.has_stem_txes())
EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::stem));
notifier.run_fluff();
ASSERT_LT(0u, io_service_.poll());
std::size_t send_count = 0;
EXPECT_EQ(0u, context->process_send_queue());
for (++context; context != contexts_.end(); ++context)
{
send_count += context->process_send_queue();
}
EXPECT_EQ(9u, send_count);
ASSERT_EQ(9u, receiver_.notified_size());
for (unsigned count = 0; count < 9u; ++count)
{
auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
EXPECT_EQ(sorted_txs, notification.txs);
EXPECT_TRUE(notification._.empty());
EXPECT_TRUE(notification.dandelionpp_fluff);
}
}
TEST_F(levin_notify, local_without_padding)
{
cryptonote::levin::notify notifier = make_notifier(0, true, false);
@@ -928,6 +989,60 @@ TEST_F(levin_notify, stem_with_padding)
}
}
TEST_F(levin_notify, stem_no_outs_with_padding)
{
cryptonote::levin::notify notifier = make_notifier(0, true, true);
for (unsigned count = 0; count < 10; ++count)
add_connection(true);
{
const auto status = notifier.get_status();
EXPECT_FALSE(status.has_noise);
EXPECT_FALSE(status.connections_filled);
}
notifier.new_out_connection();
io_service_.poll();
std::vector<cryptonote::blobdata> txs(2);
txs[0].resize(100, 'f');
txs[1].resize(200, 'e');
std::vector<cryptonote::blobdata> sorted_txs = txs;
std::sort(sorted_txs.begin(), sorted_txs.end());
ASSERT_EQ(10u, contexts_.size());
auto context = contexts_.begin();
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::stem));
io_service_.reset();
ASSERT_LT(0u, io_service_.poll());
EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff));
if (events_.has_stem_txes())
EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::stem));
notifier.run_fluff();
ASSERT_LT(0u, io_service_.poll());
std::size_t send_count = 0;
EXPECT_EQ(0u, context->process_send_queue());
for (++context; context != contexts_.end(); ++context)
{
send_count += context->process_send_queue();
}
EXPECT_EQ(9u, send_count);
ASSERT_EQ(9u, receiver_.notified_size());
for (unsigned count = 0; count < 9u; ++count)
{
auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
EXPECT_EQ(sorted_txs, notification.txs);
EXPECT_FALSE(notification._.empty());
EXPECT_TRUE(notification.dandelionpp_fluff);
}
}
TEST_F(levin_notify, local_with_padding)
{
cryptonote::levin::notify notifier = make_notifier(0, true, true);
+2 -1
View File
@@ -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;}