Pulse: Queue Block Gen code review

- Rename find_named_argument -> find_prefixed_value
- Update get_current_blockchain_height() comment to specify ability to lock
- Update memcmp(address1, address2) to address1 == address2
- Make create_next_miner_block_template call create_miner_block_template
- Update LMQ x25519 keys only when key has changed
- construct_miner_tx: Use C++17 features
- Pulse: Add log category "Pulse"
- Pulse: Check shutdown before blockchain height
- Pulse: Use get_human_readable_timespan
- Pulse: Switch to MINFO, enable with --log-level +pulse:DEBUG
- Pulse: Add height into context
- Pulse: Remove some default switch cases hiding compiler warnings
- SN: Update hardcoded '9' literals to network_version_9_service_nodes
- Core: Use using namespace std::literals
- Miner: Change num_blocks availability to debug
- RPC: Gate test rpc commands to != MAINNET
- Wallet: Store wallet before deinitialization instead of refresh
This commit is contained in:
Doyle 2020-08-06 17:21:00 +10:00
parent 601e9f77e1
commit a62ff316e3
28 changed files with 183 additions and 222 deletions

View File

@ -6,8 +6,6 @@
namespace blocks
{
using namespace std::literals;
template <cryptonote::network_type Network> std::string_view checkpoint_data() { return ""sv; }
template<> std::string_view checkpoint_data<cryptonote::network_type::MAINNET>();
template<> std::string_view checkpoint_data<cryptonote::network_type::DEVNET>();

View File

@ -114,21 +114,13 @@ std::string lowercase_ascii_string(std::string src);
/// Converts a duration into a human friendlier string.
std::string friendly_duration(std::chrono::nanoseconds dur);
/// Given an array of string arguments, look for strings of the format <prefix>=<value> and return <value>
/// Given an array of string arguments, look for strings of the format <prefix><value> and return <value>
/// Returns empty string view if not found.
template <typename It>
std::string_view find_named_argument(It begin, It end, std::string_view prefix)
std::string_view find_prefixed_value(It begin, It end, std::string_view prefix)
{
std::string_view result = {};
for (auto it = begin; it != end; it++)
{
if (starts_with(*it, prefix))
{
auto src = std::string_view(*it);
result = src.substr(prefix.size(), src.size() - prefix.size());
}
}
return result;
auto it = std::find_if(begin, end, [&](const auto& s) { return starts_with(s, prefix); });
if (it == end) return {};
return std::string_view{*it}.substr(prefix.size());
}
}

View File

@ -71,6 +71,12 @@ namespace tools
std::string get_human_readable_timespan(std::chrono::seconds seconds);
std::string get_human_readable_bytes(uint64_t bytes);
template <typename Duration, std::enable_if_t<!std::is_same_v<Duration, std::chrono::seconds>, int> = 0>
std::string get_human_readable_timespan(Duration d)
{
return get_human_readable_timespan(std::chrono::duration_cast<std::chrono::seconds>(d));
}
namespace detail {
// Copy an integer type, swapping to little-endian if needed
template <typename T, std::enable_if_t<std::is_integral<T>::value, int> = 0>

View File

@ -440,6 +440,13 @@ namespace cryptonote
uint8_t round;
uint16_t validator_bitset;
constexpr bool operator==(pulse_header const &other) const
{
return (std::memcmp(random_value.data, other.random_value.data, sizeof(random_value)) == 0) &&
round == other.round &&
validator_bitset == other.validator_bitset;
}
BEGIN_SERIALIZE()
FIELD(random_value);
FIELD(round);

View File

@ -1,6 +1,7 @@
// Copyright (c) 2014-2019, The Monero Project
// Copyright (c) 2019, The Loki Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are

View File

@ -39,6 +39,8 @@
#include <array>
#include <ratio>
using namespace std::literals;
#define CRYPTONOTE_MAX_BLOCK_NUMBER 500000000
#define CRYPTONOTE_MAX_TX_SIZE 1000000
#define CRYPTONOTE_MAX_TX_PER_BLOCK 0x10000000
@ -190,8 +192,6 @@ static_assert(STAKING_PORTIONS % 12 == 0, "Use a multiple of twelve, so that it
// New constants are intended to go here
namespace config
{
using namespace std::literals;
inline constexpr auto DNS_TIMEOUT = 20s;
inline constexpr uint64_t DEFAULT_FEE_ATOMIC_XMR_PER_KB = 500; // Just a placeholder! Change me!
inline constexpr uint8_t FEE_CALCULATION_MAX_RETRIES = 10;

View File

@ -293,7 +293,7 @@ uint64_t Blockchain::get_current_blockchain_height(bool lock) const
// WARNING: this function does not take m_blockchain_lock, and thus should only call read only
// m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
// well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
// lock if it is otherwise needed.
// lock if it is otherwise needed or set lock to true.
std::unique_lock lock_{*this, std::defer_lock};
if (lock) lock_.lock();
return m_db->height();
@ -1530,7 +1530,7 @@ bool Blockchain::create_block_template_internal(block& b, const crypto::hash *fr
// just as we compare it, we'll just use a slightly old template, but
// this would be the case anyway if we'd lock, and the change happened
// just after the block template was created
if (!memcmp(&info.miner_address, &m_btc_address, sizeof(cryptonote::account_public_address)) && m_btc_nonce == ex_nonce
if (info.miner_address != m_btc_address && m_btc_nonce == ex_nonce
&& m_btc_pool_cookie == m_tx_pool.cookie() && m_btc.prev_id == get_tail_id()) {
MDEBUG("Using cached template");
const uint64_t now = time(NULL);
@ -1542,7 +1542,7 @@ bool Blockchain::create_block_template_internal(block& b, const crypto::hash *fr
expected_reward = m_btc_expected_reward;
return true;
}
MDEBUG("Not using cached template: address " << (!memcmp(&info.miner_address, &m_btc_address, sizeof(cryptonote::account_public_address))) << ", nonce " << (m_btc_nonce == ex_nonce) << ", cookie " << (m_btc_pool_cookie == m_tx_pool.cookie()) << ", from_block " << (!!from_block));
MDEBUG("Not using cached template: address " << (bool)(info.miner_address != m_btc_address) << ", nonce " << (m_btc_nonce == ex_nonce) << ", cookie " << (m_btc_pool_cookie == m_tx_pool.cookie()) << ", from_block " << (!!from_block));
invalidate_block_template_cache();
}
@ -1701,10 +1701,7 @@ bool Blockchain::create_miner_block_template(block& b, const crypto::hash *from_
//------------------------------------------------------------------
bool Blockchain::create_next_miner_block_template(block& b, const account_public_address& miner_address, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce)
{
block_template_info info = {};
info.is_miner = true;
info.miner_address = miner_address;
return create_block_template_internal(b, NULL /*from_block*/, info, diffic, height, expected_reward, ex_nonce);
return create_miner_block_template(b, nullptr /*from_block*/, miner_address, diffic, height, expected_reward, ex_nonce);
}
//------------------------------------------------------------------
bool Blockchain::create_next_pulse_block_template(block& b, const service_nodes::payout& block_producer, uint64_t& height, uint64_t& expected_reward)

View File

@ -290,6 +290,8 @@ namespace cryptonote
/**
* @brief get the current height of the blockchain
*
* @param lock lock the blockchain before querying the lock
*
* @return the height
*/
uint64_t get_current_blockchain_height(bool lock = false) const;

View File

@ -1875,9 +1875,9 @@ namespace cryptonote
//-----------------------------------------------------------------------------------------------
bool core::handle_uptime_proof(const NOTIFY_UPTIME_PROOF::request &proof, bool &my_uptime_proof_confirmation)
{
crypto::x25519_public_key pkey;
bool result = m_service_node_list.handle_uptime_proof(proof, my_uptime_proof_confirmation, &pkey);
if (result && m_service_node_list.is_service_node(proof.pubkey, true /*require_active*/))
crypto::x25519_public_key pkey = {};
bool result = m_service_node_list.handle_uptime_proof(proof, my_uptime_proof_confirmation, pkey);
if (result && m_service_node_list.is_service_node(proof.pubkey, true /*require_active*/) && pkey)
{
lokimq::pubkey_set added;
added.insert(tools::copy_guts(pkey));

View File

@ -59,8 +59,6 @@ DISABLE_VS_WARNINGS(4355)
#include "common/loki_integration_test_hooks.h"
namespace cryptonote
{
using namespace std::literals;
struct test_options {
std::vector<std::pair<uint8_t, uint64_t>> hard_forks;
size_t long_term_block_weight_window;

View File

@ -308,21 +308,13 @@ namespace cryptonote
{
service_nodes::payout const &producer = miner_tx_context.pulse_block_producer;
for (auto const &payee : producer.payouts)
{
reward_payout &entry = rewards[rewards_length++];
entry.type = reward_type::snode;
entry.address = payee.address;
entry.amount = get_portion_of_reward(payee.portions, reward_parts.miner_reward());
}
rewards[rewards_length++] = {reward_type::snode, payee.address, get_portion_of_reward(payee.portions, reward_parts.miner_reward())};
}
}
else
{
CHECK_AND_ASSERT_MES(miner_tx_context.pulse_block_producer.payouts.empty(), false, "Constructing a reward for block produced by miner but payout entries specified");
reward_payout &entry = rewards[rewards_length++];
entry.type = reward_type::miner;
entry.address = miner_tx_context.miner_block_producer;
entry.amount = reward_parts.miner_reward();
rewards[rewards_length++] = {reward_type::miner, miner_tx_context.miner_block_producer, reward_parts.miner_reward()};
}
// NOTE: Add Service Node List Queue Winner
@ -331,12 +323,9 @@ namespace cryptonote
CHECK_AND_ASSERT_MES(miner_tx_context.block_leader.payouts.size(), false, "Constructing a block leader reward for block but no payout entries specified");
for (auto const &payee : miner_tx_context.block_leader.payouts)
{
reward_payout &entry = rewards[rewards_length++];
entry.type = reward_type::snode;
entry.address = payee.address;
entry.amount = get_portion_of_reward(payee.portions, reward_parts.service_node_paid);
rewards[rewards_length++] = {reward_type::snode, payee.address, get_portion_of_reward(payee.portions, reward_parts.service_node_paid)};
if (add_producer_reward_to_leader)
entry.amount += get_portion_of_reward(payee.portions, reward_parts.miner_reward());
rewards[rewards_length - 1].amount += get_portion_of_reward(payee.portions, reward_parts.miner_reward());
}
}
@ -351,29 +340,25 @@ namespace cryptonote
{
const network_type nettype = miner_tx_context.nettype;
cryptonote::address_parse_info governance_wallet_address;
cryptonote::get_account_address_from_str(governance_wallet_address, nettype, cryptonote::get_config(nettype).governance_wallet_address(hard_fork_version));
reward_payout &entry = rewards[rewards_length++];
entry.type = reward_type::governance;
entry.amount = reward_parts.governance_paid;
entry.address = governance_wallet_address.address;
rewards[rewards_length++] = {reward_type::governance, governance_wallet_address.address, reward_parts.governance_paid};
}
}
CHECK_AND_ASSERT_MES(rewards_length < rewards.size(), false, "More rewards specified than supported, number of rewards: " << rewards_length << ", capacity: " << rewards.size());
CHECK_AND_ASSERT_MES(rewards_length > 0, false, "Zero rewards are to be payed out, there should be atleast 1");
CHECK_AND_ASSERT_MES(rewards_length <= rewards.size(), false, "More rewards specified than supported, number of rewards: " << rewards_length << ", capacity: " << rewards.size());
CHECK_AND_ASSERT_MES(rewards_length > 0, false, "Zero rewards are to be payed out, there should be atleast 1");
// NOTE: Make TX Outputs
uint64_t summary_amounts = 0;
for (size_t reward_index = 0; reward_index < rewards_length; reward_index++)
{
reward_payout const &payout = rewards[reward_index];
auto const &[type, address, amount] = rewards[reward_index];
crypto::public_key out_eph_public_key{};
// TODO(doyle): I don't think txkey is necessary, just use the governance key?
keypair const &derivation_pair = (payout.type == reward_type::miner) ? txkey : gov_key;
keypair const &derivation_pair = (type == reward_type::miner) ? txkey : gov_key;
crypto::key_derivation derivation{};
if (!get_deterministic_output_key(payout.address, derivation_pair, reward_index, out_eph_public_key))
if (!get_deterministic_output_key(address, derivation_pair, reward_index, out_eph_public_key))
{
MERROR("Failed to generate output one-time public key");
return false;
@ -384,10 +369,10 @@ namespace cryptonote
tx_out out = {};
out.target = tk;
out.amount = payout.amount;
out.amount = amount;
tx.vout.push_back(out);
tx.output_unlock_times.push_back(height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW);
summary_amounts += payout.amount;
summary_amounts += amount;
}
uint64_t expected_amount = reward_parts.miner_reward() + reward_parts.governance_paid + reward_parts.service_node_paid;

View File

@ -33,8 +33,6 @@ extern "C"
namespace lns
{
using namespace std::literals;
enum struct lns_sql_type
{
save_owner,

View File

@ -10,6 +10,9 @@
#include "service_node_quorum_cop.h"
#include "service_node_rules.h"
#undef LOKI_DEFAULT_LOG_CATEGORY
#define LOKI_DEFAULT_LOG_CATEGORY "pulse"
enum struct round_state
{
wait_next_block,
@ -24,7 +27,6 @@ enum struct round_state
constexpr std::string_view round_state_string(round_state state)
{
using namespace std::literals;
switch(state)
{
default: assert("Invalid Code Path" == nullptr);
@ -37,6 +39,8 @@ constexpr std::string_view round_state_string(round_state state)
case round_state::wait_for_block_template: return "Wait For Block Template"sv;
case round_state::terminate: return "Terminate"sv;
}
return "Invalid2"sv;
}
struct round_context
@ -86,6 +90,8 @@ struct round_context
cryptonote::block block;
pulse::time_point end_time;
} wait_for_block_template;
uint64_t height;
};
namespace
@ -102,17 +108,15 @@ round_state thread_sleep(sleep_until until,
pulse::state &state,
cryptonote::Blockchain const &blockchain,
round_context &context,
std::mutex &mutex,
uint64_t pulse_height)
std::mutex &mutex)
{
switch(until)
{
case sleep_until::next_block:
{
std::unique_lock lock{mutex};
state.wakeup_cv.wait(lock, [&state, &blockchain, pulse_height]() {
uint64_t curr_height = blockchain.get_current_blockchain_height(true /*lock*/);
return pulse_height != curr_height || state.shutdown;
state.wakeup_cv.wait(lock, [&state, &blockchain, height = context.height]() {
return state.shutdown || height != blockchain.get_current_blockchain_height(true /*lock*/);
});
return state.shutdown ? round_state::terminate : round_state::wait_next_block;
@ -130,17 +134,16 @@ round_state thread_sleep(sleep_until until,
pulse::time_point const start_time = context.wait_next_block.round_0_start_time +
(context.wait_next_block.round * service_nodes::PULSE_TIME_PER_BLOCK);
uint64_t curr_height = pulse_height;
uint64_t curr_height = context.height;
if (auto now = pulse::clock::now(); now < start_time)
{
auto duration = std::chrono::duration_cast<std::chrono::seconds>(start_time - now).count();
MGINFO("Pulse: Sleeping " << duration << "s until pulse round " << +context.wait_next_block.round << " commences for block " << pulse_height);
MINFO("Pulse: Sleeping " << tools::get_human_readable_timespan(start_time - now) << " until pulse round " << +context.wait_next_block.round << " commences for block " << context.height);
std::unique_lock lock{mutex};
state.wakeup_cv.wait_until(lock, start_time, [&state, &blockchain, start_time, pulse_height, &curr_height]() {
state.wakeup_cv.wait_until(lock, start_time, [&state, &blockchain, start_time, height = context.height, &curr_height]() {
bool wakeup_time = pulse::clock::now() >= start_time;
curr_height = blockchain.get_current_blockchain_height(true /*lock*/);
return wakeup_time || (pulse_height != curr_height) || state.shutdown;
return wakeup_time || (height != curr_height) || state.shutdown;
});
if (state.shutdown)
@ -148,9 +151,9 @@ round_state thread_sleep(sleep_until until,
}
if (pulse_height != curr_height)
if (context.height != curr_height)
{
MGINFO("Pulse: Blockchain height changed during sleep from " << pulse_height << " to " << curr_height << ", re-evaluating pulse block");
MINFO("Pulse: Blockchain height changed during sleep from " << context.height << " to " << curr_height << ", re-evaluating pulse block");
return round_state::wait_next_block;
}
@ -160,33 +163,27 @@ round_state thread_sleep(sleep_until until,
}
}
std::string log_prefix(uint64_t height, round_context const &context)
std::string log_prefix(round_context const &context)
{
std::stringstream result;
result << "Pulse B" << height << " R" << +context.wait_next_block.round << ": ";
result << "Pulse B" << context.height << " R" << +context.wait_next_block.round << ": ";
if (context.round_starts.node_name.size()) result << context.round_starts.node_name << " ";
return result.str();
}
bool msg_time_check(uint64_t height, round_context const &context, pulse::message const &msg, pulse::time_point now, pulse::time_point start, pulse::time_point end)
bool msg_time_check(round_context const &context, pulse::message const &msg, pulse::time_point now, pulse::time_point start, pulse::time_point end)
{
if (now < start || now >= end)
{
std::stringstream stream;
stream << log_prefix(height, context) << "Dropping " << pulse::message_type_string(msg.type) << " message from validator " << msg.handshakes.quorum_position << ", message arrived ";
stream << log_prefix(context) << "Dropping " << pulse::message_type_string(msg.type) << " message from validator " << msg.handshakes.quorum_position << ", message arrived ";
if (now < start)
{
auto delta = std::chrono::duration_cast<std::chrono::seconds>(context.wait_for_handshakes.end_time - now);
stream << delta.count() << "s early";
}
stream << tools::get_human_readable_timespan(context.wait_for_handshakes.end_time - now) << " early";
else
{
auto delta = std::chrono::duration_cast<std::chrono::seconds>(now - context.wait_for_handshakes.end_time);
stream << delta.count() << "s late";
}
stream << tools::get_human_readable_timespan(now - context.wait_for_handshakes.end_time) << " late";
MGINFO(stream.str());
MINFO(stream.str());
return false;
}
@ -198,8 +195,8 @@ bool msg_time_check(uint64_t height, round_context const &context, pulse::messag
bool pulse::state::block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>&, cryptonote::checkpoint_t const *)
{
// TODO(doyle): Better check than heuristics.
cryptonote::pulse_header null_header = {};
if (block.signatures.size() != service_nodes::PULSE_BLOCK_REQUIRED_SIGNATURES || std::memcmp(&block.pulse, &null_header, sizeof(null_header) == 0))
constexpr cryptonote::pulse_header null_header = {};
if (block.signatures.size() != service_nodes::PULSE_BLOCK_REQUIRED_SIGNATURES || block.pulse == null_header)
last_miner_block = cryptonote::get_block_height(block);
wakeup_cv.notify_one();
@ -311,7 +308,7 @@ bool pulse::state::block_added(const cryptonote::block& block, const std::vector
*/
void pump_messages_from_quorumnet(void *quorumnet_state, round_state round_state, round_context &context, uint64_t pulse_height, crypto::hash const &top_hash)
void pump_messages_from_quorumnet(void *quorumnet_state, round_state round_state, round_context &context, crypto::hash const &top_hash)
{
//
// NOTE: Determine how long to pump messages from the queue
@ -336,8 +333,9 @@ void pump_messages_from_quorumnet(void *quorumnet_state, round_state round_state
if (auto now = pulse::clock::now(); now < pump_messages_until)
{
auto duration = std::chrono::duration_cast<std::chrono::seconds>(pump_messages_until - now);
MGINFO(log_prefix(pulse_height, context) << "Pumping messages for '" << round_state_string(round_state) << "' from quorumnet for " << duration.count() << "s or until all messages received.");
MINFO(log_prefix(context) << "Pumping messages for '" << round_state_string(round_state) << "' from quorumnet for "
<< tools::get_human_readable_timespan(pump_messages_until - now)
<< " or until all messages received.");
}
//
@ -353,7 +351,7 @@ void pump_messages_from_quorumnet(void *quorumnet_state, round_state round_state
{
if (msg.handshakes.quorum_position >= static_cast<int>(context.wait_for_round.quorum.validators.size()))
{
MERROR(log_prefix(pulse_height, context) << "Quorum position " << msg.handshakes.quorum_position << " in Pulse message indexes oob");
MERROR(log_prefix(context) << "Quorum position " << msg.handshakes.quorum_position << " in Pulse message indexes oob");
continue;
}
@ -373,7 +371,7 @@ void pump_messages_from_quorumnet(void *quorumnet_state, round_state round_state
if (!crypto::check_signature(hash, validator_key, msg.handshakes.signature))
{
MERROR(log_prefix(pulse_height, context) << "Signature from pulse handshake bit does not validate with node " << msg.handshakes.quorum_position << ":" << lokimq::to_hex(tools::view_guts(validator_key)) << ", at height " << pulse_height << "; Validator signing outdated height or bad handshake data");
MERROR(log_prefix(context) << "Signature from pulse handshake bit does not validate with node " << msg.handshakes.quorum_position << ":" << lokimq::to_hex(tools::view_guts(validator_key)) << ", at height " << context.height << "; Validator signing outdated height or bad handshake data");
continue;
}
}
@ -386,7 +384,7 @@ void pump_messages_from_quorumnet(void *quorumnet_state, round_state round_state
{
// TODO(doyle): We need some lenience in time for accepting early
// handshakes in case clocks are slightly out of sync.
if (!msg_time_check(pulse_height, context, msg, pulse::clock::now(), context.wait_for_handshakes.start_time, context.wait_for_handshakes.end_time))
if (!msg_time_check(context, msg, pulse::clock::now(), context.wait_for_handshakes.start_time, context.wait_for_handshakes.end_time))
continue;
uint16_t quorum_position_bit = 1 << msg.handshakes.quorum_position;
@ -398,14 +396,14 @@ void pump_messages_from_quorumnet(void *quorumnet_state, round_state round_state
{
auto position_bitset = std::bitset<sizeof(quorum_position_bit) * 8>(quorum_position_bit);
auto validator_bitset = std::bitset<sizeof(quorum_position_bit) * 8>(context.wait_for_handshakes.validator_bits);
MGINFO(log_prefix(pulse_height, context) << "Received handshake with quorum position bit (" << msg.handshakes.quorum_position <<") " << position_bitset << " saved to bitset " << validator_bitset);
MINFO(log_prefix(context) << "Received handshake with quorum position bit (" << msg.handshakes.quorum_position <<") " << position_bitset << " saved to bitset " << validator_bitset);
}
}
break;
case pulse::message_type::handshake_bitset:
{
if (!msg_time_check(pulse_height, context, msg, pulse::clock::now(), context.wait_for_handshakes.start_time, context.wait_for_handshake_bitsets.end_time))
if (!msg_time_check(context, msg, pulse::clock::now(), context.wait_for_handshakes.start_time, context.wait_for_handshake_bitsets.end_time))
continue;
uint16_t prev_bitset = context.wait_for_handshake_bitsets.bitsets[msg.handshakes.quorum_position];
@ -424,14 +422,14 @@ void pump_messages_from_quorumnet(void *quorumnet_state, round_state round_state
{
assert(!context.round_starts.is_producer);
if (!msg_time_check(pulse_height, context, msg, pulse::clock::now(), context.wait_for_handshakes.start_time, context.wait_for_block_template.end_time))
if (!msg_time_check(context, msg, pulse::clock::now(), context.wait_for_handshakes.start_time, context.wait_for_block_template.end_time))
continue;
// TODO(doyle): Time check
cryptonote::block block = {};
if (!cryptonote::t_serializable_object_from_blob(block, msg.block_template.blob))
{
MGINFO(log_prefix(pulse_height, context) << "Received unparsable pulse block template blob");
MINFO(log_prefix(context) << "Received unparsable pulse block template blob");
continue;
}
@ -439,13 +437,13 @@ void pump_messages_from_quorumnet(void *quorumnet_state, round_state round_state
crypto::hash hash = crypto::cn_fast_hash(msg.block_template.blob.data(), msg.block_template.blob.size());
if (!crypto::check_signature(hash, block_producer, msg.block_template.signature))
{
MGINFO(log_prefix(pulse_height, context) << "Received pulse block template not signed by the block producer");
MINFO(log_prefix(context) << "Received pulse block template not signed by the block producer");
continue;
}
if (block.pulse.round != context.wait_next_block.round)
{
MGINFO(log_prefix(pulse_height, context) << "Received pulse block template specifying different round " << +block.pulse.round << ", expected " << +context.wait_next_block.round);
MINFO(log_prefix(context) << "Received pulse block template specifying different round " << +block.pulse.round << ", expected " << +context.wait_next_block.round);
continue;
}
@ -453,7 +451,7 @@ void pump_messages_from_quorumnet(void *quorumnet_state, round_state round_state
{
auto block_bitset = std::bitset<sizeof(block.pulse.validator_bitset) * 8>(block.pulse.validator_bitset);
auto our_bitset = std::bitset<sizeof(block.pulse.validator_bitset) * 8>(context.submit_block_template.validator_bitset);
MGINFO(log_prefix(pulse_height, context) << "Received pulse block template specifying different validator handshake bitsets " << block_bitset << ", expected " << our_bitset);
MINFO(log_prefix(context) << "Received pulse block template specifying different validator handshake bitsets " << block_bitset << ", expected " << our_bitset);
continue;
}
@ -486,7 +484,6 @@ void pulse::main(pulse::state &state, void *quorumnet_state, cryptonote::core &c
cryptonote::block base_pulse_block = {};
crypto::hash top_hash = {};
uint64_t pulse_height = 0;
std::mutex pulse_mutex;
round_context context = {};
@ -497,15 +494,18 @@ void pulse::main(pulse::state &state, void *quorumnet_state, cryptonote::core &c
uint64_t const hf16_height = cryptonote::HardFork::get_hardcoded_hard_fork_height(blockchain.nettype(), cryptonote::network_version_16);
{
if (hf16_height == cryptonote::HardFork::INVALID_HF_VERSION_HEIGHT)
{
MERROR("Pulse: HF16 is not defined, pulse worker exiting.");
return;
}
uint64_t height = blockchain.get_current_blockchain_height(true /*lock*/);
if (height < hf16_height)
MGINFO("Pulse: Network at block " << height << " is not ready for Pulse until block " << hf16_height << ", worker going to sleep");
MINFO("Pulse: Network at block " << height << " is not ready for Pulse until block " << hf16_height << ", worker going to sleep");
for (; height < hf16_height; height = blockchain.get_current_blockchain_height(true /*lock*/))
{
auto result = thread_sleep(sleep_until::next_block, state, blockchain, context, pulse_mutex, height);
auto result = thread_sleep(sleep_until::next_block, state, blockchain, context, pulse_mutex);
if (result == round_state::terminate) return;
}
}
@ -517,9 +517,6 @@ void pulse::main(pulse::state &state, void *quorumnet_state, cryptonote::core &c
case round_state::terminate:
return;
default:
break;
case round_state::wait_next_block:
{
context = {};
@ -527,18 +524,18 @@ void pulse::main(pulse::state &state, void *quorumnet_state, cryptonote::core &c
//
// NOTE: If already processing pulse for height, wait for next height
//
if (pulse_height == blockchain.get_current_blockchain_height(true /*lock*/))
if (context.height == blockchain.get_current_blockchain_height(true /*lock*/))
{
MGINFO(log_prefix(pulse_height, context) << "Network is currently producing block " << pulse_height << ", sleeping until next block");
round_state = thread_sleep(sleep_until::next_block, state, blockchain, context, pulse_mutex, pulse_height);
MINFO(log_prefix(context) << "Network is currently producing block " << context.height << ", sleeping until next block");
round_state = thread_sleep(sleep_until::next_block, state, blockchain, context, pulse_mutex);
}
pulse_height = blockchain.get_current_blockchain_height(true /*lock*/);
top_hash = blockchain.get_block_id_by_height(pulse_height - 1);
context.height = blockchain.get_current_blockchain_height(true /*lock*/);
top_hash = blockchain.get_block_id_by_height(context.height - 1);
if (top_hash == crypto::null_hash)
{
MERROR(log_prefix(pulse_height, context) << "Block hash for height " << pulse_height << " does not exist!");
MERROR(log_prefix(context) << "Block hash for height " << context.height << " does not exist!");
continue;
}
@ -548,14 +545,14 @@ void pulse::main(pulse::state &state, void *quorumnet_state, cryptonote::core &c
#if 0
uint64_t base_height = std::max(hf16_height, state.last_miner_block.load());
#else
uint64_t base_height = std::max(hf16_height, pulse_height - 1); // (DEBUG): Make next block timestamps relative to previous block.
uint64_t base_height = std::max(hf16_height, context.height - 1); // (DEBUG): Make next block timestamps relative to previous block.
#endif
if (!base_block_initialized || (cryptonote::get_block_height(base_pulse_block) != base_height))
{
std::vector<std::pair<cryptonote::blobdata, cryptonote::block>> block;
if (!blockchain.get_blocks(base_height, 1, block))
{
MERROR(log_prefix(pulse_height, context) << " Could not query block " << base_height << " from the DB, unable to continue with Pulse");
MERROR(log_prefix(context) << " Could not query block " << base_height << " from the DB, unable to continue with Pulse");
continue;
}
@ -564,7 +561,7 @@ void pulse::main(pulse::state &state, void *quorumnet_state, cryptonote::core &c
}
auto base_timestamp = pulse::time_point(std::chrono::seconds(base_pulse_block.timestamp));
uint64_t delta_height = pulse_height - cryptonote::get_block_height(base_pulse_block);
uint64_t delta_height = context.height - cryptonote::get_block_height(base_pulse_block);
context.wait_next_block.round_0_start_time = base_timestamp + (delta_height * service_nodes::PULSE_TIME_PER_BLOCK);
//
@ -576,7 +573,7 @@ void pulse::main(pulse::state &state, void *quorumnet_state, cryptonote::core &c
}
else
{
auto const time_since_block = pulse::clock::now() - context.wait_next_block.round_0_start_time;
auto const time_since_block = now - context.wait_next_block.round_0_start_time;
size_t pulse_round_usize = time_since_block / service_nodes::PULSE_TIME_PER_BLOCK;
context.wait_next_block.round = static_cast<uint8_t>(pulse_round_usize);
}
@ -594,9 +591,9 @@ void pulse::main(pulse::state &state, void *quorumnet_state, cryptonote::core &c
//
pulse::time_point const start_time = context.wait_next_block.round_0_start_time +
(context.wait_next_block.round * service_nodes::PULSE_TIME_PER_BLOCK);
context.wait_for_handshakes.end_time = start_time + service_nodes::PULSE_WAIT_FOR_HANDSHAKES_DURATION;
context.wait_for_handshake_bitsets.end_time = context.wait_for_handshakes.end_time + service_nodes::PULSE_WAIT_FOR_OTHER_VALIDATOR_HANDSHAKES_DURATION;
context.wait_for_block_template.end_time = context.wait_for_handshake_bitsets.end_time + service_nodes::PULSE_WAIT_FOR_BLOCK_TEMPLATE_DURATION;
context.wait_for_handshakes.end_time = start_time + service_nodes::PULSE_WAIT_FOR_HANDSHAKES_DURATION;
context.wait_for_handshake_bitsets.end_time = context.wait_for_handshakes.end_time + service_nodes::PULSE_WAIT_FOR_OTHER_VALIDATOR_HANDSHAKES_DURATION;
context.wait_for_block_template.end_time = context.wait_for_handshake_bitsets.end_time + service_nodes::PULSE_WAIT_FOR_BLOCK_TEMPLATE_DURATION;
//
// NOTE: Quorum
@ -604,7 +601,7 @@ void pulse::main(pulse::state &state, void *quorumnet_state, cryptonote::core &c
context.wait_for_round.quorum =
service_nodes::generate_pulse_quorum(blockchain.nettype(),
blockchain.get_db(),
pulse_height - 1,
context.height - 1,
blockchain.get_service_node_list().get_block_leader().key,
blockchain.get_current_hard_fork_version(),
blockchain.get_service_node_list().active_service_nodes_infos(),
@ -612,12 +609,12 @@ void pulse::main(pulse::state &state, void *quorumnet_state, cryptonote::core &c
if (service_nodes::verify_pulse_quorum_sizes(context.wait_for_round.quorum))
{
round_state = thread_sleep(sleep_until::round_starts, state, blockchain, context, pulse_mutex, pulse_height);
round_state = thread_sleep(sleep_until::round_starts, state, blockchain, context, pulse_mutex);
}
else
{
MGINFO(log_prefix(pulse_height, context) << "Insufficient Service Nodes to execute Pulse on height " << pulse_height << ", we require a PoW miner block. Sleeping until next block.");
round_state = thread_sleep(sleep_until::next_block, state, blockchain, context, pulse_mutex, pulse_height);
MINFO(log_prefix(context) << "Insufficient Service Nodes to execute Pulse on height " << context.height << ", we require a PoW miner block. Sleeping until next block.");
round_state = thread_sleep(sleep_until::next_block, state, blockchain, context, pulse_mutex);
}
}
break;
@ -660,27 +657,27 @@ void pulse::main(pulse::state &state, void *quorumnet_state, cryptonote::core &c
{
context.wait_for_handshakes.validator_bits |= (1 << context.round_starts.my_quorum_position); // Add myself
MGINFO(log_prefix(pulse_height, context) << "We are a pulse validator, sending handshake bit to quorum and collecting other validator handshakes.");
MINFO(log_prefix(context) << "We are a pulse validator, sending handshake bit to quorum and collecting other validator handshakes.");
cryptonote::quorumnet_send_pulse_validator_handshake_bit(quorumnet_state, context.wait_for_round.quorum, top_hash);
round_state = round_state::wait_for_handshakes;
}
catch (std::exception const &e)
{
MERROR(log_prefix(pulse_height, context) << "Attempting to invoke and send a Pulse participation handshake unexpectedly failed. " << e.what());
round_state = thread_sleep(sleep_until::next_block_or_round, state, blockchain, context, pulse_mutex, pulse_height);
MERROR(log_prefix(context) << "Attempting to invoke and send a Pulse participation handshake unexpectedly failed. " << e.what());
round_state = thread_sleep(sleep_until::next_block_or_round, state, blockchain, context, pulse_mutex);
}
}
else
{
context.round_starts.node_name = "W[0]";
MGINFO(log_prefix(pulse_height, context) << "We are the block producer for height " << pulse_height << " in round " << +context.wait_next_block.round << ", awaiting validator handshake bitsets.");
MINFO(log_prefix(context) << "We are the block producer for height " << context.height << " in round " << +context.wait_next_block.round << ", awaiting validator handshake bitsets.");
round_state = round_state::wait_for_handshake_bitsets;
}
}
else
{
MGINFO(log_prefix(pulse_height, context) << "We are not a pulse validator. Waiting for next pulse round or block.");
round_state = thread_sleep(sleep_until::next_block_or_round, state, blockchain, context, pulse_mutex, pulse_height);
MINFO(log_prefix(context) << "We are not a pulse validator. Waiting for next pulse round or block.");
round_state = thread_sleep(sleep_until::next_block_or_round, state, blockchain, context, pulse_mutex);
}
}
@ -703,7 +700,7 @@ void pulse::main(pulse::state &state, void *quorumnet_state, cryptonote::core &c
context.wait_for_handshake_bitsets.bitsets_count++;
bool missing_handshakes = timed_out && !all_handshakes;
MGINFO(log_prefix(pulse_height, context) << "Collected validator handshakes " << bitset << (missing_handshakes ? ", we timed out and some handshakes were not seen! " : ". ") << "Sending handshake bitset and collecting other validator bitsets.");
MINFO(log_prefix(context) << "Collected validator handshakes " << bitset << (missing_handshakes ? ", we timed out and some handshakes were not seen! " : ". ") << "Sending handshake bitset and collecting other validator bitsets.");
try
{
cryptonote::quorumnet_send_pulse_validator_handshake_bitset(quorumnet_state, context.wait_for_round.quorum, top_hash, context.wait_for_handshakes.validator_bits);
@ -711,8 +708,8 @@ void pulse::main(pulse::state &state, void *quorumnet_state, cryptonote::core &c
}
catch(std::exception const &e)
{
MERROR(log_prefix(pulse_height, context) << "Attempting to invoke and send a Pulse validator bitset unexpectedly failed. " << e.what());
round_state = thread_sleep(sleep_until::next_block_or_round, state, blockchain, context, pulse_mutex, pulse_height);
MERROR(log_prefix(context) << "Attempting to invoke and send a Pulse validator bitset unexpectedly failed. " << e.what());
round_state = thread_sleep(sleep_until::next_block_or_round, state, blockchain, context, pulse_mutex);
}
}
}
@ -728,7 +725,7 @@ void pulse::main(pulse::state &state, void *quorumnet_state, cryptonote::core &c
if (timed_out || all_bitsets)
{
bool missing_bitsets = timed_out && !all_bitsets;
MGINFO(log_prefix(pulse_height, context)
MINFO(log_prefix(context)
<< "Collected " << bitsets_count << "/" << max_bitsets << " handshake bitsets"
<< (missing_bitsets ? ", we timed out and some bitsets were not seen!" : ""));
@ -745,7 +742,7 @@ void pulse::main(pulse::state &state, void *quorumnet_state, cryptonote::core &c
count = num;
}
MGINFO(log_prefix(pulse_height, context) << "Collected from V[" << validator_index << "], handshake bitset " << std::bitset<8 * sizeof(bits)>(bits));
MINFO(log_prefix(context) << "Collected from V[" << validator_index << "], handshake bitset " << std::bitset<8 * sizeof(bits)>(bits));
}
int count_threshold = (service_nodes::PULSE_QUORUM_NUM_VALIDATORS * 6 / 10);
@ -756,21 +753,21 @@ void pulse::main(pulse::state &state, void *quorumnet_state, cryptonote::core &c
// next round.
if (most_common_bitset == 0)
{
MGINFO(log_prefix(pulse_height, context) << count << "/" << max_bitsets << " validators did not send any handshake bitset or sent an empty handshake bitset");
MINFO(log_prefix(context) << count << "/" << max_bitsets << " validators did not send any handshake bitset or sent an empty handshake bitset");
}
else
{
MGINFO(log_prefix(pulse_height, context)
MINFO(log_prefix(context)
<< "We heard back from less than " << count_threshold << " of the validators (" << count << "/"
<< max_bitsets << ", waiting for next round.");
}
round_state = thread_sleep(sleep_until::next_block_or_round, state, blockchain, context, pulse_mutex, pulse_height);
round_state = thread_sleep(sleep_until::next_block_or_round, state, blockchain, context, pulse_mutex);
}
else
{
std::bitset<8 * sizeof(most_common_bitset)> bitset = most_common_bitset;
MGINFO(log_prefix(pulse_height, context) << count << "/" << max_bitsets << " validators agreed on the participating nodes in the quorum " << bitset << (context.round_starts.is_producer ? "" : ". Awaiting block template from block producer"));
MINFO(log_prefix(context) << count << "/" << max_bitsets << " validators agreed on the participating nodes in the quorum " << bitset << (context.round_starts.is_producer ? "" : ". Awaiting block template from block producer"));
context.submit_block_template.validator_bitset = most_common_bitset;
if (context.round_starts.is_producer)
@ -789,7 +786,7 @@ void pulse::main(pulse::state &state, void *quorumnet_state, cryptonote::core &c
if (list_state.empty())
{
MGINFO(log_prefix(pulse_height, context) << "Block producer (us) is not available on the service node list, waiting until next round");
MINFO(log_prefix(context) << "Block producer (us) is not available on the service node list, waiting until next round");
round_state = round_state::wait_next_block;
break;
}
@ -798,17 +795,17 @@ void pulse::main(pulse::state &state, void *quorumnet_state, cryptonote::core &c
std::shared_ptr<const service_nodes::service_node_info> info = list_state[0].info;
if (!info->is_active())
{
MGINFO(log_prefix(pulse_height, context) << "Block producer (us) is not an active service node, waiting until next round");
round_state = thread_sleep(sleep_until::next_block_or_round, state, blockchain, context, pulse_mutex, pulse_height);
MINFO(log_prefix(context) << "Block producer (us) is not an active service node, waiting until next round");
round_state = thread_sleep(sleep_until::next_block_or_round, state, blockchain, context, pulse_mutex);
break;
}
MGINFO(log_prefix(pulse_height, context) << "Validators are handshaken and ready, sending block template from producer (us) to validators.\n");
MINFO(log_prefix(context) << "Validators are handshaken and ready, sending block template from producer (us) to validators.\n");
service_nodes::payout block_producer_payouts = service_nodes::service_node_info_to_payout(key.pub, *info);
cryptonote::block block = {};
uint64_t expected_reward = 0;
blockchain.create_next_pulse_block_template(block, block_producer_payouts, pulse_height, expected_reward);
blockchain.create_next_pulse_block_template(block, block_producer_payouts, context.height, expected_reward);
block.pulse.round = context.wait_next_block.round;
block.pulse.validator_bitset = context.submit_block_template.validator_bitset;
@ -820,7 +817,7 @@ void pulse::main(pulse::state &state, void *quorumnet_state, cryptonote::core &c
crypto::generate_signature(hash, core.get_service_keys().pub, core.get_service_keys().key, block_signature);
cryptonote::quorumnet_send_pulse_block_template(quorumnet_state, std::move(block_blob), block_signature, context.wait_for_round.quorum);
round_state = thread_sleep(sleep_until::next_block, state, blockchain, context, pulse_mutex, pulse_height);
round_state = thread_sleep(sleep_until::next_block, state, blockchain, context, pulse_mutex);
}
break;
@ -831,16 +828,16 @@ void pulse::main(pulse::state &state, void *quorumnet_state, cryptonote::core &c
if (timed_out || context.wait_for_block_template.received)
{
if (context.wait_for_block_template.received)
MGINFO(log_prefix(pulse_height, context) << "Valid block received: " << cryptonote::obj_to_json_str(context.wait_for_block_template.block));
MINFO(log_prefix(context) << "Valid block received: " << cryptonote::obj_to_json_str(context.wait_for_block_template.block));
else
MGINFO(log_prefix(pulse_height, context) << "Block template not received");
MINFO(log_prefix(context) << "Block template not received");
round_state = thread_sleep(sleep_until::next_block, state, blockchain, context, pulse_mutex, pulse_height);
round_state = thread_sleep(sleep_until::next_block, state, blockchain, context, pulse_mutex);
}
}
break;
}
pump_messages_from_quorumnet(quorumnet_state, round_state, context, pulse_height, top_hash);
pump_messages_from_quorumnet(quorumnet_state, round_state, context, top_hash);
}
}

View File

@ -36,14 +36,14 @@ enum struct message_type : uint8_t
constexpr std::string_view message_type_string(message_type type)
{
using namespace std::literals;
switch(type)
{
default:
case message_type::invalid: return "Invalid"sv;
case message_type::handshake: return "Handshake"sv;
case message_type::handshake_bitset: return "Handshake Bitset"sv;
case message_type::block_template: return "Block Template"sv;
}
return "Invalid2"sv;
}
struct message

View File

@ -1808,7 +1808,7 @@ namespace service_nodes
uint64_t block_height = cryptonote::get_block_height(block);
uint8_t hf_version = block.major_version;
if (hf_version < 9)
if (hf_version < cryptonote::network_version_9_service_nodes)
return;
// Cull old history
@ -2060,11 +2060,11 @@ namespace service_nodes
bool service_node_list::validate_miner_tx(cryptonote::block const &block, cryptonote::block_reward_parts const &reward_parts) const
{
std::lock_guard lock(m_sn_mutex);
if (block.major_version < 9)
uint8_t const hf_version = block.major_version;
if (hf_version < cryptonote::network_version_9_service_nodes)
return true;
uint8_t const hf_version = block.major_version;
std::lock_guard lock(m_sn_mutex);
uint64_t const height = cryptonote::get_block_height(block);
cryptonote::transaction const &miner_tx = block.miner_tx;
@ -2125,7 +2125,7 @@ namespace service_nodes
//
// Pulse Block
// Up to 4 | Block Producer (0-3 for Pooled Service Node)
// Up To 3 | Queued Service Node
// Up To 4 | Queued Service Node
// Up To 1 | Governance
//
std::shared_ptr<const service_node_info> block_producer = nullptr;
@ -2523,7 +2523,7 @@ namespace service_nodes
#define REJECT_PROOF(log) do { LOG_PRINT_L2("Rejecting uptime proof from " << proof.pubkey << ": " log); return false; } while (0)
bool service_node_list::handle_uptime_proof(cryptonote::NOTIFY_UPTIME_PROOF::request const &proof, bool &my_uptime_proof_confirmation, crypto::x25519_public_key *x25519_pkey)
bool service_node_list::handle_uptime_proof(cryptonote::NOTIFY_UPTIME_PROOF::request const &proof, bool &my_uptime_proof_confirmation, crypto::x25519_public_key &x25519_pkey)
{
uint8_t const hf_version = m_blockchain.get_current_hard_fork_version();
uint64_t const now = time(nullptr);
@ -2603,8 +2603,8 @@ namespace service_nodes
if (derived_x25519_pubkey)
x25519_to_pub[derived_x25519_pubkey] = {proof.pubkey, now};
if (x25519_pkey)
*x25519_pkey = derived_x25519_pubkey;
if (derived_x25519_pubkey && (old_x25519 != derived_x25519_pubkey))
x25519_pkey = derived_x25519_pubkey;
return true;
}

View File

@ -436,7 +436,7 @@ namespace service_nodes
uint16_t storage_port,
uint16_t storage_lmq_port,
uint16_t quorumnet_port) const;
bool handle_uptime_proof (cryptonote::NOTIFY_UPTIME_PROOF::request const &proof, bool &my_uptime_proof_confirmation, crypto::x25519_public_key *x25519_pkey = nullptr);
bool handle_uptime_proof (cryptonote::NOTIFY_UPTIME_PROOF::request const &proof, bool &my_uptime_proof_confirmation, crypto::x25519_public_key &x25519_pkey);
void record_checkpoint_vote (crypto::public_key const &pubkey, uint64_t height, bool voted);
// Called every hour to remove proofs for expired SNs from memory and the database.

View File

@ -8,25 +8,25 @@
namespace service_nodes {
constexpr size_t PULSE_QUORUM_ENTROPY_LAG = 21; // How many blocks back from the tip of the Blockchain to source entropy for the Pulse quorums.
#if defined(LOKI_ENABLE_INTEGRATION_TEST_HOOKS)
constexpr auto PULSE_TIME_PER_BLOCK = std::chrono::seconds(20);
constexpr auto PULSE_WAIT_FOR_HANDSHAKES_DURATION = std::chrono::seconds(7);
constexpr auto PULSE_WAIT_FOR_OTHER_VALIDATOR_HANDSHAKES_DURATION = std::chrono::seconds(7);
constexpr auto PULSE_WAIT_FOR_BLOCK_TEMPLATE_DURATION = std::chrono::seconds(6);
constexpr auto PULSE_TIME_PER_BLOCK = 2s;
constexpr auto PULSE_WAIT_FOR_HANDSHAKES_DURATION = 7s;
constexpr auto PULSE_WAIT_FOR_OTHER_VALIDATOR_HANDSHAKES_DURATION = 7s;
constexpr auto PULSE_WAIT_FOR_BLOCK_TEMPLATE_DURATION = 6s;
constexpr size_t PULSE_QUORUM_NUM_VALIDATORS = 0;
constexpr size_t PULSE_BLOCK_REQUIRED_SIGNATURES = 0;
#else
constexpr auto PULSE_TIME_PER_BLOCK = std::chrono::seconds(20);
constexpr auto PULSE_WAIT_FOR_HANDSHAKES_DURATION = std::chrono::seconds(7);
constexpr auto PULSE_WAIT_FOR_OTHER_VALIDATOR_HANDSHAKES_DURATION = std::chrono::seconds(7);
constexpr auto PULSE_WAIT_FOR_BLOCK_TEMPLATE_DURATION = std::chrono::seconds(6);
constexpr auto PULSE_TIME_PER_BLOCK = 20s;
constexpr auto PULSE_WAIT_FOR_HANDSHAKES_DURATION = 7s;
constexpr auto PULSE_WAIT_FOR_OTHER_VALIDATOR_HANDSHAKES_DURATION = 7s;
constexpr auto PULSE_WAIT_FOR_BLOCK_TEMPLATE_DURATION = 6s;
constexpr size_t PULSE_QUORUM_NUM_VALIDATORS = 7;
constexpr size_t PULSE_BLOCK_REQUIRED_SIGNATURES = 7; // A block must have exactly N signatures to be considered properly
#endif
constexpr size_t PULSE_QUORUM_SIZE = PULSE_QUORUM_NUM_VALIDATORS + 1 /*Leader*/;
static_assert(PULSE_TIME_PER_BLOCK ==
static_assert(PULSE_TIME_PER_BLOCK >=
PULSE_WAIT_FOR_HANDSHAKES_DURATION + PULSE_WAIT_FOR_OTHER_VALIDATOR_HANDSHAKES_DURATION + PULSE_WAIT_FOR_BLOCK_TEMPLATE_DURATION);
static_assert(PULSE_QUORUM_NUM_VALIDATORS >= PULSE_BLOCK_REQUIRED_SIGNATURES);

View File

@ -56,8 +56,6 @@ namespace cryptonote
/* */
/************************************************************************/
using namespace std::literals;
//! tuple of <deregister, transaction fee, receive time> for organization
typedef std::pair<std::tuple<bool, double, std::time_t>, crypto::hash> tx_by_fee_and_receive_time_entry;

View File

@ -58,8 +58,6 @@ DISABLE_VS_WARNINGS(4355)
namespace cryptonote
{
using namespace std::literals;
template<class t_core>
class t_cryptonote_protocol_handler: public i_cryptonote_protocol
{

View File

@ -50,7 +50,6 @@ namespace quorumnet {
namespace {
using namespace service_nodes;
using namespace std::literals;
using namespace lokimq;
using blink_tx = cryptonote::blink_tx;
@ -1542,19 +1541,11 @@ void send_pulse_validator_handshake_bit_or_bitset(void *self, bool sending_bitse
throw std::runtime_error("Pulse: Daemon is not a service node.");
pulse::message msg = {};
bool in_quorum = false;
for (size_t index = 0; index < quorum.validators.size(); index++)
{
if (quorum.validators[index] == core.get_service_keys().pub)
{
msg.handshakes.quorum_position = index;
in_quorum = true;
break;
}
}
if (!in_quorum)
if (auto it = std::find_if(quorum.validators.begin(), quorum.validators.end(),
[&mypk=core.get_service_keys().pub] (auto const &pk) { return pk == mypk; }); it == quorum.validators.end())
throw std::runtime_error("Pulse: Could not find this node's public key in quorum");
else
msg.handshakes.quorum_position = it - quorum.validators.begin();
auto command = (sending_bitset) ? PULSE_CMD_SEND_VALIDATOR_BITSET : PULSE_CMD_SEND_VALIDATOR_BIT;
if (sending_bitset)
@ -1638,10 +1629,6 @@ void handle_pulse_participation_bit_or_bitset(Message &m, QnetState& qnet, bool
} else {
throw std::invalid_argument(std::string(INVALID_ARG_PREFIX) + std::string(PULSE_TAG_SIGNATURE) + "'");
}
assert(validator_bitset != -1);
assert(quorum_position != -1);
assert(signature);
}
else
{
@ -1657,9 +1644,6 @@ void handle_pulse_participation_bit_or_bitset(Message &m, QnetState& qnet, bool
} else {
throw std::invalid_argument(std::string(INVALID_ARG_PREFIX) + std::string(PULSE_TAG_SIGNATURE) + "'");
}
assert(quorum_position != -1);
assert(signature);
}
pulse::message msg = {};

View File

@ -38,8 +38,6 @@
#undef LOKI_DEFAULT_LOG_CATEGORY
#define LOKI_DEFAULT_LOG_CATEGORY "daemon"
using namespace std::literals;
namespace daemonize {
command_parser_executor::command_parser_executor(std::string daemon_url, const std::optional<tools::login>& login)
@ -526,14 +524,14 @@ bool command_parser_executor::start_mining(const std::vector<std::string>& args)
}
if (info.is_subaddress)
{
tools::fail_msg_writer() << "subaddress for mining reward is not yet supported!" << std::endl;
tools::fail_msg_writer() << "subaddress for mining reward is not yet supported!";
return true;
}
if(nettype != cryptonote::MAINNET)
std::cout << "Mining to a " << (nettype == cryptonote::TESTNET ? "testnet" : "devnet") << " address, make sure this is intentional!" << std::endl;
std::cout << "Mining to a " << (nettype == cryptonote::TESTNET ? "testnet" : "devnet") << " address, make sure this is intentional!";
std::string_view threads_val = tools::find_named_argument(args.begin() + 1, args.end(), "threads="sv);
std::string_view num_blocks_val = tools::find_named_argument(args.begin() + 1, args.end(), "num_blocks="sv);
std::string_view threads_val = tools::find_prefixed_value(args.begin() + 1, args.end(), "threads="sv);
std::string_view num_blocks_val = tools::find_prefixed_value(args.begin() + 1, args.end(), "num_blocks="sv);
int threads_count = 1;
uint32_t num_blocks = 0;
@ -545,8 +543,13 @@ bool command_parser_executor::start_mining(const std::vector<std::string>& args)
}
else
{
bool ok = tools::parse_int(threads_val, threads_count);
threads_count = (ok && 0 < threads_count) ? threads_count : 1;
if (!tools::parse_int(threads_val, threads_count))
{
tools::fail_msg_writer() << "Failed to parse threads value" << threads_val;
return false;
}
threads_count = 0 < threads_count ? threads_count : 1;
}
}

View File

@ -153,8 +153,13 @@ void command_server::init_commands(cryptonote::rpc::core_rpc_server* rpc_server)
m_command_lookup.set_handler(
"start_mining"
, [this](const auto &x) { return m_parser.start_mining(x); }
, "start_mining <addr> [threads=(<threads>|auto) [num_blocks=<num>]"
#if defined NDEBUG
, "start_mining <addr> [threads=(<threads>|auto)"
, "Start mining for specified address. Defaults to 1 thread; use \"auto\" to autodetect optimal number of threads."
#else
, "start_mining <addr> [threads=(<threads>|auto) [num_blocks=<num>]"
, "Start mining for specified address. Defaults to 1 thread; use \"auto\" to autodetect optimal number of threads. When num_blocks is set, continue mining until the (current_height + num_blocks) is met, irrespective of if this Daemon found those block(s) or not."
#endif
);
m_command_lookup.set_handler(
"stop_mining"

View File

@ -48,8 +48,6 @@
#include "p2p/p2p_protocol_defs.h"
#include "string_tools.h"
using namespace std::literals;
namespace
{
constexpr const std::chrono::milliseconds future_poll_interval = 500ms;

View File

@ -61,7 +61,6 @@ DISABLE_VS_WARNINGS(4355)
namespace nodetool
{
using namespace std::literals;
struct proxy
{
proxy()

View File

@ -3291,8 +3291,10 @@ namespace cryptonote { namespace rpc {
//------------------------------------------------------------------------------------------------------------------------------
TEST_TRIGGER_UPTIME_PROOF::response core_rpc_server::invoke(TEST_TRIGGER_UPTIME_PROOF::request&& req, rpc_context context)
{
if (m_core.get_nettype() != cryptonote::MAINNET)
m_core.submit_uptime_proof();
TEST_TRIGGER_UPTIME_PROOF::response res{};
m_core.submit_uptime_proof();
res.status = STATUS_OK;
return res;
}

View File

@ -4592,6 +4592,16 @@ std::optional<epee::wipeable_string> simple_wallet::open_wallet(const boost::pro
//----------------------------------------------------------------------------------------------------
bool simple_wallet::close_wallet()
{
try
{
m_wallet->store();
}
catch (const std::exception& e)
{
fail_msg_writer() << e.what();
return false;
}
if (m_idle_run.load(std::memory_order_relaxed))
{
m_idle_run.store(false, std::memory_order_relaxed);
@ -4610,16 +4620,6 @@ bool simple_wallet::close_wallet()
return false;
}
try
{
m_wallet->store();
}
catch (const std::exception& e)
{
fail_msg_writer() << e.what();
return false;
}
return true;
}
//----------------------------------------------------------------------------------------------------
@ -5081,11 +5081,7 @@ bool simple_wallet::refresh_main(uint64_t start_height, enum ResetType reset, bo
ss << tr("unknown error");
}
if (ok)
{
m_wallet->store();
}
else
if (!ok)
{
fail_msg_writer() << tr("refresh failed: ") << ss.str() << ". " << tr("Blocks received: ") << fetched_blocks;
}

View File

@ -90,8 +90,6 @@ class wallet_accessor_test;
LOKI_RPC_DOC_INTROSPECT
namespace tools
{
using namespace std::literals;
static const char *ERR_MSG_NETWORK_VERSION_QUERY_FAILED = tr("Could not query the current network version, try later");
static const char *ERR_MSG_NETWORK_HEIGHT_QUERY_FAILED = tr("Could not query the current network block height, try later: ");
static const char *ERR_MSG_SERVICE_NODE_LIST_QUERY_FAILED = tr("Failed to query daemon for service node list");

View File

@ -68,7 +68,6 @@ using namespace tools::wallet_rpc;
namespace
{
using namespace std::literals;
constexpr auto DEFAULT_AUTO_REFRESH_PERIOD = 20s;
const command_line::arg_descriptor<uint16_t, true> arg_rpc_bind_port = {"rpc-bind-port", "Sets bind port for server"};